Mit Alexa die Thermostate der FRITZ!Box steuern – ohne Skill und Cloud dank Node-RED
Kürzlich habe ich mir die DECT 301 Thermostate von AVM für die Steuerung mit der FRITZ!Box zugelegt. Leider gibt es derzeit noch nicht die Möglichkeit, diese via Alexa zu steuern. Die Möglichkeit, die ich fand und auch in der FAQ von AVM vorgeschlagen wird, ist mir nicht so ganz geheuer. Ja, der Skill funktioniert sehr gut, aber so richtig wohl ist mir dabei nicht, einen Zugang (wenn auch nur auf SmartHome beschränkt) direkt auf meine Fritzbox zuzulassen.
Also habe ich mir eine lokale Lösung gesucht und da ich mir Node-RED eh schon seit Wochen mal ansehen wollte, war nun auch ein konkreter Anwendungsfall ins Haus geflattert. ;-)
Node-RED habe ich als Docker Image auf dem Synology-NAS installiert, wie das geht ist ja hinreichend im Netz zu finden.
Um nun das zu bewerkstelligen, was mir vorschwebte, benötigt man folgende Nodes:
- https://flows.nodered.org/node/node-red-contrib-alexa-local
- https://flows.nodered.org/node/node-red-contrib-fritz
Alexa Local simuliert eine HUE-Bridge und bietet so eine Möglichkeit ein/aus/dimmen-Befehle zu empfangen und per Flow zu verarbeiten.
Fritz unterstütz die komplette TR64-API der FRITZ!Box. Nach etwas lesen der Doku bei AVM habe ich leider keine Möglichkeit gefunden, die Temperatur dort zu setzen, sondern nur sie zu lesen. Dann stolperte ich über die AHA-HTTP-Implementierung, die es möglich macht, die Temperatur auch zu setzen. Nun nutze ich also den Fritz-Node um eine Session ID zu bekommen (DeviceConfig::X_AVM-DE_CreateUrlSID). Mit dieser baue ich mir dann eine URL nach dem Format:
http://fritz.box/webservices/homeautoswitch.lua?sid=<sid>
Diese wird sich gemerkt und später um die „Eingaben“ des Alexa-Node ergänzt. Dafür ist dann wichtig, dass die Namen der Alexa „Geräte“ identisch zu den Namen in der FRITZ!Box sind. Danach mache ich gleich schon einen ersten Request, um alle in der FRITZ!Box bekannten SmartHome Aktoren und Gruppen zu bekommen.
http://fritz.box/webservices/homeautoswitch.lua?sid=<sid>&switchcmd=getdevicelistinfos
Ich wollte hier vermeiden, einen kompletten Flow für jede Aktion zu haben. Ich lade mir also alle Bezeichnungen und speichere dazu die AIN die man benötigt, um einen Schaltvorgang durchzuführen. Dazu geht die Antwort durch eine XMLtoJSON Node und dann durch meinen Function-Node.
Allocate all Names to ANI:
var all = msg.payload.devicelist.device.concat(msg.payload.devicelist.group); global.set('fritzDevices', all.reduce(function(sum, id){ sum[id.name[0]] = id.$.identifier.split(' ').join(''); return sum; },{}) ); return {payload: global.get('fritzDevices')};
Diese kann ich dann später nutzen, um von der Eingabe auf die AIN zu gelangen.
Build URL for setting temperature:
var url = global.get('fritzURL'), devices = global.get('fritzDevices'); if (devices[msg.device_name]){ msg.bri = msg.bri === 0 ? 253 : msg.bri / 0.5; url = url + '&ain='+devices[msg.device_name]+'&switchcmd=sethkrtsoll¶m=' + msg.bri } return {url: url};
Die 253 wird gesetzt, wenn über den Alexa Node der Befehl für AUS kommt, sonst muss der Wert in Celsius durch 0,5 geteilt werden um auf den Wert zu kommen den die API von AVM da vorgibt.
Zusammen sieht das Ganze dann so aus. Ich habe den Teil der SID und AIN Beschaffung in eine SubFlow ausgelagert, um die eigentliche Befehlsverarbeitung etwas übersichtlicher zu haben.
Die Gruppe nutze ich dann, um z.B. bei dem Satz „Alexa mir ist kalt.“ per Routine alle Heizungen mit einem Befehl auf z.B. 24° zu stellen.
Grundsätzlich ist es so jetzt möglich die Heizung aus: „Alexa, Heizung Küche aus“ oder auf eine bestimmte Temperatur zu stellen: „Alexa, Heizung Küche auf 23“. Da Alexa hier denkt, es sind Lampen, muss man sich das Grad dahinter „verkneifen“.
Update 04.12.2018
Ich habe noch etwas weiter gebastelt und das Dashboard von Node-RED mit eingebunden:
Und dazu mal eine Live-Demo gemacht:
Die Temperatur vom Computerzimmer ist absichtlich auf maximal 21°C :-)