OpenSprinkler – zavlažování přes HomeKit
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:
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.