Zigbee2MQTT, NodeRed a Loxone
Po delší odmlce dnes článek o tom, jak propojit Zigbee2mqtt a Loxone. Jde o volné pokračování článku “Zigbee brána pomocí Raspbery PI“. Minulý článek jsme skončili tím, že nám z RaspberyPI leze pomocí protokolu MQTT informace o stavech čidel, případně pomocí MQTT jsme schopni zapnout třeba žárovku nebo inteligentní zásuvku. Dnes se pojdmě podívat, jak to nyní propojit s Loxone tak, abychom mohli vše ovládat nativně z Loxone prostředí.
Jelikož Loxone nepodporuje MQTT (a zřejmě ani nikdy podpodorvat nebude), je opět potřeba si pomoci aplikací NodeRED, kterou jsem zde na blogu zmiňoval už spoustukrát (Propojení všeho se vším od Arduina po Loxone).
V návodu začneme směrem od Zigbme2mqtt k Loxone. Budu předpokládat, že máte čidla nainstalované a nampárované a že víte, jaká data z nich lezou (to jde vidět například v Zigbee2MQTT konzoly).
Xiaomi teploměr
Jako první ukážu propojení na teploměru Xiaomi. Jako MQTT kanál se použije dle nastavení například zigbee2mqtt/temperature01. Do kterého se posílají data:
{"temperature":26.05,"linkquality":47,"humidity":32.86,"pressure":927.38,"battery":42,"voltage":2985}
Abychom data přijali do Loxone, je potřeba je z MQTT převést do UDP (což je asi nejjednoduší a nejrychlejší cesta jak je do Loxone předat).
Vytvoříme si proto v NodeRed novou záložku Zigbee, do které jako první přidáme MQTT vstup. Ten nakonfigurujeme na připojení k našemu MQTT serveru a jako “Topic” vyplníme topic dle čidla. V našem případě “zigbee2mqtt/temperature01″
Jako další přidáme funkci, ve které napíšeme logiku převodu MQTT na UDP. V případě teploměru nás krom samotné teploty zajímá také tlak a vlhkost.
Abychom nemuseli provádět nějaké složité parsování na straně Loxone, vytvoříme v NodeRED logiku tak, že z jedné vstupní zprávy s těmito údaji vytvoříme tři výstupní UDP pakety, které se postupně pošlou do Loxonu.
var objPayload = JSON.parse(msg.payload); var temperature = new Object(); temperature.payload = "temperature01/temperature=" + objPayload.temperature; var humidity = new Object(); humidity.payload = "temperature01/humidity=" + objPayload.humidity; var preasure = new Object(); preasure.payload = "temperature01/pressure=" + objPayload.pressure; return [ [temperature,humidity,preasure] ];
Na prvním řádku převedeme Json objekt do Javascrip objektu. Díky tomu do něj můžeme dále jednoduše přistupovat.
Na řádcích 3 – 10 pak postupně vytvoříme tři objekty s výslednými daty. Každému objektu nastavíme payload, což je proměnná, které se pak v dalším bloku (UDP výstup) pošle na zadanou UDP adresu a port.
Abychom si v Loxonu parsování co nejvíce usnadnili, v každém UDP paketu posíláme název dat, rovnítko a hodnotu. Tento název spolu s rovnítkem pak budeme v řetezci hledat a v primitivních parserech Loxonu parsovat.
Jako poslední pak vrátíme pole objektů. Tím NodeREDu říkáme, že nechceme vrátit a zpracovat jeden objekt, ale několik objektů.
Xiaomi Cube
Krom čidla teploty byste mohli chtít parsovat například data z Xiami Cube. Z něj naopak čteme vždy jen jednu hodnotu, ale může jich být více typů. Proto zde přikládám i program na vyparsování typu události, její hodnoty a převod hodnoty do Loxone.
var objPayload = JSON.parse(msg.payload); if ( objPayload.action == "flip90" ) { node.error("flip90 "+ objPayload.to_side); msg.payload = "flip"+ objPayload.to_side; } else if ( objPayload.action == "flip180" ) { node.error("flip180 "+ objPayload.side); msg.payload = "flip"+ objPayload.side; } if ( objPayload.action == "rotate_right" ) { node.error("rotate_right " + objPayload.angle); msg.payload = "rotate_right"; //+ objPayload.side; return msg; } else if ( objPayload.action == "rotate_left" ) { node.error("rotate_left " + objPayload.angle); msg.payload = "rotate_left"; //+ objPayload.side; } else if ( objPayload.action == "slide" ) { node.error("slide "+objPayload.side); msg.payload = "slide"+ objPayload.side; } else if ( objPayload.action == "shake" ) { node.error("shake"); msg.payload = "shake"; } else if ( objPayload.action == "tap" ) { node.error("tap " + objPayload.side); msg.payload = "tap"+ objPayload.side; return msg; } else if ( objPayload.action == "wakeup" ) { //do nothing return null; } else { node.error("Unknown " + objPayload.action); return null; } node.error(msg.payload);
Kostku jsem nakonec do ostrého provozu nenasadil, protože citlivost ovládání není ideální a úplně mi její používání k srdci nepřirostlo. Proto program není dodělán do finální podoby (nejsou tam například klíč=hodnota příkazy) ale jde spíše u ukázku toho, jak případně logiku řešit.
UDP komunikace
Poslední node který do našeho projektu v NodeRED přidáme je UDP output. V něm nastavíme IP adresu Loxonu a port, na kterém bude Loxone naše data naslouchat.
Tím máme v NodeRED pro teď hotovo a přesuňme se do Loxone Configu, kde přidáme UDP virtuální vstup.
A do něj jednotlivé UDP příkazy. Například parsování teploty nastavíme takto:
Postupně takto vytvoříme všechny UDP příkazy, které z NodeRED posíláme:
A tím máme hotovo. Hodnoty pak použijeme v Loxone configu stejně, jako jakékoli jiné hodnoty z teploměrů a čidel.
A nyní opačný směr
Tím máme vyřešeny všechna čidla a ovladače. To další, co nás ale zajímá, je ovládání zásuvek a osvětlení z Loxone směrem k Zigbee2MQTT.
Začneme zase v NodeRED. Zde nyní jako první vytvoříme UDP vstup, na kterém bude NodeRED naslouchat příkazy, které mu budeme z Loxone posílat.
Jako druhá je opět funkce, tentokrát taková, co převede textový příkaz z Loxone na MQTT příkaz. Abych nemusel psát hromadu malých funkcí, co převede jednotlivé příkazy, vytvořil jsem si univerzální funkci, která umí převést libovolný příkaz z Loxone na MQTT.
Funkce vezme jakýkoli vstupní řetezec ve formátu GROUP/DEVICE/VALUE, rozparsuje jej a převede na MQTT příkaz. Příakaz vytvoří tak, že topic je vždy zigbee2mqtt/ následovaný parametry dle typu zařízení.
node.error("incomming: " + msg.payload); //parse incoming data to group-device-value const regex = new RegExp("([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)"); var res = regex.exec(msg.payload); var nameGroup = res[1]; var nameDevice = res[2]; var value = res[3]; node.error("group=" + nameGroup); node.error("device=" + nameDevice); node.error("value=" + value); //preapre MQTT command msg.payload = {}; msg.topic = "zigbee2mqtt/"; //create light command if ( nameGroup == "light" ) { msg.topic += nameDevice + "/set"; if ( value === 0 ) msg.payload.state = "off"; else //loxone has 0-100, but we need 0-255 msg.payload.brightness = value*2.55; } node.error(msg); return msg;
V současnosti je připravena logika jen pro světla, kdy topic je zigbee2mqtt/devicename/set a hodnota buď “off”, pokud je nastavena 0, nebo číselná hodnota 0-255 dle nastavení 0-100.
Až bude potřeba přidat například spínanou zásuvku, pridám nový group-name “powersocket” a dle potřeby vygeneruju cílový payload. Je to určitě o dost přehlednější, než mít pro každou žárovku a každou zásuvku zvlášť program.
Třetím blokem v NodeRED diagramu je pak MQTT output node. To dle nastaveného msg.payload vytvoří MQTT topic a odešle ho na zadaný server.
Loxone UDP výstup
Poslední co zbývá je Loxone UDP výstup, který bude posílat data do NodeRED.
Jako první přidáme “Virtuální výstup” do Loxone configu (bacha, zatímco existuje UDP vstup, tak opakem je Virtuální výstup, nikoli UDP výstup…..).
Tento výstup pak nakonfigurujeme jak je ukázáno na obrázku výše. Důležitá je adresa, kde to, že je to UDP určujeme přímým odkazem na zařízení v URI. Tzn v mém případě /dev/udp/192.168.0.222/60001
Příkaz pro nastavení svítivosti Ikea žárovky pak vypadá takto. Je potřeba natavit instrukci pro zapnutí a vypnutí, která je ale v našem případě stejná a až samotná hodnota určuje, zda zapínáme nebo vypínáme.
Na takto vytvoření příkaz pak normálně napojíme blok ovládání osvětlení AQ1, takže v okamžiku, kdy budete měnit osvětlení se budou přes UDP posílat příkazy s aktuální hodnotou.
Tady bohužel pak trochu narážíme na limity MQTT, jelikož při plynulé změně hodnot z 100 na 0 se pošle 100 příkazů, které se musí nejprve převést na UDP, z nějak pak na MQTT, kde ho pak Zigbee2MQTT musí převést na Zigbee a poslat žárovce. Výsledkem je, že při stmívání a rozsvěcení žárovky může dojít ke zpoždění.
Zde by bylo určitě lepší mít možnost poslat přes UDP příkaz rovnou k Zigbee bráně. Bohužel, nic takového jsem nenašel.
A to je vše
A to by mělo být vše pro to, abyste propojili Zigbee a Loxone v obou směrech. Na většinu zařízení je celý koncept naprosto dostatečný a stabilní. Jediná vyjímka jsou ta stmavovaná světla, kdy při plynulém přechodu z maxima na minium se může stlumění světla trochu zpozdit.
PS: Tak, jako je univerzální funkce na ovládání a nastavování MQTT zařízení, šla by napsat i univerzální funkce na příjem hodnot z teploměrů. Předpokládám, že až čidla po době více rozšířím, tak že i tu ještě trochu předělám.
Díky moc za popis, přenos analogových hodnot funguje!
S čím ale bojuju je přenos textových hodnot. Např. Xiaomi magnet přenáší v proměnné “contact” stavy TRUE nebo FALSE. A Loxone si s tím neumí poradit. Mám podezření že potíž bude na straně Loxone, který si neumí poradit s textovými řetězci přes UDP.
textove mam pocit jdou taky nejak, ale vim, ze s tim byl omrd ;-).
true/false bych radeji prevedl na strane node-red na nejaky 0/1 a ten poslal do loxone.
ale s klasickym textem pak bude potiz. Ale mam pocit, ze uz jsem to nekde resil a nejak se mi to do nej nacpat povedlo
Díky za článek. Já jsem komunikaci nede-red loxone rozchodil za pomocí node-red-contrib-loxone. Zajímalo by mě, jestli má někdo nějaká pro a proti pro použití UDP, node-red-contrib-loxone nebo i jiná řešení.
Co mi u komunikace mezi různými systémy pořád dělá problém je, jak zajistit ověření provedení příkazu a obnovení stavu po výpadku. Třeba při chybě komunikace se zigbee zásuvkou si loxone může myslet, že je zapnutá, ale ve skutečnosti se příkaz nedoručil. Nebo po výpadku 230 V zůstane relé v zásuvce vypnuté, i když bylo před výpadkem zapnuté.
UDP je vic ligh reseni. Ten nodered-contrib-loxone bezi na websocketech (pokud si to nepletu jeste s necim jinym) a co mam pocit, tak se tam dotazuji vsechny stavy celeho Loxonu.
Zatimco pres UDP poslu jen jednu kratkou zpravu a v pripade necinnosti se nic nedeje.
Jinak je ale urcite komunikace mozna i pres jine protokoly, je to spis o osobni preferenci, nez ze by bylo neco vylozene lepsi ci horsi.
Ad stavy, s tim toho moc nenadelas. Maximalne do Loxonu zabudovat nejaky refresh, ktery by jednou za cas poslal vse znovu.
Množství komunikace jsem trochu zkoumal a mám dojem, že se posílají jen změny stavu.
No problem je, ze stavy loxonu se meni dost casto (at uz ruzne teplomery, elektromery, atd.) a kdyz sem na to prave koukal naposled, tak to ve vysledku hrnulo strasne moc dat neustale.
Já to myslel tak, že posílá jen změny stavů sledovaných objektů, alespoň tak to vypadá podle objemu přenášených dat. Sledoval jsem, jestli se sledování dat nějak projeví na zatížení miniserveru, protože mimo zigbee stahuju data pro statistiky a na žádný problém jsem nenarazil.
IMHO,
to prenasi pouze to co ma v NR v contribu vybrano. Pouzivam to na jediny vypinac a to skrz Harmony contrib a vypinac “aktivity.
UDP je dobre imho jen na senzory
cokoli ma zpetnou vazbu (svetla apod) by melo jet skrz web socket.
prave si hraju s HUE zarovnou pripojenou do ConBee a zkusim se poprat s websocketem na analog in/out
Ještě jsem začal zkoumat plugin do Loxberry (MQTT gateway), kde mají již nějak připraven přenos do/z Loxberry přes HTTP nebo UDP. Zatím jsem to nezkoušel, ale zaujalo mě tam, že píšou:
I suggest to use HTTP instead of UDP. It is easier to configure in Loxone Config, and creates less CPU stress on the Miniserver. Only if the transferred data require to use special command recognitions, use UDP.
zdroj: https://www.loxwiki.eu/display/LOXBERRY/MQTT+Gateway+-+Troubleshooting+Guide
hm, at to vic vysvetli. takhle je to mlha sem, mlha tam.
http je obecne narocnejsi nez UDP, navic UDP neprovadi zadne querovani, takze nevidim duvod, proc by melo byt narocnejsi.
Naopak, HTTP vstupy stojej u loxone za vylizprdel, protoze co vim, tak se musi dokola dotazovat, namisto aby se na ne jen posilaly data jako v pripade UDP
Uměli by jste mě někdo prosím poradit,jakym způsobem si převedeno v Node-red text na číslo (Např. true -> 1, false -> 0)?
Já bych použil z funkcí Change. Tam je jednoduché nastavit, že konkrétní textová hodnota se má převést na číslo.
Nakonec jsem převod textu na číslo zvládnul. Asi ne úplně elegantně, ale funguje to 🙂
Kdyby někdo potřeboval, tady je export z Node-Red:
[{“id”:”42884b62.2ff894″,”type”:”influxdb out”,”z”:”4f0442f3.67b62c”,”influxdb”:””,”name”:”Xiaomi_Magnet”,”measurement”:”Xiaomi_Magnet”,”precision”:””,”retentionPolicy”:””,”x”:1060,”y”:1721,”wires”:[]},{“id”:”5fd75566.312c7c”,”type”:”json”,”z”:”4f0442f3.67b62c”,”name”:””,”property”:”payload”,”action”:””,”pretty”:false,”x”:474,”y”:1735,”wires”:[[“4950d4a8.d6374c”]]},{“id”:”4950d4a8.d6374c”,”type”:”switch”,”z”:”4f0442f3.67b62c”,”name”:””,”property”:”payload.contact”,”propertyType”:”msg”,”rules”:[{“t”:”true”},{“t”:”false”}],”checkall”:”true”,”repair”:false,”outputs”:2,”x”:608,”y”:1733,”wires”:[[“6ced72f5.69035c”],[“5d2d80f1.c33b5”]]},{“id”:”6ced72f5.69035c”,”type”:”change”,”z”:”4f0442f3.67b62c”,”name”:””,”rules”:[{“t”:”set”,”p”:”payload.contact”,”pt”:”msg”,”to”:”1″,”tot”:”num”}],”action”:””,”property”:””,”from”:””,”to”:””,”reg”:false,”x”:822,”y”:1694,”wires”:[[“42884b62.2ff894”]]},{“id”:”5d2d80f1.c33b5″,”type”:”change”,”z”:”4f0442f3.67b62c”,”name”:””,”rules”:[{“t”:”set”,”p”:”payload.contact”,”pt”:”msg”,”to”:”0″,”tot”:”num”}],”action”:””,”property”:””,”from”:””,”to”:””,”reg”:false,”x”:820,”y”:1762,”wires”:[[“42884b62.2ff894”]]},{“id”:”1ea7aa5f.afd9a6″,”type”:”mqtt in”,”z”:”4f0442f3.67b62c”,”name”:”Xiaomi_Magnet”,”topic”:”zigbee2mqtt/0x00158d0002ca3627″,”qos”:”2″,”broker”:”f4ecd1b0.57f34″,”x”:276,”y”:1794,”wires”:[[“5fd75566.312c7c”]]},{“id”:”f4ecd1b0.57f34″,”type”:”mqtt-broker”,”z”:””,”name”:”MQTT server Loxberry”,”broker”:”192.168.1.150″,”port”:”1883″,”clientid”:””,”usetls”:false,”compatmode”:true,”keepalive”:”60″,”cleansession”:true,”birthTopic”:””,”birthQos”:”0″,”birthPayload”:””,”closeTopic”:””,”closeQos”:”0″,”closePayload”:””,”willTopic”:””,”willQos”:”0″,”willPayload”:””}]
zdarec,
tak v ramci hledani jsem narazil na toto:
https://gist.github.com/sstroot/a2be61a889a6e6712fa0591ab1a69e35
bohuzel na RPI kde mam ConBee se mi nedari loxone contrib nainstalovat 🙂 a tam kde mi jede nemam USB abych tam pripojit ConBee… cekam az mi pomuze clovek co ten contrib napsal 🙁
Ahojte.
Tuje kod, ktory pouzivam na parsovanie oppo tlacidiel, aqara zaplavovych senzorov a danalock zamku.
Tlacidla musia zacinat na oppo, zaplavove senzory na leak a zamok na danalock