Home | 2013 | 02 | 17 | Siri Proxy und Arduino

Siri Proxy und Arduino

17. Februar 2013 von pulponair

Irgendwann zwischen den Jahren hab ich aus Langeweile angefangen meine Schreibtisch aufzuräumen. Dabei ist mir aufgefallen, das ich ja eigentlich ganz schön viele Microcontroller rumliegen habe. Und weil Aufräumen irgendwie doof ist und ich  mal ein Video gesehen hab in dem ein Typ sein Garagentor mit via Siri auf und zu macht, hab ich aufgehört aufzuräumen und angefangen damit rumzuspielen.

Wenn man möchte, das Siri andere Sachen macht, als das was Apple so vorgesehen hat, muss man erstmal wissen, wie Siri so grob funktioniert. Das ist im Prinzip schnell erklärt: Wenn man Siri was erzählt, dann schickt sie (oder es) die Sprachinformation an einen Appleserver zur Auswertung. Als Antwort gibt es dann, dass was der Appleserver meint verstanden zu haben in klartext zurück plus das, was Siri machen soll.

Wenn man weiss, das der Server guzzoni.apple.com heisst, dann kann man, zumindest solang man im eigenen WLAN ist, die Anfragen leicht auf eine eigene Kiste umbiegen indem man einfach einen entsprechenden Eintrag im lokalen DNS vornimmt.

Schlaue Menschen, die noch mehr Langeweile haben als ich, haben dafür extra Proxy Software gepuzzelt. Die macht im Prinzip nichts weiter, als die Anfragen an Apple weiter zu leiten und dann die Antwort abzufangen und ggf. eine eigene zu schicken.

Ganz gut funktioniert z.B. diese hier: https://github.com/jimmykane/The-Three-Little-Pigs-Siri-Proxy

Man kann den Kram auch relativ kompfortable mit eigenen Plugins erweitern. Im Prinzip läuft das so, das man die Klartext Antwort gegen ein regex pattern matched und dann was auch immer damit veranstaltet. Die API von dem Proxy stellt einige Methode zur Steurung zur Verfügung. So kann man Siri z.B. Dinge sagen lassen oder ein Bild anzeigen usw. Und man kann natürlich Proxyserver seitig veranstalten was man möchte.

Der Proxyserver ist in Ruby geschrieben und codemässig sieht ein Plugin dann etwa so aus:

class SiriProxy::Plugin::Arduino < SiriProxy::Plugin
  listen_for /Led an/i do
    say "Es werde Licht!"
    sp = SerialPort.new('/dev/ttyUSB0', 9600)
    sp.write "LED ON\n"
    sp.close
    request_completed
  end
end

Siri seitig ist man damit dann im Prinzip durch. Wenn man das ganze jetzt mit nem Microcontroller verheiraten will, in dem Fall nen kleiner Arduino, muss man natüerlich dafür sorgen, das der Proxyserver mit dem Controller spricht. Das geht am einfachsten über die serielle Schnittstelle, wie der geneigte Leser bereits erkannt haben mag.

Weil ich faul bin und mir die Kommunikation über die serielle Schnittstelle sparen wollte, hab ich mich einer Protokoll Library von Steven Cogswell (http://husks.wordpress.com/2011/05/23/a-minimal-arduino-library-for-processing-serial-commands/) und Stefan Rado (https://github.com/kroimon/Arduino-SerialCommand) bedient.

Danke Jungs!

Damit kann man easy eigene Funktionen an serielle Kommandos binden. Ich hab leider immer nur wenig elktronische Bauteile daheim, daher musste ich mich auf das Steuern einer Led und das auslesen eines DS1820 Temperatur Sensors beschränken (der Sensor hat auch noch nen Knall und zeigt 3 grad zu viel an). Da geht natürlich noch viel mehr.
Code seitig sieht das dann so aus:

#include 
#include "SerialCommand.h"
#include "DallasTemperature.h"

#define LED 13
#define ONE_WIRE_BUS 3

static const char *status[] = {
	"OFF", "ON"
};

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
bool blink = false;

SerialCommand SCmd;

void led();
void temperatur();

void unrecognized(const char *command);

void setup () {

	pinMode(LED, OUTPUT);
	digitalWrite(LED, LOW);

	Serial.begin(9600);
	Serial.flush();

	SCmd.addCommand("LED", led);
	SCmd.addCommand("TEMPERATURE", temperatur);	
	SCmd.setDefaultHandler(unrecognized);	

	sensors.begin();

	Serial.println("Ready");
}

void loop (){
	SCmd.readSerial();			
	if (blink == true) {
		digitalWrite(LED, (digitalRead(LED) + 1) % 2);
		delay(250);
	}

}

void led() {
	char *arg = SCmd.next();

	if (strncmp(arg, status[0], 3) == 0) { 
		digitalWrite(LED, LOW);
	}

	if (strncmp(arg, status[1], 2) == 0) {
		digitalWrite(LED, HIGH);
	}

	if (strncmp(arg, "BLINK", 5) == 0) {
		blink = (blink == true ? false : true);
		digitalWrite(LED, LOW);
	}

	if (strncmp(arg, "STATUS", 6) == 0) {
		Serial.println(status[digitalRead(LED)]);
	}	
}

void temperatur() {		
	sensors.requestTemperatures();
		// Sensor seems to be broken
	Serial.println(sensors.getTempCByIndex(0) - 3);	
}

void unrecognized(const char *command) {
	Serial.println("What?");
}

Die ganze Nummer läuft überigens in ner Virtualbox auf nen Debian Linux.  Für den Microcontroller Part nimmt man amtlicherseits AtmelStudio. Diese original Sketch Nummer ist echt was für Puristen.

Und das das ganze funktioniert kann man hier sehen:

YouTube Preview Image

Ach so: das Poti da hat keine besondere Funktion. Ich hatte einfach keinen passenden Pull – Wiederstand für den Sensor und musste mir daher anders behelfen.

Wie man sieht, kann man nie genung Microcontroller haben.
Das ding gibt’s einzelnt z.B. hier:
[asa default_de]B008GRTSV6[/asa]

Oder, gleich mit Klimbim im Set, damit man nicht, wie ich ständig „Potis“ missbrauchen muss:
[asa default_de]B00719T7BG[/asa]

Happy Basteling! 😉

Eine Reaktion zu “Siri Proxy und Arduino”

  1. pulponair

    Ja, mir ist nichts besseres eingefallen ;).

Einen Kommentar schreiben