Node Red Ikea tradfri 2 Tasten Taster
Ikea bietet für 6€ einen günstigen ZigBee-fähigen Dimmer an (https://www.ikea.com/de/de/p/tradfri-kabelloser-dimmer-weiss-70408595/). Diesen habe ich über einen ConBee II (Dresden Elektronik) angebunden. Ich möchte ihn über Node Red steuern können. Dafür nutze ich den Adapter node-red-contrib-deconz 1.1.10 und ioBroker mit dem Tradfri Adapter.
Der Taster liefert 6 verschiedene Statuscodes:
- 1002 – Eingeschalten (I)
- 2002 – Ausgeschalten (O)
- 1001 – Start von I wird gedrückt gehalten (Long PRESS)
- 1003 – Ende von I wird gedrückt gehalten
- 2001 – Start von O wird gedrückt gehalten (Long PRESS)
- 2003 Ende von O wird gedrückt gehalten
Mit den Werten 1002 und 2002 kann man nun einfach über einen switch ein on/off Beispiel bauen.
hier ein Beispiel für den Heizstrahler der nach dem Anschalten maximal. 15min an sein darf. Das kann durch erneutes drücken wiederholt bzw. auf 15min zurück gesetzt werden. “Display Payload” ist ein Subflow der den msg.payload auf Status mit schickt und somit unter dem Element anzeigt. Nachfolgend der Code dafür
[{"id":"9fd20961.36f768","type":"subflow","name":"Display Payload","info":"","category":"","in":[{"x":50,"y":30,"wires":[]}],"out":[{"x":140,"y":100,"wires":[{"id":"9fd20961.36f768","port":0}]}],"env":[],"color":"#DDAA99","status":{"x":160,"y":30,"wires":[{"id":"9fd20961.36f768","port":0}]}}]
Dimm Funktion
Wir wollen nun aber auch das lange drücken mit Auswerten. Dazu nutze ich zusätzlich noch node-red-contrib-simple-gate um ein Element zu haben, was ähnlich einem Tor steuerbar ist und den Inhalt einfach durchleitet.
Die Idee zum dimmen ist nun folgende: Mit dem langen Drücken von I oder O (1001 bzw. 2001) wird das Gate geöffnet und mit 1003 bzw. 2003 (Loslassen von I bzw. O) wird das Gate geschlossen.
Zyklich wird nun ein Inject (einmal pro Sekunde) auf das Gate geschickt. Kommt es durch wird der Helligkeitswert geändert.
Jetzt muss man vorab noch die “Richtung”, also hoch zählen oder runter zählen definieren. Dazu werten wir auch den Start des langen Drückens mit aus und setzen intern den Wert für die Zählrichtung.
Kommt nun ein Wert durch das Gate wird der aktuelle Wert plus gerechnet mit dem Produkt aus dem Wert wie stark es sich ändern soll und der Richtung (1 für hoch und -1 für runter) also wenn der Wert 50 ist und die Stufenbreite 10 wäre das beim Runter zählen: 50 + (10 * -1) = 40.
Geht der Wert über die Grenze von 1-100 hinaus wird er zurück gesetzt auf den Grenzwert.
var brightness = parseInt(flow.get('Brightness')) || 1;
var step = parseInt(env.get('StepBrightness')) || 10;
var direction = parseInt(msg.payload) || 1;
var newBrightness = brightness + (step * direction);
if (newBrightness > 100) newBrightness = 100;
if (newBrightness < 1) newBrightness = 1;
flow.set('Brightness', newBrightness); // save new value
msg.payload = newBrightness;
return msg;
Anschließend wird der neue Helligkeitswert aus gegeben.
Doppelklick
Auch einen Doppelklick kann man realisieren. In der Ereignisgetriebenen Entwicklung kennen wir aber nicht die Dimension Zeit. Das heißt wir wissen nicht was man vorher geklickt hat, wie lange das her ist oder wie oft. Daher werden wir vorher ein Subflow bauen, welcher speichert wie oft ein Ereignis in einer bestimmten Zeit kam. Das geht ganz einfach, indem wir den Zeitstempel (Eintreffen eines Events) in ein Array legen und im Flow speichern. Danach werden alle Einträge entfernen, welche älter sind als unser Messzeitraum. Und am Ende zählen wir die Elemente und geben die Zahl aus.
Das sieht erstmal recht unspektakulär aus:
var now = Math.floor(Date.now() / 1000 ) || 0;
function RemoveOld(ts){
var diff = env.get('TimeRangeInSeconds') || 5;
var now = Math.floor(Date.now() / 1000 ) || 0;
var now2 = now - diff;
return Math.floor(ts) > now2;
}
var data = flow.get('data') || "[]";
data = JSON.parse(data);
data.push(now);
data=data.filter(RemoveOld);
msg.payload = data.length;
flow.set('data', JSON.stringify(data));
return msg;
Über Umgebungsvariablen wird hier die Zeit übergeben. Wird der Wert nicht gesetzt wird 5 als Standard angenommen.
Mit diesem Subflow können wir nun den Wert 1002 zählen lassen. Ist dieser größer/gleich 2 können wir ein Doppelklick-Ereignis ausführen. Ich will hier eine definierte Helligkeit setzen.
Der ganze Subflow gibt natürlich auch noch einen Status aus, weswegen die Linien etwas kreuz und quer gehen. Aber hier jetzt endlich der Überblick:
Im oberen Teil ist die simple on/off-Logik, in der Mitte das Dimmen und dadrunter der Doppelklick. Die Initialisierung der Helligkeit findet ganz unten statt wo der Wert einmalig in die Flow-Variable geschrieben wird.
Hier der Code für den gesamten Subflow:
[{"id":"549c3f58.ff0c9","type":"subflow","name":"Event per Time","info":"","category":"","in":[{"x":80,"y":180,"wires":[{"id":"8cd4f008.190f"}]}],"out":[{"x":520,"y":180,"wires":[{"id":"8cd4f008.190f","port":0}]}],"env":[{"name":"TimeRangeInSeconds","type":"num","value":"5"}],"color":"#DDAA99","status":{"x":520,"y":120,"wires":[{"id":"8cd4f008.190f","port":0}]}},{"id":"8cd4f008.190f","type":"function","z":"549c3f58.ff0c9","name":"count","func":"var now = Math.floor(Date.now() / 1000 ) || 0; \n\nfunction RemoveOld(ts){\n var diff = env.get('TimeRangeInSeconds') || 5;\n var now = Math.floor(Date.now() / 1000 ) || 0;\n var now2 = now - diff; \n \n return Math.floor(ts) > now2;\n}\n\nvar data = flow.get('data') || \"[]\";\n\ndata = JSON.parse(data);\ndata.push(now);\ndata=data.filter(RemoveOld);\n\nmsg.payload = data.length;\nflow.set('data', JSON.stringify(data));\n\nreturn msg;","outputs":1,"noerr":0,"x":230,"y":180,"wires":[[]]},{"id":"4bf947ab.211498","type":"subflow","name":"Ikea Dimmer","info":"","category":"","in":[{"x":40,"y":300,"wires":[{"id":"7b4c9956.acfc58"}]}],"out":[{"x":1120,"y":340,"wires":[{"id":"32889690.fc46ea","port":0},{"id":"584679a5.c1bed8","port":0},{"id":"62117ea.1e7368","port":0}]},{"x":1320,"y":140,"wires":[{"id":"4a660c11.3eef94","port":0},{"id":"fac64923.bc6848","port":0}]}],"env":[{"name":"StartBrightness","type":"num","value":"50"},{"name":"StepBrightness","type":"num","value":"10"},{"name":"DoubleClickBrithness","type":"str","value":"1"}],"color":"#C0DEED","inputLabels":["Button Event"],"outputLabels":["Brightness","State"],"icon":"node-red-contrib-polymer/ui_radio.png","status":{"x":1420,"y":360,"wires":[{"id":"a5af8864.f47fe8","port":0},{"id":"4a660c11.3eef94","port":0},{"id":"fac64923.bc6848","port":0},{"id":"62117ea.1e7368","port":0}]}},{"id":"be8924a5.85ce88","type":"switch","z":"4bf947ab.211498","name":"Switch an / aus","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1002","vt":"num"},{"t":"eq","v":"2002","vt":"str"}],"checkall":"true","repair":true,"outputs":2,"x":460,"y":140,"wires":[["32889690.fc46ea","4a660c11.3eef94"],["fac64923.bc6848"]]},{"id":"32889690.fc46ea","type":"change","z":"4bf947ab.211498","name":"Brightness","rules":[{"t":"set","p":"payload","pt":"msg","to":"Brightness","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":80,"wires":[[]]},{"id":"4a660c11.3eef94","type":"change","z":"4bf947ab.211498","name":"true","rules":[{"t":"set","p":"payload","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":140,"wires":[[]]},{"id":"fac64923.bc6848","type":"change","z":"4bf947ab.211498","name":"false","rules":[{"t":"set","p":"payload","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":260,"wires":[[]]},{"id":"51a608f0.19e558","type":"gate","z":"4bf947ab.211498","name":"","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","defaultCmd":"default","persist":false,"x":670,"y":420,"wires":[["584679a5.c1bed8"]]},{"id":"152bae03.a8beb2","type":"change","z":"4bf947ab.211498","name":"Open","rules":[{"t":"set","p":"topic","pt":"msg","to":"control","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"open","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":420,"wires":[["51a608f0.19e558"]]},{"id":"f05a97bf.f288b8","type":"change","z":"4bf947ab.211498","name":"close","rules":[{"t":"set","p":"topic","pt":"msg","to":"control","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"close","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":360,"wires":[["51a608f0.19e558"]]},{"id":"7b4c9956.acfc58","type":"switch","z":"4bf947ab.211498","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1001","vt":"num"},{"t":"eq","v":"1002","vt":"str"},{"t":"eq","v":"1003","vt":"str"},{"t":"eq","v":"2001","vt":"str"},{"t":"eq","v":"2002","vt":"str"},{"t":"eq","v":"2003","vt":"str"}],"checkall":"false","repair":true,"outputs":6,"x":150,"y":300,"wires":[["152bae03.a8beb2","8669e2f1.85e18"],["be8924a5.85ce88","f86a943.76f5a68"],["f05a97bf.f288b8"],["152bae03.a8beb2","c9fa3fd7.398fa"],["be8924a5.85ce88"],["f05a97bf.f288b8"]]},{"id":"b610e1da.630f1","type":"inject","z":"4bf947ab.211498","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":110,"y":740,"wires":[["435751f4.1dc28"]]},{"id":"435751f4.1dc28","type":"function","z":"4bf947ab.211498","name":"set brightness","func":"flow.set('Brightness', env.get('StartBrightness'));\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":740,"wires":[[]]},{"id":"8669e2f1.85e18","type":"change","z":"4bf947ab.211498","name":"1","rules":[{"t":"set","p":"richtung","pt":"flow","to":"1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":500,"wires":[[]]},{"id":"c9fa3fd7.398fa","type":"change","z":"4bf947ab.211498","name":"-1","rules":[{"t":"set","p":"richtung","pt":"flow","to":"-1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":540,"wires":[[]]},{"id":"f02ae375.ce76d","type":"inject","z":"4bf947ab.211498","name":"","topic":"","payload":"richtung","payloadType":"flow","repeat":"1","crontab":"","once":false,"onceDelay":0.1,"x":500,"y":480,"wires":[["51a608f0.19e558"]]},{"id":"584679a5.c1bed8","type":"function","z":"4bf947ab.211498","name":"calc Brightness","func":"var brightness = parseInt(flow.get('Brightness')) || 1;\nvar step = parseInt(env.get('StepBrightness')) || 10;\nvar direction = parseInt(msg.payload) || 1;\n\nvar newBrightness = brightness + (step * direction);\nif (newBrightness > 100) newBrightness=100;\nif (newBrightness < 1) newBrightness = 1;\n\nflow.set('Brightness', newBrightness);\n\nmsg.payload = newBrightness;\nreturn msg;","outputs":1,"noerr":0,"x":860,"y":420,"wires":[["a5af8864.f47fe8","4a660c11.3eef94"]]},{"id":"a5af8864.f47fe8","type":"function","z":"4bf947ab.211498","name":"Status Text","func":"msg.payload = \"Brightness \" + msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":1150,"y":420,"wires":[[]]},{"id":"f86a943.76f5a68","type":"subflow:549c3f58.ff0c9","z":"4bf947ab.211498","name":"","env":[{"name":"TimeRangeInSeconds","value":"2","type":"num"}],"x":540,"y":580,"wires":[["72e4c98e.d8c378"]]},{"id":"72e4c98e.d8c378","type":"switch","z":"4bf947ab.211498","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":750,"y":580,"wires":[["4a660c11.3eef94","62117ea.1e7368"]]},{"id":"62117ea.1e7368","type":"change","z":"4bf947ab.211498","name":"Brightness","rules":[{"t":"set","p":"payload","pt":"msg","to":"DoubleClickBrithness","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":910,"y":580,"wires":[[]]},{"id":"cec0708c.4d36b","type":"comment","z":"4bf947ab.211498","name":"Double Click","info":"","x":550,"y":540,"wires":[]},{"id":"24357078.86ba6","type":"comment","z":"4bf947ab.211498","name":"dimming function","info":"","x":700,"y":380,"wires":[]},{"id":"710c80ee.7da92","type":"comment","z":"4bf947ab.211498","name":"direct Switch","info":"","x":470,"y":100,"wires":[]},{"id":"7b10ac7.5b7b554","type":"comment","z":"4bf947ab.211498","name":"Init Brightness","info":"","x":110,"y":700,"wires":[]}]
Wie ihr seht, hat der Subflow 2 Ausgänge. Der 1. Ausgang steuert die Helligkeit und der 2. den Status an/aus. Diese müssen dann noch verbunden werden. Als Eingang dienst der Ikea-Taster mit seinen 6 Statuscodes.
Hey Danny, toller Beitrag, danke dafür!
Ich kämpfe gerade ein wenig mit meinen Basic Skills und der Verbindung von Deconz (u.a. soll der von dir beschriebene Ikea On/Off-Schalter eingesetzt werden) und Loxone.
Irgendwie scheitere ich aber schon an der Intepretation der Werte 1002 und 2002 in den Switch-Einstellungen. Habe bereits versucht die Werte per Switch und Change-Befehl in On-Off umzuwandeln, allerdings ohne Erfolg. Hast du einen Tipp, was ich noch versuchen könnte? Danke dir schon mal vorab!
Hast du bei dem DeConz input den State auf “buttonevent” gestellt? das macht die Sache etwas einfacher
Ja, der steht auf buttonevent.
Ich nehme mal, das Problem entsteht dann im nächsten Schritt:
https://abload.de/img/screenshots4j8v.jpg
du darfst nicht msg.state nehmen, sondern im msg.payload steht der Wert 🙂
https://www.screenpresso.com/=BGN8g
Danke, jetzt hat es funktioniert 😉
u.a. war auch ein Problem, dass die Werte nicht auf Number sondern String standen.
Prima
Hallo Danny,
ich würde gerne deinen Subflow verwenden.
Ich arbeite mich gerade in node red ein und habe daher noch keine Erfahrung.
Ich habe den Code für den gesamten Subflow kopiert und in eine Datei geschrieben.
Dann habe ich versucht diese in node red zu importieren.
Dabei gab es einen Fehler “SyntaxError: Unexpected token [ in JSON at position 734”
Ist dies der richtige Weg?
Import nicht möglich!!!
Hallo, ich schaffe es nicht vom Server den API Key zu bekommen. ich habe marthoc/deconz im Docker installiert und damit läuft der conbee II. Das ganze auf Port 80 und WebSocket Port 443. Dadurch benötige ich das HA addon nicht. sondern nur die Integration Phoscon.
In HA bekomme ich über deconz_event alle clicks meiner Zigbee angezeigt. nun fehlt nur noch die Verbindung API mit Node-Red.
Wer kann mir bitte helfen?
Hallo Danny, ich habe diesen Schalter in Node Red über meine Homematic CCU3 mit dem Zigbee Stick verbunden. Ich bekomme aus msg.payload.Click on und off Signale die ich in true und false umgewandelt habe. Im debug msg.payload.Click bekomme ich nun auch den Wert true und fals angezeigt als bulien. Die Lampe, die ich verbinden habe wird aber nur angeschaltet. Ich bekomme sie nicht aus. Ich suche mir einen Wolf und finde den Fehler nicht. Hast Du eine Idee wo mein Denkfehler sein kann? Ich will mit Tastendruck 1 anschalten und mit Tastendruck 0 ausschalten. Viele Grüße Martin
Hi, toller Beitrag der mir sehr geholfen hat.
Ich möchte gerne den Bewegungsmelder mit dem Schalter deaktivieren. Also Licht bleibt an, wenn Schalter gedrückt wurde.
Ich finde hier leider keine Lösung mit dem Ikea Schalter, da er keinen abrufbares Objekt darstellen kann.