My node-red + HomeKit + OpenHAB setup

My take on this is to use a stateless programmable switch. I put up the wiki page about it almost 2 weeks ago.

You get to choose within the switch (button) which scene is triggered by that button press. You would be able to send {"ProgrammableSwitchEvent":0/1/2} into the stateless switch node to trigger that switch button.

I like to do this in OpenHAB with a “dummy switch” that has expire binding set to like 5 seconds. Then make a rule (OH or node red) that changes ON to a number 0/1/2 and send it into your homekit node.

I’m happy to answer any questions, check out that wiki page I linked above and let me know what you think.

That was the Wiki page I stumbled upon when searching for a solution. Sadly I didn’t manage to get it work on my end. I’m using a standard “proxy” On/Off Switch item in OH which I hoped to be able to propagate to HomeKit to enable and disable a given scene.

Meanwhile I’ve seen that the Home app does indeed allow to enable a scene, but not to disable it like a tap on an enabled scene in the Home app does. So I apparently can’t use the “off” state of the switch in OH to deactivate a scene in HomeKit.

I was getting an example ready for you then I stumbled upon your issue as mentioned above - homekit won’t run an automation to “disable a scene”. Best I can tell this is a homekit limitation and scenes can’t be “turned off” from anything but pressing on the scene in the home app… It makes sense though, what would a garage door or thermostat do when it was “turned off”? If the scene is to set the thermostat to 70º, what does turning the scene off set it to?

A (cumbersome) workaround would be to make “on scenes” and “off scenes” in HomeKit. It’ll get messy pretty quickly but it would work.

I’m assuming that you have various “official homekit” devices you are trying to control from OH? Otherwise you could keep the scenes within OH / node red…

Since I was already mostly through the example, I’ll go ahead and share it here:

Note: change the inject nodes for your OH item

40%20AM

This flow gives you 2 “buttons”. I’ve set them to be “arrive home” and “leave home”. As stated above you’ve got the issue where homekit won’t automate scenes turning off.

Now you can link these buttons to set any scene in homekit, I’ve chosen “ON” to be “arrive home” and “OFF” to be “leave home”:

45%20AM

And the copy-paste for you to see my code:

[{"id":"3fdc6bf0.b7263c","type":"homekit-service","z":"c3a5a440.d4673","isParent":true,"bridge":"fc1c5b0d.cd50f8","parentService":"","name":"shutterfreak","serviceName":"StatelessProgrammableSwitch","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{}","x":790,"y":360,"wires":[[]]},{"id":"e0102731.e16d5","type":"inject","z":"c3a5a440.d4673","name":"ON from OpenHAB","topic":"","payload":"ON","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":340,"wires":[["3350e929.8cfb7e"]]},{"id":"52408ac8.b705bc","type":"inject","z":"c3a5a440.d4673","name":"OFF from OpenHAB","topic":"","payload":"OFF","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":380,"wires":[["3350e929.8cfb7e"]]},{"id":"3350e929.8cfb7e","type":"change","z":"c3a5a440.d4673","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"ON","fromt":"str","to":"{\"ProgrammableSwitchEvent\":0}","tot":"json"},{"t":"change","p":"payload","pt":"msg","from":"OFF","fromt":"str","to":"{\"ProgrammableSwitchEvent\":1}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":360,"wires":[["3fdc6bf0.b7263c"]]},{"id":"fc1c5b0d.cd50f8","type":"homekit-bridge","z":"","bridgeName":"Irrigation","pinCode":"123-45-321","port":"","allowInsecureRequest":false,"manufacturer":"Garage","model":"Pi HAT","serialNo":"3Aplus","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true}]
1 Like

I forgot to mention another issue you may run into with the proxy switch - for a normal switch (not stateless), homekit will ignore repeated commands since it remembers the state.

So you can’t send “on” twice in a row and expect the homekit automation to run for the second “on” command - it will be ignored because the light is already on.

The normal switches work like the OH item changed to on rules…

Stateless switches DO respond to repeated commands.

1 Like

@crxporter or others watching this thread, I have question/problem: it seems that HomeKit gets out of sync with the state of things, which then causes issues when I try and use Siri to update an item. For example, HK will think a switch is On, and it I issue a command “turn switch on”, nothing will happen. I believe this is because HK thinks it doesn’t need to take any action. If I were to say “turn switch off”, followed by “turn switch on”, it works, because the “off” command will cause HK to update on its end. If I recall from when I used the HK binding, HK does poll items, but I’m guessing that Node Red is caching the state (or maybe not?). Has anyone seen this problem before?

HomeKit doesn’t really poll anything. The important thing for this to be working properly is to have an openhab node which will receive the item updates then connect that to your homekit node (you’ll need a couple functions in between)

Generally the openhab node should only need to pass state changes into homekit but if it’s anpolling item, that shouldn’t cause problems.

If this doesn’t make sense- share a screenshot of your node red flow and I’ll try pointing you in the right direction!

I’m using basically the setup/functions that you posted at the start of this thread. They seem to generally work fine, in that I can control w/HK → OH w/o issue. The only issue is when HK seems to not have the proper status (sometimes after a restart, or perhaps they get a wrong status somehow?)

Also, if HK doesn’t poll, how does it get an initial status, or what happens after we restart Node RED? Does NR just push all of the statuses of the Items?

Another question around all of this (and maybe part of the problem) is how Dimmers work. I.e. Dimmers originally send their target status (i.e. if it’s turning off, it sends 0), but then will send updated status as they transition, so it looks something start: 100, then 0, then 50, then 0 (depending on timing). Some of this ends up looking a bit odd in HK, as if you turn off a Dimmer, it go from Off, to On (partially) and then eventually off.

Finally, re: polling. When I was using the OH/Homekit binding, I noticed that when you load the HK app on your phone, it would query OH for that statuses of the items. Is that not the case?

Currently the node red homekit node does not have any persistence through node red restarts. There has been some work to add this but it isn’t ready yet.

Everything will go back to the default state- off for switches and dimmers, unlocked for locks, I think closed for contacts- whatever is the “0” value. It will stay there until a different value is sent to the homekit node.

If you are restarting a lot then you will need to find a way to update the status… you can use an inject node during startup to poll openhab and use that polling to go on to homekit. Essentially you need to think of homekit nodes just showing the most recent value they got - or “0” if they haven’t gotten anything since restart. This can be a pain during setup (have to go back and switch everything on/off once to be correct) but once you’re in the running mode it’ll go for months without being touched…

No. The homekit node does not do any action when you open the app on your phone. There was briefly a PR that had another output on the node for this - but it also caused other issues and was not merged in the main code.

Regarding your dimmers - dimmers are a tough item to get just right… I recommend checking out my dimmer example, really study the functions because they’re very important in keeping the dimmer values straight… what hardware are you using?

Your dimmers might need a trigger node to avoid the repeated commands- how quick is the series of commands while they turn off? Example: if your dimmer takes 2 seconds to send everything, set a trigger node that sends nothing - waits 2.5 seconds - then sends the most recent value. That would give you a little buffer to essentially ignore all of the updates that come through while the light turns off.

If you can’t get it sorted then come back and we can dig into it more…

That may be the ideal solution for now then…I’m restarting often enough right now, so ideally things return to their proper state.

Ya, I started off with your function, except I’m not storing the value as I always want mine to rest to 100% whenever they’re turned on. In terms of hardware, I have some older GE ones as well as some Zwaveproducts ones (same hardware as Homeseer ones). The GE ones are definitely more troublesome as that was before they had proper instant status.

That may be the way to go…I’ll look into using trigger nodes.

@crxporter I wonder if there’s a better/easier way to do something like this:

…I tried to remove as much duplication in the chain as possible (i.e. having a translation method for each pair of OH/HK items), and then used the message topic to filter and allow only needing one HK -> OH node (I use the item name as the topic and then pass that through). I think I’ll need a tweak the delay node a bit, but it works roughly how I need.

Has anyone here used a HomePod in the their NR/HK setup? I’ve been having some hiccups, where if I tell my HomePod a command, it will say it’s successful, but does not perform the action (but sometimes it does). I finally had some time today to dig in deeper and have noticed a few things:

  1. When the HP doesn’t send the action, it looks NodeRED doesn’t even get the command (aka it’s not a fault of the functions/etc). I’m guessing either this is a fault of Apple, or HAP-NodeJS.

  2. Sometimes it seems that the HomeKit statuses don’t sync across all HK instances. I.e. I’ve had cases where if I use Siri on my iPhone, it will perform the action and update there, but then the Home app on my Mac or the HomePod doesn’t reflect the change.

Anyone else experience issues like this and know of a way to debug better?

Interesting. I have 3 homepods, 2 iPhone users, 2 iPad users, 2 watch users, and 2 computers (me and my wife each have each)… as long as there’s a change, the HomePod works every time.

I say “as long as there’s a change” because if homekit thinks the light is off and you say “hey Siri turn off the light” it will respond something like “that’s done” but not actually send a command because homekit thinks it’s already off.

As for syncing between devices, sometimes if changes are made on the phone, the computer doesn’t update right away, I have to quit/reopen home app to update. But generally, everything is in sync.

I do remember some growing pains at the beginning where the changes made on the phone wouldn’t update to other devices, but I think that’s a different issue…

Also - make sure you restart node red before going too much further in your troubleshooting… that nasty bug where “deploy” doesn’t work right hasn’t been fixed quite yet.

On a pi:

sudo systemctl restart nodered.service

Good to know (re: your setup working). I also tried updating node-red and we’ll see what happens.

That’s an interesting concept. I now have 2 sets of roller shutters: one set doesn’t report their position (Z-Wave), and another one that does report their position (Z-Wave plus). I was trying to come up with a solution using Node-RED and so far all I could come up with, was keeping track of HomeKit interactions in the flow’s session/state. If you don’t do this, then the frequent position updates will confuse the HomeKit node.

By using a trigger node you can circumvent this problem, but you’ll always have to use a time buffer that covers the maximum travel time. For roller shutters, this is typically the “full raise” travel time.

I wanted to keep track of the current position and the target position, and I considered using a delay node with a variable delay time (expressed as a fraction of the maximum travel time, depending on the difference between current and target value), with a minimum guard time.

So it basically boils down to report ** immediately** any state changes that occur outside HomeKit, and to use the more convoluted delayed-message approach only when HomeKit is involved.

The flow logic gets convoluted because the OH node is unable to distinguish between HomeKit actions and non-HomeKit actions, so it must be stored in the flow’s state (using context.set() and context.get()).

I’ll report my progress if I find time implementing it.

Here’s how I turned the Fibaro FGSD-002 Smoke Sensor into an HomeKit accessory.

The flow itself:


And the REFRESH sub flow:

Here’s the JSON code of the flow:

[
   {
      "id":"5aea18b7.bbc2f8",
      "type":"tab",
      "label":"Attic smoke alarm",
      "disabled":false,
      "info":""
   },
   {
      "id":"f3617abd.d3d688",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Smoke Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Smoke",
      "x":130,
      "y":80,
      "wires":[
         [
            "b0a53b24.84fbe8"
         ],
         [

         ]
      ]
   },
   {
      "id":"e1f58d8f.d03a4",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH alarm to HomeKit",
      "func":"if(msg.payload == \"ON\"){\n    msg.payload = {\n        \"SmokeDetected\": 1\n    };\n    return msg\n}\nelse if(msg.payload == \"OFF\" || msg.payload == \"NULL\"){\n    msg.payload = {\n        \"SmokeDetected\": 0\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":730,
      "y":80,
      "wires":[
         [
            "dc115a03.f7d6b"
         ]
      ]
   },
   {
      "id":"dc115a03.f7d6b",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"OTHER",
      "parentService":"",
      "name":"Attic Smoke Sensor: Smoke Alarm",
      "serviceName":"SmokeSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false\n}",
      "x":1280,
      "y":140,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"8e6231e8.7e1638",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Heat Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Heat",
      "x":120,
      "y":560,
      "wires":[
         [
            "eff4cc97.546298"
         ],
         [

         ]
      ]
   },
   {
      "id":"352eef0.4c31c12",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"",
      "name":"Attic Smoke Sensor: Heat Alarm",
      "serviceName":"SmokeSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false\n}",
      "x":1270,
      "y":400,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"d75c6980.db6ae",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Smoke Alarm State",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Smoke",
      "x":640,
      "y":140,
      "wires":[
         [
            "e1f58d8f.d03a4"
         ]
      ]
   },
   {
      "id":"b0a53b24.84fbe8",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n        return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":80,
      "wires":[
         [
            "e1f58d8f.d03a4"
         ],
         [
            "f9c0a042.0ae1c8"
         ]
      ]
   },
   {
      "id":"b5b699f3.adccc8",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH alarm to HomeKit",
      "func":"if(msg.payload == \"ON\"){\n    msg.payload = {\n        \"SmokeDetected\": 1\n    };\n    return msg\n}\nelse if(msg.payload == \"OFF\" || msg.payload == \"NULL\"){\n    msg.payload = {\n        \"SmokeDetected\": 0\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":730,
      "y":560,
      "wires":[
         [
            "352eef0.4c31c12"
         ]
      ]
   },
   {
      "id":"8d3f31b3.90ae7",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Heat Alarm State",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Heat",
      "x":660,
      "y":620,
      "wires":[
         [
            "b5b699f3.adccc8"
         ]
      ]
   },
   {
      "id":"eff4cc97.546298",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":560,
      "wires":[
         [
            "b5b699f3.adccc8"
         ],
         [
            "f1bc8079.817d18"
         ]
      ]
   },
   {
      "id":"d4ece5ea.7ff4d",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Tamper Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Tamper",
      "x":130,
      "y":320,
      "wires":[
         [
            "919db550.c0892"
         ],
         [

         ]
      ]
   },
   {
      "id":"cb4eb522.f96ef8",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH alarm to HomeKit StatusTampered",
      "func":"if(msg.payload == \"ON\"){\n    msg.payload = {\n        \"StatusTampered\": 1\n    };\n    return msg\n}\nelse if(msg.payload == \"OFF\" || msg.payload == \"NULL\"){\n    msg.payload = {\n        \"StatusTampered\": 0\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":780,
      "y":320,
      "wires":[
         [
            "dc115a03.f7d6b",
            "352eef0.4c31c12",
            "4a076e7d.21753"
         ]
      ]
   },
   {
      "id":"2549bf16.660a9",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Tamper Alarm State",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Tamper",
      "x":640,
      "y":380,
      "wires":[
         [
            "cb4eb522.f96ef8"
         ]
      ]
   },
   {
      "id":"919db550.c0892",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":320,
      "wires":[
         [
            "cb4eb522.f96ef8"
         ],
         [
            "ee2cbdb8.ec9dc8"
         ]
      ]
   },
   {
      "id":"6c1373d1.96e414",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Low Battery Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Battery",
      "x":140,
      "y":440,
      "wires":[
         [
            "f5ce769a.966728"
         ],
         [

         ]
      ]
   },
   {
      "id":"6af243fc.04fd54",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH alarm to HomeKit StatusLowBattery",
      "func":"if(msg.payload == \"ON\"){\n    msg.payload = {\n        \"StatusLowBattery\": 1\n    };\n    return msg\n}\nelse if(msg.payload == \"OFF\" || msg.payload == \"NULL\"){\n    msg.payload = {\n        \"StatusLowBattery\": 0\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":790,
      "y":440,
      "wires":[
         [
            "dc115a03.f7d6b",
            "352eef0.4c31c12",
            "14b05210.9b7b0e"
         ]
      ]
   },
   {
      "id":"612711be.2014f",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Low Battery Alarm State",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Battery",
      "x":680,
      "y":500,
      "wires":[
         [
            "6af243fc.04fd54"
         ]
      ]
   },
   {
      "id":"f5ce769a.966728",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":440,
      "wires":[
         [
            "6af243fc.04fd54"
         ],
         [
            "487a4c41.366adc"
         ]
      ]
   },
   {
      "id":"f3ad8597.d4a4f8",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Temperature",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Temperature",
      "x":120,
      "y":740,
      "wires":[
         [
            "cca3b2d8.9b71b"
         ],
         [

         ]
      ]
   },
   {
      "id":"4a076e7d.21753",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"",
      "name":"Attic Smoke Sensor: Temperature",
      "serviceName":"TemperatureSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false,\n    \"CurrentTemperature\": 0.0\n}",
      "x":1280,
      "y":700,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"6dce9de8.9f628c",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH state to HomeKit",
      "func":"currentTemp = parseFloat(msg.payload.split(\" \")[0])\n\n\nif (! isNaN(currentTemp)) {\n    msg.payload = {\n        \"CurrentTemperature\": currentTemp\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":730,
      "y":740,
      "wires":[
         [
            "4a076e7d.21753"
         ]
      ]
   },
   {
      "id":"5d3d83eb.278adc",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Termperature",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Temperature",
      "x":640,
      "y":800,
      "wires":[
         [
            "6dce9de8.9f628c"
         ]
      ]
   },
   {
      "id":"cca3b2d8.9b71b",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":740,
      "wires":[
         [
            "6dce9de8.9f628c"
         ],
         [
            "12150af3.27a70d"
         ]
      ]
   },
   {
      "id":"e377c7d6.32b518",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Battery Level",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Battery",
      "x":130,
      "y":880,
      "wires":[
         [
            "3a8c15e0.fdd6a2"
         ],
         [

         ]
      ]
   },
   {
      "id":"c37c1b3c.5977",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH state to HomeKit",
      "func":"currentLevel = parseFloat(msg.payload)\n\n\nif (! isNaN(currentLevel)) {\n    msg.payload = {\n        \"BatteryLevel\": currentLevel\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":730,
      "y":880,
      "wires":[
         [
            "14b05210.9b7b0e"
         ]
      ]
   },
   {
      "id":"56d43ef1.836f98",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic Battery Level",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Battery",
      "x":640,
      "y":940,
      "wires":[
         [
            "c37c1b3c.5977"
         ]
      ]
   },
   {
      "id":"3a8c15e0.fdd6a2",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":880,
      "wires":[
         [
            "c37c1b3c.5977"
         ],
         [
            "ad439e75.e537c"
         ]
      ]
   },
   {
      "id":"319e28f1.69b708",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Smoke Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Smoke",
      "topic":"",
      "payload":"",
      "x":490,
      "y":1100,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"9b6dd772.ce8938",
      "type":"inject",
      "z":"5aea18b7.bbc2f8",
      "name":"REFRESH",
      "topic":"",
      "payload":"REFRESH",
      "payloadType":"str",
      "repeat":"",
      "crontab":"",
      "once":false,
      "onceDelay":0.1,
      "x":140,
      "y":1180,
      "wires":[
         [
            "319e28f1.69b708",
            "7ebfc29a.7266ac",
            "14ba4155.348197",
            "92ee5ecb.0f69c8",
            "d2d1e2cd.7632d8",
            "18e0d6dd.710ae1",
            "aa19a46d.93e24"
         ]
      ]
   },
   {
      "id":"7ebfc29a.7266ac",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Heat Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Heat",
      "topic":"",
      "payload":"",
      "x":480,
      "y":1140,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"14ba4155.348197",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Tamper Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Tamper",
      "topic":"",
      "payload":"",
      "x":490,
      "y":1220,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"92ee5ecb.0f69c8",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Low Battery Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Battery",
      "topic":"",
      "payload":"",
      "x":510,
      "y":1260,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"75914009.6daf58",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic System Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_System",
      "x":130,
      "y":200,
      "wires":[
         [
            "c6e6f30a.34b9b8"
         ],
         [

         ]
      ]
   },
   {
      "id":"1b120f3e.58b6c9",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Translate OH alarm to HomeKit StatusFault",
      "func":"if(msg.payload == \"ON\"){\n    msg.payload = {\n        \"StatusFault\": 1,\n        \"StatusActive\": false\n    };\n    return msg\n}\nelse if(msg.payload == \"OFF\" || msg.payload == \"NULL\"){\n    msg.payload = {\n        \"StatusFault\": 0,\n        \"StatusActive\": true\n    };\n    return msg\n}\n// return msg;",
      "outputs":1,
      "noerr":0,
      "x":770,
      "y":200,
      "wires":[
         [
            "dc115a03.f7d6b",
            "352eef0.4c31c12",
            "4a076e7d.21753"
         ]
      ]
   },
   {
      "id":"6acf05f.ff1b0fc",
      "type":"openhab2-get",
      "z":"5aea18b7.bbc2f8",
      "name":"Get Attic System Alarm State",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_System",
      "x":640,
      "y":260,
      "wires":[
         [
            "1b120f3e.58b6c9"
         ]
      ]
   },
   {
      "id":"c6e6f30a.34b9b8",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Check NULL state",
      "func":"if(msg.payload == \"NULL\"){\n    return [null, msg];\n} else {\n    return [msg, null];\n}",
      "outputs":2,
      "noerr":0,
      "x":370,
      "y":200,
      "wires":[
         [
            "1b120f3e.58b6c9"
         ],
         [
            "a26073a0.31fa38"
         ]
      ]
   },
   {
      "id":"d2d1e2cd.7632d8",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic System Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_System",
      "topic":"",
      "payload":"",
      "x":490,
      "y":1180,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"18e0d6dd.710ae1",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Temperature",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Temperature",
      "topic":"",
      "payload":"",
      "x":490,
      "y":1320,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"aa19a46d.93e24",
      "type":"openhab2-out",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Battery Level",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Battery",
      "topic":"",
      "payload":"",
      "x":490,
      "y":1360,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"14b05210.9b7b0e",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":false,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"4a076e7d.21753",
      "name":"Attic Smoke Sensor: Battery Level",
      "serviceName":"BatteryService",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"ChargingState\": 2\n}",
      "x":1280,
      "y":760,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"f9c0a042.0ae1c8",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":440,
      "y":140,
      "wires":[
         [
            "d75c6980.db6ae"
         ]
      ]
   },
   {
      "id":"a26073a0.31fa38",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":440,
      "y":260,
      "wires":[
         [
            "6acf05f.ff1b0fc"
         ]
      ]
   },
   {
      "id":"ee2cbdb8.ec9dc8",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":440,
      "y":380,
      "wires":[
         [
            "2549bf16.660a9"
         ]
      ]
   },
   {
      "id":"487a4c41.366adc",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":460,
      "y":500,
      "wires":[
         [
            "612711be.2014f"
         ]
      ]
   },
   {
      "id":"f1bc8079.817d18",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":460,
      "y":620,
      "wires":[
         [
            "8d3f31b3.90ae7"
         ]
      ]
   },
   {
      "id":"12150af3.27a70d",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":460,
      "y":800,
      "wires":[
         [
            "5d3d83eb.278adc"
         ]
      ]
   },
   {
      "id":"ad439e75.e537c",
      "type":"delay",
      "z":"5aea18b7.bbc2f8",
      "name":"",
      "pauseType":"delay",
      "timeout":"5",
      "timeoutUnits":"seconds",
      "rate":"1",
      "nbRateUnits":"1",
      "rateUnits":"second",
      "randomFirst":"1",
      "randomLast":"5",
      "randomUnits":"seconds",
      "drop":false,
      "x":460,
      "y":940,
      "wires":[
         [
            "56d43ef1.836f98"
         ]
      ]
   },
   {
      "id":"f6e63178.0817a8",
      "type":"openhab2-controller",
      "z":"",
      "name":"OH2 RPi3",
      "protocol":"http",
      "host":"localhost",
      "port":"8080",
      "path":"",
      "username":"",
      "password":""
   },
   {
      "id":"27a289cc.9765c6",
      "type":"homekit-bridge",
      "z":"",
      "bridgeName":"openHAB2",
      "pinCode":"031-45-154",
      "port":"",
      "allowInsecureRequest":false,
      "manufacturer":"openHAB",
      "model":"RPi3B+",
      "serialNo":"Default Serial Number",
      "customMdnsConfig":false,
      "mdnsMulticast":true,
      "mdnsInterface":"",
      "mdnsPort":"",
      "mdnsIp":"",
      "mdnsTtl":"",
      "mdnsLoopback":true,
      "mdnsReuseAddr":true,
      "allowMessagePassthrough":true
   }
]

So far the main problem I have, is that the temperature sensor is always set to inactive :frowning:


Also, and this seems to be a limitation of the Home app, temperatures are always rounded to a full degree.

I managed to find a solution.

Meanwhile I rewrote the flow to make it more readable.

The logic resides in Process ItemStateChangedEvent which I wired to the raw event port (2nd output) of the leftmost openHAB item nodes:

// Only process ItemStateChangedEvent (contains old and new state)
SMOKE_ALARM = " SmokeAlarm "
HEAT_ALARM = " HeatAlarm "
TEMPERATURE = " Temperature "
BATTERY = " Battery "

/* Telegram emoji (HTML codes): */
EMOJI_alarm = "⚠️"
EMOJI_fire = "🔥"
EMOJI_battery = "🔋"
EMOJI_thermometer = "🌡️"
EMOJI_ok_button = "🆗"
EMOJI_green_circle = "🟢"
EMOJI_yellow_circle = "🟡"
EMOJI_orange_circle = "🟠"
EMOJI_red_circle = "🔴"
EMOJI_hot_springs = "♨️"
EMOJI_siren = "🚨"
EMOJI_gear = "⚙️"

if (msg.payload.type == "ItemStateChangedEvent") {

    x = msg.item.split("_SmokeAlarm_")
    item_id = x[0]
    event_id = x[1]

    oldState = msg.payload.payload.oldValue
    newState = msg.payload.payload.value

    /*
    node.log("[Process ItemStateChangedEvent] - (OK - 1) message item: " + JSON.stringify(msg.item))
    node.log("[Process ItemStateChangedEvent] - (OK - 2) message payload: " + JSON.stringify(msg.payload))
    node.log("[Process ItemStateChangedEvent] - (OK - 3) - " + item_id + " (" + event_id + ") - state changed from '" + oldState + "' to '" + newState + "'")
    */

    // Homekit Accessory Protocol message:
    hapMsg = {
        topic: msg.payload.topic,
        item: msg.item,
        type: msg.payload.type,
        target: {},
        payload: {}
    }
    
    // Telegram message (HTML)
    telegramMsg = {
        method: "sendMessage",
        payload: {
            parse_mode: "HTML",
            text: "<b>" + event_id + " for " + msg.item + "</b> (was '" + oldState + "', is now '" + newState + "')"
        }
    }
    
    isOk = false
    sendTelegram = false
    val = null
    isActive = null
    
    switch(event_id) {
        case "Alarm_Smoke":
            alarm_type = "Smoke"
            if (newState == "ON") {
                val = 1
                telegramMsg.payload.text = EMOJI_alarm + " [" + EMOJI_fire + "<b>" + alarm_type + " Alarm</b>] triggered for <b>" + item_id + "</b>: Please check!"
                sendTelegram = true
            } else {
                val = 0
                // Only send a Telegram message if the old state was "ON" (not "NULL")
                if (oldState == "ON") {
                    telegramMsg.payload.text = EMOJI_green_circle + " [" + EMOJI_fire + "<b>" + alarm_type + " Alarm</b>] for <b>" + item_id + "</b> has been disarmed."
                    sendTelegram = true
                }
            }
            hapMsg.target = SMOKE_ALARM
            hapMsg.payload = { "SmokeDetected": val }
            isOk = true
            break;
    
        case "Alarm_Heat":
            alarm_type = "Heat"
            if (newState == "ON") {
                val = 1
                telegramMsg.payload.text = EMOJI_alarm + " [" + EMOJI_hot_springs + "<b>" + alarm_type + " Alarm</b>] triggered for <b>" + item_id + "</b>: Please check!"
                sendTelegram = true
            } else {
                val = 0
                // Only send a Telegram message if the old state was "ON" (not "NULL")
                if (oldState == "ON") {
                    telegramMsg.payload.text = EMOJI_green_circle + " [" + EMOJI_hot_springs + "<b>" + alarm_type + " Alarm</b>] for <b>" + item_id + "</b> has been disarmed."
                    sendTelegram = true
                }
            }
            // TODO: replace SmokeDetected with 'HeatDetected' when available in HomeKit HAP
            hapMsg.target = HEAT_ALARM
            hapMsg.payload = { "SmokeDetected": val }
            isOk = true
            break;
    
        case "Alarm_Tamper":
            alarm_type = "Tamper"
            if (newState == "ON") {
                val = 1
                telegramMsg.payload.text = EMOJI_alarm + " [" + EMOJI_siren + "<b>" + alarm_type + " Alarm</b>] triggered for <b>" + item_id + "</b>: Please check!"
                sendTelegram = true
            } else {
                val = 0
                // Only send a Telegram message if the old state was "ON" (not "NULL")
                if (oldState == "ON") {
                    telegramMsg.payload.text = EMOJI_green_circle + " [" + EMOJI_siren + "<b>" + alarm_type + " Alarm</b>] for <b>" + item_id + "</b> has been disarmed."
                    sendTelegram = true
                }
            }
            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE
            hapMsg.payload = { "StatusTampered": val }
            isOk = true
            break;
    
        case "Alarm_Battery":
            alarm_type = "Battery Low"
            if (newState == "ON") {
                val = 1
                telegramMsg.payload.text = EMOJI_alarm + " [" + EMOJI_battery + "<b>" + alarm_type + " Alarm</b>] triggered for <b>" + item_id + "</b>: Please check!"
                sendTelegram = true
            } else {
                val = 0
                // Only send a Telegram message if the old state was "ON" (not "NULL")
                if (oldState == "ON") {
                    telegramMsg.payload.text = EMOJI_green_circle + " [" + EMOJI_battery + "<b>" + alarm_type + " Alarm</b>] for <b>" + item_id + "</b> has been disarmed."
                    sendTelegram = true
                }
            }
            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE
            hapMsg.payload = { "StatusLowBattery": val }
            isOk = true
            break;
    
        case "Alarm_System":
            alarm_type = "System"
            if (newState == "ON") {
                val = 1
                isActive = false
                telegramMsg.payload.text = EMOJI_alarm + " [" + EMOJI_gear + "<b>" + alarm_type + " Alarm</b>] triggered for <b>" + item_id + "</b>: Smoke Alarm Unit Defective: Please check!"
                sendTelegram = true
            } else {
                val = 0
                isActive = true
                // Only send a Telegram message if the old state was "ON" (not "NULL")
                if (oldState == "ON") {
                    telegramMsg.payload.text = EMOJI_green_circle + " [" + EMOJI_gear + "<b>" + alarm_type + " Alarm</b>] for <b>" + item_id + "</b> has been disarmed."
                    sendTelegram = true
                }
            }
            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE
            hapMsg.payload = {
                "StatusFault": val,
                "StatusActive": isActive
            }
            isOk = true
            break;
            
        case "Temperature":
            currentTemp = parseFloat(newState.split(" ")[0])

            if (! isNaN(currentTemp)) {
                hapMsg.target = TEMPERATURE
                hapMsg.payload = { "CurrentTemperature": currentTemp }
                isOk = true
            }
            break;
    
        case "Battery":
            currentLevel = parseFloat(newState)
            
            if (! isNaN(currentLevel)) {
                hapMsg.target = BATTERY // SMOKE_ALARM + HEAT_ALARM + TEMPERATURE
                hapMsg.payload = { "BatteryLevel": currentLevel }
                isOk = true
            }
            break;
    
    }

    // First return the HAP message, then the Telegram message, finally the original StateChangedEvent message (for debugging / logging)
    if (isOk === true) {
        return [hapMsg, (sendTelegram === true ? telegramMsg : null), msg];
    }
} /* else {
    node.warn("Unexpected event type for message: " + JSON.stringify(msg))
} */

The output is then wired to the TriggerAlarm switch and routes the messages to the 4 HAP nodes, depending on the value of HAPmsg.target.

Here’s the full code of the flow:

[
   {
      "id":"f3617abd.d3d688",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Smoke Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Smoke",
      "x":130,
      "y":140,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"dc115a03.f7d6b",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"OTHER",
      "parentService":"",
      "name":"Attic Smoke Sensor: Smoke Alarm",
      "serviceName":"SmokeSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false\n}",
      "x":1280,
      "y":140,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"8e6231e8.7e1638",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Heat Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Heat",
      "x":120,
      "y":380,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"352eef0.4c31c12",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"",
      "name":"Attic Smoke Sensor: Heat Alarm",
      "serviceName":"SmokeSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false\n}",
      "x":1270,
      "y":200,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"d4ece5ea.7ff4d",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Tamper Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Tamper",
      "x":130,
      "y":260,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"6c1373d1.96e414",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Low Battery Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_Battery",
      "x":140,
      "y":320,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"f3ad8597.d4a4f8",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Temperature",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Temperature",
      "x":120,
      "y":460,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"4a076e7d.21753",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":true,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"",
      "name":"Attic Smoke Sensor: Temperature",
      "serviceName":"TemperatureSensor",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"StatusActive\": true,\n    \"StatusTampered\": false,\n    \"StatusFault\": false,\n    \"StatusLowBattery\": false,\n    \"CurrentTemperature\": 0.0\n}",
      "x":1280,
      "y":260,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"e377c7d6.32b518",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic Battery Level",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Battery",
      "x":130,
      "y":520,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"75914009.6daf58",
      "type":"openhab2-in",
      "z":"5aea18b7.bbc2f8",
      "name":"Attic System Alarm",
      "controller":"f6e63178.0817a8",
      "itemname":"AT_Attic_SmokeAlarm_Alarm_System",
      "x":130,
      "y":200,
      "wires":[
         [

         ],
         [
            "f9d062b8.4e159"
         ]
      ]
   },
   {
      "id":"14b05210.9b7b0e",
      "type":"homekit-service",
      "z":"5aea18b7.bbc2f8",
      "isParent":false,
      "bridge":"27a289cc.9765c6",
      "accessoryCategory":"SENSOR",
      "parentService":"4a076e7d.21753",
      "name":"Attic Smoke Sensor: Battery Level",
      "serviceName":"BatteryService",
      "topic":"",
      "filter":false,
      "manufacturer":"Fibaro",
      "model":"FGSD-002 ZW5 v3.3",
      "serialNo":"000 000 294 265",
      "cameraConfigVideoProcessor":"ffmpeg",
      "cameraConfigSource":"",
      "cameraConfigStillImageSource":"",
      "cameraConfigMaxStreams":2,
      "cameraConfigMaxWidth":1280,
      "cameraConfigMaxHeight":720,
      "cameraConfigMaxFPS":10,
      "cameraConfigMaxBitrate":300,
      "cameraConfigVideoCodec":"libx264",
      "cameraConfigAudioCodec":"libfdk_aac",
      "cameraConfigAudio":false,
      "cameraConfigPacketSize":1316,
      "cameraConfigVerticalFlip":false,
      "cameraConfigHorizontalFlip":false,
      "cameraConfigMapVideo":"0:0",
      "cameraConfigMapAudio":"0:1",
      "cameraConfigVideoFilter":"scale=1280:720",
      "cameraConfigAdditionalCommandLine":"-tune zerolatency",
      "cameraConfigDebug":false,
      "cameraConfigSnapshotOutput":"disabled",
      "characteristicProperties":"{\n    \"ChargingState\": 2\n}",
      "x":1280,
      "y":320,
      "wires":[
         [

         ],
         [

         ]
      ]
   },
   {
      "id":"741030fc.43dd58",
      "type":"telegrambot-payload",
      "z":"5aea18b7.bbc2f8",
      "name":"homebrainz payload",
      "bot":"d9273cbd.1fd778",
      "chatId":"858292107",
      "sendMethod":"",
      "payload":"",
      "x":780,
      "y":320,
      "wires":[
         [

         ]
      ]
   },
   {
      "id":"630909b.41afef8",
      "type":"debug",
      "z":"5aea18b7.bbc2f8",
      "name":"Debug info: Process ItemStateChangeEvent",
      "active":false,
      "tosidebar":true,
      "console":true,
      "tostatus":false,
      "complete":"true",
      "targetType":"full",
      "x":860,
      "y":420,
      "wires":[

      ]
   },
   {
      "id":"f9d062b8.4e159",
      "type":"function",
      "z":"5aea18b7.bbc2f8",
      "name":"Process ItemStateChangedEvent",
      "func":"// Only process ItemStateChangedEvent (contains old and new state)\nSMOKE_ALARM = \" SmokeAlarm \"\nHEAT_ALARM = \" HeatAlarm \"\nTEMPERATURE = \" Temperature \"\nBATTERY = \" Battery \"\n\n/* Telegram emoji (HTML codes): */\nEMOJI_alarm = \"&#9888;&#65039;\"\nEMOJI_fire = \"&#x1f525;\"\nEMOJI_battery = \"&#128267;\"\nEMOJI_thermometer = \"&#127777;&#65039;\"\nEMOJI_ok_button = \"&#127383;\"\nEMOJI_green_circle = \"&#128994;\"\nEMOJI_yellow_circle = \"&#128993;\"\nEMOJI_orange_circle = \"&#128992;\"\nEMOJI_red_circle = \"&#128308;\"\nEMOJI_hot_springs = \"&#9832;&#65039;\"\nEMOJI_siren = \"&#128680;\"\nEMOJI_gear = \"&#9881;&#65039;\"\n\n/*\nnode.log(\"[Process ItemStateChangedEvent] - (1) message: \" + JSON.stringify(msg))\nnode.log(\"[Process ItemStateChangedEvent] - (2) message payload: \" + JSON.stringify(msg.payload))\nnode.log(\"[Process ItemStateChangedEvent] - (3) message payload type: \" + JSON.stringify(msg.payload.type))\n*/\n\nif (msg.payload.type == \"ItemStateChangedEvent\") {\n\n    x = msg.item.split(\"_SmokeAlarm_\")\n    item_id = x[0]\n    event_id = x[1]\n\n    oldState = msg.payload.payload.oldValue\n    newState = msg.payload.payload.value\n\n    node.log(\"[Process ItemStateChangedEvent] - (OK - 1) message item: \" + JSON.stringify(msg.item))\n    node.log(\"[Process ItemStateChangedEvent] - (OK - 2) message payload: \" + JSON.stringify(msg.payload))\n    node.log(\"[Process ItemStateChangedEvent] - (OK - 3) - \" + item_id + \" (\" + event_id + \") - state changed from '\" + oldState + \"' to '\" + newState + \"'\")\n    \n    // Homekit Accessory Protocol message:\n    hapMsg = {\n        topic: msg.payload.topic,\n        item: msg.item,\n        type: msg.payload.type,\n        target: {},\n        payload: {}\n    }\n    \n    // Telegram message (HTML) // fire emoji :== \"\\xF0\\x9F\\x94\\xA5\"\n    telegramMsg = {\n        method: \"sendMessage\",\n        payload: {\n            parse_mode: \"HTML\",\n            text: \"<b>\" + event_id + \" for \" + msg.item + \"</b> (was '\" + oldState + \"', is now '\" + newState + \"')\"\n        }\n    }\n    \n    isOk = false\n    sendTelegram = false\n    val = null\n    isActive = null\n    \n    switch(event_id) {\n        case \"Alarm_Smoke\":\n            alarm_type = \"Smoke\"\n            if (newState == \"ON\") {\n                val = 1\n                telegramMsg.payload.text = EMOJI_alarm + \" [\" + EMOJI_fire + \"<b>\" + alarm_type + \" Alarm</b>] triggered for <b>\" + item_id + \"</b>: Please check!\"\n                sendTelegram = true\n            } else {\n                val = 0\n                // Only send a Telegram message if the old state was \"ON\" (not \"NULL\")\n                if (oldState == \"ON\") {\n                    telegramMsg.payload.text = EMOJI_green_circle + \" [\" + EMOJI_fire + \"<b>\" + alarm_type + \" Alarm</b>] for <b>\" + item_id + \"</b> has been disarmed.\"\n                    sendTelegram = true\n                }\n            }\n            hapMsg.target = SMOKE_ALARM\n            hapMsg.payload = { \"SmokeDetected\": val }\n            isOk = true\n            break;\n    \n        case \"Alarm_Heat\":\n            alarm_type = \"Heat\"\n            if (newState == \"ON\") {\n                val = 1\n                telegramMsg.payload.text = EMOJI_alarm + \" [\" + EMOJI_hot_springs + \"<b>\" + alarm_type + \" Alarm</b>] triggered for <b>\" + item_id + \"</b>: Please check!\"\n                sendTelegram = true\n            } else {\n                val = 0\n                // Only send a Telegram message if the old state was \"ON\" (not \"NULL\")\n                if (oldState == \"ON\") {\n                    telegramMsg.payload.text = EMOJI_green_circle + \" [\" + EMOJI_hot_springs + \"<b>\" + alarm_type + \" Alarm</b>] for <b>\" + item_id + \"</b> has been disarmed.\"\n                    sendTelegram = true\n                }\n            }\n            // TODO: replace SmokeDetected with 'HeatDetected' when available\n            hapMsg.target = HEAT_ALARM\n            hapMsg.payload = { \"SmokeDetected\": val }\n            isOk = true\n            break;\n    \n        case \"Alarm_Tamper\":\n            alarm_type = \"Tamper\"\n            if (newState == \"ON\") {\n                val = 1\n                telegramMsg.payload.text = EMOJI_alarm + \" [\" + EMOJI_siren + \"<b>\" + alarm_type + \" Alarm</b>] triggered for <b>\" + item_id + \"</b>: Please check!\"\n                sendTelegram = true\n            } else {\n                val = 0\n                // Only send a Telegram message if the old state was \"ON\" (not \"NULL\")\n                if (oldState == \"ON\") {\n                    telegramMsg.payload.text = EMOJI_green_circle + \" [\" + EMOJI_siren + \"<b>\" + alarm_type + \" Alarm</b>] for <b>\" + item_id + \"</b> has been disarmed.\"\n                    sendTelegram = true\n                }\n            }\n            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE\n            hapMsg.payload = { \"StatusTampered\": val }\n            isOk = true\n            break;\n    \n        case \"Alarm_Battery\":\n            alarm_type = \"Battery Low\"\n            if (newState == \"ON\") {\n                val = 1\n                telegramMsg.payload.text = EMOJI_alarm + \" [\" + EMOJI_battery + \"<b>\" + alarm_type + \" Alarm</b>] triggered for <b>\" + item_id + \"</b>: Please check!\"\n                sendTelegram = true\n            } else {\n                val = 0\n                // Only send a Telegram message if the old state was \"ON\" (not \"NULL\")\n                if (oldState == \"ON\") {\n                    telegramMsg.payload.text = EMOJI_green_circle + \" [\" + EMOJI_battery + \"<b>\" + alarm_type + \" Alarm</b>] for <b>\" + item_id + \"</b> has been disarmed.\"\n                    sendTelegram = true\n                }\n            }\n            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE\n            hapMsg.payload = { \"StatusLowBattery\": val }\n            isOk = true\n            break;\n    \n        case \"Alarm_System\":\n            alarm_type = \"System\"\n            if (newState == \"ON\") {\n                val = 1\n                isActive = false\n                telegramMsg.payload.text = EMOJI_alarm + \" [\" + EMOJI_gear + \"<b>\" + alarm_type + \" Alarm</b>] triggered for <b>\" + item_id + \"</b>: Smoke Alarm Unit Defective: Please check!\"\n                sendTelegram = true\n            } else {\n                val = 0\n                isActive = true\n                // Only send a Telegram message if the old state was \"ON\" (not \"NULL\")\n                if (oldState == \"ON\") {\n                    telegramMsg.payload.text = EMOJI_green_circle + \" [\" + EMOJI_gear + \"<b>\" + alarm_type + \" Alarm</b>] for <b>\" + item_id + \"</b> has been disarmed.\"\n                    sendTelegram = true\n                }\n            }\n            hapMsg.target = SMOKE_ALARM + HEAT_ALARM + TEMPERATURE\n            hapMsg.payload = {\n                \"StatusFault\": val,\n                \"StatusActive\": isActive\n            }\n            isOk = true\n            break;\n            \n        case \"Temperature\":\n            currentTemp = parseFloat(newState.split(\" \")[0])\n\n            if (! isNaN(currentTemp)) {\n                hapMsg.target = TEMPERATURE\n                hapMsg.payload = { \"CurrentTemperature\": currentTemp }\n                isOk = true\n            }\n            break;\n    \n        case \"Battery\":\n            currentLevel = parseFloat(newState)\n            \n            if (! isNaN(currentLevel)) {\n                hapMsg.target = BATTERY // SMOKE_ALARM + HEAT_ALARM + TEMPERATURE\n                hapMsg.payload = { \"BatteryLevel\": currentLevel }\n                isOk = true\n            }\n            break;\n    \n    }\n\n    // First return the HAP message, then the Telegram message, finally the original StateChangedEvent message (for debugging / logging)\n    if (isOk === true) {\n        return [hapMsg, (sendTelegram === true ? telegramMsg : null), msg];\n    }\n} /* else {\n    node.warn(\"Unexpected event type for message: \" + JSON.stringify(msg))\n} */",
      "outputs":3,
      "noerr":0,
      "x":460,
      "y":320,
      "wires":[
         [
            "3c891b83.70038c"
         ],
         [
            "741030fc.43dd58"
         ],
         [
            "630909b.41afef8"
         ]
      ]
   },
   {
      "id":"3c891b83.70038c",
      "type":"switch",
      "z":"5aea18b7.bbc2f8",
      "name":"TriggerAlarm",
      "property":"msg.target",
      "propertyType":"jsonata",
      "rules":[
         {
            "t":"cont",
            "v":"SmokeAlarm",
            "vt":"str"
         },
         {
            "t":"cont",
            "v":"HeatAlarm",
            "vt":"str"
         },
         {
            "t":"cont",
            "v":"Temperature",
            "vt":"str"
         },
         {
            "t":"cont",
            "v":"Battery",
            "vt":"str"
         }
      ],
      "checkall":"true",
      "repair":false,
      "outputs":4,
      "x":750,
      "y":220,
      "wires":[
         [
            "dc115a03.f7d6b"
         ],
         [
            "352eef0.4c31c12"
         ],
         [
            "4a076e7d.21753"
         ],
         [
            "14b05210.9b7b0e"
         ]
      ]
   },
   {
      "id":"f6e63178.0817a8",
      "type":"openhab2-controller",
      "z":"",
      "name":"OH2 RPi3",
      "protocol":"http",
      "host":"localhost",
      "port":"8080",
      "path":"",
      "username":"",
      "password":""
   },
   {
      "id":"27a289cc.9765c6",
      "type":"homekit-bridge",
      "z":"",
      "bridgeName":"openHAB2",
      "pinCode":"031-45-154",
      "port":"",
      "allowInsecureRequest":false,
      "manufacturer":"openHAB",
      "model":"RPi3B+",
      "serialNo":"Default Serial Number",
      "customMdnsConfig":false,
      "mdnsMulticast":true,
      "mdnsInterface":"",
      "mdnsPort":"",
      "mdnsIp":"",
      "mdnsTtl":"",
      "mdnsLoopback":true,
      "mdnsReuseAddr":true,
      "allowMessagePassthrough":true
   },
   {
      "id":"d9273cbd.1fd778",
      "type":"telegrambot-config",
      "z":"",
      "botname":"homebrainz",
      "usernames":"",
      "chatIds":"858292107",
      "pollInterval":"300"
   }
]

The items are defined as follows:

Group gSmokeAlarms

// Attic smoke alarm: Fibaro FGSD-002 ZW5 v3.3 smoke and heat sensor
Group AT_Attic_SmokeAlarm (gSmokeAlarms)
Number:Temperature AT_Attic_SmokeAlarm_Temperature "Attic Temperature [%.1f %unit%]" <temperature> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange) {
    channel="zwave:device:controller:node13:sensor_temperature"
}
Switch             AT_Attic_SmokeAlarm_Alarm_Heat    "Heat alarm"       <alarm> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange) {
    channel="zwave:device:controller:node13:alarm_heat"
}
Switch             AT_Attic_SmokeAlarm_Alarm_Smoke   "Smoke alarm"      <alarm> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange) {
    channel="zwave:device:controller:node13:alarm_smoke"
}
Switch             AT_Attic_SmokeAlarm_Alarm_System   "Hardware failure alarm"      <alarm> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange) {
    channel="zwave:device:controller:node13:alarm_system"
}
Switch             AT_Attic_SmokeAlarm_Alarm_Tamper   "Tamper alarm"      <alarm> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange) {
    channel="zwave:device:controller:node13:alarm_tamper"
}
Switch             AT_Attic_SmokeAlarm_Alarm_Battery   "Battery Low"      <lowbattery> (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange, gBatteryLow) {
    channel="zwave:device:controller:node13:alarm_battery"
}
Number              AT_Attic_SmokeAlarm_Battery        "Attic Smoke Alarm: Battery Level [%.1f %%]" <battery>     (AT_Attic_SmokeAlarm, gHome_AT_Attic, gPersist_everyChange, gBattery, gBatteryLevel, gBatteryType_CR123A) {
    channel="zwave:device:controller:node13:battery-level"
}

Anyone can explain why my lightbulb doesn’t go on and everything inside node red and homekit shows it’s working?

MQTT does give error. Maybe that’s why?

Hi @rkrisi,
i would be interested in the white bulb code

May you pls share that?
I am a bit lost with converting colortemp values between OH > HomeKit > OH

thanks

There are a number of example here, written mostly by @crxporter:

However the ColorTemp and Brightness together doesn’t have an example setup.

Basically, for Brightness, you can use the examples there, from the “Dimmable bulb” part.
On ColorTemp, you need some conversion before applying. I’m assuming you have colorTemp in Kelvin right?