I want to set the status of the garagedoor by 2 switches at the garagedoor.
But i cant manage to get the feedback to the garagedoor-homekit-accessory.
When i send {"CurrentDoorState":true} or {"CurrentDoorState":false} the accessory is showing that it got the state but is not updating the button in the home-app. I have no clue how to solve that.
Have you restarted nodered to make sure it’s not related to #12?
If yes, do you have the spinning symbol in your garage door item in the Home App?
I think I have ultimate solution for such problems.
I am closing this issue as there are no more answers. If you happen to have this problem again the consider my above message.
Remember that 0.5.0 fixed some problems. And next time please share your flow so we can investigate better.
Please reopen it, I faced same issue.
So on nodered start GarageDoor had open state (in app) and if we inject {"CurrentDoorState":1} nothing happens. Even if we have 2 sensors which send correct state (CurrentDoorState) it will be anyway closed on startup.
But after injection {"TargetDoorState":1} and immediately {"CurrentDoorState":1} it became locked. Also to set it open we should do {"TargetDoorState":0} and only then {"CurrentDoorState":0}, sending simple {"CurrentDoorState":0} is not enough.
By the way {"CurrentDoorState"} values 2-4 visually do nothing.
So we need to set correct CurrentDoorState somehow on startup in simple way according to existing sensors. It can be opened, closed and unknown (semi-open, should be shown as open) and we definitely know it state from sensors.
Here is my workaround (initial state from sensors: door fully closed), should I add it to wiki?
[{"id":"5534366a.7ef91","type":"homekit-service","z":"75848247.7201a4","isParent":true,"bridge":"1f4da0a9.4023c7","parentService":"","name":"Garage Door","serviceName":"GarageDoorOpener","topic":"","filter":false,"manufacturer":"ptath","model":"Default Model","serialNo":"0001","characteristicProperties":"{\n \"CurrentDoorState\":1\n}","x":518,"y":256,"wires":[["14d4bf27.4db229","745cd5b8.149d1c","d12ee2b5.67db6"]]},{"id":"14d4bf27.4db229","type":"debug","z":"75848247.7201a4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":894,"y":256,"wires":[]},{"id":"f0a87280.f66ea","type":"inject","z":"75848247.7201a4","name":"TargetDoorState 0 To Open","topic":"","payload":"{\"TargetDoorState\": 0}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":142,"y":40,"wires":[["5534366a.7ef91"]]},{"id":"2f0bb109.cee4ee","type":"inject","z":"75848247.7201a4","name":"TargetDoorState 1 To Close","topic":"","payload":"{\"TargetDoorState\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":152,"y":80,"wires":[["5534366a.7ef91"]]},{"id":"26ef612d.04cd86","type":"inject","z":"75848247.7201a4","name":"CurrentDoorState 0 opened","topic":"","payload":"{\"CurrentDoorState\":0}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":152,"y":168,"wires":[["5534366a.7ef91"]]},{"id":"1dcedc5c.cc1004","type":"inject","z":"75848247.7201a4","name":"CurrentDoorState 1 closed","topic":"","payload":"{\"CurrentDoorState\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":142,"y":208,"wires":[["5534366a.7ef91"]]},{"id":"75402de5.d52d84","type":"inject","z":"75848247.7201a4","name":"ObstructionDetected 1 true","topic":"","payload":"{\"ObstructionDetected\":1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":152,"y":400,"wires":[["5534366a.7ef91"]]},{"id":"70fdf078.8d2b48","type":"inject","z":"75848247.7201a4","name":"ObstructionDetected 0 false","topic":"","payload":"{\"ObstructionDetected\":0}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":152,"y":440,"wires":[["5534366a.7ef91"]]},{"id":"ea0e73a2.6eba48","type":"inject","z":"75848247.7201a4","name":"CurrentDoorState 4 stopped in the middle","topic":"","payload":"{\"CurrentDoorState\":4}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":192,"y":328,"wires":[["5534366a.7ef91"]]},{"id":"d12ee2b5.67db6","type":"function","z":"75848247.7201a4","name":"Save STATE","func":"var GD1 = global.get(\"GD1\");\n\nif (msg.payload.TargetDoorState !== undefined) {\n global.set(\"GD1.TargetState\", msg.payload.TargetDoorState);\n // 0 - want to open, 1 — want to close\n}\n\n//node.warn(GD1);\nreturn msg;","outputs":1,"noerr":0,"x":718,"y":296,"wires":[[]]},{"id":"d9b75532.233b28","type":"function","z":"75848247.7201a4","name":"Set GD1 — initial state (from sensors)","func":"var GD1 = {\n SensorState: 1, // set real init state according to sensor\n RunTime: 20, // time in seconds to fully open/close door (not implemented here)\n ObstructionDetected: false // set real init state according to sensor\n}\n\nglobal.set(\"GD1\", GD1);\n\n//node.warn(GD1);\n\nreturn [GD1];","outputs":1,"noerr":0,"x":686,"y":40,"wires":[[]]},{"id":"a45db63a.eb474","type":"inject","z":"75848247.7201a4","name":"Set initial state","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":432,"y":40,"wires":[["d9b75532.233b28"]]},{"id":"745cd5b8.149d1c","type":"function","z":"75848247.7201a4","name":"Main Logic","func":"var GD1 = global.get(\"GD1\");\n\nif ((msg.payload.TargetDoorState === 1) && \n (GD1.ObstructionDetected === false) && \n (GD1.CurrentState === 0)) {\n // real command to close here\n return {\"payload\": \"CLOSE COMMAND\"}\n}\n\nif (msg.payload.TargetDoorState === 0) {\n // real command to open here\n return {\"payload\": \"OPEN COMMAND\"}\n}","outputs":1,"noerr":0,"x":718,"y":336,"wires":[["14d4bf27.4db229"]]},{"id":"c53b5c5a.49826","type":"function","z":"75848247.7201a4","name":"Set initial HomeKit state","func":"var GD1 = global.get(\"GD1\");\n\nif (GD1.SensorState === 1) {\n var newMsg = {\"payload\": {\n \"TargetDoorState\":1,\n \"CurrentDoorState\":1 }\n }\n //node.warn(newMsg);\n return newMsg\n}\n\nif (GD1.SensorState === 0) {\n var newMsg = {\"payload\": {\n \"TargetDoorState\":0,\n \"CurrentDoorState\":0 }\n }\n //node.warn(newMsg);\n return newMsg\n}","outputs":1,"noerr":0,"x":726,"y":80,"wires":[["5534366a.7ef91"]]},{"id":"38b37223.7302b6","type":"inject","z":"75848247.7201a4","name":"Send initial state to HomeKit","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.5","x":472,"y":80,"wires":[["c53b5c5a.49826"]]},{"id":"35daf933.b31bae","type":"inject","z":"75848247.7201a4","name":"CurrentDoorState 2 opening","topic":"","payload":"{\"CurrentDoorState\":2}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":152,"y":248,"wires":[[]]},{"id":"ab4940dd.c6e4f","type":"inject","z":"75848247.7201a4","name":"CurrentDoorState 3 closing","topic":"","payload":"{\"CurrentDoorState\":3}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":142,"y":288,"wires":[[]]},{"id":"d3e3a15f.775f","type":"inject","z":"75848247.7201a4","name":"Sensor Closed","topic":"1","payload":"SensorState","payloadType":"global","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":432,"y":432,"wires":[["dcae49cf.d24648"]]},{"id":"d57c187.234f768","type":"inject","z":"75848247.7201a4","name":"Sensor Opened","topic":"0","payload":"SensorState","payloadType":"global","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":432,"y":472,"wires":[["c37a0663.e9b01"]]},{"id":"c37a0663.e9b01","type":"function","z":"75848247.7201a4","name":"","func":"// sensor send opened state\n\nvar GD1 = global.get(\"GD1\");\nglobal.set(\"GD1.CurrentState\", 0);\nvar newMsg = {\"payload\": {\"CurrentDoorState\":0 }}\nreturn newMsg;","outputs":1,"noerr":0,"x":586,"y":472,"wires":[["5534366a.7ef91"]]},{"id":"dcae49cf.d24648","type":"function","z":"75848247.7201a4","name":"","func":"// sensor send closed state\n\nvar GD1 = global.get(\"GD1\");\nglobal.set(\"GD1.CurrentState\", 1);\nvar newMsg = {\"payload\": {\"CurrentDoorState\":1 }}\nreturn newMsg;","outputs":1,"noerr":0,"x":586,"y":432,"wires":[["5534366a.7ef91"]]},{"id":"b49fbf5e.c23e08","type":"inject","z":"75848247.7201a4","name":"Sensor Unknown","topic":"0","payload":"SensorState","payloadType":"global","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":432,"y":512,"wires":[["91fbd029.4be268"]]},{"id":"91fbd029.4be268","type":"function","z":"75848247.7201a4","name":"","func":"// sensor send unknown (not closed and not opened) state\n\nvar GD1 = global.get(\"GD1\");\n\nif (GD1.TargetState === 0) {\n var newMsg = {\"payload\": {\"CurrentDoorState\":2 }}\n} else if (GD1.TargetState === 1) {\n var newMsg = {\"payload\": {\"CurrentDoorState\":3 }}\n} else {\n var newMsg = {\"payload\": {\"CurrentDoorState\":4 }}\n}\n\n// dunno what to do with this info =)\nreturn newMsg;","outputs":1,"noerr":0,"x":586,"y":512,"wires":[["5534366a.7ef91"]]},{"id":"1f4da0a9.4023c7","type":"homekit-bridge","z":"","bridgeName":"villa-test","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"ptath","model":"raspberry pi zeroW","serialNo":"12345678"}]
Sure someone needs to optimize it )
Ok, so I got it on production =)
sonoff-tasmota with two sensors (cannot find obstruction sensor in stores) so we have fully opened and fully closed positions:

Works fine, but sometimes it shows incorrect opening/closing state (opened/closed works well) cause I'm lacking programming skills ) Brokes when I used default RF key to operate door.
[{"id":"ef3da932.35748","type":"tab","label":"Ворота","disabled":false,"info":""},{"id":"7e32d16e.303f2","type":"mqtt in","z":"ef3da932.35748","name":"Garage door sensors","topic":"tele/garage/SENSOR","qos":"1","datatype":"json","broker":"943c23bf.fcecb","x":124,"y":40,"wires":[["24cc9423.ce3fac"]]},{"id":"9c2fa281.4864c8","type":"debug","z":"ef3da932.35748","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":838,"y":160,"wires":[]},{"id":"24cc9423.ce3fac","type":"function","z":"ef3da932.35748","name":"Current state (from sensors)","func":"var GarageDoor = global.get(\"GarageDoor\");\n\n// fully opened\nif ((msg.payload.Switch1 == \"ON\") && (msg.payload.Switch2 == \"OFF\")) {\n GarageDoor.SensorState = 0;\n GarageDoor.Closing = false;\n GarageDoor.Opening = false\n} \n\n// fully closed\nif ((msg.payload.Switch1 == \"OFF\") && (msg.payload.Switch2 == \"ON\")) {\n GarageDoor.SensorState = 1;\n GarageDoor.Closing = false;\n GarageDoor.Opening = false\n\n} \n\n// stopped in the middle, both sensors off\nif ((msg.payload.Switch1 == \"OFF\") && (msg.payload.Switch2 == \"OFF\")) {\n if (GarageDoor.SensorState === 1) {\n GarageDoor.Opening = true\n } else if (GarageDoor.SensorState === 0) {\n GarageDoor.Closing = true\n }\n GarageDoor.SensorState = 4\n}\n\nGarageDoor.RunTime = 20, // time in seconds to fully open/close door (not implemented here)\nGarageDoor.ObstructionDetected = false // set real init state according to sensor\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\n//node.warn(global.get(\"GarageDoor\"));\n\nreturn [GarageDoor];","outputs":1,"noerr":0,"x":400,"y":96,"wires":[["462afe77.f078f"]]},{"id":"70bdfc35.c17b1c","type":"function","z":"ef3da932.35748","name":"Set initial HomeKit state","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar newpayload = {};\n\nif (GarageDoor.SensorState === 1) {\n newpayload.TargetDoorState = 1;\n newpayload.CurrentDoorState = 1\n }\n\nif (GarageDoor.SensorState === 0) {\n newpayload.TargetDoorState = 0;\n newpayload.CurrentDoorState = 0\n}\n\nif (GarageDoor.SensorState === 4) {\n newpayload.CurrentDoorState = 4\n}\n\nnewMsg = { \"payload\": newpayload }\nreturn newMsg;","outputs":1,"noerr":0,"x":166,"y":216,"wires":[["2888b0a0.49e8d8"]]},{"id":"4a7e730b.167fac","type":"inject","z":"ef3da932.35748","name":"Send initial state to HomeKit","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"5","x":144,"y":168,"wires":[["70bdfc35.c17b1c"]]},{"id":"2888b0a0.49e8d8","type":"homekit-service","z":"ef3da932.35748","isParent":true,"bridge":"1f4da0a9.4023c7","parentService":"","name":"Гараж","serviceName":"GarageDoorOpener","topic":"","filter":false,"manufacturer":"ptath","model":"Гаражные ворота","serialNo":"0001","characteristicProperties":"{}","x":610,"y":216,"wires":[["9c2fa281.4864c8","25850506.4f1e7a"]]},{"id":"e717a300.804b2","type":"mqtt out","z":"ef3da932.35748","name":"cmnd/garage/Power 3","topic":"cmnd/garage/Power","qos":"1","retain":"","broker":"943c23bf.fcecb","x":708,"y":312,"wires":[]},{"id":"25850506.4f1e7a","type":"function","z":"ef3da932.35748","name":"Main Logic","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar newpayload = {};\n\nif (msg.hap.context !== undefined) {\n\n if ((msg.payload.TargetDoorState === 1) && (GarageDoor.SensorState === 0)) {\n // real command to close here\n node.warn (\"CLOSING..\");\n GarageDoor.Closing = true;\n newpayload = \"3\"\n //return {\"payload\": \"3\"}\n }\n\n if ((msg.payload.TargetDoorState === 0) && (GarageDoor.SensorState === 1)) {\n // real command to open here\n node.warn (\"OPENING...\");\n GarageDoor.Opening = true;\n newpayload = \"3\"\n //return {\"payload\": \"3\"}\n }\n \n if ((msg.payload.TargetDoorState === 0) && (GarageDoor.SensorState === 4)) {\n // real command to open here\n node.warn (\"MOVE TO OPEN...\");\n GarageDoor.Opening = true;\n newpayload = \"3\"\n }\n \n if ((msg.payload.TargetDoorState === 1) && (GarageDoor.SensorState === 4)) {\n // real command to open here\n node.warn (\"MOVE TO CLOSE...\");\n GarageDoor.Closing = true;\n newpayload = \"3\"\n }\n\n global.set(\"GarageDoor\", GarageDoor);\n\n newMsg = { \"payload\": newpayload }\n return newMsg;\n \n}","outputs":1,"noerr":0,"x":654,"y":264,"wires":[["9c2fa281.4864c8","e717a300.804b2"]]},{"id":"462afe77.f078f","type":"function","z":"ef3da932.35748","name":"Set real HomeKit state","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar newpayload = {};\n\n// closed 1\nif (GarageDoor.SensorState === 1) {\n newpayload.CurrentDoorState = 1\n}\n\n// opened 0\nif (GarageDoor.SensorState === 0) {\n newpayload.CurrentDoorState = 0\n}\n\n// opening 2, closing 3 or stopped 4\nif (GarageDoor.SensorState === 4) {\n if (GarageDoor.Opening === true) {\n newpayload.CurrentDoorState = 2\n } else if (GarageDoor.Closing === true) {\n newpayload.CurrentDoorState = 3\n } else { newpayload.CurrentDoorState = 4 }\n}\n\nnewMsg = { \"payload\": newpayload }\nreturn newMsg;","outputs":1,"noerr":0,"x":524,"y":40,"wires":[["2888b0a0.49e8d8"]]},{"id":"d5022a7e.2abde","type":"inject","z":"ef3da932.35748","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":122,"y":336,"wires":[["be48d339.cc3ae8"]]},{"id":"be48d339.cc3ae8","type":"function","z":"ef3da932.35748","name":"Initial GarageDoor","func":"var GarageDoor = {};\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\n//node.warn(global.get(\"GarageDoor\"));\n\nreturn [GarageDoor];","outputs":1,"noerr":0,"x":306,"y":336,"wires":[[]]},{"id":"943c23bf.fcecb","type":"mqtt-broker","z":"","name":"villa","broker":"192.168.100.10","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"1f4da0a9.4023c7","type":"homekit-bridge","z":"","bridgeName":"villa-test","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"ptath","model":"raspberry pi zeroW","serialNo":"12345678"}]
The worst thing is that I don't have a garage myself and we have a huge distance between us so I can't help you on site :)
From what I understand - when you use RF key then garage sensor should inform node-red about that.
No way to do this, nodered can only read sensors state. RF works like dumb switch:
So:
Ok - it looks like you have the following input into your functions all coming from tele/garage/SENSOR (tasmota, right?) What is the command to close / open the door? Is it a pulse out of the tasmota? I use that in one of my tasmota's to "press the microwave button"...
msg.payload.Switch1 // "ON" for fully open door, "OFF" for at least partly closed door
msg.payload.Switch2 // "ON" for fully closed door, "OFF" for at least partly opened door
You're keeping the states stored globally in GarageDoor correct? like this:
GarageDoor = {
"SensorState": "1 or 0",
"Closing": "true/false",
"Opening": "true/false",
"RunTime": 20,
"ObstructionDetected": false
}
With these assumptions, I'm going to put together how I would approach this. 20 seconds seems like a pretty slow-closing door but that's cool, you can adjust accordingly.
One question for now: do you have a separate "open" and "close" command? (for when it's partly open)
By the way {"CurrentDoorState"} values 2-4 visually do nothing.
I agree mostly - if CurrentDoorState = 4 and TargetDoorState = 1 then you get a picture of a CLOSED door that says OPEN... Very subtle.

@crxporter Its what CurrentDoorState = 4 is about :)
"not open nor closed"
@ptath I have some comments:

Initial states shouldn't be necessary. Instead you can (in a function node) have your global.get look like:
global.get("GarageDoor") || {};
This will either load GarageDoor from your context store or initialize it to an empty JSON. No problems should happen from the empty JSON since you're creating an empty JSON in "your way".
I don't think your Set initial HomeKit would have been working properly since it was loading an empty set (GarageDoor.SensorState would be undefined?)
Now an explanation:
I've made some assumptions. First is that you have your Tasmota set to teleperiod of around 5 seconds. Second is that it takes less than 20 seconds for your door to open and close. If this is inaccurate or not possible we can adjust.
I've set the code to just use 2 variables in GarageDoor they are GarageDoor.CurrentState andGarageDoor.LastState`. There is a trigger node to handle when the door has not had one or the other sensor triggered and thus assumed to be stopped in the middle. The trigger is set to 30 seconds.
The State Handler node should watch your TELE message from MQTT and set the proper state in your GarageDoor global variable. Then if you have the double-off sensor condition it will check if the last state was "opened" (door must be closing!) or if the last state was "closed" (door must be opening). Finally if it doesn't trigger one of the two sensors for 30 seconds it will set to "stopped".
The CurrentState is passed to the To HomeKit node - that one just gets "OPENED", "CLOSED", "OPENING", "CLOSING", or "STOPPED". These messages will be sent to HomeKit to update the CurrentDoorState and TargetDoorState accordingly.
Next up is homekit node. You know what this one does.
Output from HomeKit goes into Main Logic to send commands wherever you need them! I don't know what your MQTT commands are to open/close the door so change lines 7 and 13 of that one accordingly. Additionally there is an output of the current state on that one in case you would like to act on that somewhere else.
I think I've captured the essentials of what your code did. Might be cleaner - I added the "stopped" timer. Let me know what you think!
Obligatory screenshot:

[{"id":"bc6e4345.084ac","type":"mqtt in","z":"4d879aca.7b54dc","name":"Garage door sensors","topic":"tele/garage/SENSOR","qos":"1","datatype":"json","broker":"d87a3640.7f627","x":400,"y":960,"wires":[["d69a3755.1a5f88"]]},{"id":"d99e0f8d.235dd8","type":"debug","z":"4d879aca.7b54dc","name":"Current State after HomeKit change","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1530,"y":980,"wires":[]},{"id":"c93ca563.787b6","type":"homekit-service","z":"4d879aca.7b54dc","isParent":true,"bridge":"75959f07.380d7","parentService":"","name":"Garage","serviceName":"GarageDoorOpener","topic":"","filter":false,"manufacturer":"ptath","model":"Ptath","serialNo":"0001","characteristicProperties":"{}","x":1080,"y":940,"wires":[["cd90fd3d.d5e928"]]},{"id":"42c6fd02.78f68c","type":"mqtt out","z":"4d879aca.7b54dc","name":"cmnd/garage/Power 3","topic":"cmnd/garage/Power","qos":"1","retain":"","broker":"d87a3640.7f627","x":1480,"y":900,"wires":[]},{"id":"cd90fd3d.d5e928","type":"function","z":"4d879aca.7b54dc","name":"Main Logic","func":"var GarageDoor = global.get(\"GarageDoor\");\n\nif (msg.hap !== undefined && msg.hap.context !== undefined) {\n var command;\n if (msg.payload.TargetDoorState === 1 && GarageDoor.LastState !== \"CLOSED\") {\n // close door command\n command = CloseDoor\n node.warn (\"CLOSING...\");\n GarageDoor.LastState = \"OPENED\"\n GarageDoor.CurrentState = \"CLOSING\";\n }\n if (msg.payload.TargetDoorState === 0 && GarageDoor.LastState !== \"OPENED\") {\n // open door command\n command = OpenDoor\n node.warn (\"OPENING...\");\n GarageDoor.LastState = \"CLOSED\"\n GarageDoor.CurrentState = \"OPENING\";\n }\n global.set(\"GarageDoor\", GarageDoor);\n return [{\"payload\":command},{\"payload\":GarageDoor.CurrentState}]\n}\n","outputs":2,"noerr":0,"x":1250,"y":940,"wires":[["42c6fd02.78f68c"],["d99e0f8d.235dd8"]]},{"id":"d69a3755.1a5f88","type":"function","z":"4d879aca.7b54dc","name":"State Handler","func":"var GarageDoor = global.get(\"GarageDoor\") || {}; // load \"GarageDoor\" or set to empty\n\nif (msg.payload.Switch1 == \"ON\" && msg.payload.Switch2 == \"OFF\") {\n // The door is fully opened\n GarageDoor.LastState = \"OPENED\";\n GarageDoor.CurrentState = \"OPENED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"ON\") {\n // The door is fully closed\n GarageDoor.LastState = \"CLOSED\";\n GarageDoor.CurrentState = \"CLOSED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"OFF\") {\n // The door is in the middle\n if (GarageDoor.LastState == \"OPENED\") GarageDoor.CurrentState = \"CLOSING\";\n if (GarageDoor.LastState == \"CLOSED\") GarageDoor.CurrentState = \"OPENING\";\n if (GarageDoor.LastState == \"STOPPED\") GarageDoor.CurrentState = \"STOPPED\";\n}\n\nvar moving = false;\nif (GarageDoor.CurrentState == \"OPENING\" || GarageDoor.CurrentState == \"CLOSING\") moving = true;\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\nif (moving){\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": 1}]\n} else {\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": \"RESET\"}]\n}\n","outputs":2,"noerr":0,"x":660,"y":960,"wires":[["1faf4d56.8fa40b"],["8dcaa284.cf07a8"]]},{"id":"8dcaa284.cf07a8","type":"trigger","z":"4d879aca.7b54dc","op1":"","op2":"","op1type":"nul","op2type":"date","duration":"30","extend":false,"units":"s","reset":"RESET","bytopic":"all","name":"Trigger","x":830,"y":1000,"wires":[["3e47e06f.7bf22"]]},{"id":"3e47e06f.7bf22","type":"function","z":"4d879aca.7b54dc","name":"Set stopped","func":"var GarageDoor = global.get(\"GarageDoor\") || {};\nGarageDoor.CurrentState = \"STOPPED\";\nGarageDoor.LastState = \"STOPPED\";\nglobal.set(\"GarageDoor\", GarageDoor);","outputs":0,"noerr":0,"x":1020,"y":1000,"wires":[]},{"id":"287ac37.005403c","type":"debug","z":"4d879aca.7b54dc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1090,"y":880,"wires":[]},{"id":"1faf4d56.8fa40b","type":"function","z":"4d879aca.7b54dc","name":"To HomeKit","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar output = {};\n\nif (GarageDoor.CurrentState == \"OPENED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 0,\n \"TargetDoorState\": 0\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 1,\n \"TargetDoorState\": 1\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"OPENING\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 2,\n \"TargetDoorState\": 0\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSING\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 3,\n \"TargetDoorState\": 1\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"STOPPED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 4,\n \"TargetDoorState\": 0\n }\n }\n}\n\nreturn output;","outputs":1,"noerr":0,"x":880,"y":940,"wires":[["c93ca563.787b6","287ac37.005403c"]]},{"id":"d87a3640.7f627","type":"mqtt-broker","z":"","name":"villa","broker":"192.168.100.10","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"75959f07.380d7","type":"homekit-bridge","z":"","bridgeName":"villa-test","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"ptath","model":"raspberry pi zeroW","serialNo":"12345678","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true}]
Note - don't copy from email, copy from GitHub website. I made some edits. There were a couple of errors in my function...
Also this flow should work no matter how you open the door... RF key, homekit, button on the wall, etc. HomeKit app shouldn't ever be more than 5 seconds off from what is actually happening!
Great work, thank you!
I can check it in real, but my house is far enough and no cameras yet =) I'll try to do this tomorrow and will post a result!
What's the command going to cmnd/garage/power in order to open/close the door? I'll update so it should be ready to go!
What's the command going to
cmnd/garage/powerin order to open/close the door? I'll update so it should be ready to go!
This is the same command to open, stop and close: "Power 3" (special "blink" for 0.2 sec), e.g. full topic is /cmnd/garage/power 3
In my old sample (before mqtt-IN node "cmnd/garage/Power"):
if ((msg.payload.TargetDoorState === 1) && (GarageDoor.SensorState === 0)) {
node.warn ("CLOSING..");
GarageDoor.Closing = true;
---- >>> newpayload = "3" <----- HERE IS IT =)
}
This is getting good. I've added your output commands and added a place for you to add an obstruction detector. The obstruction detector is assumed to work the same as your opened/closed sensors but is Switch3 in Tasmota.
Obstruction "ON" means there is something blocking, "OFF" means all clear. The Main Logic node has a check to be sure there is no obstruction before sending a "close" command.
I'm going to include all of my simulators in this version and a debug node that shows the current state of the door. In production you can take away all of the Simulator nodes.

[{"id":"bc6e4345.084ac","type":"mqtt in","z":"4d879aca.7b54dc","name":"Garage door sensors","topic":"tele/garage/SENSOR","qos":"1","datatype":"json","broker":"2b31433.66791bc","x":400,"y":960,"wires":[["d69a3755.1a5f88","5a0aa919.e262a8"]]},{"id":"d99e0f8d.235dd8","type":"debug","z":"4d879aca.7b54dc","name":"Current State","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1460,"y":960,"wires":[]},{"id":"c93ca563.787b6","type":"homekit-service","z":"4d879aca.7b54dc","isParent":true,"bridge":"75959f07.380d7","parentService":"","name":"Garage","serviceName":"GarageDoorOpener","topic":"","filter":false,"manufacturer":"ptath","model":"Ptath","serialNo":"0001","characteristicProperties":"{}","x":1060,"y":920,"wires":[["cd90fd3d.d5e928"]]},{"id":"42c6fd02.78f68c","type":"mqtt out","z":"4d879aca.7b54dc","name":"cmnd/garage/Power 3","topic":"cmnd/garage/Power","qos":"1","retain":"","broker":"2b31433.66791bc","x":1480,"y":900,"wires":[]},{"id":"cd90fd3d.d5e928","type":"function","z":"4d879aca.7b54dc","name":"Main Logic","func":"if (msg.hap !== undefined && msg.hap.context !== undefined) {\n var GarageDoor = global.get(\"GarageDoor\");\n var command;\n if (msg.payload.TargetDoorState === 1 && GarageDoor.LastState !== \"CLOSED\") {\n // close door command\n if (GarageDoor.Obstruction !== \"TRUE\") {\n command = {\"payload\": \"3\"};\n node.warn (\"CLOSING...\");\n GarageDoor.LastState = \"OPENED\" // so it will show properly next teleperiod\n GarageDoor.CurrentState = \"CLOSING\";\n } else {\n node.warn (\"Obstruction! Clear the door area!\");\n command = null;\n }\n }\n if (msg.payload.TargetDoorState === 0 && GarageDoor.LastState !== \"OPENED\") {\n // open door command\n command = {\"payload\": \"3\"};\n node.warn (\"OPENING...\");\n GarageDoor.LastState = \"CLOSED\" // so it will show properly next teleperiod\n GarageDoor.CurrentState = \"OPENING\";\n }\n global.set(\"GarageDoor\", GarageDoor);\n return [command,{\"payload\":GarageDoor.CurrentState}]\n}\n","outputs":2,"noerr":0,"x":1250,"y":920,"wires":[["42c6fd02.78f68c","d99e0f8d.235dd8"],["d99e0f8d.235dd8"]]},{"id":"d69a3755.1a5f88","type":"function","z":"4d879aca.7b54dc","name":"State Handler","func":"var GarageDoor = global.get(\"GarageDoor\") || {}; // load \"GarageDoor\" or set to empty\n\nif (msg.payload.Switch1 == \"ON\" && msg.payload.Switch2 == \"OFF\") {\n // The door is fully opened\n GarageDoor.LastState = \"OPENED\";\n GarageDoor.CurrentState = \"OPENED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"ON\") {\n // The door is fully closed\n GarageDoor.LastState = \"CLOSED\";\n GarageDoor.CurrentState = \"CLOSED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"OFF\") {\n // The door is in the middle\n if (GarageDoor.LastState == \"OPENED\") GarageDoor.CurrentState = \"CLOSING\";\n if (GarageDoor.LastState == \"CLOSED\") GarageDoor.CurrentState = \"OPENING\";\n if (GarageDoor.LastState == \"STOPPED\") GarageDoor.CurrentState = \"STOPPED\";\n}\n\nvar moving = false;\nif (GarageDoor.CurrentState == \"OPENING\" || GarageDoor.CurrentState == \"CLOSING\") moving = true;\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\nif (moving){\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": 1}]\n} else {\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": \"RESET\"}]\n}\n","outputs":2,"noerr":0,"x":660,"y":960,"wires":[["1faf4d56.8fa40b","d99e0f8d.235dd8"],["8dcaa284.cf07a8"]]},{"id":"8dcaa284.cf07a8","type":"trigger","z":"4d879aca.7b54dc","op1":"","op2":"","op1type":"nul","op2type":"date","duration":"30","extend":false,"units":"s","reset":"RESET","bytopic":"all","name":"Trigger","x":870,"y":1000,"wires":[["3e47e06f.7bf22"]]},{"id":"3e47e06f.7bf22","type":"function","z":"4d879aca.7b54dc","name":"Set stopped","func":"var GarageDoor = global.get(\"GarageDoor\") || {};\nGarageDoor.CurrentState = \"STOPPED\";\nGarageDoor.LastState = \"STOPPED\";\nglobal.set(\"GarageDoor\", GarageDoor);","outputs":0,"noerr":0,"x":1030,"y":1000,"wires":[]},{"id":"7b4e0744.4569e8","type":"inject","z":"4d879aca.7b54dc","name":"Neither","topic":"","payload":"{\"Switch1\":\"OFF\",\"Switch2\":\"OFF\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":390,"y":780,"wires":[["5613a5fc.2cd41c"]]},{"id":"e8ed339e.4a9458","type":"inject","z":"4d879aca.7b54dc","name":"Opened","topic":"","payload":"{\"Switch1\":\"ON\",\"Switch2\":\"OFF\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":390,"y":820,"wires":[["5613a5fc.2cd41c"]]},{"id":"a80b4b5b.a39c18","type":"inject","z":"4d879aca.7b54dc","name":"Closed","topic":"","payload":"{\"Switch1\":\"OFF\",\"Switch2\":\"ON\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":390,"y":860,"wires":[["5613a5fc.2cd41c"]]},{"id":"1faf4d56.8fa40b","type":"function","z":"4d879aca.7b54dc","name":"To HomeKit","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar output = {};\n\nif (GarageDoor.CurrentState == \"OPENED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 0,\n \"TargetDoorState\": 0\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 1,\n \"TargetDoorState\": 1\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"OPENING\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 2,\n \"TargetDoorState\": 0\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSING\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 3,\n \"TargetDoorState\": 1\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"STOPPED\") {\n output = {\n \"payload\": {\n \"CurrentDoorState\": 4,\n \"TargetDoorState\": 0\n }\n }\n}\n\nreturn output;","outputs":1,"noerr":0,"x":870,"y":920,"wires":[["c93ca563.787b6"]]},{"id":"5613a5fc.2cd41c","type":"mqtt out","z":"4d879aca.7b54dc","name":"Simulator","topic":"tele/garage/SENSOR","qos":"1","retain":"","broker":"2b31433.66791bc","x":680,"y":740,"wires":[]},{"id":"60a0c2bd.cff424","type":"function","z":"4d879aca.7b54dc","name":"Simulator","func":"var Newmsg = {};\nNewmsg.hap = {\"context\":\"defined\"};\nNewmsg.payload = {\"TargetDoorState\":msg.payload};\nreturn Newmsg;\n","outputs":1,"noerr":0,"x":1060,"y":720,"wires":[["cd90fd3d.d5e928"]]},{"id":"3e2fc32.597943c","type":"inject","z":"4d879aca.7b54dc","name":"Close","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":890,"y":680,"wires":[["60a0c2bd.cff424"]]},{"id":"cb10fb9c.9fc808","type":"inject","z":"4d879aca.7b54dc","name":"Open","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":890,"y":720,"wires":[["60a0c2bd.cff424"]]},{"id":"4a68dbf0.f6e5dc","type":"inject","z":"4d879aca.7b54dc","name":"OBSTRUCTION","topic":"","payload":"{\"Switch3\":\"ON\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":420,"y":660,"wires":[["5613a5fc.2cd41c"]]},{"id":"46b09ca9.8f3684","type":"inject","z":"4d879aca.7b54dc","name":"All clear","topic":"","payload":"{\"Switch3\":\"OFF\"}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":390,"y":700,"wires":[["5613a5fc.2cd41c"]]},{"id":"b9939fa4.a4bb18","type":"function","z":"4d879aca.7b54dc","name":"Obstruction Handler","func":"GarageDoor = global.get(\"GarageDoor\");\nvar output = {};\n\nif (msg.payload.Switch3 === \"ON\") {\n if (GarageDoor.CurrentState !== \"CLOSED\"){\n output = {\n \"payload\": {\n \"ObstructionDetected\": true\n }\n }\n GarageDoor.Obstruction = \"TRUE\"\n } else {\n output = {\n \"payload\": {\n \"ObstructionDetected\": false\n }\n }\n }\n} else {\n output = {\n \"payload\": {\n \"ObstructionDetected\": false\n }\n }\n GarageDoor.Obstruction = \"FALSE\"\n}\nglobal.set(\"GarageDoor\", GarageDoor);\n\nreturn output;\n","outputs":1,"noerr":0,"x":840,"y":880,"wires":[["c93ca563.787b6"]]},{"id":"e3b40238.4a14b","type":"comment","z":"4d879aca.7b54dc","name":"Obstruction simulator","info":"","x":420,"y":620,"wires":[]},{"id":"5a0aa919.e262a8","type":"delay","z":"4d879aca.7b54dc","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":650,"y":880,"wires":[["b9939fa4.a4bb18"]]},{"id":"807ff83b.4c1f3","type":"comment","z":"4d879aca.7b54dc","name":"MQTT simulator","info":"","x":400,"y":740,"wires":[]},{"id":"23c6ddfc.f30ea2","type":"comment","z":"4d879aca.7b54dc","name":"HomeKit simulator","info":"","x":890,"y":640,"wires":[]},{"id":"2b31433.66791bc","type":"mqtt-broker","z":"","name":"villa","broker":"192.168.100.10","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"75959f07.380d7","type":"homekit-bridge","z":"","bridgeName":"villa-test","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"ptath","model":"raspberry pi zeroW","serialNo":"12345678","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true}]
Comment on the obstruction sensor - you will probably want to subscribe to the switch topic for that so it stays updated all the time. If I remember tasmota right it's something like stat/garage/power3 or something similar. Once you get it you can watch the console on tasmota to figure it out!
It's important for that one to be immediately updated. For safety.
The sensor topics can be slower - also they need to be sent in pairs.
OK, it works in real (clickable)!
One problem is it cannot be stopped in this way. Sometimes I need to stop the door and in my initial script it works when I click on garage door icon (same scenario when door is closed):
This is a default behavior with RF control (stop step). If I press RF button door stops (and after 30 sec timeout correctly show "CurrentDoorState: 4") and some clicks in home.app does nothing. After 3rd click door starts opening (home.app shows "Closing") and after fully open correctly shows "Opened".
So I definitely should add somehow this case (stop step) to Main Logic node. Maybe I should reduce telemetry from tele/garage/SENSOR to 1sec and somehow use it when home.app button pressed while door is moving?
I hadn’t considered the case of pushing the button while it’s moving! Yes it should be doable in the Main Logic node.
I actually never tested this example from the home app, just kept it all in node red... Shouldn’t be much more effort to add a stop option. I’ll take a look later, update here if you get to it first.
Might not need to do the 1 second tele. Watch the homekit output to see what clicking while it’s moving does (including quick press before tele comes in)

I think linking the 2nd output of Main Logic to the To HomeKit node will let the half-open command work! No code change necessary just throw that link in!
I think linking the 2nd output of
Main Logicto theTo HomeKitnode will let the half-open command work! No code change necessary just throw that link in!
Don't think so, there is no real command to mqtt to do smth with the door. I forgot to tell than Main Logic in my case now looks like:
var GarageDoor = global.get("GarageDoor");
if (msg.hap !== undefined && msg.hap.context !== undefined) {
var command;
if (msg.payload.TargetDoorState === 1 && GarageDoor.LastState !== "CLOSED") {
// close door command
// command = CloseDoor
command = "3"; <=======================HERE
node.warn ("CLOSING...");
GarageDoor.LastState = "OPENED";
GarageDoor.CurrentState = "CLOSING";
}
if (msg.payload.TargetDoorState === 0 && GarageDoor.LastState !== "OPENED") {
// open door command
// command = OpenDoor
command = "3"; <=======================HERE
node.warn ("OPENING...");
GarageDoor.LastState = "CLOSED";
GarageDoor.CurrentState = "OPENING";
}
global.set("GarageDoor", GarageDoor);
return [{"payload":command},{"payload":GarageDoor.CurrentState}]
}
Second Main Logic output does nothing (no command to the door, and in should be "3" to mqtt), it just "payload":GarageDoor.CurrentState. It will change visual state in HomeKit to open and will not stop the door really.
Let’s see. You labeled where the two 3’s are sent.
Try changing two lines below the first 3 to:
GarageDoor.LastState = "CLOSING";
And below the second 3 to:
GarageDoor.LastState = "OPENING";
Then it wouldn’t ignore the next command - and should send another 3 when you hit it during opening/closing.
Can you tell I never leave my garage doors partly open? I didn’t even think of the stop case.
Another option is to take away the && GarageDoorLastState ... from the if statements. That’s why the “stop” command from homekit isn’t going through. Combo of that check and my comment a couple of hours ago about updating that variable. Either / both should work.
Also you’re right the extra output on Main Logic is unnecessary. Mostly there in case you want something else to react to the door state (turn on a light somewhere?). I do like sending it back into the homekit to update the state more quickly when you click in the Home app...
So I always try to re-write my functions at least 10 times before I move on to a new project. I think we are getting closer?
This time I actually tested how the functions respond in HomeKit. I think the "stop" command is working.
I've also added "instant" feedback. Tasmota should send a SwitchTopic whenever your sensors change between ON/OFF. You can subscribe to this switch topic in the new MQTT nodes and you should begin to get instant feedback in the Home app when you control the door from your RF remote. The Tele messages are still important because they will run the timer up to 30 seconds and switch you over to "stopped" status. It's always good to have the tele part so things stay updated properly.
NOTE: you'll need to verify the MQTT topics. I don't have the normal SwitchTopic so you'll want to see what yours is (hint - watch Tasmota console when the sensors trigger).

Once you have your feature requests finished I'll move this to the wiki. Always good to test in real life first.
[{"id":"69226b8c.22ab04","type":"homekit-service","z":"3e0d11cf.29e996","isParent":true,"bridge":"56f83ee1.f0bbd","parentService":"","name":"Ptath","serviceName":"GarageDoorOpener","topic":"","filter":false,"manufacturer":"Default Manufacturer","model":"Default Model","serialNo":"Default Serial Number","characteristicProperties":"{}","x":890,"y":1000,"wires":[["81e26608.9dcf1"]]},{"id":"7ba4d5eb.9d83ec","type":"mqtt in","z":"3e0d11cf.29e996","name":"TELE Sensors","topic":"tele/garage/SENSOR","qos":"1","datatype":"json","broker":"8de2bd93.86c898","x":210,"y":1060,"wires":[["564864bb.b1601c","1a3938a1.19889f"]]},{"id":"15ff5e5a.1ac742","type":"mqtt out","z":"3e0d11cf.29e996","name":"cmnd/garage/Power 3","topic":"cmnd/garage/Power","qos":"1","retain":"","broker":"8de2bd93.86c898","x":1300,"y":960,"wires":[]},{"id":"81e26608.9dcf1","type":"function","z":"3e0d11cf.29e996","name":"Main Logic","func":"if (msg.hap !== undefined && msg.hap.context !== undefined) {\n var GarageDoor = global.get(\"GarageDoor\");\n var command;\n \n if (msg.payload.TargetDoorState === 1) {\n if (GarageDoor.CurrentState === \"OPENED\") {\n // Normal close command\n if (GarageDoor.Obstruction !== \"TRUE\") {\n // Close if no obstruction\n command = {\"payload\": \"3\"};\n node.warn (\"CLOSING...\");\n GarageDoor.CurrentState = \"CLOSING\";\n } else {\n // Do not close if obstruction detected\n node.warn (\"Obstruction! Clear the door area!\");\n command = null;\n }\n } else if (GarageDoor.CurrentState === \"OPENING\") {\n // Stop door while opening\n command = {\"payload\": \"3\"};\n node.warn (\"STOPPING...\");\n GarageDoor.LastState = \"STOPPED\";\n GarageDoor.CurrentState = \"STOPPED\";\n } else if (GarageDoor.CurrentState === \"STOPPED\") {\n // Restart door from stopped\n if (GarageDoor.Obstruction !== \"TRUE\") {\n // Close if no obstruction\n command = {\"payload\": \"3\"};\n node.warn (\"CLOSING...\");\n GarageDoor.LastState = \"OPENED\"\n GarageDoor.CurrentState = \"CLOSING\";\n } else {\n // Do not close if obstruction detected\n node.warn (\"Obstruction! Clear the door area!\");\n command = null;\n }\n }\n } else if (msg.payload.TargetDoorState === 0) {\n if (GarageDoor.CurrentState === \"CLOSED\") {\n // Normal open command\n command = {\"payload\": \"3\"};\n node.warn (\"OPENING...\");\n // GarageDoor.LastState = \"CLOSED\";\n GarageDoor.CurrentState = \"OPENING\";\n } else if (GarageDoor.CurrentState === \"CLOSING\") {\n // Stop door while closing\n command = {\"payload\": \"3\"};\n node.warn (\"STOPPING...\");\n GarageDoor.LastState = \"STOPPED\";\n GarageDoor.CurrentState = \"STOPPED\";\n } else if (GarageDoor.CurrentState === \"STOPPED\") {\n // Restart door from stopped, assume it's going to close.\n if (GarageDoor.Obstruction !== \"TRUE\") {\n // Close if no obstruction\n command = {\"payload\": \"3\"};\n node.warn (\"CLOSING...\");\n GarageDoor.LastState = \"OPENED\"\n GarageDoor.CurrentState = \"CLOSING\";\n } else {\n // Do not close if obstruction detected\n node.warn (\"Obstruction! Clear the door area!\");\n command = null;\n }\n }\n }\n return [command, {\"payload\": GarageDoor.CurrentState}]\n}","outputs":2,"noerr":0,"x":1070,"y":1000,"wires":[["15ff5e5a.1ac742"],["76c85a60.bd0004"]]},{"id":"564864bb.b1601c","type":"function","z":"3e0d11cf.29e996","name":"State Handler","func":"var GarageDoor = global.get(\"GarageDoor\") || {}; // load \"GarageDoor\" or set to empty\n\nif (msg.payload.Switch1 == \"ON\" && msg.payload.Switch2 == \"OFF\") {\n // The door is fully opened\n GarageDoor.LastState = \"OPENED\";\n GarageDoor.CurrentState = \"OPENED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"ON\") {\n // The door is fully closed\n GarageDoor.LastState = \"CLOSED\";\n GarageDoor.CurrentState = \"CLOSED\";\n}\n\nif (msg.payload.Switch1 == \"OFF\" && msg.payload.Switch2 == \"OFF\") {\n // The door is in the middle\n if (GarageDoor.LastState == \"OPENED\") GarageDoor.CurrentState = \"CLOSING\";\n if (GarageDoor.LastState == \"CLOSED\") GarageDoor.CurrentState = \"OPENING\";\n if (GarageDoor.LastState == \"STOPPED\") GarageDoor.CurrentState = \"STOPPED\";\n}\n\nvar moving = false;\nif (GarageDoor.CurrentState == \"OPENING\" || GarageDoor.CurrentState == \"CLOSING\") moving = true;\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\nif (moving){\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": 1}]\n} else {\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": \"RESET\"}]\n}\n","outputs":2,"noerr":0,"x":500,"y":1060,"wires":[["fb761eae.a5ef8"],["d1438336.ad7238"]]},{"id":"d1438336.ad7238","type":"trigger","z":"3e0d11cf.29e996","op1":"","op2":"","op1type":"nul","op2type":"date","duration":"30","extend":false,"units":"s","reset":"RESET","bytopic":"all","name":"Trigger","x":730,"y":1220,"wires":[["97dd7cf5.c6075"]]},{"id":"97dd7cf5.c6075","type":"function","z":"3e0d11cf.29e996","name":"Set stopped","func":"var GarageDoor = global.get(\"GarageDoor\") || {};\nGarageDoor.CurrentState = \"STOPPED\";\nGarageDoor.LastState = \"STOPPED\";\nglobal.set(\"GarageDoor\", GarageDoor);","outputs":0,"noerr":0,"x":910,"y":1220,"wires":[]},{"id":"81d3c123.834598","type":"inject","z":"3e0d11cf.29e996","name":"Neither","topic":"","payload":"{\"Switch1\":\"OFF\",\"Switch2\":\"OFF\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":840,"wires":[["c18468e.fdde518"]]},{"id":"ef6c6ca4.618ae","type":"inject","z":"3e0d11cf.29e996","name":"Opened","topic":"","payload":"{\"Switch1\":\"ON\",\"Switch2\":\"OFF\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":880,"wires":[["c18468e.fdde518"]]},{"id":"1ed91362.10f605","type":"inject","z":"3e0d11cf.29e996","name":"Closed","topic":"","payload":"{\"Switch1\":\"OFF\",\"Switch2\":\"ON\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":920,"wires":[["c18468e.fdde518"]]},{"id":"fb761eae.a5ef8","type":"function","z":"3e0d11cf.29e996","name":"To HomeKit","func":"var GarageDoor = global.get(\"GarageDoor\");\nvar output = {};\n\nif (GarageDoor.CurrentState == \"OPENED\") {\n output = {\n \"payload\": {\n \"TargetDoorState\": 0,\n \"CurrentDoorState\": 0\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSED\") {\n output = {\n \"payload\": {\n \"TargetDoorState\": 1,\n \"CurrentDoorState\": 1\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"OPENING\") {\n output = {\n \"payload\": {\n \"TargetDoorState\": 0,\n \"CurrentDoorState\": 3\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"CLOSING\") {\n output = {\n \"payload\": {\n \"TargetDoorState\": 1,\n \"CurrentDoorState\": 2\n }\n }\n}\nelse if (GarageDoor.CurrentState == \"STOPPED\") {\n output = {\n \"payload\": {\n \"TargetDoorState\": 0,\n \"CurrentDoorState\": 4\n }\n }\n}\n\nreturn output;","outputs":1,"noerr":0,"x":710,"y":1020,"wires":[["69226b8c.22ab04"]]},{"id":"c18468e.fdde518","type":"mqtt out","z":"3e0d11cf.29e996","name":"Simulator","topic":"tele/garage/SENSOR","qos":"1","retain":"","broker":"8de2bd93.86c898","x":500,"y":720,"wires":[]},{"id":"1450ca78.249d8e","type":"function","z":"3e0d11cf.29e996","name":"Simulator","func":"var Newmsg = {};\nNewmsg.hap = {\"context\":\"defined\"};\nNewmsg.payload = {\"TargetDoorState\":msg.payload};\nreturn Newmsg;\n","outputs":1,"noerr":0,"x":860,"y":720,"wires":[["81e26608.9dcf1"]]},{"id":"4eb7eeb2.56b25","type":"inject","z":"3e0d11cf.29e996","name":"Close","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":710,"y":720,"wires":[["1450ca78.249d8e"]]},{"id":"3d998491.e2daac","type":"inject","z":"3e0d11cf.29e996","name":"Open","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":710,"y":760,"wires":[["1450ca78.249d8e"]]},{"id":"152449f6.bcaece","type":"inject","z":"3e0d11cf.29e996","name":"OBSTRUCTION","topic":"","payload":"{\"Switch3\":\"ON\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":260,"y":720,"wires":[["c18468e.fdde518"]]},{"id":"e359a895.408258","type":"inject","z":"3e0d11cf.29e996","name":"All clear","topic":"","payload":"{\"Switch3\":\"OFF\"}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":760,"wires":[["c18468e.fdde518"]]},{"id":"d2add466.b69c98","type":"function","z":"3e0d11cf.29e996","name":"Obstruction Handler","func":"GarageDoor = global.get(\"GarageDoor\");\nvar output = {};\n\nif (msg.payload.Switch3 === \"ON\") {\n if (GarageDoor.CurrentState !== \"CLOSED\"){\n output = {\n \"payload\": {\n \"ObstructionDetected\": true\n }\n }\n GarageDoor.Obstruction = \"TRUE\"\n } else {\n output = {\n \"payload\": {\n \"ObstructionDetected\": false\n }\n }\n }\n} else {\n output = {\n \"payload\": {\n \"ObstructionDetected\": false\n }\n }\n GarageDoor.Obstruction = \"FALSE\"\n}\nglobal.set(\"GarageDoor\", GarageDoor);\n\nreturn output;\n","outputs":1,"noerr":0,"x":680,"y":960,"wires":[["69226b8c.22ab04"]]},{"id":"a09fe844.ef8af","type":"comment","z":"3e0d11cf.29e996","name":"Obstruction simulator","info":"","x":260,"y":680,"wires":[]},{"id":"1a3938a1.19889f","type":"delay","z":"3e0d11cf.29e996","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":490,"y":960,"wires":[["d2add466.b69c98"]]},{"id":"7e1c4b.927f33b4","type":"comment","z":"3e0d11cf.29e996","name":"Teleperiod simulator","info":"","x":250,"y":800,"wires":[]},{"id":"97e48d59.73d608","type":"comment","z":"3e0d11cf.29e996","name":"HomeKit simulator","info":"","x":730,"y":680,"wires":[]},{"id":"b67bb3a5.19e1f8","type":"link in","z":"3e0d11cf.29e996","name":"","links":["76c85a60.bd0004"],"x":555,"y":1000,"wires":[["fb761eae.a5ef8"]]},{"id":"76c85a60.bd0004","type":"link out","z":"3e0d11cf.29e996","name":"","links":["b67bb3a5.19e1f8"],"x":1215,"y":1040,"wires":[]},{"id":"b7e5025d.e11e58","type":"mqtt in","z":"3e0d11cf.29e996","name":"SwitchTopic (on=opened off=closing)","topic":"cmnd/SwitchTopic/POWER1","qos":"1","datatype":"auto","broker":"8de2bd93.86c898","x":230,"y":1180,"wires":[["81eb9be3.c25088"]]},{"id":"6c47141f.43b344","type":"mqtt in","z":"3e0d11cf.29e996","name":"SwitchTopic (on=closed off=opening)","topic":"cmnd/SwitchTopic/POWER2","qos":"1","datatype":"auto","broker":"8de2bd93.86c898","x":230,"y":1240,"wires":[["5d350244.59bd4c"]]},{"id":"81eb9be3.c25088","type":"function","z":"3e0d11cf.29e996","name":"Opened Handler","func":"var GarageDoor = global.get(\"GarageDoor\") || {}; // load \"GarageDoor\" or set to empty\n\nif (msg.payload == \"ON\") {\n // Sensor just turned on = door is fully opened\n GarageDoor.LastState = \"OPENED\";\n GarageDoor.CurrentState = \"OPENED\";\n} else if (msg.payload == \"OFF\" && GarageDoor.LastState == \"OPENED\") {\n // Sensor just turned off == door is starting to close\n GarageDoor.CurrentState = \"CLOSING\";\n}\n\nvar moving = false;\nif (GarageDoor.CurrentState == \"OPENING\" || GarageDoor.CurrentState == \"CLOSING\") moving = true;\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\nif (moving){\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": 1}]\n} else {\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": \"RESET\"}]\n}","outputs":2,"noerr":0,"x":480,"y":1180,"wires":[["fb761eae.a5ef8"],["d1438336.ad7238"]]},{"id":"5d350244.59bd4c","type":"function","z":"3e0d11cf.29e996","name":"Closed Handler","func":"var GarageDoor = global.get(\"GarageDoor\") || {}; // load \"GarageDoor\" or set to empty\n\nif (msg.payload == \"ON\") {\n // Sensor just turned on = door is fully opened\n GarageDoor.LastState = \"CLOSED\";\n GarageDoor.CurrentState = \"CLOSED\";\n} else if (msg.payload == \"OFF\" && GarageDoor.LastState == \"CLOSED\") {\n // Sensor just turned off == door is starting to close\n GarageDoor.CurrentState = \"OPENING\";\n}\n\nvar moving = false;\nif (GarageDoor.CurrentState == \"OPENING\" || GarageDoor.CurrentState == \"CLOSING\") moving = true;\n\nglobal.set(\"GarageDoor\", GarageDoor);\n\nif (moving){\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": 1}]\n} else {\n return [{\"payload\": GarageDoor.CurrentState}, {\"payload\": \"RESET\"}]\n}","outputs":2,"noerr":0,"x":480,"y":1240,"wires":[["fb761eae.a5ef8"],["d1438336.ad7238"]]},{"id":"37c95a46.9afdb6","type":"inject","z":"3e0d11cf.29e996","name":"opened = ON","topic":"cmnd/SwitchTopic/POWER1","payload":"ON","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1070,"y":720,"wires":[["77d679b2.662be"]]},{"id":"f8407fd2.2cef88","type":"inject","z":"3e0d11cf.29e996","name":"Closing = OFF","topic":"cmnd/SwitchTopic/POWER1","payload":"OFF","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1070,"y":760,"wires":[["77d679b2.662be"]]},{"id":"1fd925ac.3d202a","type":"inject","z":"3e0d11cf.29e996","name":"Closed = ON","topic":"cmnd/SwitchTopic/POWER2","payload":"ON","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1070,"y":820,"wires":[["77d679b2.662be"]]},{"id":"4894bcad.103fec","type":"inject","z":"3e0d11cf.29e996","name":"Opening = OFF","topic":"cmnd/SwitchTopic/POWER2","payload":"OFF","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1080,"y":860,"wires":[["77d679b2.662be"]]},{"id":"77d679b2.662be","type":"mqtt out","z":"3e0d11cf.29e996","name":"state change","topic":"","qos":"1","retain":"false","broker":"8de2bd93.86c898","x":1310,"y":720,"wires":[]},{"id":"facbd911.62551","type":"comment","z":"3e0d11cf.29e996","name":"Instant feedback simulator","info":"","x":1090,"y":680,"wires":[]},{"id":"c2c8c131.b76c48","type":"inject","z":"3e0d11cf.29e996","name":"Obstruction","topic":"cmnd/SwitchTopic/POWER3","payload":"ON","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1310,"y":820,"wires":[["77d679b2.662be"]]},{"id":"38ae5250.c50d16","type":"inject","z":"3e0d11cf.29e996","name":"Clear","topic":"cmnd/SwitchTopic/POWER3","payload":"OFF","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1290,"y":860,"wires":[["77d679b2.662be"]]},{"id":"56f83ee1.f0bbd","type":"homekit-bridge","z":"","bridgeName":"villa-test","pinCode":"111-11-111","port":"","allowInsecureRequest":false,"manufacturer":"ptath","model":"raspberry pi zeroW","serialNo":"12345678","customMdnsConfig":false,"mdnsMulticast":true,"mdnsInterface":"","mdnsPort":"","mdnsIp":"","mdnsTtl":"","mdnsLoopback":true,"mdnsReuseAddr":true},{"id":"8de2bd93.86c898","type":"mqtt-broker","z":"","name":"villa","broker":"192.168.100.10","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""}]
Thank you, but now I’m going to vacation for a week, will check this ASAP and post a result
OK, I've tested this, works fine.
Stop function works, but after stopping in the middle should click on door in home.app twice to start it moving, now trying to figure it out why it is happens.
How are we doing here?
@Shaquu @crxporter
Hello, I'm back )
Tasmota should send a SwitchTopic whenever your sensors change between ON/OFF
No, it does not, so these nodes does nothing. I can manually send STATUS or SENSORS topic to get status, now looking for a better solution.
Today installed second nodemcu for the gate and tomorrow will try to finish this )
I can manually send STATUS or SENSORS topic to get status, now looking for a better solution.
I configured mine months ago so I don’t remember all of the implications but check here for information about the different ways for sending the switch data when it changes.
My tasmota set up with sensors has the following:
switchmode 2
switchtopic relayState
This setup sends a message ON or OFF over MQTT topic: cmnd/relayState/POWER1 whenever the state of switch 1 changes.
The tasmota software does a lot if you know what you’re looking for... I think this would help your garage door sensors update quicker and take away the need for the high frequency telemetry messages...
This setup sends a message
ONorOFFover MQTT topic:cmnd/relayState/POWER1whenever the state of switch 1 changes.
In my case cmnd/garage/relaystate_or_anythng/POWER1 actually toggles RELAY regardless defined rules O_o.
So now I'm trying to use SwitchTopic 1 (rules works fine) and to adapt existing nodes. Think the best way to do this is:
Rule1 on switch1#state do publish stat/garage/RESULT {"SENSOR_CLOSED":"%value%"} endon
Rule2 on switch2#state do publish stat/garage/RESULT {"SENSOR_OPENED":"%value%"} endon
Away from door, will try it later.
Bump, @DaPeace, @ptath and others how is the situation here?
I really hate opened Issues :)
Closing as it’s inactive and it looks like a problem is resolved and Issue started to be about the logic itself.
Sent with GitHawk
Sorry, the work still in progress.
Problems with gate hardware, I still promise to put live working result to wiki =)
I have the same issue; clicking on the RF while the door is moving stops the door. Apple documentation mentions a state 4, STOPPED for garage doors. But I cannot get this to work.
Help is appreciated.
@ahartman share your nodes from node-red
I am not working with node-red but with homebridge. However, I have the same problem.
Giving back the STOPPED status to Homekit seems to have no effect at all.
Sorry for delay in answer. Then it looks like a problem with Hap-NodeJS.
I don't have garage door so if you want me to help you for real then send me one :)
Jokes aside, I think you can still make it work with nrchkb but you have to resign from some features.
Nope, I suppose it is a HomeKit problem. STOPPED is a valid status for a door to be in, but in the Home App, it is actually reported as OPEN (
Can you describe issue again? I have looked into Garage Door and for me everything is logical here.
I am professional programmer so it's clear for me, maybe some of you guys think in different level and you misunderstand something?
It would be good if someone describe again what is a problem and what do you want to achieve.
Do you want nrchkb to work as RF? Exactly as it?
CurrentDoorState | uint8 | 0 - 4 | Open=0, closed=1, opening=2, closing=3, stopped=4
-- | -- | -- | --
So sending "CurrentDoorState": 4 does nothing, in Home.app (iOS/Mac) door appears as Open. It is true cause it is semi-open =)
Well characteristics are for HomeKit devices manufacturers at first. So it’s for us to know what is happening and what is the state and for HomeKit to store it and sometimes show it in Home.app. It doesn’t have to change something for end user every time.
Look from another side. As an integration you could enable dim light when door is opening and enable full light when it’s opened. Or blink on opening. Or blink red when it’s opening and blink green when closing. Etc. So it’s not useless. Or you can start opening gate as soon as you start opening your garage door at the same time to not wait until one opens first.
But I understand you wanted it to work in different way :)
On 8 Oct 2019, 22:45 +0200, ptath notifications@github.com, wrote:
CurrentDoorState
uint8
0 - 4
Open=0, closed=1, opening=2, closing=3, stopped=4
So sending "CurrentDoorState": 4 does nothing, in Home.app (iOS/Mac) door appears as Open. It is true cause it is semi-open =)
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub, or mute the thread.
Nope, I suppose it is a HomeKit problem. STOPPED is a valid status for a door to be in, but in the Home App, it is actually reported as OPEN (
If I remember right - sending "stopped" will say "open" but have a picture of a closed door? I remember playing with that a while ago and thinking "oh that's neat"
I will check that, that would be a very subtle icon, indeed.
However, the feedback is only part of the problem.
After an intermediate press, the garage door stops but the plugin continues emulating the opening or closing delay.
Pressing again makes starts the garage door again in the reverse direction; homebridge and the garage door are now out of sync.
Homebridge/Homekit indicate an open garage door, while in fact, after two intermediate presses, the garage door moved in the reverse direction and is now closed.
So, the intermediate press should be recognised by the plugin as a press inside the delay.
The next press should start the door in the reverse direction.
Kind regards, ahartman, belgium
Op 10 okt. 2019, om 22:23 heeft crxporter notifications@github.com het volgende geschreven:
Nope, I suppose it is a HomeKit problem. STOPPED is a valid status for a door to be in, but in the Home App, it is actually reported as OPEN (
If I remember right - sending "stopped" will say "open" but have a picture of a closed door? I remember playing with that a while ago and thinking "oh that's neat"
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/NRCHKB/node-red-contrib-homekit-bridged/issues/33?email_source=notifications&email_token=AAFIBPD722UWYJ7PUWENIBDQN6FLFA5CNFSM4GPSSVF2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEA5YWDA#issuecomment-540773132, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFIBPA2WKNTGUJHNLQI5W3QN6FLFANCNFSM4GPSSVFQ.
How are we here? Is it a problem with HomeKit, Home.app, hap-nodejs or nrchkb?
I have official homekit garage doors (chamberlain brand). I’d be happy to go through clicking things and seeing how everything responds with official hardware.
Just let me know what to test!
@Shaquu I believe things are working properly, let's clean up and close some older issues.
Everyone - please comment or open a new issue if you need more help.