My node-red + HomeKit + OpenHAB setup

@ae_0017 Sure, that’d be great!

[{"id":"203774c6.1da0e4","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current Mode","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentMode","x":110,"y":236,"wires":[["d75cad4b.f19bf"],[]]},{"id":"4811709a.5baa7","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentTemperature","x":101.5,"y":323,"wires":[["c08ebe89.d3ee1"],[]]},{"id":"45959d01.a9b2d4","type":"openhab2-in","z":"187a1471.2d90bc","name":"Target Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_TargetSetPoint","x":101.5,"y":434,"wires":[["b56489e4.c69458"],[]]},{"id":"d75cad4b.f19bf","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"COOL","vt":"str"},{"t":"eq","v":"HEAT","vt":"str"},{"t":"eq","v":"AUTO","vt":"str"},{"t":"eq","v":"OFF","vt":"str"},{"t":"eq","v":"ECO","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":261,"y":232,"wires":[["11dcbaf7.1cdb8d","2bb21ab.8412866"],["ec48caa3.7bd978","4b023924.a43628"],["a52c39b2.77654","3a0093b4.989984"],["72c67fa8.b96f98","14ce4810.576148"],["72c67fa8.b96f98","14ce4810.576148"]]},{"id":"b56489e4.c69458","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":276.5,"y":485,"wires":[["2803a82f.2dc2b8"]]},{"id":"2803a82f.2dc2b8","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n TargetTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":465.5,"y":527,"wires":[["b9e4991b.c0ce2"]]},{"id":"c08ebe89.d3ee1","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n CurrentTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":464.5,"y":468,"wires":[["b9e4991b.c0ce2"]]},{"id":"14ce4810.576148","type":"change","z":"187a1471.2d90bc","name":"Current Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":416,"wires":[["b9e4991b.c0ce2"]]},{"id":"72c67fa8.b96f98","type":"change","z":"187a1471.2d90bc","name":"Target Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":445,"y":372,"wires":[["b9e4991b.c0ce2"]]},{"id":"3a0093b4.989984","type":"change","z":"187a1471.2d90bc","name":"Current Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":3}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":454,"y":321,"wires":[["b9e4991b.c0ce2"]]},{"id":"a52c39b2.77654","type":"change","z":"187a1471.2d90bc","name":"Target Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":3}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":446,"y":265,"wires":[["b9e4991b.c0ce2"]]},{"id":"4b023924.a43628","type":"change","z":"187a1471.2d90bc","name":"Current Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":217,"wires":[["b9e4991b.c0ce2"]]},{"id":"ec48caa3.7bd978","type":"change","z":"187a1471.2d90bc","name":"Target Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":451,"y":166,"wires":[["b9e4991b.c0ce2"]]},{"id":"2bb21ab.8412866","type":"change","z":"187a1471.2d90bc","name":"Current Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":449,"y":118,"wires":[["b9e4991b.c0ce2"]]},{"id":"11dcbaf7.1cdb8d","type":"change","z":"187a1471.2d90bc","name":"Target Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":446,"y":70,"wires":[[]]},{"id":"b9e4991b.c0ce2","type":"homekit-service","z":"187a1471.2d90bc","bridge":"1532ba0d.edf9e6","name":"Thermostat","serviceName":"Thermostat","manufacturer":"NestLabs","model":"3rd Generation","serialNo":"Default Serial Number","characteristicProperties":"{}","x":637.5,"y":286,"wires":[["c9b9a891.73d338","a52d155.0fceae8"]]},{"id":"c9b9a891.73d338","type":"switch","z":"187a1471.2d90bc","name":"HomeKit Triggered","property":"hap.context","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":870,"y":245,"wires":[["d7ef2956.8f7a78"]]},{"id":"a52d155.0fceae8","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":819.5,"y":311,"wires":[["2fd8e382.8b6c3c"]]},{"id":"2fd8e382.8b6c3c","type":"json","z":"187a1471.2d90bc","name":"","property":"payload","action":"","pretty":false,"x":958,"y":368,"wires":[["c9123698.04db58"]]},{"id":"d7ef2956.8f7a78","type":"template","z":"187a1471.2d90bc","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.TargetHeatingCoolingState}}","output":"str","x":1035,"y":213,"wires":[["bed43c8a.9b9b2"]]},{"id":"bed43c8a.9b9b2","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":1187,"y":180,"wires":[["1ab3e473.cebc34"],["203b514b.555fee"],["eb554923.ee1828"],["7666e7e6.86c8e"]]},{"id":"c9123698.04db58","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"TargetTemperature","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1126,"y":368,"wires":[["831367a9.57a3c"]]},{"id":"831367a9.57a3c","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = msg.payload.substring(21,msg.payload.length - 1) + \" °C\";\nreturn msg;","outputs":1,"noerr":0,"x":1300,"y":368,"wires":[["c79cf5db.d7e8f"]]},{"id":"7666e7e6.86c8e","type":"change","z":"187a1471.2d90bc","name":"Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT/COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1324,"y":256,"wires":[["fce431e4.be80a"]]},{"id":"eb554923.ee1828","type":"change","z":"187a1471.2d90bc","name":"Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1322,"y":198,"wires":[["fce431e4.be80a"]]},{"id":"203b514b.555fee","type":"change","z":"187a1471.2d90bc","name":"Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1322,"y":143,"wires":[["fce431e4.be80a"]]},{"id":"1ab3e473.cebc34","type":"change","z":"187a1471.2d90bc","name":"Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"ECO","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1319,"y":90,"wires":[["fce431e4.be80a"]]},{"id":"fce431e4.be80a","type":"openhab2-out","z":"187a1471.2d90bc","name":"Target Mode","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentMode","topic":"ItemCommand","payload":"","x":1508,"y":179,"wires":[]},{"id":"c79cf5db.d7e8f","type":"openhab2-out","z":"187a1471.2d90bc","name":"Target Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_TargetSetPoint","topic":"ItemCommand","payload":"","x":1511,"y":369,"wires":[]},{"id":"b762b8c6.ca55a8","type":"openhab2-controller","z":"","name":"OpenHAB","protocol":"http","host":"localhost","port":"8080","path":"","username":"openhabianpi","password":"Nexus_0017"},{"id":"1532ba0d.edf9e6","type":"homekit-bridge","z":"","bridgeName":"Hallway Bridge","pinCode":"225-00-212","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"}]

I’ve attached a screenshot and the flow code. It’s easier for me to do it this way as it allows me to step through the code much easier than integrating it all in a function. I have a trigger node which institutes a 3 second delay before the function sends the target temperature to the Nest API. This is because Google limits the number of API calls (and while probably not necessary) just keeps my mind at ease.

Oh and currently my “Off” call is really a call to Eco mode on the NEST. Obviously you can change that to truly reflect off, but I’d personally rather put it in Eco anyway.

1 Like

ok, i tried it like this

[{"id":"75ce3e3e.3aaaf","type":"homekit-service","z":"f3d5f228.79716","bridge":"a7511ed2.bcd4f","name":"Timer HHK","serviceName":"Switch","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{\n \"On\":true,\n \"On\":false\n} \n","x":579.5,"y":694,"wires":[["425e973b.189c78"]]},{"id":"425e973b.189c78","type":"debug","z":"f3d5f228.79716","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1015.5,"y":700,"wires":[]},{"id":"a7511ed2.bcd4f","type":"homekit-bridge","z":"","bridgeName":"Homekit-Bridge","pinCode":"031-45-154","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"}]

But i get NO message in the debug-node.

For this one you’ll need to clear out the “characteristic properties” - that should just be {} for a normal switch.

Then deploy and restart node red with sudo systemctl restart nodered.service (assuming you’re on raspbian?)

Once you’ve done this you should be able to switch “Timer HHK” on and off from your phone homekit and see this in the debug:

{"On": true}
{"On": false}

From there you can read about how the bigtimer works and should be able to put it together. I have a similar item in my setup that lets me turn on/off my “haunted” mode - for making the lights turn on and off at random when we are on vacation or want to creep out visitors. Looks like this:

Code:

[{"id":"5221bc4a.7406e4","type":"homekit-service","z":"5d639f8.868e4e","bridge":"4b4fbb6e.6cfaec","name":"Haunted","serviceName":"Switch","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{}","x":100,"y":1240,"wires":[["2ca07061.e7c7b8"]]},{"id":"2ca07061.e7c7b8","type":"function","z":"5d639f8.868e4e","name":"Make it haunted","func":"var haunt = global.get('haunt')||0;\nif(msg.payload.On === false){\n    haunt = 0;\n    global.set('haunt',haunt);\n}\nif(msg.payload.On === true){\n    haunt = 1;\n    global.set('haunt',haunt);\n}\nmsg.payload = haunt;\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":1240,"wires":[[]]},{"id":"4b4fbb6e.6cfaec","type":"homekit-bridge","z":"","bridgeName":"Node Red","pinCode":"514-02-658","port":"","manufacturer":"Garrett Porter","model":"Pi3","serialNo":"Rev.1"}]

ok, thanks very much, Garrett!!
This worked. Now i have to figure out, how to keep the state form this homekit-switch over all iOS-Devices.

…solved it like this:

Thanks @crxporter and @ae_0017 for all the help with my NEST setup.

Here is what I’ve come up with. I started with @ae_0017’s flow but modified it to handle Fahrenheit temperatures coming from and to openHAB (I just did mathematical conversions in the function nodes). I also included humidity measurements just for fun and split up the target and current state messages. Now, HomeKit can show me when the furnace is actually calling for heat rather than just when it’s turned on and ready to go.

[{"id":"27de070e.894f88","type":"openhab2-in","z":"4cdce619.771d08","name":"Current Mode","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_Mode","x":90,"y":160,"wires":[["c6914aa1.7d6478"],[]]},{"id":"46e37c08.e44a84","type":"openhab2-in","z":"4cdce619.771d08","name":"Current Temp","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_Temp","x":90,"y":400,"wires":[["7c1a89cc.fd8c68"],[]]},{"id":"d0d38764.0cc648","type":"openhab2-in","z":"4cdce619.771d08","name":"Target Temp","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_SP","x":90,"y":280,"wires":[["99912d20.0e466"],[]]},{"id":"c6914aa1.7d6478","type":"switch","z":"4cdce619.771d08","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"COOL","vt":"str"},{"t":"eq","v":"HEAT","vt":"str"},{"t":"eq","v":"AUTO","vt":"str"},{"t":"eq","v":"OFF","vt":"str"},{"t":"eq","v":"ECO","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":450,"y":80,"wires":[["5e3d8c65.474bb4"],["61fcaf63.86e9b"],["75ec1436.fde05c"],["bb063419.b46468"],["bb063419.b46468"]]},{"id":"99912d20.0e466","type":"trigger","z":"4cdce619.771d08","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":320,"y":280,"wires":[["3b73aba.6b2e054"]]},{"id":"3b73aba.6b2e054","type":"function","z":"4cdce619.771d08","name":"","func":"{\nval = parseFloat(msg.payload).toFixed(1);\nf = (val - 32) * 0.5556;\n}\n\n{\nmsg.payload = {\n    TargetTemperature: + f\n    }\n;\n}\nreturn msg;","outputs":1,"noerr":0,"x":650,"y":300,"wires":[["495bb036.a22c5"]]},{"id":"7c1a89cc.fd8c68","type":"function","z":"4cdce619.771d08","name":"","func":"\n{\nval = parseFloat(msg.payload).toFixed(1)\nf = (val - 32) * 0.5556;\n\n}\n{\nmsg.payload = {\n CurrentTemperature: + f\n\n}\n}\nreturn msg;\n\n\n\n","outputs":1,"noerr":0,"x":650,"y":380,"wires":[["495bb036.a22c5"]]},{"id":"cbab5368.42145","type":"change","z":"4cdce619.771d08","name":"Current Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":180,"wires":[["495bb036.a22c5"]]},{"id":"bb063419.b46468","type":"change","z":"4cdce619.771d08","name":"Target Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":140,"wires":[["495bb036.a22c5"]]},{"id":"75ec1436.fde05c","type":"change","z":"4cdce619.771d08","name":"Target Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":3}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":100,"wires":[["495bb036.a22c5"]]},{"id":"a564a00b.10c64","type":"change","z":"4cdce619.771d08","name":"Current Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":220,"wires":[["495bb036.a22c5"]]},{"id":"61fcaf63.86e9b","type":"change","z":"4cdce619.771d08","name":"Target Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":60,"wires":[["495bb036.a22c5"]]},{"id":"d93d193.09e57e8","type":"change","z":"4cdce619.771d08","name":"Current Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":260,"wires":[["495bb036.a22c5"]]},{"id":"5e3d8c65.474bb4","type":"change","z":"4cdce619.771d08","name":"Target Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":20,"wires":[["495bb036.a22c5"]]},{"id":"495bb036.a22c5","type":"homekit-service","z":"4cdce619.771d08","bridge":"467c262f.9839","name":"NEST","serviceName":"Thermostat","manufacturer":"NestLabs","model":"3rd Generation","serialNo":"Default Serial Number","characteristicProperties":"{}","x":830,"y":40,"wires":[["f5d928d6.3ffaf8","bde0fd55.4fb44"]]},{"id":"bde0fd55.4fb44","type":"switch","z":"4cdce619.771d08","name":"HomeKit Triggered","property":"hap.context","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":1010,"y":40,"wires":[["b366eb66.3435d8"]]},{"id":"bb2d229f.70fdf","type":"trigger","z":"4cdce619.771d08","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":900,"y":320,"wires":[["bab80779.30ffe8"]]},{"id":"bab80779.30ffe8","type":"json","z":"4cdce619.771d08","name":"","property":"payload","action":"","pretty":false,"x":1030,"y":320,"wires":[["b82a7183.fdb8e"]]},{"id":"b366eb66.3435d8","type":"template","z":"4cdce619.771d08","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.TargetHeatingCoolingState}}","output":"str","x":1200,"y":40,"wires":[["ca965786.c6e858"]]},{"id":"ca965786.c6e858","type":"switch","z":"4cdce619.771d08","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":850,"y":220,"wires":[["e6c0c805.049d28"],["ee3a4f61.aeef3"],["cf0b76a7.efe538"],["91ff824a.6ad7e"]]},{"id":"b82a7183.fdb8e","type":"switch","z":"4cdce619.771d08","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"TargetTemperature","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1150,"y":320,"wires":[["fce5dd93.006588"]]},{"id":"91ff824a.6ad7e","type":"change","z":"4cdce619.771d08","name":"Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT/COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":280,"wires":[["2f313a68.bb2456"]]},{"id":"cf0b76a7.efe538","type":"change","z":"4cdce619.771d08","name":"Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":240,"wires":[["2f313a68.bb2456"]]},{"id":"ee3a4f61.aeef3","type":"change","z":"4cdce619.771d08","name":"Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":200,"wires":[["2f313a68.bb2456"]]},{"id":"e6c0c805.049d28","type":"change","z":"4cdce619.771d08","name":"Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"ECO","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":160,"wires":[["2f313a68.bb2456"]]},{"id":"2f313a68.bb2456","type":"openhab2-out","z":"4cdce619.771d08","name":"Target Mode","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_Mode","topic":"ItemCommand","payload":"","x":1170,"y":220,"wires":[]},{"id":"3c5991ec.13b55e","type":"openhab2-out","z":"4cdce619.771d08","name":"Target Temp","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_SP","topic":"ItemCommand","payload":"","x":1170,"y":380,"wires":[]},{"id":"fce5dd93.006588","type":"function","z":"4cdce619.771d08","name":"","func":"{\nval = msg.payload.substring(21,msg.payload.length - 1)\nf = (val * 1.8) + 32;\npl = f + \" °F\";\n}\n\n{\nmsg.payload = pl;\n    \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":870,"y":380,"wires":[["3c5991ec.13b55e"]]},{"id":"5ec48513.35bcac","type":"openhab2-in","z":"4cdce619.771d08","name":"Current Humidity","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_Hum","x":100,"y":340,"wires":[["1cb2cdbd.595752"],[]]},{"id":"1cb2cdbd.595752","type":"function","z":"4cdce619.771d08","name":"","func":"\n{\n\nval = parseFloat(msg.payload).toFixed(1);\n\n}\n{\nmsg.payload = {\n CurrentRelativeHumidity: + val\n\n}\n}\nreturn msg;\n\n\n\n","outputs":1,"noerr":0,"x":650,"y":340,"wires":[["495bb036.a22c5"]]},{"id":"b454298d.584de8","type":"openhab2-in","z":"4cdce619.771d08","name":"","controller":"b71fea36.e2bda","itemname":"A_HVAC_NEST_State","x":120,"y":220,"wires":[["40a52f45.8c73f"],[]]},{"id":"1248a4fb.f123fb","type":"switch","z":"4cdce619.771d08","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"OFF","vt":"str"},{"t":"eq","v":"HEATING","vt":"str"},{"t":"eq","v":"COOLING","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":470,"y":220,"wires":[["cbab5368.42145"],["a564a00b.10c64"],["d93d193.09e57e8"]]},{"id":"7ac4610e.0af2b","type":"comment","z":"4cdce619.771d08","name":"HomeKit / openHAB / NEST Integration","info":"Modified by DOME for Fahrenheit values and to utilize NEST current state and humidity readings.","x":170,"y":40,"wires":[]},{"id":"f5d928d6.3ffaf8","type":"link out","z":"4cdce619.771d08","name":"","links":["d84e8b.ca26e178"],"x":935,"y":80,"wires":[]},{"id":"d84e8b.ca26e178","type":"link in","z":"4cdce619.771d08","name":"","links":["f5d928d6.3ffaf8"],"x":795,"y":320,"wires":[["bb2d229f.70fdf"]]},{"id":"40a52f45.8c73f","type":"trigger","z":"4cdce619.771d08","op1":"","op2":"","op1type":"pay","op2type":"payl","duration":"5","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":320,"y":220,"wires":[["1248a4fb.f123fb"]]},{"id":"b71fea36.e2bda","type":"openhab2-controller","z":"","name":"openHAB Archon","protocol":"http","host":"192.168.1.80","port":"8080","path":"","username":"","password":""},{"id":"467c262f.9839","type":"homekit-bridge","z":"","bridgeName":"node-RED","pinCode":"111-11-111","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"}]

Here is a simple Security System/Mode interface.

[{"id":"e169f5fb.2d6e58","type":"homekit-service","z":"d27b17dd.6f9178","bridge":"467c262f.9839","name":"Mode","serviceName":"SecuritySystem","manufacturer":"openHAB","model":"Security","serialNo":"SEC1","characteristicProperties":"{}","x":650,"y":320,"wires":[["1dd129ed.3600c6"]]},{"id":"4de2a843.357ec8","type":"comment","z":"d27b17dd.6f9178","name":"Security System & Mode","info":"","x":150,"y":340,"wires":[]},{"id":"b842c690.e32798","type":"openhab2-in","z":"d27b17dd.6f9178","name":"","controller":"b71fea36.e2bda","itemname":"S_SYSP_Mode","x":120,"y":400,"wires":[["5800eb72.6bcba4"],[]]},{"id":"5800eb72.6bcba4","type":"switch","z":"d27b17dd.6f9178","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Home","vt":"str"},{"t":"eq","v":"Away","vt":"str"},{"t":"eq","v":"Night","vt":"str"},{"t":"eq","v":"Off","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":310,"y":400,"wires":[["70ea5789.c46808"],["ccda47c0.c3e438"],["efec486b.b17f88"],["f7594072.3ef1c"]]},{"id":"70ea5789.c46808","type":"change","z":"d27b17dd.6f9178","name":"Home","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"SecuritySystemCurrentState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":340,"wires":[["e169f5fb.2d6e58"]]},{"id":"ccda47c0.c3e438","type":"change","z":"d27b17dd.6f9178","name":"Away","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"SecuritySystemCurrentState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":380,"wires":[["e169f5fb.2d6e58"]]},{"id":"efec486b.b17f88","type":"change","z":"d27b17dd.6f9178","name":"Night","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"SecuritySystemCurrentState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":420,"wires":[["e169f5fb.2d6e58"]]},{"id":"f7594072.3ef1c","type":"change","z":"d27b17dd.6f9178","name":"Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"SecuritySystemCurrentState\":3}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":460,"wires":[["e169f5fb.2d6e58"]]},{"id":"1dd129ed.3600c6","type":"function","z":"d27b17dd.6f9178","name":"Anti-Loop","func":"if (msg.hap.context !== undefined) {\n    msg.payload = msg.payload.SecuritySystemTargetState\n    return msg\n}\n","outputs":1,"noerr":0,"x":820,"y":320,"wires":[["94c901f5.2e114"]]},{"id":"94c901f5.2e114","type":"switch","z":"d27b17dd.6f9178","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":670,"y":440,"wires":[["380c3abe.a99706"],["3b47e835.7dd538"],["c5e1398d.8ff418"],["6cf45b25.38f794"]]},{"id":"380c3abe.a99706","type":"change","z":"d27b17dd.6f9178","name":"Home","rules":[{"t":"set","p":"payload","pt":"msg","to":"Home","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":380,"wires":[["1045dc74.7d3194"]]},{"id":"3b47e835.7dd538","type":"change","z":"d27b17dd.6f9178","name":"Away","rules":[{"t":"set","p":"payload","pt":"msg","to":"Away","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":420,"wires":[["1045dc74.7d3194"]]},{"id":"c5e1398d.8ff418","type":"change","z":"d27b17dd.6f9178","name":"Night","rules":[{"t":"set","p":"payload","pt":"msg","to":"Night","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":460,"wires":[["1045dc74.7d3194"]]},{"id":"6cf45b25.38f794","type":"change","z":"d27b17dd.6f9178","name":"Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"Off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":500,"wires":[["1045dc74.7d3194"]]},{"id":"1045dc74.7d3194","type":"openhab2-out","z":"d27b17dd.6f9178","name":"","controller":"b71fea36.e2bda","itemname":"S_SYSP_Mode","topic":"ItemCommand","payload":"","x":1040,"y":420,"wires":[]},{"id":"467c262f.9839","type":"homekit-bridge","z":"","bridgeName":"node-RED","pinCode":"111-11-111","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"},{"id":"b71fea36.e2bda","type":"openhab2-controller","z":"","name":"openHAB Archon","protocol":"http","host":"192.168.1.80","port":"8080","path":"","username":"","password":""}]

Here’s a simple Fan:

[{"id":"51eae811.05e998","type":"comment","z":"4cdce619.771d08","name":"Fans","info":"","x":70,"y":620,"wires":[]},{"id":"a77548c3.da8458","type":"function","z":"4cdce619.771d08","name":"HK to OH","func":"var b = context.get('b')||0;\nif(msg.payload.RotationSpeed){\n    b = msg.payload.RotationSpeed;\n    context.set('b',b);\n    msg.payload=b\n}\nif (msg.hap.context !== undefined) {\n    if(msg.payload.RotationSpeed === 0){\n        msg.payload = 0\n    }\n    if(msg.payload.On === false){\n        msg.payload = 0\n    }\n    if(msg.payload.On === true){\n        msg.payload = b\n    }\n    return msg\n}","outputs":1,"noerr":0,"x":800,"y":680,"wires":[["6e9e333f.42f65c"]]},{"id":"56b3c941.017218","type":"homekit-service","z":"4cdce619.771d08","bridge":"467c262f.9839","name":"Sun Room Fan","serviceName":"Fan","manufacturer":"Jasco","model":"Jasco","serialNo":"J1","characteristicProperties":"{\"RotationSpeed\":true}","x":580,"y":680,"wires":[["a77548c3.da8458"]],"inputLabels":["{\"RotationSpeed\":true}"]},{"id":"6e9e333f.42f65c","type":"openhab2-out","z":"4cdce619.771d08","name":"","controller":"b71fea36.e2bda","itemname":"A_3SUN_ZW_Fan_Speed","topic":"ItemCommand","payload":"","x":1040,"y":680,"wires":[]},{"id":"1abba446.11c8bc","type":"function","z":"4cdce619.771d08","name":"OH to HK","func":"var input = msg.payload;\nif (input < 101){\n    if (input < 1) {\n        msg.payload = {\n        \"On\": false\n    }\n    }\n    else {\n        msg.payload = {\n        \"RotationSpeed\": input,\n        \"On\": true\n    }\n    }\n    return msg;\n}","outputs":1,"noerr":0,"x":380,"y":680,"wires":[["56b3c941.017218"]]},{"id":"45b8ca63.f51544","type":"openhab2-in","z":"4cdce619.771d08","name":"","controller":"b71fea36.e2bda","itemname":"A_3SUN_ZW_Fan_Speed","x":130,"y":680,"wires":[["1abba446.11c8bc"],[]]},{"id":"467c262f.9839","type":"homekit-bridge","z":"","bridgeName":"node-RED","pinCode":"111-11-111","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"},{"id":"b71fea36.e2bda","type":"openhab2-controller","z":"","name":"openHAB Archon","protocol":"http","host":"192.168.1.80","port":"8080","path":"","username":"","password":""}]

Again, thanks for all the help. I’m having a lot of fun and am working to move all my automations and rules to node-RED.

1 Like

@crxporter
Hello,
to manage the TV with volume and mute which accessory should I use?

If you want these to be available in Apple’s home app you could use mute as an on/off switch and volume as a dimmer. Or combine them into one dimmer.

I haven’t ever used the audio system items of homekit though I know you need to use an app like eve to control those items.

The beauty of this node red setup is you’re only limited by your imagination and programming skills!! Play with it for a while then let us know what you come up with!

Quick update for everyone: a new version of this just dropped (version 0.6) with some very cool new features that I don’t think are available elsewhere for openhab <-> homekit.

The big one is linked services. This will allow many new features to be added to homekit using this plugin including:

  • Battery status (battery level, charging state, low battery warning)
  • HVAC and air purifier filter status
  • Multi valve irrigation system (instead of individual valves)
  • Linking multi-sensors (Aotec MultiSensor 6 for example)

Additionally a lot of work is being done on this node-red plugin. I’ve been working a lot on new documentation and examples.

Over the coming weeks I plan to add some openhab specific examples - first up will be adding “No Response” reporting to homekit for any item who’s state is “null” in openhab.

If anyone has an idea of something they’d like to see - comment and I’ll see what I can put together!

1 Like

I played with this some more and got Heating and Cooling Thresholds to work properly as well. So now the auto mode actually adjusts the temperature range like it should. It’s amazing how powerful these nodes are.

[{"id":"93dcea3d.c82c98","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current State","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentState","x":98.5,"y":128,"wires":[["21838fa.3150bf"],[]]},{"id":"203774c6.1da0e4","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current Mode","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentMode","x":110,"y":236,"wires":[["d75cad4b.f19bf"],[]]},{"id":"4811709a.5baa7","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentTemperature","x":101.5,"y":323,"wires":[["c08ebe89.d3ee1"],[]]},{"id":"45959d01.a9b2d4","type":"openhab2-in","z":"187a1471.2d90bc","name":"Target Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_TargetSetPoint","x":106.5,"y":377,"wires":[["b56489e4.c69458"],[]]},{"id":"ab218723.9e0778","type":"openhab2-in","z":"187a1471.2d90bc","name":"Auto Heat Target","controller":"b762b8c6.ca55a8","itemname":"NestHallwayThermostat_MinSetPoint","x":113.5,"y":430,"wires":[["d1eb3a40.4e04c8"],[]]},{"id":"cfe6bf7f.bd27","type":"openhab2-in","z":"187a1471.2d90bc","name":"Auto Cool Target","controller":"b762b8c6.ca55a8","itemname":"NestHallwayThermostat_MaxSetPoint","x":112.5,"y":479,"wires":[["e9c116e6.16815"],[]]},{"id":"b0b142a0.f7d1f8","type":"openhab2-in","z":"187a1471.2d90bc","name":"Current Humidity","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_Humidity","x":130.5,"y":536,"wires":[["f446d29c.0a0fc8"],[]]},{"id":"21d65d98.379052","type":"openhab2-in","z":"187a1471.2d90bc","name":"Fan","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_FanTimerActive","x":107.5,"y":587,"wires":[["f4685822.504fb"],[]]},{"id":"f4685822.504fb","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"ON","vt":"str"},{"t":"eq","v":"OFF","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":240.5,"y":622,"wires":[["69f600d8.f282e8","347d14ed.827de4"],["e06bcc9d.d91e9"]]},{"id":"e9c116e6.16815","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":300,"y":480,"wires":[["dbfc0848.be5808"]]},{"id":"d1eb3a40.4e04c8","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":296,"y":436,"wires":[["2990f648.23bb2a"]]},{"id":"b56489e4.c69458","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":292.5,"y":382,"wires":[["2803a82f.2dc2b8"]]},{"id":"d75cad4b.f19bf","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"COOL","vt":"str"},{"t":"eq","v":"HEAT","vt":"str"},{"t":"eq","v":"HEAT_COOL","vt":"str"},{"t":"eq","v":"ECO","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":272,"y":244,"wires":[["11dcbaf7.1cdb8d"],["ec48caa3.7bd978"],["a52c39b2.77654"],["72c67fa8.b96f98"]]},{"id":"21838fa.3150bf","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"COOLING","vt":"str"},{"t":"eq","v":"HEATING","vt":"str"},{"t":"eq","v":"OFF","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":266.5,"y":165,"wires":[["2bb21ab.8412866"],["4b023924.a43628"],["14ce4810.576148"]]},{"id":"2bb21ab.8412866","type":"change","z":"187a1471.2d90bc","name":"Current Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":464,"y":36,"wires":[["b9e4991b.c0ce2"]]},{"id":"4b023924.a43628","type":"change","z":"187a1471.2d90bc","name":"Current Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":463,"y":76,"wires":[["b9e4991b.c0ce2"]]},{"id":"14ce4810.576148","type":"change","z":"187a1471.2d90bc","name":"Current Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":462,"y":114,"wires":[["b9e4991b.c0ce2"]]},{"id":"11dcbaf7.1cdb8d","type":"change","z":"187a1471.2d90bc","name":"Target Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":446,"y":239,"wires":[["b9e4991b.c0ce2"]]},{"id":"ec48caa3.7bd978","type":"change","z":"187a1471.2d90bc","name":"Target Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":447,"y":285,"wires":[["b9e4991b.c0ce2"]]},{"id":"a52c39b2.77654","type":"change","z":"187a1471.2d90bc","name":"Target Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":3}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":448,"y":329,"wires":[["b9e4991b.c0ce2"]]},{"id":"72c67fa8.b96f98","type":"change","z":"187a1471.2d90bc","name":"Target Eco","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetHeatingCoolingState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":448,"y":371,"wires":[["b9e4991b.c0ce2"]]},{"id":"f446d29c.0a0fc8","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n CurrentRelativeHumidity: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":456,"y":501,"wires":[["b9e4991b.c0ce2"]]},{"id":"69f600d8.f282e8","type":"change","z":"187a1471.2d90bc","name":"Current Fan On","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentFanState\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":461,"y":542,"wires":[[]]},{"id":"347d14ed.827de4","type":"openhab2-get","z":"187a1471.2d90bc","name":"","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentState","x":470.5,"y":581,"wires":[["ed7665.b6823998"]]},{"id":"e06bcc9d.d91e9","type":"change","z":"187a1471.2d90bc","name":"Current Fan Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"CurrentFanState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":461,"y":620,"wires":[[]]},{"id":"ed7665.b6823998","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload.state","propertyType":"msg","rules":[{"t":"eq","v":"OFF","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":709.5,"y":614,"wires":[["66fa22fe.35eb7c"],["6ef73424.a5b274"]]},{"id":"dbfc0848.be5808","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n CoolingThresholdTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":616,"y":513,"wires":[["b9e4991b.c0ce2"]]},{"id":"2990f648.23bb2a","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n HeatingThresholdTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":617,"y":463,"wires":[["b9e4991b.c0ce2"]]},{"id":"c08ebe89.d3ee1","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n CurrentTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":618.5,"y":411,"wires":[["b9e4991b.c0ce2"]]},{"id":"2803a82f.2dc2b8","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = {\n TargetTemperature: + parseFloat(msg.payload).toFixed(1)\n};\nreturn msg;","outputs":1,"noerr":0,"x":617.5,"y":352,"wires":[["b9e4991b.c0ce2"]]},{"id":"b9e4991b.c0ce2","type":"homekit-service","z":"187a1471.2d90bc","bridge":"1532ba0d.edf9e6","name":"Thermostat","serviceName":"Thermostat","manufacturer":"NestLabs","model":"3rd Generation","serialNo":"Default Serial Number","characteristicProperties":"{}","x":637.5,"y":286,"wires":[["c9b9a891.73d338","2fd8e382.8b6c3c"]]},{"id":"c9b9a891.73d338","type":"switch","z":"187a1471.2d90bc","name":"HomeKit Triggered","property":"hap.context","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":870,"y":245,"wires":[["d7ef2956.8f7a78"]]},{"id":"2fd8e382.8b6c3c","type":"json","z":"187a1471.2d90bc","name":"","property":"payload","action":"","pretty":false,"x":823,"y":314,"wires":[["c9123698.04db58"]]},{"id":"66fa22fe.35eb7c","type":"change","z":"187a1471.2d90bc","name":"Target Fan Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetFanState\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":896,"y":568,"wires":[[]]},{"id":"6ef73424.a5b274","type":"change","z":"187a1471.2d90bc","name":"Target Fan Manual","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"TargetFanState\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":907,"y":612,"wires":[[]]},{"id":"c9123698.04db58","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"TargetTemperature","vt":"str"},{"t":"cont","v":"HeatingThreshold","vt":"str"},{"t":"cont","v":"CoolingThreshold","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":960,"y":344,"wires":[["831367a9.57a3c"],["4dbc416a.98f478"],["d9241767.0595f8"]]},{"id":"d7ef2956.8f7a78","type":"template","z":"187a1471.2d90bc","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.TargetHeatingCoolingState}}","output":"str","x":1035,"y":213,"wires":[["bed43c8a.9b9b2"]]},{"id":"bed43c8a.9b9b2","type":"switch","z":"187a1471.2d90bc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":1187,"y":180,"wires":[["1ab3e473.cebc34"],["203b514b.555fee"],["eb554923.ee1828"],["7666e7e6.86c8e"]]},{"id":"831367a9.57a3c","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = msg.payload.substring(21,msg.payload.length - 1) + \" °C\";\nreturn msg;","outputs":1,"noerr":0,"x":1175,"y":333,"wires":[["bbbb8110.640c58"]]},{"id":"4dbc416a.98f478","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = msg.payload.substring(31,msg.payload.length - 1) + \" °C\";\nreturn msg;","outputs":1,"noerr":0,"x":1175,"y":377,"wires":[["33ac206e.65a908"]]},{"id":"d9241767.0595f8","type":"function","z":"187a1471.2d90bc","name":"","func":"msg.payload = msg.payload.substring(31,msg.payload.length - 1) + \" °C\";\nreturn msg;","outputs":1,"noerr":0,"x":1176,"y":423,"wires":[["8fe9e967.ffa808"]]},{"id":"1ab3e473.cebc34","type":"change","z":"187a1471.2d90bc","name":"Eco","rules":[{"t":"set","p":"payload","pt":"msg","to":"ECO","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1319,"y":90,"wires":[["fce431e4.be80a"]]},{"id":"203b514b.555fee","type":"change","z":"187a1471.2d90bc","name":"Heat","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1322,"y":143,"wires":[["fce431e4.be80a"]]},{"id":"eb554923.ee1828","type":"change","z":"187a1471.2d90bc","name":"Cool","rules":[{"t":"set","p":"payload","pt":"msg","to":"COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1322,"y":198,"wires":[["fce431e4.be80a"]]},{"id":"7666e7e6.86c8e","type":"change","z":"187a1471.2d90bc","name":"Auto","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEAT_COOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1324,"y":256,"wires":[["fce431e4.be80a"]]},{"id":"bbbb8110.640c58","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":1338.5,"y":351,"wires":[["c79cf5db.d7e8f"]]},{"id":"33ac206e.65a908","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":1339,"y":396,"wires":[["716d018b.1425e"]]},{"id":"8fe9e967.ffa808","type":"trigger","z":"187a1471.2d90bc","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":1341,"y":442,"wires":[["90dc541d.f677a"]]},{"id":"fce431e4.be80a","type":"openhab2-out","z":"187a1471.2d90bc","name":"Target Mode","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_CurrentMode","topic":"ItemCommand","payload":"","x":1508,"y":179,"wires":[]},{"id":"c79cf5db.d7e8f","type":"openhab2-out","z":"187a1471.2d90bc","name":"Target Temp","controller":"b762b8c6.ca55a8","itemname":"HallwayThermostat_TargetSetPoint","topic":"ItemCommand","payload":"","x":1511,"y":369,"wires":[]},{"id":"716d018b.1425e","type":"openhab2-out","z":"187a1471.2d90bc","name":"Auto Heat Target","controller":"b762b8c6.ca55a8","itemname":"NestHallwayThermostat_MinSetPoint","topic":"ItemCommand","payload":"","x":1530.5,"y":415,"wires":[]},{"id":"90dc541d.f677a","type":"openhab2-out","z":"187a1471.2d90bc","name":"Auto Cool Target","controller":"b762b8c6.ca55a8","itemname":"NestHallwayThermostat_MaxSetPoint","topic":"ItemCommand","payload":"","x":1527.5,"y":460,"wires":[]},{"id":"b762b8c6.ca55a8","type":"openhab2-controller","z":"","name":"OpenHAB","protocol":"http","host":"localhost","port":"8080","path":"","username":"openhabianpi","password":"Nexus_0017"},{"id":"1532ba0d.edf9e6","type":"homekit-bridge","z":"","bridgeName":"Hallway Bridge","pinCode":"225-00-212","port":"","manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number"}]
1 Like

Woah this is intense. I’ve been thinking about moving my ecobee so it goes through openhab instead of native homekit (it’s less reliable on homekit than ecobee app).

I’ll be back here for this once I get around to that change.

That’s excellent! It’s also applicable to roller shutters.

What you basically do, is first sending a message containing the TargetPosition to the HomeKit node, and then waiting until the curtains (or roller shutters) have been fully opened or closed (fixed timer - in your case 12 seconds) before issuing a delayed message containing the TargetPosition stored in the CurrentPosition parameter, so HomeKit knows the target value has been reached.

I’d say that it’s a very valuable addition in case you don’t have positional feedback from your curtains, blinds or roller shutters.

To make the code easier to understand, I’d suggest renaming delay with delayedMsg or even msgAfterCompletion.

Another important element in this flow is to carefully observe the proper order of the outputs and wires, and making sure you define 2 outputs in the function node, since you’re returning an array of outputs:

  1. msg → output 0 (top) → HomeKit node
  2. delay (or the renamed version) → output 1 (bottom) → Delay node

Normally msg.payload should only contain integer values between 0 and 100, so the following test:

if(input < 101){

could be rewritten in a more intuitive (yet more verbose) way as:

if(input >= 0 && input <= 100){

In case you have roller shutters or curtains that only support full open and full close operations, then the test block can be rewritten as follows:

if ((input == 0) || (input == 100)){
    msg.payload = {
        "TargetPosition": input
    };
    delayedMsg.payload = {
        "CurrentPosition": input
    };
    return [msg,delayedMsg];
} else {
    node.warn("Invalid payload '" + input + "' (expecting 0 or 100) - do nothing")
}

The HomeKit node should use WindowCovering as service.

Normally you don’t need to define Characteristic Properties, unless your blinds or roller shutters only support a fixed number of levels (e.g. steps of 10%). In that case, you may need to set minStep for the Characteristic.

I find this function node the most difficult to understand.

I believe you want to keep track of the TargetPosition value in context variable 't'. It is undefined only when node-red restarts. To make this function code easier to read, I’d suggest giving a more meaningful name to the context variable t.

In this function, I’d also suggest renaming delay so it’s clear that it’s the message that is issued by the delay timer. Here again, make sure to define 2 outputs in the function node and to properly wire them.

If I get it right:

  • You only rewrite the message payload when TargetPosition is defined, so the openhab2-out node can consume the state change (it doesn’t know about the TargetPosition element, as it only expects a number for the state)
  • The delayed message (containing CurrentPosition which is set to TargetPosition after the timer expired) is only needed in case the flow was initiated through HomeKit (e.g. the Home app).

The code contains duplication for TargetPosition nonzero and zero. It can be simplified as follows:

var t = context.get('t')||0;
var delay = {payload:0}
if(msg.payload.TargetPosition !==  undefined){
    t = msg.payload.TargetPosition;
    context.set('t',t);
    msg.payload=t
}
if (msg.hap.context !== undefined){
    delay.payload = {
        "CurrentPosition": t
    };
    return [msg,delay]
}

Finally, by using the link out node to go back to the delay node via the link in node, you make sure the delay timer is used at either side of the HomeKit node.

A neat trick is to use an inject node wired to the HomeKit node, and inject the following JSON:

{"foo":"bar"}

The debug log will complain (“foo” is not defined in HomeKit) show the available set of supported commands, e.g.:

Characteristic foo cannot be written.Try one of these: Name, CurrentPosition, TargetPosition, PositionState, TargetHorizontalTiltAngle, TargetVerticalTiltAngle, CurrentHorizontalTiltAngle, CurrentVerticalTiltAngle, ObstructionDetected, Name

What I couldn’t yet find out, is finding a way to stop the roller shutters (or blinds) in the HomeKit app. If you click the roller shutter button in the Home app, it will only raise or lower the shutters (or blinds), but not halt them if they’re moving.

Finally, I’m still struggling to reliably manage the state changes between Node-Red and OpenHAB2, but I’m afraid that it’s mainly due to the roller shutters I have at home.

First - awesome analysis, and rewrite of my work! It looks like you got it all right. Secretly I’m not really a trained JavaScript programmer (or any other language)… I just hack my way through stuff - believe it or not this is after several rounds of me realizing better ways to do stuff.

I’m probably going to steal a lot of this. I especially like the node.warn - that’ll help me pull errors from my many functions…

There’s been a lot of work recently over at the github site… check out the HoldPosition, PositionState, or ObstructionDetected items on the characteristics wiki page. I would think this would work for reporting to homekit that there is a problem but I don’t think it will give you control over homekit to say “Hey siri stop the shutters!” or anything.

var t = context.get('t')||0;
var delay = {payload:0}
if(msg.payload.TargetPosition){
    t = msg.payload.TargetPosition;
    context.set('t',t);
    msg.payload=t
}
if(msg.payload.TargetPosition === 0){
    t = msg.payload.TargetPosition;
    context.set('t',t);
    msg.payload=t
}
if (msg.hap.context !== undefined){
    delay.payload = {
        "CurrentPosition": t
    };
    return [msg,delay]
}

Regarding this function - I’ll clarify a bit. The only output from HomeKit is TargetPosition when you’re controlling the shutter from within the Home app. This is essentially a request to set the position. The output goes into openhab every time - because that’s a request to change the state of my item. Target position is saved as context mostly because that’s my habit, reviewing today I don’t know if it’s actually necessary here, makes me feel good though.

Then the CurrentPosition message is sent around (through the link node) into the 12 second delay. That’s so HomeKit doesn’t get stuck on “opening” or “closing” status. If CurrentPosition is not equal to TargetPosition then the Home app will show either opening or closing.

Thank you Garrett for your handy solution to HomeKit bridging, I had all but given up hope of presenting my automation in a usable manner on the family iOS devices without the stuck updating and no response.

At the risk of potentially veering a little off topic, with my limited experience I currently don’t know whether I am looking at a node-RED or OpenHAB + Z-Wave binding issue, I am now left with an intermittent problem I have yet to narrow down, I have created two automation rules in HomeKit to turn on my partner’s hydroponics lighting in the morning and off in the evening using OpenHAB2 + Z-Wave + Fibaro power socket switch in place of her old stand alone plug in micro controller timer switch however it is not yet reliable enough to leave in place, basically OpenHAB and HomeKit show the correct status for the switch but the switch itself is not in the desired state.

One observation I have made is I now have two channels shown for the node in the paper UI, one named “Hydroponics” which originates from my items + sitemaps files and the original “Switch” channel from when the Z-Wave device was added to OpenHAB. When either channel is triggered via PaperUI the other soon reflects the same state hence I assumed “Hydroponics” effectively is just an alias, however I note that following the failure of the HomeKit automation the two channels are out of step.

Apologies for the potential thread hijacking, however I am wondering whether this could be related to msg.hap.context checks in the Node-RED flows somehow loosing some state? Any thoughts on likely cause and how to debug it would be appreciated. Thank you.

Actually having started thinking further about this and searching some more, could this be as simple as an association group issue? I’d have thought this only becomes an issue if somebody is making changes outside of the control loop, e.g. press the button on the side of the power switch to change state.

If you figure it out - great!

If you need some help, share the related openhab item(s) and node-red flow. I’d be happy to take a look, along with many others around here

1 Like

Hi there, I’m very interessted in your implementation of:

Would you be so nice to paste your solution here? Would spare me (and others?) al lot of time!
Thanks in advance, Thomas

Have a look at our new Wiki page:

Wiki

Not all of your requested implementation can be found there (I also having problems with some of them), but I will add which I can, in that Wiki soon (maybe weekend). What I could add: Motion Sensor and Contact Sensor.

Lamp with ColorTemp and Brightness (under Light Bulb), TemperatureSensor is there. Have a look at it.

1 Like