SIRI like Spracherkennung unter MacOS Mountain Lion

Geht momentan nicht? Aber hallo wie gut das mit einem kleinen Umweg geht!

Seit kurzem ist Mountain Lion mit der Diktierfunktion raus (für mich genauso unbrauchbar wie am iPad 3). Auch wenn ich es nie zum Diktieren benutzen wollte ist es für eine Steuerung der Hausautomation prinzipiell prädestiniert, da die Erkennungsquote sehr gut ist und die Spracherkennung einen String zurückliefert den man sehr leicht in Skripten auswerten kann. So habe ich mal ein wenig getestet und war begeistert!

1. Feststellung: die Diktierfunktion ist relativ zügig
2. Feststellung: die Diktierfunktion erkennt ein Terminal Fenster als „Textbox“

Der schnellste Weg führte natürlich in Richtung AppleScript, da ich das schon ganz gut drauf habe.

Bevor wir zum Scripting kommen, die Vorbereitungen, damit das prinzipiell jeder umsetzen kann, was ich hier erkläre:

1. Diktierfunktion in den Systemeinstellungen aktivieren

Und den Kurzbefehl zum Aktivieren der Diktierfunktion auf:

2. Sprachausgabe auf Deutsch Stimme „Steffi“ einstellen
einfach im Fenster der Diktierfunktion den Reiter auf „Sprachausgabe“ wechseln

3. In den Bedienungshilfen die „speakable items“ aktivieren

Darauf hin erscheint der Controller

Nun können wir zu den beiden Scripten kommen. Das erste ist ein Hilfsscript welches durch die „speakable item“ ausgelöst wird. Dieses wird später in den Pfad der verfügbaren Sprachbefehle kopiert, wo sich die leider alle in Englisch gesprochenen rudimentären Sprachbefehle von MacOS befinden.

Nun das Script voicehelper.scpt

tell application "Terminal" to activate
delay 1
tell application "Terminal" to activate
tell application "System Events"
    tell process "Terminal"
        -- Bitte den Pfad auf den eigenen Benutzerordner anpassen!
        keystroke "cd /Users/max/Desktop/ac_voice/" & return
        keystroke "osascript voice.scpt "
        keystroke (ASCII character 34)
        delay 1
        keystroke "d" using command down
        delay 5
        keystroke "d" using command down
        delay 1
        keystroke (ASCII character 34)
        key code 76 -- Enter auf Nummernblock
        delay 5
        --keystroke "q" using command down -- beendet TextEdit per Apfel-Q
    end tell
end tell
tell application "Terminal" to quit

Das Script manipuliert schlicht das Terminalfenster und übergibt so das Gesprochene an das eigentliche „intelligente“ Script voice.scpt weiter, welches die Worte in Befehle umsetzt.

voicehelper.scpt muss z.B. in home.scpt umbenannt werden (vorzugsweise als Duplikat) und dann in den „speakable items“ Ordner in der Benutzerlibrary kopiert werden, damit es dort als neuer Sprachbefehl erkannt wird.

Nun das Script voice.scpt :

Der Aufruf aus dem Terminal sieht quasi so aus: osascript voice.scpt „Schalte das Licht in der Küche ein“

-- URL für Homematic XMLAPI Request
property XMLAPI : "http://192.168.1.10:90/xmlapi/statechange.cgi"

on run this_file
    set voicecommand to " "
    set goodcommand to 0
    --say (this_file)
    set voicecommand to (this_file) as text
    --say voicecommand

    if voicecommand contains "Kaffee" then
        set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=15961&new_value=true'"
        set goodcommand to 1
    end if

    if voicecommand contains "Abend" then
        set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=7765&new_value=false'"
        set goodcommand to 1
    end if

    if voicecommand contains "Alles aus" then
        set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=7773&new_value=false'"
        set goodcommand to 1
    end if

    if voicecommand contains "Siri" then
        say "Verdammt hör auf mich so zu nennen! Ich bin 10 mal besser als Siri."
        set goodcommand to 1
    end if

    if voicecommand contains "hass" then
        say "Das beruht ganz auf Gegenseitigkeit. Wenn du mich so hasst dann schalte ich halt keine Lichter mehr für dich!"
        set goodcommand to 1
    end if

    if voicecommand contains "versteh" then
        say "Dann sprich deutlicher."
        set goodcommand to 1
    end if

    if voicecommand contains "Jalousien" then
        if voicecommand contains "runter" then
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=36931&new_value=0.0'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33590&new_value=0.0'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33565&new_value=0.0'"
            set goodcommand to 1
        end if

        if voicecommand contains "hoch" then
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=36931&new_value=1.0'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33590&new_value=1.0'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33565&new_value=1.0'"
            set goodcommand to 1
        end if

        if voicecommand contains "stop" then
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=36932&new_value=true'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33591&new_value=true'"
            set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=33566&new_value=true'"
            set goodcommand to 1
        end if
    end if

    if voicecommand contains "Licht" then
        if voicecommand contains "Küche" then
            if voicecommand contains "ein" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1465&new_value=true'"
                set goodcommand to 1
            end if
            if voicecommand contains "aus" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1465&new_value=false'"
                set goodcommand to 1
            end if

        end if
        if voicecommand contains "Vitrine" then
            if voicecommand contains "ein" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1494&new_value=true'"
                set goodcommand to 1
            end if
            if voicecommand contains "aus" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1494&new_value=false'"
                set goodcommand to 1
            end if

        end if
        if voicecommand contains "Wandlampe" then
            if voicecommand contains "ein" or "ein" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1623&new_value=true'"
                set goodcommand to 1
            end if
            if voicecommand contains "aus" or "aus" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of (XMLAPI & "?") & "' -d 'ise_id=1623&new_value=false'"
                set goodcommand to 1
            end if

        end if
    end if

    if voicecommand contains "led" then
        if voicecommand contains "Wohnzimmer" then
            if voicecommand contains "orange" then
                -- Ansteuerung LED Controller
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Za255a72a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "blau" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Za21a0a255a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "rot" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Za255a0a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "grün" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Za0a255a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "aus" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Za0a0a0a5'"
                set goodcommand to 1
            end if

        end if
        if voicecommand contains "Kugel" then
            if voicecommand contains "orange" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Ya255a72a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "blau" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Ya21a0a255a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "rot" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Ya255a0a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "grün" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Ya0a255a0a5'"
                set goodcommand to 1
            end if

            if voicecommand contains "aus" then
                set ReturnValue to do shell script "curl  -s '" & quoted form of ("http://192.168.1.20:8080/ledcontr/contr.php?" & "?") & "' -d 'com=Ya0a0a0a5'"
                set goodcommand to 1
            end if

        end if

    end if

    if goodcommand = 0 then
        say "Entschuldigung. Ich verstehe den Befehl, " & voicecommand & ", nicht."
    end if

end run

Durch die Verschachtelung wird ohne weiteres zutun ein Satz wie: „Schalte das Licht in der Küche aus“ ausgewertet nach den Kriterien „Licht“ & „Küche“ & „aus„. Vom Sinn kann also auch ohne Probleme „Licht Küche aus“ oder „Bitte das Licht in der Küche ausschalten“ gesagt werden 🙂

Das voice-Script kann so nach eigenen Bedürfnisses quasi grenzenlos erweitert werden…

Build your own Siri !

Ich war echt erstaunt, wie gut das mit den verschachtelten IF-Bedingungen geklappt hat 🙂 Geht mit Sicherheit eleganter, ist vielleicht ein guter Denkanstoß für Andere…

Das komplette Paket mit den Scripten gibts hier zum Download…

click

Hier noch ein Video vom Einsatz der Scripte:

Fragen und Anmerkungen willkommen! Bitte zeigt dann euere Projekte, falls Ihr meinen Quellcode verwendet oder ihn als Denkanstoß nutzt.

Nachtrag „Tips & Trick“ Ansteuerbare Geräte und Haussteuerungen:

Ich verwende, wie an vielen Stellen erwähnt, die Homematic Steuerung (CCU-1) von ELV. Die Zentrale hat ein AddOn „XMLAPI“ installiert welche auf einem 2. Webserver über (wie im Skript) CURL angesprochen wird. Stellvertretend kann man also über einfache HTTP Request so ziemlich alle anderen Systeme ansteuern. (Beispiele wo es sofort ohne Weiteres möglich ist: Dreambox, IR-Trans, Homematic mit XMLAPI). Bei der Dreambox kann man über das Webinterface alle Tasten der Fernbdienung „drücken“ und somit das Fernsehen per Sprache kontrollieren. Beim IR-Trans in Verbindung mit der Gerätedatenbank selbiges für alle angelernten IR Befehle.

VN:F [1.9.22_1171]
Rating: 4.3/5 (9 votes cast)

Homematic Klapp-Statusanzeige

…absolut überflüssig aber irgendwie lustig

Und vorallem habe ich diesmal einen Anwendungszweck: mein Schild am Büro ob jemand da ist oder unterwegs 🙂

Aber vorher muss es zusammengebaut werden:

Tadaa…

Insgesamt aufzulötende Bauteile: 2
Anzuschließende Kabel: 4

Taster mit integrierter LED…

Ob das der gleiche Motor ist wie beispielsweise in den Heizungsstellern?

Mechanik zusammenbauen…

Die üblichen kleinen Torx-Schrauben kommen zum Einsatz

Das Klappschild-Plättchen

Auf an die Elektronik…

Taster und Quarz

Transreceiver

Kabel der Batteriehalterung einfädeln

Kabel Motor…

Fädel, fädel – Antenne am Rand oben

Super spektakulärer Zusammenbau der nun auch schon abgeschlossen ist…
Die Technik kommt in eines der neu designten Halbschalengehäuse zum zusammenschieben, wie es auch in einer kleineren Bauweise beim Webradio zum Einsatz gekommen ist.

Yeaahhh

Ohhhh…

Abschließend noch ein kurzes Video in Aktion:

Das Einbinden in der Homematic zeige ich diesmal nicht – ist genauso wie bei einem normalen Schaltaktor. Als Geräteoption besteht die Möglichkeit die interne LED zu aktivieren oder eben nicht. Diese leuchtet dann im Zustand „Ein“. Ansonsten gibt es nicht viel zu berichten. Eine Möglichkeit den Motor anders anzusteuern bietet die Firmware und Homematic WEB UI nicht (schade aber wie sollte es anders sein – zweckentfremden nicht erwünscht).

Fragen dürfen gerne gestellt werden – wenn mein neues Schild fertig ist gibts ein Foto 😉

VN:F [1.9.22_1171]
Rating: 5.0/5 (2 votes cast)

Homematic LED-Statusanzeige

 … lange drauf gewartet aber leider etwas mager von der Funktion

Aufgrund dessen, dass einer meiner Kunden so ein Teil haben wollte und die Lieferzeiten so lange sind, habe ich 2 Bausätze bestellt und Ihn heute zusammengebaut.

Im Lieferumfang – viele Kleinteile aber wenig notwendige und zu bestückende Bauteile. Manchmal stellt sich die Frage, warum die wenigen Bauteile nicht auch gleich vom ELV bestückt werden…

Von der Platine müssen diese, mit einer Sollbruchstelle befestigten Anstandhalter abgetrennt werden. Die Grate habe ich dann mit einer Nagelfeile abgeschliffen…

Die Abstandshalter werden dann in die beiden vorgesehen Schlitze in der LED Maske eingesteckt.

Die Abstandshalter halten später die Diffusorfolie in Position und ergeben die Kammer für das Beschriftungsblättchen was der Anwender später zur Beschriftung einlegen kann. (was heißt kann, ohne macht das Teil vielleicht nur noch als Binäruhr Sinn ;-))

Nun geht es ans Bestücken der überschaubaren Anzahl an Bauteilen.

Zuerst die Kondensatoren…

Dann der Transreceiver, bei dem zuerst die Pinleiste eingelötet werden muss…

Auf der Oberseite wird nun die Transreceiverplatine augesteckt und angelötet…

Jetzt fehlt nun noch die Stromversorgungsbuchse.

Sitzt…

Das war der ganze „Zusammenbau“ der Platine. Nun müssen nur noch die ganzen Gehäuseteile zusammengefriemelt werden.

Im Deckel des Gehäuses werden nun links und rechts die Diffusorfolien eingelegt.
Darauf wird dann die LED-Maske gelegt, die Abstandshalter halten nun die Diffusorfolien in Position.

Darauf wird die Platine eingelegt und mit Hilfe der Kunststoffzapfen arretiert. Die Antenne des Transreceivers verschwindet hinter den Stegen an der Innenseite links oben. Die Platine wird nun noch an den vorgesehenen Stellen mit den kleinen beigelegten Torx Schrauben am Gehäuse befestigt.

Nun werden noch die Kunststoffknöpfe auf die Taster gelegt, dann kann die Untere Hälfte des Gehäuses aufgesezt und verschraubt werden.

So sollte das dann von Oben ausschauen…

Jetzt noch die beiden Standfüsse reinklicken und den Stromstecker einstecken und das Kabel in die Kerbe (der verstümmelten Batteriehalterungen ^^) als Schlaufe einstecken.

Deckel drauf und das wars…

Selbsttest nach Einstecken der Stromversorgung…
grün-rot-gelb aus… Bereit zum anlernen.

Ab ins CCU Interface und den Anlernmodus aktiviert…

Nun noch hinten and er Anzeige auf Pfeil hoch / learn drücken und warten bis die LED 1 grün blinkt und dann schneller blinkt bis sie ausgeht und schon sollte die Anzeige im Geräte-Posteingang erscheinen…

Schnell ein Testprogramm zusammenklicken: Öffnungskontakt am Oberlicht – Status übermitteln; Oberlicht auf LED1 – rot, Oberlicht zu auf LED1 – grün

Und fertig und klappt..

Fazit: ich werd das Teil vermutlich nicht brauchen und nun irgendwo zusammengabaut an die Frau oder den Mann bringen 😉
Für mich wäre sowas erst interessant wenn es aus einem Oleddisplay bestehen würde, wo die Beschriftungen „draufstehen“ und evtl. noch mehr Möglichkeiten durch Anzeige von grafischen Elementen eröffnet werden. Für das was alleine der Bausatz kostet ist die Ausstattung mehr als Mager und das finde ich sehr Schade.

Fragen und Anregungen willkommen …

Achja hier noch ein kleines Beispiel wenn man „Scripten“ möchte:

var x = dom.GetObject("BidCos-RF.JEQXXXXXX:1.ALL_LEDS").State(255);

Diese Zeile schaltet die ersten 4 LEDs auf gelb… Sobald ich den Zyklus der Binärverschaltung raus habe teile ich das hier mit…

Hier noch ein Einfacher Zähler zum rumtesten:

integer statcounter = dom.GetObject("statcounter");
!var f = statcounter.State(0);
var f = statcounter.State(statcounter.State() + 3);

var x = dom.GetObject("BidCos-RF.JEQXXXXXXX:1.ALL_LEDS").State(statcounter.State().ToInteger());
WriteLine(statcounter.State().ToInteger());

!Bitte die Systemvariable statcounter anlegen...

Kleines Beispiel für das aufleuchten lassen von jeweils einer LED:

Im Prinzip geht es hier um das „kleine 1×1“ 😉
1 rot = 1
2 rot = 4 (1 * 4)
3 rot = 16 (4 * 4)
4 rot = 64 (16 * 4)
usw.

1 grün = 2
2 grün = 8 (2 * 4)
3 grün = 32 (8 * 4)
4 grün = 128 (32 * 4)
usw.

1 gelb = 3
2 gelb = 12 (3 * 4)
3 gelb = 48 (12 * 4)
4 gelb = 192 (48 * 4)
usw.

Auf diese weise lassen sich alle anzeigbaren Kombinationen auf der Statusanzeige darstellen. Auch der spasseshalber erwähnten Binäruhr stünde nichts im Wege 😛
Ich denke gerade über den Rechenfaktor für eine Balkenanzeige nach… Bestimmt keine hohe Wissenschaft, ich poste es trotzdem hier 😉

Noch ein paar Tests:

integer statcounter = dom.GetObject("statcounter");
!var f = statcounter.State(2);
var f = statcounter.State(statcounter.State() * 4);

var x = dom.GetObject("BidCos-RF.JEQXXXXXX:1.ALL_LEDS").State(statcounter.State().ToInteger());
WriteLine(statcounter.State().ToInteger());

!Bitte die Systemvariable statcounter anlegen und auf 2 initialisieren...

VN:F [1.9.22_1171]
Rating: 5.0/5 (4 votes cast)