My node-red + HomeKit + OpenHAB setup

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

Thanks a lot, it helped and inspired even more ideas :wink:

FYI, I believe I have got to the bottom of my issue now, I updated the lifeline association group of the Fibaro wall socket switch to “Controller” and all subsequent automation events from home kit have succeeded. Not sure if it is just required in general or is making the setup more resilient against a different issue however the setup now appears far more robust that when I posted my question.

Thank you.

If you’re fortunate that your Z-Wave device supports a Lifeline association group and autonomously reports its state, then that’s indeed the best way forward.

Otherwise, you’ll have to provide some extra logic to do the work.

Some older Z-Wave devices don’t report their state, apparently due to a patent application that expired a while ago. In essence a Z-Wave device reporting its state would only be allowed to do so if a license was obtained from the patent applicant. In this case, the only way to get the state of your Z-Wave device, is by explicitly polling. This can happen either in the Z-Wave binding (by setting the command poll period - but limited by the binding to 15 seconds) or in a rule that schedules a status poll after a command was received. Have a look at the following thread for a solution for this case: Z-Wave binding_cmdrepollperiod cannot exceed 15 seconds
Don’t forget to disable autoupdate for such node in case you’re using the rule-based approach. The autoupdate will not check if the end state has been reached, it will assume it did. This can yield inconsistent state information, which you want to avoid in Node-RED when setting up HomeKit support for such device.

I have 3 roof shutters that don’t provide a status update, probably due to this (now expired) patent. Since they take longer than 15 seconds to fully open / close, I had to use a rule to explicitly poll their status after I knew they should have reached their requested end position. They are lowered in 15 seconds and raised in 18 seconds, so I defined 20 seconds as a realistic time interval for polling the roller shutters with a rule (and a timer).

In Node-RED the left-hand side of the homekit-service node can then also be simplified, since the OpenHAB2-in node will only report state updates once they’ve been reached. In that case, there’s no need for the delay node to convey the OpenHAB2-in state to the homekit-service node: just make sure msg.payload sets the target and the current value at the same time to the OH2 state (you may have to convert the OH2 state to HomeKit state depending on the device type), and send it straight to the homekit-service node.


The delay node is only required in case you manipulate a node through HomeKit (e.g., in the Home app). In this case, you want to first send the desired state change (target state in HomeKit language) to the openhab2-out node after converting it if needed, and then sending another message through the delay node to inform HomeKit after a given time (set in the delay node) that the requested position has indeed been reached (current state in HomeKit language).

In essence, the function node at the left can then be simplified to only have 1 output, and the following JS code:

/* OH2 defines OPEN/UP as 0 and CLOSED/DOWN as 100
 * Z-Wave and HomeKit define OPEN as 100 and CLOSED as 0
 *
 * Note: the Fakro ARZ "v2013" roller shutters don't report their state unless explicitly polled.
 * As a result, you can assume that the OH2 state change received in Node-RED has already been reached.
 * This means that there is no delayed message required to manage the state transition in HomeKit
 */

var subject = ""
if (msg.item !== undefined) {
    subject = '[Item ' + msg.item + ']'
} else {
    if (msg.topic !== undefined) {
        subject = '[Topic ' + msg.topic + ']'
    } else {
        subject = '[undefined]'
    }
}
node.log(subject + " - JSON msg = " + JSON.stringify(msg))

var input = msg.payload
node.log(subject + " - Payload: '" + input + "'")

var updatedPosition = 50;
if (input == 'UP') {
    input = 0
} else if(input == 'DOWN') {
    input = 100
}

node.log(subject + " will be " + (input == 0 ? 'OPEN' : (input == 100 ? 'CLOSED' : 'set at ' + input)) )

if ((input == 0) || (input == 100)){ // OH2 state > HomeKit state: invert position
    updatedPosition = 100 - input
} else {
    node.warn(subject + " - Warning: position update '" + input + "' is undefined (expecting 0 or 100)")
}
// Prepare the message for HomeKit (instant state update, hence TargetPosition and CurrentPosition are sent together)
msg.payload = {
    "TargetPosition": updatedPosition,
    "CurrentPosition": updatedPosition
};
return msg;

And to the right of the homekit-service node, the function node still has 2 outputs, but the code reads as follows:

/* OH2 defines OPEN/UP as 0 and CLOSED/DOWN as 100
 * Z-Wave and HomeKit define OPEN as 100 and CLOSED as 0
 *
 * We were called from HomeKit if msg.hap.context is defined (only for new target position)
 *
 * HomeKit will display a spinning sign during the position state update (processed with fixed delay).
 * To stop HomeKit state update from spinning, we will issue a delayed message where "CurrentPosition"
 * will be set to th requested "TargetPosition" value.
 *
 * Note: the Fakro ARZ "v2013" roller shutters don't report their state unless explicitly polled.
 */

if (msg.payload.TargetPosition !== undefined) { // Target Position has been set
    node.log(msg.name + " will be " + (msg.payload.TargetPosition == 100 ? 'OPEN' : (msg.payload.TargetPosition == 0 ? 'CLOSED' : 'set at ' + msg.payload.TargetPosition)) )

    // HomeKit --> OH2: invert position state!
    var OH2state = 100 - msg.payload.TargetPosition
    node.log(msg.name + ": A - HomeKit position '" + msg.payload.TargetPosition + "' --> OH2 state '" + OH2state + "'")
    
    // Update the message payload so OH2 can properly consume it:
    msg.payload = OH2state

    // If we were called through HomeKit, then properly handle the state transition (fixed delay timer)
    if (msg.hap.context !== undefined) {
        node.log(msg.name + ": B - HomeKit context defined - process the HomeKit position update and prepare HomeKit state transition")
        // HomeKit state transition completed message (sets CurrentPosition to TargetPosition):
        var homeKitStateTransitionCompletedMsg = {payload:0}
        homeKitStateTransitionCompletedMsg.payload = { // Set HomeKit CurrentPosition to TargetPosition
            "CurrentPosition": msg.payload.TargetPosition
        };
        // Send msg to OH2 and send homeKitStateTransitionCompletedMsg to the delay node (for HomeKit state update)
        return [msg, homeKitStateTransitionCompletedMsg];
    } /* else {
        node.log(msg.name + ": C - HomeKit context NOT defined - Send OH2 state update but don't do HomeKit stuff")
        return [msg, null]
    } */
} else {
    node.log(msg.name + ": X - TargetPosition not defined (nothing to forward to HomeKit or to OH2)")
    if (msg.payload.CurrentPosition !== undefined) { // Current Position has been set (HomeKit state update)
        node.log(msg.name + " is currently " + (msg.payload.CurrentPosition == 100 ? 'OPEN' : (msg.payload.CurrentPosition == 0 ? 'CLOSED' : 'set at ' + msg.payload.CurrentPosition)) )
        var OH2state = 100 - msg.payload.CurrentPosition
        node.log(msg.name + ": Z - HomeKit position '" + msg.payload.CurrentPosition + "' --> OH2 state '" + OH2state + "'")
    }
}

I added a lot of comments and log messages in the code for comprehension purposes.

1 Like

Many thanks Oliver. Every day is a school day currently for me wrt OpenHAB2, Z-Wave and HomeKit.

Good morning one and all,
Im very new to Node-Red and this forum has been very helpful getting me up and running with HomeKit,
I just have one item that I’m struggling to get my head around–

Im trying to get the Homekit Television service to work but I don’t know what to put in the Characteristics section,

As it stands, I have the OpenHab TV scene working as a switch and this works perfectly but it would be nice to have that TV icon in the HomeKit app.
Any help would be greatly appreciated.

[{"id":"2a96d629.8ad92a","type":"function","z":"54581168.5f6b6","name":"OpenHab To HomeKit","func":"if (msg.payload == \"ON\") {\n    msg.payload = {\n        \"On\": true\n    };\n} else {\n    msg.payload = {\n        \"On\": false\n    };\n}\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":220,"wires":[["1a1e0ed.c7bcc71"]]},{"id":"1a1e0ed.c7bcc71","type":"homekit-service","z":"54581168.5f6b6","isParent":true,"bridge":"90af8346.e9d348","parentService":"","name":"TV","serviceName":"Switch","topic":"","filter":false,"manufacturer":"Neeo","model":"Neeo Scene TV","serialNo":"Default Serial Number","characteristicProperties":"{\n    \n}\n","x":490,"y":220,"wires":[["145f6337.372ecd"]]},{"id":"f21d6a08.74bfe8","type":"openhab2-in","z":"54581168.5f6b6","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","x":110,"y":220,"wires":[["2a96d629.8ad92a"],[]]},{"id":"145f6337.372ecd","type":"function","z":"54581168.5f6b6","name":"HomeKit To OpenHab","func":"if (msg.hap.context !== undefined )\n{\nif(msg.payload.On === false){\n    msg.payload = \"OFF\";\n}\nelse {\n    if(msg.payload.On === true){\n    msg.payload = \"ON\";\n}\n}\nreturn msg;\n}","outputs":1,"noerr":0,"x":680,"y":220,"wires":[["263cb471.47edf4"]]},{"id":"263cb471.47edf4","type":"openhab2-out","z":"54581168.5f6b6","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","topic":"ItemCommand","payload":"","x":850,"y":220,"wires":[["bc50815a.a15c"]]},{"id":"bc50815a.a15c","type":"debug","z":"54581168.5f6b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1010,"y":220,"wires":[]},{"id":"90af8346.e9d348","type":"homekit-bridge","z":"","bridgeName":"Pi3B+","pinCode":"031-45-138","port":"","allowInsecureRequest":true,"manufacturer":"Rasberry Pi3 B+","model":"Pi3 B+","serialNo":"Default Serial Number","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true},{"id":"9650ccbc.234be","type":"openhab2-controller","z":"","name":"OpenHab","protocol":"http","host":"192.168.86.27","port":"8080","path":"","username":"openhabian","password":"openhabian"}]

The TV item is new and most of us (users) are still trying to figure that one out. It does work, I had a working test setup for a few hours but then moved on to something else.

Check out the discussion here for a partial example. I believe the current struggle is getting volume control working. Stay tuned for more on that.

Thanks Garrett for the quick reply,
I will have a look now at the link… For the moment all I want the TV item to do is switch the OpenHab TV scene on and off.
Thanks again for your help.

Shouldn’t be too much trouble to pull out the command(s) to turn it on and off. I don’t remember if it’s a single message or multiple sending to homekit.

Let me know if you can’t get it. The tv item is on my to do list for my next examples…

This is what I have so far but I’m getting this error code.

msg : string[1128]

“response error '{“statusCode”:400,“body”:”\n\n<meta http-equiv=“Content-Type” content=“text/html;charset=utf-8”/>\nError 400 Bad Request\n\n

HTTP ERROR 400

\n

Problem accessing /rest/items/Living_Room_TV. Reason:\n

 Bad Request

<a href=“http://eclipse.org/jetty”>Powered by Jetty:// 9.4.12.v20180830
\n\n\n\n",“headers”:{“connection”:“close”,“cache-control”:“must-revalidate,no-cache,no-store”,“content-type”:“text/html;charset=iso-8859-1”,“content-length”:“346”,“server”:“Jetty(9.4.12.v20180830)”},“request”:{“uri”:{“protocol”:“http:”,“slashes”:true,“auth”:“openhabian:openhabian”,“host”:“192.168.86.27:8080”,“port”:“8080”,“hostname”:“192.168.86.27”,“hash”:null,“search”:null,“query”:null,“pathname”:"/rest/items/Living_Room_TV",“path”:"/rest/items/Living_Room_TV",“href”:“http://openhabian:openhabian@192.168.86.27:8080/rest/items/Living_Room_TV"},“method”:“POST”,“headers”:{“authorization”:"Basic b3B…”
[{"id":"6c070a7.71ca174","type":"debug","z":"2534cf2f.5cfa28","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1050,"y":160,"wires":[]},{"id":"625578c4.99863","type":"homekit-service","z":"2534cf2f.5cfa28","isParent":true,"bridge":"90af8346.e9d348","parentService":"","name":"TTV","serviceName":"Television","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"","x":470,"y":160,"wires":[["b6958fbe.3d93d"]]},{"id":"71d57b31.18c80c","type":"function","z":"2534cf2f.5cfa28","name":"","func":"if (msg.payload===false){\n    msg.payload={\"Active\":0}\n//        nrSource:true\n} else {\n    msg.payload={\"Active\":1}\n//        nrSource:true\n}\nreturn msg","outputs":1,"noerr":0,"x":310,"y":160,"wires":[["625578c4.99863"]]},{"id":"b6958fbe.3d93d","type":"function","z":"2534cf2f.5cfa28","name":"","func":"switch (msg.payload.Active){\n    case 0:\n        msg1 = {payload:\"Off\"};\n        break;\n    case 1:\n        msg1 = {payload:\"On\"};\n        break;\n    default:\n        msg1 = {};\n        return;\n}\nreturn msg1;","outputs":1,"noerr":0,"x":630,"y":160,"wires":[["8690b13c.d8f6"]]},{"id":"8690b13c.d8f6","type":"openhab2-out","z":"2534cf2f.5cfa28","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","topic":"ItemCommand","payload":"","x":830,"y":160,"wires":[["6c070a7.71ca174"]]},{"id":"bed8ea6e.5a22d","type":"openhab2-in","z":"2534cf2f.5cfa28","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","x":110,"y":160,"wires":[["71d57b31.18c80c"],[]]},{"id":"90af8346.e9d348","type":"homekit-bridge","z":"","bridgeName":"Pi3B+","pinCode":"031-45-138","port":"","allowInsecureRequest":true,"manufacturer":"Rasberry Pi3 B+","model":"Pi3 B+","serialNo":"Default Serial Number","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true},{"id":"9650ccbc.234be","type":"openhab2-controller","z":"","name":"OpenHab","protocol":"http","host":"192.168.86.27","port":"8080","path":"","username":"openhabian","password":"openhabian"}]

That looks like an issue with your openhab node - looking at your functions it looks like the old one sent "ON" or "OFF" but your new one is sending "On" and "Off".

That error is with the REST api connection to OpenHab.

My recommendation is put debug nodes all over, watch what comes in/out of them, and make sure the functions you make are all exactly like the messages that need to be sent.

Hi Garrett,
I now have it working.
Im now going to have a play with the inputs to see what els I can do.
Thank you for all your help

[{"id":"625578c4.99863","type":"homekit-service","z":"2534cf2f.5cfa28","isParent":true,"bridge":"90af8346.e9d348","parentService":"","name":"TV","serviceName":"Television","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"","x":470,"y":140,"wires":[["b6958fbe.3d93d"]]},{"id":"71d57b31.18c80c","type":"function","z":"2534cf2f.5cfa28","name":"OpenHab - HomeKit","func":"if (msg.payload == \"ON\") \n{msg.payload={\"Active\":1};\n    \n} \nelse {\n    msg.payload = {\"Active\":0}\n    \n}\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":140,"wires":[["625578c4.99863"]]},{"id":"b6958fbe.3d93d","type":"function","z":"2534cf2f.5cfa28","name":"HomeKit - OpenHab","func":"switch (msg.payload.Active){\n    case 0:\n        msg1 = {payload:\"OFF\"};\n        break;\n    case 1:\n        msg1 = {payload:\"ON\"};\n        break;\n    default:\n        msg1 = {};\n        return;\n}\nreturn msg1;","outputs":1,"noerr":0,"x":660,"y":140,"wires":[["a37f70e9.10f318"]]},{"id":"bed8ea6e.5a22d","type":"openhab2-in","z":"2534cf2f.5cfa28","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","x":90,"y":140,"wires":[["71d57b31.18c80c"],[]]},{"id":"a37f70e9.10f318","type":"openhab2-out","z":"2534cf2f.5cfa28","name":"TV","controller":"9650ccbc.234be","itemname":"Living_Room_TV","topic":"ItemCommand","payload":"","x":850,"y":140,"wires":[[]]},{"id":"90af8346.e9d348","type":"homekit-bridge","z":"","bridgeName":"Pi3B+","pinCode":"031-45-138","port":"","allowInsecureRequest":true,"manufacturer":"Rasberry Pi3 B+","model":"Pi3 B+","serialNo":"Default Serial Number","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true},{"id":"9650ccbc.234be","type":"openhab2-controller","z":"","name":"OpenHab","protocol":"http","host":"192.168.86.27","port":"8080","path":"","username":"openhabian","password":"openhabian"}]

Alas I spoke too soon, the lifeline association group had helped, but, we were still experiencing the occasional missed HomeKit automation event (hydroponics lighting not switching on in the morning or off at night) hence I shall now try Olivier’s other suggestion.

Edit: Argh! So as soon as I went to clear the lifeline association group and try the rules route instead I am left wondering why OpenHAB2 does not show the controller listed for the device. I wonder if I am experiencing Z-wave things lose their Lifeline Association Group or similar.

Because there is a bug in Paper UI that means it doesn’t show the associations properly. If you are using OH2.5, it should not be possible to remove the lifeline as the binding will prevent this if the controller is set to be the master.

If you have problems with this, then I’d suggest to open another discussion and provide debug logs showing the issue as this thread is not really the right place to discuss this issue I think :slight_smile:

1 Like

Did you find any reference for this? I will try your example to turn tv on and off. Would be great if additonal inputs could be selected

Check the issues on the node red plugin GitHub page. I’ve done a quick demo and know that tv on/off as well as input selection (linked services) is working fine. The big unknown right now is volume control…

I’d search for “television”

Thanks, however I couldn’t find the demo code of yours…

Ps.: Television is working flawlessly, however I have added an InputSource linked to the Television but I can’t see it there.

I personally haven’t done any examples.

Check this issue, there are some pasted flows and some text files with flows