OpenSprinkler – zavlažování přes HomeKit

Několik let jsem úspěšně provozoval automatizovanou závlahu řízenou jednotkou Hunter XCore. Při přemýšlení o dalším upgrade věcí do HomeKitu jsem dospěl k tomu, že je na čase nahradit tuto jednotku něčím inteligentnějším.

Výchozí situace je sice funkční, nicméně uživatelsky ne úplně přívětivá jednotka od Hunteru a pomalé krůčky s domácí automatizací.

Prvním krokem bylo hledání vhodných řídících komponentů. Volba padla na Sonoff 4CH PRO, který má široké možnosti napájení a obyčejné „suché“ výstupy (verze PRO), takže není omezeni vstupním/výstupním napětím. Pro řízení jsem zvolil software OpenSprinkler (OS), který se dá jednoduše rozběhnout, jako webový server s jednoduchým UI a více možnostmi, jak ovládat ventily. OpenSprinkler prodává hotovou jednotku, i desku pro Raspberry Pi, nicméně vzhledem k tomu, že OS umožňuje ovládat ventily přes HTTP příkaz, nebylo nutné dokupovat další hardware a využil jsem vlastní malinu.


Postup instalace firmware OpenSprinkler na RPI: https://openthings.freshdesk.com/support/solutions/articles/5000631599-installing-and-updating-the-unified-firmware-on-ospi

Po připojení do RPi přes SSH zadejte příkaz:

sudo apt-get install build-essential
cd ~
git clone https://github.com/OpenSprinkler/OpenSprinkler-Firmware.git

změňte adresář:

cd OpenSprinkler-Firmware

a spusťte instalační skript:

sudo ./build.sh ospi

Po instalaci je server k dispozici na adrese http://<ip-vašeho-raspberry>:8080/


Instalace firmware Tasmota do Sonoff4CH je o něco málo složitější, celý postup je ve videu zde:


Příkazy k ovládání jednotlivých relé v tasmotizovaném Sonoffu jsou:

Zapnutí:

http://<ip>/cm?user=<username>&password=<password>&cmnd=Power<číslo výstupu>%20On

Vypnutí:

http://<ip>/cm?user=<username>&password=<password>&cmnd=Power<číslo výstupu>%20Off

username a password je samozřejmě možné vynechat pokud je v Tasmotě nenastavíte. S příkazy On/Off si vystačíme, kompletní seznam je zde:

https://tasmota.github.io/docs/Commands/


Následuje konfigurace Opensprinkleru, aby „volal“ příslušné výstupy:

Zvolíme ozubené kolečko vedle příslušné sekce

Nic teď nebrání připojení stávajícího rozvodu závlahy k Sonoffu. Já použil stávající napájecí adaptér Hunter, odstranil původní jednotku, připojil napájení Sonoffu na 240 a ovládání ventilů na Hunter, ovládání přes Opensprinkler funguje bezvadně, systém má i aplikaci pro iPhone, která samozřejmě funguje „zvenčí“ jen s VPN, nebo DynDNS.

Můžeme tedy ovládat závlahu přes počítač/tablet/mobil, ale s tím se rozhodně nespokojíme. Dalším krokem je propojení závlahového systému do HomeKitu, ke kterému použijeme osvědčený Node-RED a NRCHKB. Aby byla záležitost pokud možno bezpracná, využijeme vzorové flow publikované NRCHB Wiki zde:

https://github.com/NRCHKB/node-red-contrib-homekit-bridged/wiki/Valve

Nicméně je v něm potřeba nastavit správně komunikaci s OpenSprinklerem v posledním HK->OS nodu. Vložte IP adresu OpenSprinkler serveru a heslo pro přístup do systému. To je potřeba zahashovat například zde. Takže například výchozí heslo „opendoor“ vložíme jako „a6d82bced638de3def1e9bbb4983225c


Po deployi už by nemělo nic bránit propsání služby ventilů do Homekitu a ovládání.

Upozornění – bug v aktuální verzi IOS způsobuje, že se výchozí hodnota zalévání při prostém stisku ikony ventilu v HK dá nastavit pouze na 5 a 10 minut, snad bude v příštím updatu opraveno. Pokud požádáte SIRI o delší zalévání, vyhoví. V Homekitu se zobrazuje i zbývající čas zalévání při běhu programu z OpenSprinkleru a lze jej ručně přerušit.


Výsledek nyní patří spíše do elektrikářských kuriozit, ale budu osazovat samozřejmě ještě krabici a nehořlavou podložku.


A jako obvykle kompletní flow:

[{"id":"972fe2e4.b830e8","type":"http request","z":"d58d7d15.df3be8","name":"GET all","method":"GET","ret":"obj","paytoqs":false,"url":"http://localhost:8080/ja","tls":"","proxy":"","authType":"basic","x":340,"y":460,"wires":[["d94230d6.8aef9"]]},{"id":"d94230d6.8aef9","type":"function","z":"d58d7d15.df3be8","name":"Sprinkler -> HK","func":"var out = {};\nfor (i = 0; i < 4; i++) {\n    out[i] = {\n        \"payload\": {\n            \"Active\":Math.min(1,msg.payload.settings.ps[i][0]),\n            \"InUse\":msg.payload.status.sn[i],\n            \"RemainingDuration\":msg.payload.settings.ps[i][1]\n        },\n        \"topic\": String(i)\n    };\n}\nout[4] = {\n    \"payload\": {\n        \"Active\":Math.max(\n            out[0].payload.Active,\n            out[1].payload.Active,\n            out[2].payload.Active,\n            out[3].payload.Active\n            ),\n        \"InUse\":Math.max(\n            out[0].payload.InUse,\n            out[1].payload.InUse,\n            out[2].payload.InUse,\n            out[3].payload.InUse\n            ),\n        \"RemainingDuration\":(\n            out[0].payload.RemainingDuration +\n            out[1].payload.RemainingDuration +\n            out[2].payload.RemainingDuration +\n            out[3].payload.RemainingDuration\n            )\n    },\n    \"topic\": String(4)\n};\nvar prevout = context.get(\"prevout\") || {};\nreturn [[out[0], out[1], out[2], out[3], out[4]]];\n","outputs":1,"noerr":0,"x":520,"y":460,"wires":[["aac7c238.08a87"]]},{"id":"c61a0975.d8116","type":"inject","z":"d58d7d15.df3be8","name":"Cron","topic":"","payload":"","payloadType":"date","repeat":"2","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":460,"wires":[["972fe2e4.b830e8"]]},{"id":"aac7c238.08a87","type":"rbe","z":"d58d7d15.df3be8","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":720,"y":460,"wires":[["9f1112f8.bcec38","b4c04a5a.94dc6","4a61c969.7498e","41a98348.87c93c","af1afae5.f437f8"]]},{"id":"470fbc10.3b41b4","type":"function","z":"d58d7d15.df3be8","name":"Duration","func":"var out = {};\nfor (i = 0; i < 4; i++) {\n    out[i] = {\n        \"payload\": {\n            \"SetDuration\": msg.payload\n        },\n        \"topic\": String(i)\n    }\n}\nreturn [[out[0], out[1], out[2], out[3]]];\n","outputs":1,"noerr":0,"x":540,"y":400,"wires":[["aac7c238.08a87"]]},{"id":"9f1112f8.bcec38","type":"homekit-service","z":"d58d7d15.df3be8","isParent":true,"bridge":"6a8d3ef1.88061","parentService":"","name":"Butterfly Garden","serviceName":"Valve","topic":"0","filter":true,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{\n    \"ValveType\":\n    {\n        \"minValue\":1,\n        \"maxValue\":1\n    },\n    \"SetDuration\":\n    {\n        \"minValue\":300,\n        \"maxValue\":1800\n    }\n}","x":940,"y":340,"wires":[["3f49c0d.c9f03c"]]},{"id":"b4c04a5a.94dc6","type":"homekit-service","z":"d58d7d15.df3be8","isParent":true,"bridge":"6a8d3ef1.88061","parentService":"","name":"Driveway","serviceName":"Valve","topic":"1","filter":true,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{\n    \"ValveType\":\n    {\n        \"minValue\":1,\n        \"maxValue\":1\n    },\n    \"SetDuration\":\n    {\n        \"minValue\":300,\n        \"maxValue\":1800\n    }\n}","x":920,"y":400,"wires":[["3f49c0d.c9f03c"]]},{"id":"4a61c969.7498e","type":"homekit-service","z":"d58d7d15.df3be8","isParent":true,"bridge":"6a8d3ef1.88061","parentService":"","name":"Front Yard","serviceName":"Valve","topic":"2","filter":true,"manufacturer":"Rainbird 500","model":"Default Model","serialNo":"Zone 3","characteristicProperties":"{\n    \"ValveType\":\n    {\n        \"minValue\":1,\n        \"maxValue\":1\n    },\n    \"SetDuration\":\n    {\n        \"minValue\":300,\n        \"maxValue\":1800\n    }\n}","x":930,"y":460,"wires":[["3f49c0d.c9f03c"]]},{"id":"41a98348.87c93c","type":"homekit-service","z":"d58d7d15.df3be8","isParent":true,"bridge":"6a8d3ef1.88061","parentService":"","name":"Back Yard","serviceName":"Valve","topic":"3","filter":true,"manufacturer":"RainBird 500","model":"Default Model","serialNo":"Zone 4","characteristicProperties":"{\n    \"ValveType\":\n    {\n        \"minValue\":1,\n        \"maxValue\":1\n    },\n    \"SetDuration\":\n    {\n        \"minValue\":300,\n        \"maxValue\":1800\n    }\n}","x":930,"y":520,"wires":[["3f49c0d.c9f03c"]]},{"id":"af1afae5.f437f8","type":"homekit-service","z":"d58d7d15.df3be8","isParent":true,"bridge":"6a8d3ef1.88061","parentService":"","name":"Whole Yard","serviceName":"Valve","topic":"4","filter":true,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{\n    \"ValveType\":\n    {\n        \"minValue\":1,\n        \"maxValue\":1\n    }\n}","x":930,"y":580,"wires":[["3f49c0d.c9f03c"]]},{"id":"7437d718.0a2d98","type":"link in","z":"d58d7d15.df3be8","name":"Run program","links":["5bf24742.9efdf"],"x":530,"y":520,"wires":[["aac7c238.08a87"]],"l":true},{"id":"e5af1a32.c833c","type":"inject","z":"d58d7d15.df3be8","name":"10 minute default run time","topic":"","payload":"600","payloadType":"num","repeat":"","crontab":"00 22 * * *","once":false,"onceDelay":"10","x":280,"y":400,"wires":[["470fbc10.3b41b4"]]},{"id":"5d81641e.9b310c","type":"inject","z":"d58d7d15.df3be8","name":"5 minute runtime","topic":"","payload":"300","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":"10","x":320,"y":340,"wires":[["470fbc10.3b41b4"]]},{"id":"3f49c0d.c9f03c","type":"function","z":"d58d7d15.df3be8","name":"HK -> OS","func":"var Zone = parseInt(msg.topic, 10); // Zone = zone number - 1\n\nvar duration = flow.get(\"duration\") || {\n    0: 300,\n    1: 300,\n    2: 300,\n    3: 300\n};\n\nif (msg.payload.SetDuration) {\n    duration[Zone] = msg.payload.SetDuration;\n}\n\nflow.set(\"duration\", duration);\n\nif (msg.hap !== undefined && msg.hap.context !== undefined && msg.payload.Active !== undefined) {\n    var ip = \"http://localhost:8080/\";\n    var cmd;\n    var msg2 = null;\n    if (Zone !== 4) {\n        cmd = \"cm?sid=\" + Zone + \"&en=\" + msg.payload.Active + \"&t=\" + duration[Zone];\n    } else {\n        if (msg.payload.Active === 1) {\n            cmd = \"mp?pid=1&uwt=1\";\n        } else {\n            cmd = \"cv?rsn=1\";\n        }\n        msg2 = {\n            \"payload\": {\n                \"Active\": msg.payload.Active\n            },\n            \"topic\": String(Zone)\n        };\n    }\n    return [{\"url\": ip + cmd}, msg2];\n}\n","outputs":2,"noerr":0,"x":1160,"y":460,"wires":[["73635ba2.3827c4"],["5bf24742.9efdf"]]},{"id":"73635ba2.3827c4","type":"http request","z":"d58d7d15.df3be8","name":"HTTP command","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","proxy":"","authType":"basic","x":1340,"y":440,"wires":[[]]},{"id":"5bf24742.9efdf","type":"link out","z":"d58d7d15.df3be8","name":"Run program","links":["7437d718.0a2d98"],"x":1330,"y":480,"wires":[],"l":true},{"id":"6a8d3ef1.88061","type":"homekit-bridge","z":"","bridgeName":"Garage","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"Garrett","model":"Pi HAT","serialNo":"3","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true}]

Kompletní dokumentace API OpenSprinkler je zde.


Zanechat komentář