I know others have connected their devices and everyone has their own twist on how to do this. My preferred method is to use function nodes wherever possible. This keeps things from getting too messy with all of the switch and change nodes that come up in similar setups.
It came up today when I started showing @rkrisi how to use MQTT+Node-Red to send command line codes to other computers. So here goes.
A couple of prerequisites:
-Install node-red (obviously)
-Add the flow “node-red-contrib-homekit-bridged” from the “Manage Pallets” item in the node-red hamburger menu (top right)
A couple of important comments to avoid problems:
The HomeKit node has a problem when ever it is deployed. If you have to deploy it more than once (hint: you will have to) then you’ll want to restart node-red for HomeKit to keep working. Easiest restart:
sudo systemctl restart nodered.service
Once you’ve got the HomeKit items pretty well set you can go ahead and just set node-red to only deploy modified nodes. Then you’ll only have to restart node-red if your homekit items show the little blue dot (means they’re going to be updated).
Main takeaway here: if homekit is being weird, restart node-red.
Edit: December 18, 2020- this is and has been fixed for a while.
I’ll put screenshots of the whole flow then paste in my functions. In comment #2 on this thread I’ll put my flows that you can just copy and paste into node-red to see everything for yourself.
Switch Item
HomeKit service: “Switch”
OpenHAB to HomeKit function:
if (msg.payload == "ON") {
msg.payload = {
"On": true
};
} else {
msg.payload = {
"On": false
};
}
return msg;
OpenHAB to HomeKit function:
if (msg.hap.context !== undefined )
{
if(msg.payload.On === false){
msg.payload = "OFF";
}
else {
if(msg.payload.On === true){
msg.payload = "ON";
}
}
return msg;
}
These functions “translate” the commands to/from OpenHAB/HomeKit. Pretty straightforward I think except the msg.hap.context which is only “undefined” if the message didn’t come from HomeKit (if you use your phone or siri to control an item then hap.context is NOT undefined - so the first line returns “true”). This prevents loops since the HomeKit node passes everything through. This if statement is used in all of my outgoing functions.
Outlet Item
HomeKit service: “Outlet”
I use this for my MQTT relays. Functions are exactly the same as the switch item above. The “outlet” item has extra items that the switch doesn’t have. For outlet this includes:
"InUse": true //switch using power
"InUse": false //switch not using power
I would use this if I had any power-monitoring outlets - I would set a rule in tasmota to send a message through openhab or just MQTT so that I could trigger whether the outlet is drawing power. Special note if you do this is you’ll want to add “Characteristic Properties” in the HomeKit node so that HomeKit actually shows that “In Use” is an option. There is an example of this below for my dimmers. I haven’t used this characteristic properties for anything but dimmers.
Feel free to show me if you add this.
Fan Item
HomeKit service: “Fan”
Again - same functions as above.
Additional “Characteristic Properties” for this one are (as far as I know):
-fan speed
-oscillating on/off
I have a pretty good idea of how to add this - but I only have on/off bathroom fans in my system so I haven’t actually done it.
Dimmer Item
HomeKit service: “Lightbulb”
Now we need to get more interesting with the functions. First step is put the following in “Characteristic Properties” in the Chandelier HomeKit node:
{"Brightness":true}
This will make it always show as a dimmer in HomeKit instead of an on/off lightbulb.
Dimmer to HK function:
var input = msg.payload;
if (input < 101){
if (input < 1) {
msg.payload = {
"On": false
}
}
else {
msg.payload = {
"Brightness": input,
"On": true
}
}
return msg;
}
I had to be a little careful here with my OpenHAB rules for dimmers. OpenHAB can send “ON”, “OFF”, “NULL”, or a brightness level 0-100. I’ve set my rules so that they only send numerical updates. If I was sending “ON” and “OFF” messages through dimmers I would have to add if statements for those commands.
Dimmer to OH function:
var b = context.get('b')||0;
if(msg.payload.Brightness){
b = msg.payload.Brightness;
context.set('b',b);
msg.payload=b
}
if (msg.hap.context !== undefined) {
if(msg.payload.Brightness === 0){
msg.payload = 0
}
if(msg.payload.On === false){
msg.payload = 0
}
if(msg.payload.On === true){
msg.payload = b
}
return msg
}
The special item here is my global variable. It holds on to the previous state when the item is turned off. This is because HomeKit always remembers the previous state of a dimmer and restores that state with a simple {“On”: true} message. Since OpenHAB doesn’t remember the previous state I just keep it saved in a node-red context variable (context stays only within the current flow).
Smoke Detector
HomeKit service type: “SmokeSensor”
This is an easy one. I’ve got a hardwired relay from my smoke detector to my OpenHAB GPIO. “Open” is fire. “Closed” is no fire.
Run function:
if(msg.payload == "OPEN"){
msg.payload = {
"SmokeDetected": 1
};
return msg
}
if(msg.payload == "CLOSED"){
msg.payload = {
"SmokeDetected": 0
};
return msg
}
This doesn’t have anything coming out of HomeKit because HomeKit can’t set off the fire alarm. It’s a one-way item.
Curtains
HomeKit service type: “WindowCovering”
My curtains are seen by OpenHAB as a dimmer switch. The functions are very similar to dimmers above - with one addition. The “WindowCovering” item looks for 2 signals one to come after the other. First it sets “Target Position” - or where HomeKit wants the curtain to be. Second it sets “Current Position” - or where the curtain actually is. If “target position” is closed when current position is open HomeKit shows “closing”. If target is open when the current position is closed HomeKit shows “opening”.
My curtains take about 12 seconds to open and close so I send the messages out of the function nodes into HomeKit but with a 12-second delay on the “Current Position” so it shows “opening” and “closing” while it’s in motion. Unnecessary but a nice detail.
Target Position function:
var input = msg.payload;
var delay = {payload:0};
if(input < 101){
msg.payload = {
"TargetPosition": input
};
delay.payload = {
"CurrentPosition": input
};
return [msg,delay];
}
Curtain out function:
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]
}
Extra items are available on this one in HomeKit as well. I believe blinds angle and some things with angles. I don’t have windows or blinds like this so I haven’t explored.
Sprinklers Bonus Item
HomeKit item type: “Valve”
This one is not one that just anyone can copy. I’m happy to share more code (I believe I have posted versions of this before) but I had to do a lot more work for this one. I had to get access to the Skydrop sprinkler developer API, use OAUTH2 authentication with myopenhab.org, and put together some nodes (not shown) to hold my access and refresh tokens. But now I can say “hey Siri, start watering the flowers” - which I think is very cool.
This could be done pretty easily I suppose with a few relays attached to a wemos… I won’t go into that. As everything else, feel free to request more details about how I’m handling the sprinklers in HomeKit.
Final Comments
Another thing I’ve done is add extra “switch” items in HomeKit to send messages back to OpenHAB. I use this for presence detection so I have “Anyone Home” as an item that HomeKit turns on when we arrive and off when we leave. Works pretty well for presence detection.
I went into this setup because I wanted to fix some of my issues with HomeKit that seem to be pitfalls with OpenHAB including the poor handling of dimmers, limited HomeKit object types, and problems with disappearing items when I made changes to my .items files. This setup has been running without issues for 3 or 4 months now in my house.
The best way to find out which items are available is to make yourself an inject node, connect it to a HomeKit node and check the “errors” tab in node red. The inject command needs to be JSON and can be any message, I use:
{"Break":"HomeKit"}
I’ll post the text version of all of this (except sprinklers) in my next comment. Then y’all can go ahead and paste it right into node red (hamburger menu - import for beginners).
Enjoy.
Update December 18, 2020: I don’t hang around here much any more. If anyone has questions, feel free to come find me at this GitHub project