MQTT garage door opener with Node-RED

Reduced logs to minimum.

Absolutely will do. I’m sure it’s worth to everyone.

Latest flow for testing in your Lab (AKA plastic tray). Let me know if you find any 'issues'.

[{"id":"efead956.ba99","type":"function","z":"c00250c7.18a848","name":"real_gate_fsm","func":"// It is assumed the two relays are used as follows\n// RLA controls the motor On/Off\n// RLB controls direction of rotation\n\n//  RLA     RLB     Action\n//  ---     ---     ------\n//  off      -      Motor stopped\n//  on      off     Motor turns clockwise >> opening the gate\n//  on      on      Motor turns anti-clockwise >> closing the gate\n\n\nvar fsm_state = flow.get(\"gate_fsm_state_register\") || \"stopped\";\n\nvar closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\nvar opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nvar button_pressed = flow.get(\"button_pressed\") || \"stopped\";\n\nswitch (fsm_state)\n   {\n        case \"stopped\":\n        if ( (button_pressed == \"open\") && (opened_limit_switch == \"inactive\") ) {\n            fsm_state = \"opening\";\n            node.status({text:\"State register = Opening\"});\n            node.send( [{payload: \"on\"},{payload: \"off\"}] );       // These outputs operate the relays \n        }\n        else if ( (button_pressed == \"close\") && (closed_limit_switch == \"inactive\") ) {\n            fsm_state = \"closing\";\n            node.status({text:\"State register = Closing\"});\n            node.send( [{payload: \"on\"},{payload: \"on\"}] );       // These outputs operate the relays \n        }\n        break;\n       \n        case \"opening\":\n        if  ( (button_pressed == \"stop\") || (opened_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = Stopped\"});\n            node.send( [{payload: \"off\"},{payload: \"off\"}] );       // These outputs operate the relays \n            flow.set(\"button_pressed\",\"stop\");\n        }\n        else {  \n            fsm_state = \"opening\";\n            node.status({text:\"State register = Opening\"});\n            node.send( [{payload: \"on\"},{payload: \"off\"}] );       // These outputs operate the relays \n        }\n        break;\n       \n        case \"closing\":\n        if  ( (button_pressed == \"stop\") || (closed_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = stopped\"});\n            node.send( [{payload: \"off\"},{payload: \"off\"}] );       // These outputs operate the relays \n            flow.set(\"button_pressed\",\"stop\");\n        }\n        else {\n            fsm_state = \"closing\";\n            node.status({text:\"State register = Closing\"});\n            node.send( [{payload: \"on\"},{payload: \"on\"}] );       // These outputs operate the relays \n        }\n        break;\n   }\n\nflow.set(\"gate_fsm_state_register\", fsm_state);\n\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":620,"y":260,"wires":[["d7c96b7b.839e58"],["3f5fc38f.be4a14"]],"inputLabels":["Sys_clk"],"outputLabels":["RLA","RLB"]},{"id":"afb905ac.b06ca","type":"inject","z":"c00250c7.18a848","name":"Clock Pulse Generator","repeat":"1","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":190,"y":260,"wires":[["efead956.ba99"]]},{"id":"744384b8.fefe44","type":"debug","z":"c00250c7.18a848","name":"Relay_A","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1100,"y":220,"wires":[]},{"id":"e361315a.44e0b","type":"debug","z":"c00250c7.18a848","name":"Relay_B","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1100,"y":300,"wires":[]},{"id":"c803a8d1.d81f3","type":"comment","z":"c00250c7.18a848","name":"ReadMe... Details about the FSM","info":"The FSM has five inputs...\n\nBtn_Open\nBtn_Close\nBtn_STOP\n\nClose_limit_switch\nOpen_limit_switch\n\nThe FSM also has a system clock (Frequency = 1Hz)\nThe frequency can be reduced to 2Hz, 3Hz etc...\n\nThe FSM has two outputs...\n\nRelay_A\nRelay_B\n\nThese two relays switch the motor on/off and \nalso define the direction of rotation (clockwise or anticlock) \n","x":610,"y":320,"wires":[]},{"id":"94ef1010.594a58","type":"comment","z":"c00250c7.18a848","name":"Inputs come in via MQTT or Telegram","info":"","x":190,"y":60,"wires":[]},{"id":"576b5f3e.7606f8","type":"comment","z":"c00250c7.18a848","name":"Outputs go out via MQTT or Telegram","info":"","x":1050,"y":60,"wires":[]},{"id":"678f6501.54c444","type":"inject","z":"c00250c7.18a848","name":"Set initial conditions","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"reset","payload":"1","payloadType":"num","x":320,"y":120,"wires":[["2c9c795a.9ae3ce","546ea8b4.c8fbd8"]]},{"id":"2c9c795a.9ae3ce","type":"function","z":"c00250c7.18a848","name":"Set initial conditions","func":"flow.set(\"gate_fsm_state_register\",\"stopped\");\n\nflow.set(\"button_pressed\",\"stop\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":600,"y":140,"wires":[["ae451d39.af89b8","d7c96b7b.839e58","3f5fc38f.be4a14"]]},{"id":"4752ba7a.a1506c","type":"ui_button","z":"c00250c7.18a848","name":"Open","group":"3303e1ed.7a4b3e","order":2,"width":"3","height":"1","passthru":false,"label":"Open","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_open","payloadType":"str","topic":"","x":530,"y":440,"wires":[["8b07b459.83c05"]]},{"id":"ee86c352.634228","type":"ui_button","z":"c00250c7.18a848","name":"Close","group":"3303e1ed.7a4b3e","order":3,"width":"3","height":"1","passthru":false,"label":"Close","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_close","payloadType":"str","topic":"","x":530,"y":540,"wires":[["7c43191d.9f2df8"]]},{"id":"e02040a0.a6a57","type":"ui_button","z":"c00250c7.18a848","name":"STOP","group":"3303e1ed.7a4b3e","order":5,"width":"3","height":"1","passthru":false,"label":"STOP","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_stop","payloadType":"str","topic":"","x":530,"y":660,"wires":[["bc09fc46.ca5e28"]]},{"id":"8b07b459.83c05","type":"function","z":"c00250c7.18a848","name":"","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nif (opened_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"close\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"open\");\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"x":680,"y":400,"wires":[["ae451d39.af89b8"]]},{"id":"7c43191d.9f2df8","type":"function","z":"c00250c7.18a848","name":"","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\n\nif (closed_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"open\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"close\");\n    }\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":520,"wires":[["ae451d39.af89b8"]]},{"id":"bc09fc46.ca5e28","type":"function","z":"c00250c7.18a848","name":"","func":"flow.set(\"button_pressed\",\"stop\");\nreturn msg;","outputs":1,"noerr":0,"x":680,"y":640,"wires":[["ae451d39.af89b8"]]},{"id":"ae451d39.af89b8","type":"function","z":"c00250c7.18a848","name":"","func":"var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n\nif (button_pressed == \"open\") {\n    node.send( [{background:\"red\"},{background:\"#097479\"},{background:\"#097479\"}] );\n}\nelse if (button_pressed == \"close\") {\n    node.send( [{background: \"#097479\"},{background:\"red\"},{background: \"#097479\"}] );\n}\nelse if (button_pressed == \"stop\") {\n    node.send( [{background: \"#097479\"},{background: \"#097479\"},{background:\"red\"}] );\n}\n","outputs":3,"noerr":0,"initialize":"","finalize":"","x":820,"y":460,"wires":[["4752ba7a.a1506c"],["ee86c352.634228"],["e02040a0.a6a57"]]},{"id":"cf1b87e4.d2ea8","type":"inject","z":"c00250c7.18a848","name":"Simulate Open Button","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":340,"wires":[["8b07b459.83c05"]]},{"id":"c6c047f0.c2c2b","type":"inject","z":"c00250c7.18a848","name":"Simulate Close Button","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":400,"wires":[["7c43191d.9f2df8"]]},{"id":"85dec8e3.51037","type":"inject","z":"c00250c7.18a848","name":"Simulate STOP Button","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":460,"wires":[["bc09fc46.ca5e28"]]},{"id":"d7c96b7b.839e58","type":"function","z":"c00250c7.18a848","name":"Show RLA state","func":"if (msg.topic == \"reset\") {\n    msg.payload = \"off\";\n    flow.set(\"rla_status\",msg.payload)\n    node.status({text:\"RLA = \"+msg.payload});\n    return msg;\n}\nelse {\n    var RLA_status = flow.get(\"rla_status\") || \"blank\";\n\n    if (msg.payload != RLA_status) {\n        flow.set(\"rla_status\",msg.payload)\n        node.status({text:\"RLA = \"+msg.payload});\n        return msg;\n    }\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":900,"y":220,"wires":[["744384b8.fefe44","7dcccb9b.df0804"]]},{"id":"3f5fc38f.be4a14","type":"function","z":"c00250c7.18a848","name":"Show RLB state","func":"if (msg.topic == \"reset\") {\n    msg.payload = \"off\";\n    flow.set(\"rla_status\",msg.payload)\n    node.status({text:\"RLA = \"+msg.payload});\n    return msg;\n}\nelse {\n    var RLB_status = flow.get(\"rlb_status\") || \"blank\";\n\n    if (msg.payload != RLB_status) {\n        flow.set(\"rlb_status\",msg.payload)\n        node.status({text:\"RLB = \"+msg.payload});\n        return msg;\n    }\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":900,"y":300,"wires":[["e361315a.44e0b","c46aa2d7.e899a8"]]},{"id":"28c40ba8.d63dec","type":"inject","z":"c00250c7.18a848","name":"Toggle Open_Limit_switch","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":170,"y":540,"wires":[["327892ca.b92416"]]},{"id":"327892ca.b92416","type":"function","z":"c00250c7.18a848","name":"Toggle opened_limit_switch","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\");\n\nif (opened_limit_switch == \"activated\") {\n    flow.set(\"opened_limit_switch\",\"inactive\");\n    node.status({text:\"opened_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"opened_limit_switch\",\"activated\");\n    node.status({text:\"opened_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":600,"wires":[[]]},{"id":"546ea8b4.c8fbd8","type":"function","z":"c00250c7.18a848","name":"For testing only >> set limit switches","func":"flow.set(\"closed_limit_switch\",\"inactive\");\nflow.set(\"opened_limit_switch\",\"inactive\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":650,"y":60,"wires":[[]]},{"id":"c8398f3c.4d35d8","type":"inject","z":"c00250c7.18a848","name":"Toggle Closed_Limit_switch","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":180,"y":660,"wires":[["2cf6d51b.2cde12"]]},{"id":"2cf6d51b.2cde12","type":"function","z":"c00250c7.18a848","name":"Toggle closed_limit_switch","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\");\n\nif (closed_limit_switch == \"activated\") {\n    flow.set(\"closed_limit_switch\",\"inactive\");\n    node.status({text:\"closed_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"closed_limit_switch\",\"activated\");\n    node.status({text:\"closed_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"x":240,"y":720,"wires":[[]]},{"id":"7dcccb9b.df0804","type":"mqtt out","z":"c00250c7.18a848","name":"","topic":"cmnd/EastGate/POWER7","qos":"","retain":"","broker":"85d0777b.d218e","x":1130,"y":140,"wires":[]},{"id":"c46aa2d7.e899a8","type":"mqtt out","z":"c00250c7.18a848","name":"","topic":"cmnd/EastGate/POWER8","qos":"","retain":"","broker":"85d0777b.d218e","x":1130,"y":360,"wires":[]},{"id":"3303e1ed.7a4b3e","type":"ui_group","z":"","name":"Simulation control buttons","tab":"492855af.586314","order":3,"disp":true,"width":"12","collapse":false},{"id":"85d0777b.d218e","type":"mqtt-broker","z":"","name":"pi","broker":"192.168.1.9","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"492855af.586314","type":"ui_tab","z":"","name":"Gate simulation","icon":"dashboard","order":41,"disabled":false,"hidden":false}]

I forgot to say... I personally like the dark theme for the dashboard - easier on my old, tired eyes.
These are my settings.

1 Like

Just tried linking my Telegram app to the garage door opener. The inline keyboard works a treat.
Screen Shot 09-24-20 at 05.06 PM

This app is for turning my print server on/off, but for testing purposes, I remapped the 'Status' button as 'Open', Turn ON' as 'Close' and 'Turn OFF' as 'STOP'.

Here's the slightly modified NR flow I used to test the operation from my mobile phone.


Sorry - I'll need to de-couple the Telegram end of the NR flow (from my home) before I can publish it here.

1 Like

Dave,

i tested the latest flow you shared and see some common issues.

As far as i understand whether i press 'open', 'close' or 'stop' after verifying the current state whether moving or not, in every scenario there should be only on MQTT payload sent as instruction to the particular relay so that motor can do as told. Am i correct ?

Below screenshot Debugs show every button press resulted in sending same payload to both relays.

Also, i think the fsm config readme and code is also passed to the MQTT out node. i think that should be kept within NodeRed itself. as it can be a security risk.

supporting logs showing same on syslog server

Sep 25 00:09:25 192.168.1.73 Utanki-0689 ESP-WIF: Checking connection...
Sep 25 00:09:25 192.168.1.73 Utanki-0689 ESP-WIF: Connected
Sep 25 00:09:31 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:31 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER7, Data Size 3, Data off
Sep 25 00:09:31 192.168.1.246 EastGate ESP-RSL: Group 0, Index 7, Command POWER, Data off
Sep 25 00:09:31 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER7":"OFF"}
Sep 25 00:09:31 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER7 = OFF
Sep 25 00:09:31 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:31 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER8, Data Size 3, Data off
Sep 25 00:09:31 192.168.1.246 EastGate ESP-RSL: Group 0, Index 8, Command POWER, Data off
Sep 25 00:09:31 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER8":"OFF"}
Sep 25 00:09:31 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER8 = OFF
Sep 25 00:09:31 192.168.1.246 EastGate ESP-CFG: Saved to flash at F9, Count 201, Bytes 3584
Sep 25 00:09:44 192.168.1.246 EastGate ESP-WIF: Checking connection...
Sep 25 00:09:44 192.168.1.246 EastGate ESP-WIF: Connected
Sep 25 00:09:45 192.168.1.73 Utanki-0689 ESP-WIF: Checking connection...
Sep 25 00:09:45 192.168.1.73 Utanki-0689 ESP-WIF: Connected
Sep 25 00:09:48 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:48 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER7, Data Size 2, Data on
Sep 25 00:09:48 192.168.1.246 EastGate ESP-RSL: Group 0, Index 7, Command POWER, Data on
Sep 25 00:09:48 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER7":"ON"}
Sep 25 00:09:48 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER7 = ON
Sep 25 00:09:48 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:48 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER8, Data Size 2, Data on
Sep 25 00:09:48 192.168.1.246 EastGate ESP-RSL: Group 0, Index 8, Command POWER, Data on
Sep 25 00:09:48 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER8":"ON"}
Sep 25 00:09:48 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER8 = ON
Sep 25 00:09:48 192.168.1.246 EastGate ESP-CFG: Saved to flash at F8, Count 202, Bytes 3584
Sep 25 00:09:53 192.168.1.246 EastGate ESP-MQT: tele/EastGate/STATE = {"Time":"2020-09-24T19:39:53","Uptime":"0T07:20:33","Vcc":3.002,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":19,"POWER1":"OFF","POWER2":"OFF","POWER3":"OFF","POWER4":"OFF","POWER5":"OFF","POWER6":"OFF","POWER7":"ON","POWER8":"ON","Wifi":{"AP":1,"SSId":"Nova_WIFI","BSSId":"50:2B:73:53:FE:A1","Channel":11,"RSSI":90}}
Sep 25 00:09:54 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:54 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER7, Data Size 3, Data off
Sep 25 00:09:54 192.168.1.246 EastGate ESP-RSL: Group 0, Index 7, Command POWER, Data off
Sep 25 00:09:54 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER7":"OFF"}
Sep 25 00:09:54 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER7 = OFF
Sep 25 00:09:54 192.168.1.246 EastGate ESP-SRC: MQTT
Sep 25 00:09:54 192.168.1.246 EastGate ESP-RSL: Received Topic cmnd/EastGate/POWER8, Data Size 3, Data off
Sep 25 00:09:54 192.168.1.246 EastGate ESP-RSL: Group 0, Index 8, Command POWER, Data off
Sep 25 00:09:54 192.168.1.246 EastGate ESP-MQT: stat/EastGate/RESULT = {"POWER8":"OFF"}
Sep 25 00:09:54 192.168.1.246 EastGate ESP-MQT: stat/EastGate/POWER8 = OFF
Sep 25 00:09:54 192.168.1.246 EastGate ESP-CFG: Saved to flash at F7, Count 203, Bytes 3584
Sep 25 00:10:04 192.168.1.246 EastGate ESP-WIF: Checking connection...
Sep 25 00:10:04 192.168.1.246 EastGate ESP-WIF: Connected
Sep 25 00:10:05 192.168.1.73 Utanki-0689 ESP-WIF: Checking connection...
Sep 25 00:10:05 192.168.1.73 Utanki-0689 ESP-WIF: Connected
[{"id":"efead956.ba99","type":"function","z":"c00250c7.18a848","name":"real_gate_fsm","func":"// It is assumed the two relays are used as follows\n// RLA controls the motor On/Off\n// RLB controls direction of rotation\n\n// RLA RLB Action\n// --- --- ------\n// off - Motor stopped\n// on off Motor turns clockwise >> opening the gate\n// on on Motor turns anti-clockwise >> closing the gate\n\n\nvar fsm_state = flow.get("gate_fsm_state_register") || "stopped";\n\nvar closed_limit_switch = flow.get("closed_limit_switch") || "activated";\nvar opened_limit_switch = flow.get("opened_limit_switch") || "activated";\n\nvar button_pressed = flow.get("button_pressed") || "stopped";\n\nswitch (fsm_state)\n {\n case "stopped":\n if ( (button_pressed == "open") && (opened_limit_switch == "inactive") ) {\n fsm_state = "opening";\n node.status({text:"State register = Opening"});\n node.send( [{payload: "on"},{payload: "off"}] ); // These outputs operate the relays \n }\n else if ( (button_pressed == "close") && (closed_limit_switch == "inactive") ) {\n fsm_state = "closing";\n node.status({text:"State register = Closing"});\n node.send( [{payload: "on"},{payload: "on"}] ); // These outputs operate the relays \n }\n break;\n \n case "opening":\n if ( (button_pressed == "stop") || (opened_limit_switch == "activated") ) {\n fsm_state = "stopped";\n node.status({text:"State register = Stopped"});\n node.send( [{payload: "off"},{payload: "off"}] ); // These outputs operate the relays \n flow.set("button_pressed","stop");\n }\n else { \n fsm_state = "opening";\n node.status({text:"State register = Opening"});\n node.send( [{payload: "on"},{payload: "off"}] ); // These outputs operate the relays \n }\n break;\n \n case "closing":\n if ( (button_pressed == "stop") || (closed_limit_switch == "activated") ) {\n fsm_state = "stopped";\n node.status({text:"State register = stopped"});\n node.send( [{payload: "off"},{payload: "off"}] ); // These outputs operate the relays \n flow.set("button_pressed","stop");\n }\n else {\n fsm_state = "closing";\n node.status({text:"State register = Closing"});\n node.send( [{payload: "on"},{payload: "on"}] ); // These outputs operate the relays \n }\n break;\n }\n\nflow.set("gate_fsm_state_register", fsm_state);\n\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":620,"y":260,"wires":[["d7c96b7b.839e58"],["3f5fc38f.be4a14"]],"inputLabels":["Sys_clk"],"outputLabels":["RLA","RLB"]},{"id":"afb905ac.b06ca","type":"inject","z":"c00250c7.18a848","name":"Clock Pulse Generator","repeat":"1","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":190,"y":260,"wires":[["efead956.ba99"]]},{"id":"744384b8.fefe44","type":"debug","z":"c00250c7.18a848","name":"Relay_A","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1100,"y":220,"wires":},{"id":"e361315a.44e0b","type":"debug","z":"c00250c7.18a848","name":"Relay_B","active":true,"tosidebar":true,"console":Sep 25 00:10:24 192.168.1.246 EastGate ESP-WIF: Checking connection...
Sep 25 00:10:24 192.168.1.246 EastGate ESP-WIF: Connected

i'll delete the logs later, once you've reviewed these.

Note - syslog server and nodered(on pc) are in 2 different time-zones just to avoid any confusion...above all is captured at same time.

Sorted out some issues, so please try this version.

[{"id":"efead956.ba99","type":"function","z":"c00250c7.18a848","name":"real_gate_fsm","func":"if (msg.topic == \"reset\") {\n    flow.set(\"gate_fsm_state_register\",\"stopped\");\n    flow.set(\"button_pressed\",\"stop\");\n    \n    node.status({text:\"State register = Stopped\"});\n    node.send( {payload: \"stopped\"} );\n    node.done();\n}\n\nvar fsm_state = flow.get(\"gate_fsm_state_register\") || \"stopped\";\n\nvar closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\nvar opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nvar button_pressed = flow.get(\"button_pressed\") || \"stopped\";\n\nswitch (fsm_state)\n   {\n        case \"stopped\":\n        if ( (button_pressed == \"open\") && (opened_limit_switch == \"inactive\") ) {\n            fsm_state = \"opening\";\n            node.status({text:\"State register = Opening\"});\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        else if ( (button_pressed == \"close\") && (closed_limit_switch == \"inactive\") ) {\n            fsm_state = \"closing\";\n            node.status({text:\"State register = Closing\"});\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n       \n        case \"opening\":\n        if  ( (button_pressed == \"stop\") || (opened_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = Stopped\"});\n            flow.set(\"button_pressed\",\"stop\");\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n       \n        case \"closing\":\n        if  ( (button_pressed == \"stop\") || (closed_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = stopped\"});\n            flow.set(\"button_pressed\",\"stop\");\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n   }\n\nflow.set(\"gate_fsm_state_register\", fsm_state);\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":280,"wires":[["d7c96b7b.839e58"]],"inputLabels":["Sys_clk"],"outputLabels":["RLA"]},{"id":"afb905ac.b06ca","type":"inject","z":"c00250c7.18a848","name":"Clock Pulse Generator","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":290,"y":280,"wires":[["efead956.ba99"]]},{"id":"744384b8.fefe44","type":"debug","z":"c00250c7.18a848","name":"Relay_A","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1200,"y":220,"wires":[]},{"id":"e361315a.44e0b","type":"debug","z":"c00250c7.18a848","name":"Relay_B","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1200,"y":320,"wires":[]},{"id":"c803a8d1.d81f3","type":"comment","z":"c00250c7.18a848","name":"ReadMe... Details about the FSM","info":"The FSM has five inputs...\n\nBtn_Open\nBtn_Close\nBtn_STOP\n\nClose_limit_switch\nOpen_limit_switch\n\nThe FSM also has a system clock (Frequency = 1Hz)\nThe frequency can be reduced to 2Hz, 3Hz etc...\n\nThe FSM has two outputs...\n\nRelay_A\nRelay_B\n\nThese two relays switch the motor on/off and \nalso define the direction of rotation (clockwise or anticlock) \n","x":590,"y":220,"wires":[]},{"id":"576b5f3e.7606f8","type":"comment","z":"c00250c7.18a848","name":"Outputs go out via MQTT or Telegram","info":"","x":1210,"y":160,"wires":[]},{"id":"678f6501.54c444","type":"inject","z":"c00250c7.18a848","name":"Set initial conditions","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"reset","payload":"1","payloadType":"num","x":280,"y":140,"wires":[["2c9c795a.9ae3ce","546ea8b4.c8fbd8","efead956.ba99"]]},{"id":"2c9c795a.9ae3ce","type":"function","z":"c00250c7.18a848","name":"Set initial conditions","func":"flow.set(\"gate_fsm_state_register\",\"stopped\");\n\nflow.set(\"button_pressed\",\"stop\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":600,"y":160,"wires":[["ae451d39.af89b8"]]},{"id":"4752ba7a.a1506c","type":"ui_button","z":"c00250c7.18a848","name":"Open","group":"3303e1ed.7a4b3e","order":2,"width":"3","height":"1","passthru":false,"label":"Open","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_open","payloadType":"str","topic":"","x":530,"y":460,"wires":[["8b07b459.83c05"]]},{"id":"ee86c352.634228","type":"ui_button","z":"c00250c7.18a848","name":"Close","group":"3303e1ed.7a4b3e","order":3,"width":"3","height":"1","passthru":false,"label":"Close","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_close","payloadType":"str","topic":"","x":530,"y":560,"wires":[["7c43191d.9f2df8"]]},{"id":"e02040a0.a6a57","type":"ui_button","z":"c00250c7.18a848","name":"STOP","group":"3303e1ed.7a4b3e","order":5,"width":"3","height":"1","passthru":false,"label":"STOP","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_stop","payloadType":"str","topic":"","x":530,"y":680,"wires":[["bc09fc46.ca5e28"]]},{"id":"8b07b459.83c05","type":"function","z":"c00250c7.18a848","name":"","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nif (opened_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"close\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"open\");\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":420,"wires":[["ae451d39.af89b8"]]},{"id":"7c43191d.9f2df8","type":"function","z":"c00250c7.18a848","name":"","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\n\nif (closed_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"open\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"close\");\n    }\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":540,"wires":[["ae451d39.af89b8"]]},{"id":"bc09fc46.ca5e28","type":"function","z":"c00250c7.18a848","name":"","func":"flow.set(\"button_pressed\",\"stop\");\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":640,"wires":[["ae451d39.af89b8"]]},{"id":"ae451d39.af89b8","type":"function","z":"c00250c7.18a848","name":"","func":"var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n\nif (button_pressed == \"open\") {\n    node.send( [{background:\"red\"},{background:\"#097479\"},{background:\"#097479\"}] );\n}\nelse if (button_pressed == \"close\") {\n    node.send( [{background: \"#097479\"},{background:\"red\"},{background: \"#097479\"}] );\n}\nelse if (button_pressed == \"stop\") {\n    node.send( [{background: \"#097479\"},{background: \"#097479\"},{background:\"red\"}] );\n}\n","outputs":3,"noerr":0,"initialize":"","finalize":"","x":880,"y":480,"wires":[["4752ba7a.a1506c"],["ee86c352.634228"],["e02040a0.a6a57"]]},{"id":"cf1b87e4.d2ea8","type":"inject","z":"c00250c7.18a848","name":"Simulate Open Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":360,"wires":[["8b07b459.83c05"]]},{"id":"c6c047f0.c2c2b","type":"inject","z":"c00250c7.18a848","name":"Simulate Close Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":420,"wires":[["7c43191d.9f2df8"]]},{"id":"85dec8e3.51037","type":"inject","z":"c00250c7.18a848","name":"Simulate STOP Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":480,"wires":[["bc09fc46.ca5e28"]]},{"id":"d7c96b7b.839e58","type":"function","z":"c00250c7.18a848","name":"Decode 'fsm state' and map to relays","func":"// It is assumed the two relays are used as follows\n// RLA controls the motor On/Off\n// RLB controls direction of rotation\n\n//  RLA     RLB     Action\n//  ---     ---     ------\n//  off     off     Motor stopped\n//  off     on      - not used -\n//  on      off     Motor turns clockwise >> opening the gate\n//  on      on      Motor turns anti-clockwise >> closing the gate\n\n\nif (msg.payload == \"stopped\") {\n    node.status({text:\"RLA = Off  RLB = Off\"});\n    node.send( [{payload: \"off\"},{payload: \"off\"}] );  \n    node.done();\n}\nelse if (msg.payload == \"opening\") {\n    node.status({text:\"RLA = On  RLB = Off\"});\n    node.send( [{payload: \"on\"},{payload: \"off\"}] );  \n    node.done();\n}\nelse if (msg.payload == \"closing\") {\n    node.status({text:\"RLA = On  RLB = On\"});\n    node.send( [{payload: \"on\"},{payload: \"on\"}] );  \n    node.done();\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":930,"y":280,"wires":[["744384b8.fefe44"],["e361315a.44e0b"]]},{"id":"28c40ba8.d63dec","type":"inject","z":"c00250c7.18a848","name":"Toggle Open_Limit_switch","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.5","topic":"","payload":"1","payloadType":"num","x":180,"y":560,"wires":[["327892ca.b92416"]]},{"id":"327892ca.b92416","type":"function","z":"c00250c7.18a848","name":"Toggle opened_limit_switch","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\");\n\nif (opened_limit_switch == \"activated\") {\n    flow.set(\"opened_limit_switch\",\"inactive\");\n    node.status({text:\"opened_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"opened_limit_switch\",\"activated\");\n    node.status({text:\"opened_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":620,"wires":[[]]},{"id":"546ea8b4.c8fbd8","type":"function","z":"c00250c7.18a848","name":"For testing only >> initially set limit switches to DOOR CLOSED position","func":"// You can change the initial state of the limit switches HERE\n//\n\n\nflow.set(\"closed_limit_switch\",\"inactive\");\nflow.set(\"opened_limit_switch\",\"activated\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":80,"wires":[[]]},{"id":"c8398f3c.4d35d8","type":"inject","z":"c00250c7.18a848","name":"Toggle Closed_Limit_switch","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.5","topic":"","payload":"1","payloadType":"num","x":180,"y":680,"wires":[["2cf6d51b.2cde12"]]},{"id":"2cf6d51b.2cde12","type":"function","z":"c00250c7.18a848","name":"Toggle closed_limit_switch","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\");\n\nif (closed_limit_switch == \"activated\") {\n    flow.set(\"closed_limit_switch\",\"inactive\");\n    node.status({text:\"closed_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"closed_limit_switch\",\"activated\");\n    node.status({text:\"closed_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":740,"wires":[[]]},{"id":"7dcccb9b.df0804","type":"mqtt out","z":"c00250c7.18a848","name":"","topic":"cmnd/EastGate/POWER7","qos":"","retain":"","broker":"85d0777b.d218e","x":1250,"y":260,"wires":[]},{"id":"c46aa2d7.e899a8","type":"mqtt out","z":"c00250c7.18a848","name":"","topic":"cmnd/EastGate/POWER8","qos":"","retain":"","broker":"85d0777b.d218e","x":1250,"y":360,"wires":[]},{"id":"3303e1ed.7a4b3e","type":"ui_group","z":"","name":"Simulation control buttons","tab":"492855af.586314","order":3,"disp":true,"width":"12","collapse":false},{"id":"85d0777b.d218e","type":"mqtt-broker","z":"","name":"pi","broker":"192.168.1.9","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"492855af.586314","type":"ui_tab","z":"","name":"Gate simulation","icon":"dashboard","order":41,"disabled":false,"hidden":false}]

I need you to explain how the two relays are used to operate the motor (on/off and direction).

Will try this and update you in an hour.

Thought I'd take a bit of time-out to explain how the finite state machine (FSM) works.

Here's the state-diagram for the FSM for the garage door mechanism.

As you can see it has three states: 'stopped', 'opening' and 'closing'.

The initial state is 'stopped'.

In your garage-door opener project, you can move from the 'stopped state to the 'opening' state if the 'Open button' is pressed AND the 'Open limit switch' is low (i.e. not activated). In a similar way you can move from the 'stopped' state to the 'closing' state if the 'Close button' is pressed AND the 'Close limit switch' is low (i.e. not activated).

If the FSM is in the 'opening' state (i.e. the motor is running and opening the door) then you can move to the 'stopped' state under TWO conditions. If the 'Stop button' is pressed OR the 'Open limit switch' is high (i.e. activated).

In a similar way, if the FSM is in the 'closing' state (i.e. the motor is running and closing the door) then you can move to the 'stopped' state under TWO conditions. If the 'Stop button' is pressed OR the 'Stop limit switch' is high (i.e. activated).

The various conditions (or transitions) are labelled on the state-diagram. Once you have worked-out the various transitions you start coding the FSM. I've used the classical way of coding the state machine using a case construct. Here's a small fragment of the code showing the transition from 'stopped' to 'opening'.

        case "stopped":
        if ( (button_pressed == "open") && (opened_limit_switch == "inactive") ) {
            fsm_state = "opening";
            node.status({text:"State register = Opening"});
            node.send( {payload: fsm_state} ); 
            node.done();
        }

The complete FSM code can be viewed by importing one of my previous listings into Node-RED.

Dave,

i don't know what went wrong but it the motor is just moving and moving. connections are same way. i tried your new flow.
Nodemcu D7 and D8 were connected with L298N H-Bridge with one motor since yesterday till we figure out the code/flow mechanism. (previously it was working fine)

without changing anything, the moment NodeMCU is powered ON the motor starts rotating. Doesn't accept any commands like previously it was. planning to redo wiring with Relays

Relay i have disconnected temporarily. allow me sometime to figure it out. wrong connections i'm sure

NR flow with minor changes to match the pins on the L298 H-Bridge. (Updated: 25/09/20 @ 15:00 hrs)
The starting point for the flow is the door is closed and the 'closed_limit_switch' has been activated.

[{"id":"efead956.ba99","type":"function","z":"c00250c7.18a848","name":"real_gate_fsm","func":"if (msg.topic == \"reset\") {\n    flow.set(\"gate_fsm_state_register\",\"stopped\");\n    flow.set(\"button_pressed\",\"stop\");\n    \n    node.status({text:\"State register = Stopped\"});\n    node.send( {payload: \"stopped\"} );\n    node.done();\n}\n\nvar fsm_state = flow.get(\"gate_fsm_state_register\") || \"stopped\";\n\nvar closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\nvar opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nvar button_pressed = flow.get(\"button_pressed\") || \"stopped\";\n\nswitch (fsm_state)\n   {\n        case \"stopped\":\n        if ( (button_pressed == \"open\") && (opened_limit_switch == \"inactive\") ) {\n            fsm_state = \"opening\";\n            node.status({text:\"State register = Opening\"});\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        else if ( (button_pressed == \"close\") && (closed_limit_switch == \"inactive\") ) {\n            fsm_state = \"closing\";\n            node.status({text:\"State register = Closing\"});\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n       \n        case \"opening\":\n        if  ( (button_pressed == \"stop\") || (opened_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = Stopped\"});\n            flow.set(\"button_pressed\",\"stop\");\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n       \n        case \"closing\":\n        if  ( (button_pressed == \"stop\") || (closed_limit_switch == \"activated\") ) {\n            fsm_state = \"stopped\";\n            node.status({text:\"State register = stopped\"});\n            flow.set(\"button_pressed\",\"stop\");\n            node.send( {payload: fsm_state} );       // These outputs operate the relays \n            node.done();\n        }\n        break;\n   }\n\nflow.set(\"gate_fsm_state_register\", fsm_state);\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":300,"wires":[["d7c96b7b.839e58"]],"inputLabels":["Sys_clk"],"outputLabels":["RLA"]},{"id":"afb905ac.b06ca","type":"inject","z":"c00250c7.18a848","name":"Clock Pulse Generator","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":290,"y":300,"wires":[["efead956.ba99"]]},{"id":"744384b8.fefe44","type":"debug","z":"c00250c7.18a848","name":"L298 Input C","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1210,"y":240,"wires":[]},{"id":"e361315a.44e0b","type":"debug","z":"c00250c7.18a848","name":"L298 Input D","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1210,"y":340,"wires":[]},{"id":"c803a8d1.d81f3","type":"comment","z":"c00250c7.18a848","name":"ReadMe... Details about the FSM","info":"The FSM has five inputs...\n\nBtn_Open\nBtn_Close\nBtn_STOP\n\nClose_limit_switch\nOpen_limit_switch\n\nThe FSM also has a system clock (Frequency = 1Hz)\nThe frequency can be reduced to 2Hz, 3Hz etc...\n\nThe FSM has two outputs...\n\nRelay_A\nRelay_B\n\nThese two relays switch the motor on/off and \nalso define the direction of rotation (clockwise or anticlock) \n","x":590,"y":240,"wires":[]},{"id":"576b5f3e.7606f8","type":"comment","z":"c00250c7.18a848","name":"Outputs go out via MQTT or Telegram","info":"","x":1210,"y":160,"wires":[]},{"id":"678f6501.54c444","type":"inject","z":"c00250c7.18a848","name":"Set initial conditions","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.5","topic":"reset","payload":"1","payloadType":"num","x":240,"y":100,"wires":[["2c9c795a.9ae3ce","546ea8b4.c8fbd8","efead956.ba99"]]},{"id":"2c9c795a.9ae3ce","type":"function","z":"c00250c7.18a848","name":"Set initial conditions","func":"flow.set(\"gate_fsm_state_register\",\"stopped\");\n\nflow.set(\"button_pressed\",\"stop\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":600,"y":180,"wires":[["ae451d39.af89b8"]]},{"id":"4752ba7a.a1506c","type":"ui_button","z":"c00250c7.18a848","name":"Open","group":"3303e1ed.7a4b3e","order":2,"width":"3","height":"1","passthru":false,"label":"Open","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_open","payloadType":"str","topic":"","x":530,"y":480,"wires":[["8b07b459.83c05"]]},{"id":"ee86c352.634228","type":"ui_button","z":"c00250c7.18a848","name":"Close","group":"3303e1ed.7a4b3e","order":3,"width":"3","height":"1","passthru":false,"label":"Close","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_close","payloadType":"str","topic":"","x":530,"y":580,"wires":[["7c43191d.9f2df8"]]},{"id":"e02040a0.a6a57","type":"ui_button","z":"c00250c7.18a848","name":"STOP","group":"3303e1ed.7a4b3e","order":5,"width":"3","height":"1","passthru":false,"label":"STOP","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"btn_stop","payloadType":"str","topic":"","x":530,"y":700,"wires":[["bc09fc46.ca5e28"]]},{"id":"8b07b459.83c05","type":"function","z":"c00250c7.18a848","name":"","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\") || \"activated\";\n\nif (opened_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"close\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"open\");\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":440,"wires":[["ae451d39.af89b8"]]},{"id":"7c43191d.9f2df8","type":"function","z":"c00250c7.18a848","name":"","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\") || \"activated\";\n\nif (closed_limit_switch == \"inactive\") {\n    var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n    if (button_pressed == \"open\") {\n        flow.set(\"button_pressed\", \"stop\");\n    }\n    else {\n        flow.set(\"button_pressed\",\"close\");\n    }\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":560,"wires":[["ae451d39.af89b8"]]},{"id":"bc09fc46.ca5e28","type":"function","z":"c00250c7.18a848","name":"","func":"flow.set(\"button_pressed\",\"stop\");\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":660,"wires":[["ae451d39.af89b8"]]},{"id":"ae451d39.af89b8","type":"function","z":"c00250c7.18a848","name":"","func":"var button_pressed = flow.get(\"button_pressed\") || \"stop\";\n\nif (button_pressed == \"open\") {\n    node.send( [{background:\"red\"},{background:\"#097479\"},{background:\"#097479\"}] );\n}\nelse if (button_pressed == \"close\") {\n    node.send( [{background: \"#097479\"},{background:\"red\"},{background: \"#097479\"}] );\n}\nelse if (button_pressed == \"stop\") {\n    node.send( [{background: \"#097479\"},{background: \"#097479\"},{background:\"red\"}] );\n}\n","outputs":3,"noerr":0,"initialize":"","finalize":"","x":880,"y":500,"wires":[["4752ba7a.a1506c"],["ee86c352.634228"],["e02040a0.a6a57"]]},{"id":"cf1b87e4.d2ea8","type":"inject","z":"c00250c7.18a848","name":"Simulate Open Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":380,"wires":[["8b07b459.83c05"]]},{"id":"c6c047f0.c2c2b","type":"inject","z":"c00250c7.18a848","name":"Simulate Close Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":440,"wires":[["7c43191d.9f2df8"]]},{"id":"85dec8e3.51037","type":"inject","z":"c00250c7.18a848","name":"Simulate STOP Button","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":160,"y":500,"wires":[["bc09fc46.ca5e28"]]},{"id":"d7c96b7b.839e58","type":"function","z":"c00250c7.18a848","name":"Decode 'fsm state' and map to L298","func":"// L298 H-bridge\n//\n// The En pin is kept Hi\n//\n//  C   D   Action\n//  --- --- ------\n//  L   L   Fast stop\n//  L   H   Reverse     Motor turns anti-clockwise >> opening the gate\n//  H   L   Forward     Motor turns clockwise << closing the gate\n//  H   H   Fast stop   *** This condition is not used as it is the same as L, L ***\n\nif (msg.payload == \"stopped\") {\n    node.status({text:\"Pin-C = L and Pin-D = L\"});\n    node.send( [{payload: \"L\"},{payload: \"L\"}] );  // Fast stop\n    node.done();\n}\nelse if (msg.payload == \"opening\") {\n    node.status({text:\"Pin-C = L and Pin-D = H\"});\n    node.send( [{payload: \"L\"},{payload: \"H\"}] );  \n    node.done();\n}\nelse if (msg.payload == \"closing\") {\n    node.status({text:\"Pin-C = H and Pin-D = L\"});\n    node.send( [{payload: \"H\"},{payload: \"L\"}] );  \n    node.done();\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":930,"y":300,"wires":[["744384b8.fefe44"],["e361315a.44e0b"]]},{"id":"28c40ba8.d63dec","type":"inject","z":"c00250c7.18a848","name":"Toggle Open_Limit_switch","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":170,"y":580,"wires":[["327892ca.b92416"]]},{"id":"327892ca.b92416","type":"function","z":"c00250c7.18a848","name":"Toggle opened_limit_switch","func":"var opened_limit_switch = flow.get(\"opened_limit_switch\");\n\nif (opened_limit_switch == \"activated\") {\n    flow.set(\"opened_limit_switch\",\"inactive\");\n    node.status({text:\"opened_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"opened_limit_switch\",\"activated\");\n    node.status({text:\"opened_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":640,"wires":[[]]},{"id":"546ea8b4.c8fbd8","type":"function","z":"c00250c7.18a848","name":"For testing only >> initially set limit switches to DOOR CLOSED position","func":"// You can change the initial state of the limit switches HERE\n//\n\nflow.set(\"closed_limit_switch\",\"inactive\");\nflow.set(\"opened_limit_switch\",\"activated\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":100,"wires":[["327892ca.b92416","2cf6d51b.2cde12"]]},{"id":"c8398f3c.4d35d8","type":"inject","z":"c00250c7.18a848","name":"Toggle Closed_Limit_switch","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"1","topic":"","payload":"1","payloadType":"num","x":180,"y":700,"wires":[["2cf6d51b.2cde12"]]},{"id":"2cf6d51b.2cde12","type":"function","z":"c00250c7.18a848","name":"Toggle closed_limit_switch","func":"var closed_limit_switch = flow.get(\"closed_limit_switch\");\n\nif (closed_limit_switch == \"activated\") {\n    flow.set(\"closed_limit_switch\",\"inactive\");\n    node.status({text:\"closed_limit_switch = inactive\"});\n}\nelse {\n    flow.set(\"closed_limit_switch\",\"activated\");\n    node.status({text:\"closed_limit_switch = activated\"});\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":760,"wires":[[]]},{"id":"3303e1ed.7a4b3e","type":"ui_group","z":"","name":"Simulation control buttons","tab":"492855af.586314","order":3,"disp":true,"width":"12","collapse":false},{"id":"492855af.586314","type":"ui_tab","z":"","name":"Gate simulation","icon":"dashboard","order":41,"disabled":false,"hidden":false}]

Just a thought... if you are using Arduino code inside the Nodemcu then maybe you could just send the FSM-state as a text string, via a single MQTT-Out node, and decode the string inside the ESP8266 (and then manipulate the D7 and D8 GPIO pins). That might be faster than doing two MQTT transfers (which would introduce a slight lag between the transfers).

2 Likes

Here is a more transportable version of my garage access control flow. This version uses 3 sensors, which is over kill. You can use this same flow with 2 or even 1 sensor, to get the job done. But why do something that is less fun?

[{"id":"16e0868c.41e039","type":"tab","label":"Garage Access Control 1.0.5","disabled":false,"info":""},{"id":"5e90a96a.f2f0b8","type":"pi-gpiod in","z":"16e0868c.41e039","name":"GPIO 17 Board 11 Wire Grey","host":"localhost","port":8888,"pin":"17","intype":"PUD_DOWN","debounce":"250","read":false,"x":140,"y":80,"wires":[["a4903ff.613224"]]},{"id":"458ad282.dadac4","type":"pi-gpiod in","z":"16e0868c.41e039","name":"GPIO 27 Board 13 Wire Blue","host":"localhost","port":8888,"pin":"27","intype":"PUD_DOWN","debounce":"250","read":false,"x":140,"y":400,"wires":[["59df6adc.b76a94"]]},{"id":"a7a43bd4.964da8","type":"pi-gpiod in","z":"16e0868c.41e039","name":"GPIO 22 Board 15 Wire Purple","host":"localhost","port":8888,"pin":"22","intype":"PUD_DOWN","debounce":"250","read":false,"x":150,"y":240,"wires":[["95da3e2f.267508"]]},{"id":"4c22593c.d69ca","type":"ui_led","z":"16e0868c.41e039","group":"f7937274.35e3a","order":2,"width":3,"height":1,"label":"{{msg.label}}","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"green","value":"green","valueType":"str"},{"color":"red","value":"red","valueType":"str"},{"color":"gray","value":"gray","valueType":"str"},{"color":"blue","value":"blue","valueType":"str"}],"allowColorForValueInMessage":false,"name":"Diode","x":1010,"y":480,"wires":[]},{"id":"8ffcaf6f.8f6c38","type":"ui_button","z":"16e0868c.41e039","name":"Control","group":"f7937274.35e3a","order":1,"width":2,"height":1,"passthru":false,"label":"{{msg.title}}","tooltip":"","color":"","bgcolor":"","icon":"","payload":"#:(persistent)::state","payloadType":"flow","topic":"","x":300,"y":600,"wires":[["1d99fc90.0a178b","50c29b33.9e648c"]]},{"id":"9971412f.438748","type":"inject","z":"16e0868c.41e039","name":"1","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/11","payload":"1","payloadType":"num","x":210,"y":120,"wires":[["a4903ff.613224"]]},{"id":"ed43e5b0.e414b8","type":"inject","z":"16e0868c.41e039","name":"0","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/11","payload":"0","payloadType":"num","x":210,"y":160,"wires":[["a4903ff.613224"]]},{"id":"6f819c86.704d74","type":"ui_text","z":"16e0868c.41e039","group":"cb8f5e22.d3b02","order":1,"width":3,"height":1,"name":"High","label":"High","format":"{{msg.payload}}","layout":"row-spread","x":630,"y":120,"wires":[]},{"id":"666914f4.ae5894","type":"ui_text","z":"16e0868c.41e039","group":"cb8f5e22.d3b02","order":2,"width":3,"height":1,"name":"Purple","label":"Purple","format":"{{msg.purple}}","layout":"row-spread","x":990,"y":200,"wires":[]},{"id":"2fc1049a.311224","type":"ui_text","z":"16e0868c.41e039","group":"cb8f5e22.d3b02","order":3,"width":3,"height":1,"name":"Low","label":"Low","format":"{{msg.low}}","layout":"row-spread","x":990,"y":280,"wires":[]},{"id":"85a8bb0b.57645","type":"inject","z":"16e0868c.41e039","name":"1","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/15","payload":"1","payloadType":"num","x":230,"y":280,"wires":[["95da3e2f.267508"]]},{"id":"57247880.50c41","type":"inject","z":"16e0868c.41e039","name":"0","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/15","payload":"0","payloadType":"num","x":230,"y":320,"wires":[["95da3e2f.267508"]]},{"id":"553d20a9.6637a","type":"inject","z":"16e0868c.41e039","name":"1","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/13","payload":"1","payloadType":"num","x":210,"y":440,"wires":[["59df6adc.b76a94"]]},{"id":"be67472b.c8017","type":"inject","z":"16e0868c.41e039","name":"0","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"pi/13","payload":"0","payloadType":"num","x":210,"y":480,"wires":[["59df6adc.b76a94"]]},{"id":"225a5987.e571de","type":"inject","z":"16e0868c.41e039","name":"Reset","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":720,"wires":[["40c21b83.a6adfc"]]},{"id":"5edf676d.dac018","type":"link in","z":"16e0868c.41e039","name":"","links":["62b7a07f.0399e","88a0b7c3.190528","d229ee8b.e9acb","8fd6acb4.f41fc","2ecbc1a8.fb703e","4bbb8c2d.c02404"],"x":875,"y":240,"wires":[["2fc1049a.311224","666914f4.ae5894","7cecbc68.8c3b54"]]},{"id":"568455ca.9fd78c","type":"link in","z":"16e0868c.41e039","name":"","links":["62b7a07f.0399e","88a0b7c3.190528","121c4dd0.4fd2aa"],"x":755,"y":480,"wires":[["5325d524.4094d4"]]},{"id":"e4f215.982825e8","type":"comment","z":"16e0868c.41e039","name":"Wheels = 8?","info":"","x":250,"y":680,"wires":[]},{"id":"40c21b83.a6adfc","type":"change","z":"16e0868c.41e039","name":"Set","rules":[{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"Closed","tot":"str"},{"t":"set","p":"#:(persistent)::wheels","pt":"flow","to":"8","tot":"num"},{"t":"set","p":"#:(persistent)::wheel","pt":"flow","to":"0","tot":"num"},{"t":"set","p":"#:(persistent)::purple","pt":"flow","to":"0","tot":"num"},{"t":"set","p":"#:(persistent)::low","pt":"flow","to":"0","tot":"num"},{"t":"set","p":"#:(persistent)::percentage","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":230,"y":720,"wires":[["4bbb8c2d.c02404"]]},{"id":"4bbb8c2d.c02404","type":"link out","z":"16e0868c.41e039","name":"","links":["7d278eba.e54fa","5edf676d.dac018","fc28a5da.cb0de"],"x":335,"y":720,"wires":[]},{"id":"7d278eba.e54fa","type":"link in","z":"16e0868c.41e039","name":"","links":["4bbb8c2d.c02404","de42b291.ab536","a76609c3.e99a98","e1df97dd.0cecd8","b5405451.5c282","7f1b3220.86cbcc","d4c07ba4.d1f3a8","61a79a60.284004","219e6158.88ce7e"],"x":35,"y":580,"wires":[["decadc82.964b68"]]},{"id":"decadc82.964b68","type":"function","z":"16e0868c.41e039","name":"Control","func":"const PERSISTENT = 'persistent';\n\nconst CLOSED = 'Closed',\n      CLOSE = 'Close',\n      OFF = 'Off',\n      ON = 'On',\n      OPEN = 'Open',\n      OPENED = 'Opened',\n      HALT = 'Halt',\n      RESET = 'Reset';\n\nconst GREEN = 'green',\n      GREY = 'grey',\n      RED = 'red',\n      BLUE = 'blue';\n      \nconst ZERO = 0,\n      ONE =1;\n\nmsg.time = new Date().getTime();\n\nmsg.state = flow.get('state', PERSISTENT);\nmsg.wheel = flow.get('wheel', PERSISTENT);\nmsg.wheels = flow.get('wheels', PERSISTENT);\nmsg.reverse = flow.get('reverse', PERSISTENT);\nmsg.diode = flow.get('diode', PERSISTENT);\nmsg.title = flow.get('title', PERSISTENT);\nmsg.label = flow.get('label', PERSISTENT);\nmsg.relay = flow.get('relay', PERSISTENT);\n\nnode.warn(`State ${msg.state}`);\n\nswitch (msg.state) {\n    case RESET: {\n        \n        msg.state = CLOSED;\n        msg.relay = ZERO;\n        \n        break;\n    }\n    case OPEN: {\n\n        msg.state = HALT;\n        msg.title = msg.state;\n        msg.label = OPEN;\n        msg.diode = GREEN;\n        msg.reverse = CLOSE;\n\n        break;\n    }\n    case CLOSE: {\n\n        msg.state = HALT;\n        msg.title  = msg.state;\n        msg.label = CLOSE;\n        msg.diode = RED;\n        msg.reverse = OPEN;\n\n        break;\n    }\n    case HALT: {\n        \n        msg.title = (msg.reverse !== OPEN) ? CLOSE : OPEN;\n        msg.state = msg.title;\n        msg.diode = GREY;\n        msg.label = HALT;\n\n        break;\n    }\n    case ON: {\n        \n        msg.label = 'Close Relay';\n        msg.diode = BLUE;\n\n        break;\n    }\n    case OFF: {\n        \n        msg.label = 'Open Relay';\n        msg.diode = GREY;\n\n        break;\n    }\n    case OPENED: {\n    \n        msg.state = CLOSE;\n        msg.title = CLOSE;\n        msg.label = OPENED;\n        msg.diode = GREEN;\n        msg.reverse = CLOSE;\n        \n        break;\n    }\n    case CLOSED: {\n        \n        msg.state = OPEN;\n        msg.title  = OPEN;\n        msg.label = CLOSED;\n        msg.diode = RED;\n        msg.reverse = OPEN;\n\n        break;\n    }\n}\n\nflow.set('time', msg.time, PERSISTENT);\n\nflow.set('state', msg.state, PERSISTENT);\nflow.set('wheel', msg.wheel, PERSISTENT);\n// Wheels\nflow.set('reverse', msg.reverse, PERSISTENT);\nflow.set('diode', msg.diode, PERSISTENT);\nflow.set('title', msg.title, PERSISTENT);\nflow.set('label', msg.label, PERSISTENT);\nflow.set('relay', msg.relay, PERSISTENT);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":140,"y":580,"wires":[["121c4dd0.4fd2aa","8ffcaf6f.8f6c38"]]},{"id":"1d99fc90.0a178b","type":"trigger","z":"16e0868c.41e039","name":"Relay On/Off (250ms)","op1":"1","op2":"0","op1type":"num","op2type":"num","duration":"250","extend":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":2,"x":500,"y":620,"wires":[["5c0a08ef.48314"],["c9e32090.0fe86"]]},{"id":"5c0a08ef.48314","type":"change","z":"16e0868c.41e039","name":"On","rules":[{"t":"set","p":"#:(persistent)::relay","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"On","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":690,"y":600,"wires":[["a76609c3.e99a98"]]},{"id":"c9e32090.0fe86","type":"change","z":"16e0868c.41e039","name":"Off","rules":[{"t":"set","p":"#:(persistent)::relay","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"Off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":690,"y":640,"wires":[["a76609c3.e99a98"]]},{"id":"5325d524.4094d4","type":"change","z":"16e0868c.41e039","name":"Diode","rules":[{"t":"set","p":"payload","pt":"msg","to":"diode","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":870,"y":480,"wires":[["4c22593c.d69ca"]]},{"id":"121c4dd0.4fd2aa","type":"link out","z":"16e0868c.41e039","name":"","links":["568455ca.9fd78c","6492ac3.69ed554","63841261.20c884","9836bab0.b1ca2","85a23845.813fd","6589d9da.5728a"],"x":255,"y":560,"wires":[]},{"id":"a76609c3.e99a98","type":"link out","z":"16e0868c.41e039","name":"","links":["4de1619b.686ae","7d278eba.e54fa"],"x":795,"y":600,"wires":[]},{"id":"50c29b33.9e648c","type":"delay","z":"16e0868c.41e039","name":"Delay (500ms)","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":480,"y":580,"wires":[["1bff4332.660aad"]]},{"id":"1bff4332.660aad","type":"change","z":"16e0868c.41e039","name":"State","rules":[{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":690,"y":560,"wires":[["a76609c3.e99a98"]]},{"id":"78052aee.7c4b4c","type":"ui_text","z":"16e0868c.41e039","group":"cb8f5e22.d3b02","order":4,"width":3,"height":1,"name":"Reverse","label":"Reverse","format":"{{msg.reverse}}","layout":"row-spread","x":1000,"y":520,"wires":[]},{"id":"6492ac3.69ed554","type":"link in","z":"16e0868c.41e039","name":"","links":["121c4dd0.4fd2aa"],"x":875,"y":520,"wires":[["78052aee.7c4b4c"]]},{"id":"b5405451.5c282","type":"link out","z":"16e0868c.41e039","name":"","links":["7d278eba.e54fa"],"x":1115,"y":380,"wires":[]},{"id":"95da3e2f.267508","type":"switch","z":"16e0868c.41e039","name":"Zero?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":370,"y":280,"wires":[["67b1fee1.4031a"]]},{"id":"59df6adc.b76a94","type":"switch","z":"16e0868c.41e039","name":"Zero?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":350,"y":440,"wires":[["22057155.8b7eee"]]},{"id":"22057155.8b7eee","type":"change","z":"16e0868c.41e039","name":"Low","rules":[{"t":"set","p":"#:(persistent)::sensor","pt":"flow","to":"Low","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":440,"wires":[["2285e4ac.f0a5c4"]]},{"id":"2f57a7a7.479dc8","type":"function","z":"16e0868c.41e039","name":"Sensor","func":"const PERSISTENT = 'persistent',\n      PURPLE = 'Purple';\n      LOW = 'Low',\n      OPEN = 'Open',\n      CLOSE = 'Close';\n      \nconst HUNDRED = 100,\n      ONE = 1;\n\nvar theNudge = (flow.get('reverse', PERSISTENT) !== OPEN) ? ONE : -ONE,\n    theWheel = flow.get('wheel', PERSISTENT);\n    \ntheWheel += theNudge;\n\nmsg.purple = flow.get('purple', PERSISTENT);\nmsg.low = flow.get('low', PERSISTENT);\n\nswitch (flow.get('sensor', PERSISTENT)) {\n    case PURPLE: {\n\n        msg.purple += theNudge;\n        \n        break;\n    }\n    case LOW: {\n        \n        msg.low += theNudge;\n        \n        break;\n    }\n}\n\nmsg.percentage = (HUNDRED * (theWheel / (flow.get('wheels', PERSISTENT) + ONE))).toFixed(ONE);\n\nflow.set('percentage', msg.percentage, PERSISTENT);\nflow.set('wheel', theWheel, PERSISTENT);\nflow.set('low', msg.low, PERSISTENT);\nflow.set('purple', msg.purple, PERSISTENT);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":360,"wires":[["dcf4ea8a.26f15","d229ee8b.e9acb"]]},{"id":"dcf4ea8a.26f15","type":"switch","z":"16e0868c.41e039","name":"Wheel?","property":"#:(persistent)::wheel","propertyType":"flow","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"gt","v":"#:(persistent)::wheels","vt":"flow"}],"checkall":"true","repair":false,"outputs":2,"x":840,"y":380,"wires":[["f1b141c0.e16cc"],["62d41608.255e58"]]},{"id":"f1b141c0.e16cc","type":"change","z":"16e0868c.41e039","name":"Closed","rules":[{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"Closed","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"","tot":"date"},{"t":"set","p":"#:(persistent)::purple","pt":"flow","to":"0","tot":"num"},{"t":"set","p":"#:(persistent)::low","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":360,"wires":[["b5405451.5c282"]]},{"id":"62d41608.255e58","type":"change","z":"16e0868c.41e039","name":"Opened","rules":[{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"Opened","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":400,"wires":[["b5405451.5c282"]]},{"id":"67b1fee1.4031a","type":"change","z":"16e0868c.41e039","name":"Purple","rules":[{"t":"set","p":"#:(persistent)::sensor","pt":"flow","to":"Purple","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":280,"wires":[["c0c6d32e.aa3dc8"]]},{"id":"2285e4ac.f0a5c4","type":"link out","z":"16e0868c.41e039","name":"","links":["dbff4fb6.49bf3"],"x":595,"y":440,"wires":[]},{"id":"dbff4fb6.49bf3","type":"link in","z":"16e0868c.41e039","name":"","links":["2285e4ac.f0a5c4","c0c6d32e.aa3dc8"],"x":555,"y":360,"wires":[["2f57a7a7.479dc8"]]},{"id":"c0c6d32e.aa3dc8","type":"link out","z":"16e0868c.41e039","name":"","links":["dbff4fb6.49bf3"],"x":615,"y":280,"wires":[]},{"id":"d229ee8b.e9acb","type":"link out","z":"16e0868c.41e039","name":"","links":["531e2940.e9eea","5edf676d.dac018"],"x":795,"y":340,"wires":[]},{"id":"7cecbc68.8c3b54","type":"ui_text","z":"16e0868c.41e039","group":"cb8f5e22.d3b02","order":3,"width":3,"height":1,"name":"Percentage","label":"Percentage","format":"{{msg.percentage}}","layout":"row-spread","x":1010,"y":240,"wires":[]},{"id":"e949962.53bda68","type":"change","z":"16e0868c.41e039","name":"0","rules":[{"t":"set","p":"#:(persistent)::high","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"#:(persistent)::state","pt":"flow","to":"Opened","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":140,"wires":[["6f819c86.704d74"]]},{"id":"a4903ff.613224","type":"switch","z":"16e0868c.41e039","name":"High?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":350,"y":120,"wires":[["f106a995.a98968"],["e949962.53bda68"]]},{"id":"f106a995.a98968","type":"change","z":"16e0868c.41e039","name":"1","rules":[{"t":"set","p":"high","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":100,"wires":[["6f819c86.704d74"]]},{"id":"f7937274.35e3a","type":"ui_group","z":"","name":"Access","tab":"17746764.02edd9","order":2,"disp":true,"width":5,"collapse":true},{"id":"cb8f5e22.d3b02","type":"ui_group","z":"","name":"Sensors","tab":"17746764.02edd9","order":2,"disp":true,"width":"3","collapse":true},{"id":"17746764.02edd9","type":"ui_tab","z":"","name":"Garage","icon":"dashboard","disabled":false,"hidden":false}]

The above flow just needs to know the total number of wheels it will count, as they pass in front of the low and purple sensors. In my case this is 8, this is because where the sensors are, a few wheels are countered twice by design.

I used simple infrared distance sensors, but you could use use sonic or magnetic sensors with similar ease. The specific sensors trigger low, not high state, by the way. Here is a simple diagram of how my sensors are placed...

The placement was based on where the door rail already had flushed openings for easy sensor placement.

As requested, above I shared my Garage Access Control flow, it will need the ui-led module to work, but I trust that is not too big an issue. Also, it uses the RPiGPIOd module, but I figure everyone uses that? The trigger of the relay (for garage door switch) is simiulated, and I added buttons to simulate the sensor triggering. Enjoy!

1 Like

All door controllers are FSA (Finite State Automatons) or FSM models. Meaning they all must always reside at a know state. This comes from the classic vendor machine problem design methodology. Ever wonder how a dump vendor machine knows how to return the correct change? Use of FSA or FSM design theory! Even 100% mechanical slot machines, as complex as they seemed, where based on FSA or FSM design theory. What else... Cash registers, get this, very mechanical clock, is a FSA or FSM model. LOL!.

Truly Appreciated. Thanks

Hi Schorschi Decker,

Quick question - Do you have a raspberry pi itself hooked up with/near the motor and GPIO pins do this ? i knew this is doable, but isn't it a overkill or more expensive ? also, wouldn't there be other factors that come into play like for example i am planning(hoping) to have local mqtt server/broker operational though in future i wanted to use additional cloud mqtt server/broker...if there's a way.

Anyway, i imported your flow and something unexpected happened. even after i disabled it the UI for nodered was showing some error. sharing screenshots hoping you'd know what went wrong.

Yes, Pi device in the garage, PiZero $10, and ESP module like $3 to $6. You could also use an ESP device, you would just sent to it MQTT commands, and ESP device GPIO to accept sensor data, and drive a relay for the garage door motor control. The core of the flow would remain unchanged, just different inputs and outputs, i.e. the sensors and relay. I already had the Pi available because it also controls my sprinklers. :slight_smile:

The flow replies on two modules, node-red-contrib-ui-led, and node-red-node-pi-gpiod. Just add those to your NR configuration via manage palette via the install tab. I mentioned this in the above discussion, that the flow would need a couple of modules.

This was one of my early flows... so I am sure there are other more elegant ways to do it, or design same. But if you have any questions just ask. More than happy to discuss it as needed.

1 Like

it's getting more and more fascinating. i don't know much at this point but i'm getting to understand and all i have is time. :slight_smile:

is there a video or detailed guide article from wiring/hardware to software that i can refer to.

i don't have programming background but yes network and voip is all i've been doing..this is becoming my hobby though

1 Like

Thanks Schorschi Decker,

i get the cost factor isn't significant...i've couple things that i've been trying to use for this. not sure what's the most convenient or best you'd say. nodemcu/spare-RaspberryPI3B+,couple relays and all kind of jumper wires plus one arduino...using raspberry for few years but again inside home for plex media server etc..

reply to above post of yours..considering this is wifi/tasmota/nodered and i'm able to move a little with it. i guess continuing is best...again i'm available to do this anyway you'd suggest me to follow whatever steps.

is there a way to put MQTT in place of GPIO in your flow ? (reason i'm trying to keep nodemcu on the gate with motor and l298n in a box)

Also i see there's couple of mac-address, what role are they playing ?

for this i guess i'll need to do wiring exactly the same way, am i correct ? (hoping these GPIO pins are same for PiZero and RaspberrypiB+)

when you say, ESP device GPIO to accept sensor data... May i know which sensor exactly ?

i've been able to do very limited stuff so far and sometimes not have much explanations.
for example, i run tasmota on my nodemcu and have logging pointed to syslog, modified topics etc..in fact for disaster-recovery scenario i've already saved config-dump for tasmota-ui-configurations...so that i simply restore it to new one with same pins in use.. but the same config doesn't work with one particular nodemcu don't know what went wrong with it...but that one is just keeping motor rotating and rotating. i doubted my connections, motor, wiring...kinda spent whole day but today with this spare nodemcu...it's all well.

plan is to make it simple and stable without having to push or pull the gate,

please look at my tiny-flow below, all i'm trying to add is a stop button...open & close work (rotate the motor in different directions)

[{"id":"ad39963d.ea598","type":"tab","label":"Home","disabled":false,"info":""},{"id":"b57a7eb0.293e2","type":"Sonoff device Enhanced","z":"ad39963d.ea598","mode":"0","broker":"b650332e.d12ee","device":"Utanki","name":"Utanki","onValue":"ON","offValue":"OFF","toggleValue":"toggle","cmdPrefix":"cmnd","statPrefix":"stat","telePrefix":"tele","x":530,"y":80,"wires":[[]]},{"id":"ade4cb79.1136f8","type":"ui_switch","z":"ad39963d.ea598","name":"PUMP","label":"WATER PUMP","tooltip":"","group":"a5146bf8.bcab5","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"/home/Utanki","style":"","onvalue":"on","onvalueType":"str","onicon":"","oncolor":"","offvalue":"off","offvalueType":"str","officon":"","offcolor":"","x":110,"y":100,"wires":[["b57a7eb0.293e2"]],"icon":"font-awesome/fa-bolt","info":"# मोटर"},{"id":"cc0c3c8c.7baf9","type":"mqtt out","z":"ad39963d.ea598","name":"Set power7","topic":"cmnd/SouthGate-NodeMCU/POWER7","qos":"0","retain":"","broker":"b650332e.d12ee","x":550,"y":240,"wires":[]},{"id":"5853c462.56da64","type":"ui_switch","z":"ad39963d.ea598","name":"","label":"OPEN","tooltip":"","group":"865b091a.458898","order":3,"width":0,"height":0,"passthru":false,"decouple":"true","topic":"SouthGate-NodeMCU/POWER7","style":"","onvalue":"ON","onvalueType":"str","onicon":"","oncolor":"","offvalue":"OFF","offvalueType":"str","officon":"","offcolor":"","x":330,"y":240,"wires":[["cc0c3c8c.7baf9"]]},{"id":"d3672b46.e5de78","type":"mqtt in","z":"ad39963d.ea598","name":"power7","topic":"stat/SouthGate-NodeMCU/POWER7","qos":"0","datatype":"auto","broker":"b650332e.d12ee","x":130,"y":240,"wires":[["5853c462.56da64"]]},{"id":"9f8c24cc.c20a58","type":"mqtt out","z":"ad39963d.ea598","name":"Set power8","topic":"cmnd/SouthGate-NodeMCU/POWER8","qos":"0","retain":"","broker":"b650332e.d12ee","x":550,"y":300,"wires":[]},{"id":"6936c542.1d086c","type":"ui_switch","z":"ad39963d.ea598","name":"","label":"CLOSE","tooltip":"","group":"865b091a.458898","order":2,"width":0,"height":0,"passthru":false,"decouple":"true","topic":"SouthGate-NodeMCU/POWER8","style":"","onvalue":"ON","onvalueType":"str","onicon":"","oncolor":"","offvalue":"OFF","offvalueType":"str","officon":"","offcolor":"","x":340,"y":300,"wires":[["9f8c24cc.c20a58"]]},{"id":"7521d8b6.c9c6d8","type":"mqtt in","z":"ad39963d.ea598","name":"power8","topic":"stat/SouthGate-NodeMCU/POWER8","qos":"0","datatype":"auto","broker":"b650332e.d12ee","x":130,"y":300,"wires":[["6936c542.1d086c"]]},{"id":"b650332e.d12ee","type":"mqtt-broker","z":"","name":"pi","broker":"192.168.1.9","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"a5146bf8.bcab5","type":"ui_group","z":"","name":"PUMP","tab":"4bf5eaa5.38967c","disp":true,"width":"8","collapse":false},{"id":"865b091a.458898","type":"ui_group","z":"","name":"SOUTH GATE","tab":"4bf5eaa5.38967c","order":2,"disp":true,"width":"6","collapse":false},{"id":"4bf5eaa5.38967c","type":"ui_tab","z":"","name":"Home","icon":"home","order":1,"disabled":false,"hidden":false}]

Note - i have a sonoff-tasmotized separately running under the same noderedUI/group, which is working okay. named PUMP

i'll love to add sensors and switches but i guess i'm not at the level to digest the flow that you've shared.

i appreciate this forum and your knowledge/expertise on this.

to clarify both pictures below, make the southgate(motor) stop.. ideally when 'close' is pressed 'open' shouldn't be ON... am i right :slight_smile:

Not sure if you would like my logic, but is it possible to send 2 mqtt commands
currently, if i press open it's rotation the motor anticlockwise (reason close button is off)
and when i press close it's rotating the motor clockwise (reason open button is off)
problem i'm seeing with this basic flow that when the other button is off or on...the scenario changes.
so, i'm willing to have manual stop button or stop sent when the other button is pressed.

POWER7 is OPEN
POWER8 is CLOSE

see if the following logs give you information how i'm sending the commands to the topic
Sep 26 14:30:45 192.168.1.138 SouthGate-NodeMCU ESP-WIF: Connected
Sep 26 14:30:56 192.168.1.138 SouthGate-NodeMCU ESP-SRC: MQTT
Sep 26 14:30:56 192.168.1.138 SouthGate-NodeMCU ESP-RSL: Received Topic cmnd/SouthGate-NodeMCU/POWER7, Data Size 2, Data ON
Sep 26 14:30:56 192.168.1.138 SouthGate-NodeMCU ESP-RSL: Group 0, Index 7, Command POWER, Data ON
Sep 26 14:30:56 192.168.1.138 SouthGate-NodeMCU ESP-MQT: stat/SouthGate-NodeMCU/RESULT = {"POWER7":"ON"}
Sep 26 14:30:56 192.168.1.138 SouthGate-NodeMCU ESP-MQT: stat/SouthGate-NodeMCU/POWER7 = ON
Sep 26 14:30:57 192.168.1.138 SouthGate-NodeMCU ESP-CFG: Saved to flash at F9, Count 580, Bytes 3584
Sep 26 14:31:03 192.168.1.138 SouthGate-NodeMCU ESP-SRC: MQTT
Sep 26 14:31:03 192.168.1.138 SouthGate-NodeMCU ESP-RSL: Received Topic cmnd/SouthGate-NodeMCU/POWER7, Data Size 3, Data OFF
Sep 26 14:31:03 192.168.1.138 SouthGate-NodeMCU ESP-RSL: Group 0, Index 7, Command POWER, Data OFF
Sep 26 14:31:03 192.168.1.138 SouthGate-NodeMCU ESP-MQT: stat/SouthGate-NodeMCU/RESULT = {"POWER7":"OFF"}
Sep 26 14:31:03 192.168.1.138 SouthGate-NodeMCU ESP-MQT: stat/SouthGate-NodeMCU/POWER7 = OFF
Sep 26 14:31:04 192.168.1.138 SouthGate-NodeMCU ESP-CFG: Saved to flash at F8, Count 581, Bytes 3584
Sep 26 14:31:05 192.168.1.138 SouthGate-NodeMCU ESP-WIF: Checking connection...
Sep 26 14:31:05 192.168.1.138 SouthGate-NodeMCU ESP-WIF: Connected

With any design just create it in steps. So lets list all the things you want to do first. Then we pick one, complete it, then the next and so on.

So the first thing is, I think added MQTT, what is the goal of this? motor control? That means you have two specific requirements, 1) something to send commands and something to receive the commands. And if using MQTT you have a MQTT broker somewhere, right?

So assuming you are using NR, and an MQTT broker instance, you design is some thing like this?

NR (Pi) -> MQTT messages ->. MQTT Broker -> ESP module -> Motor On and Off
NR (Pi) -> MQTT messages ->. MQTT Broker -> ESP module -> Motor Set Direction

Is the above correct?

Don't worry about actually making the motor do any thing. Just focus on what you need to do in NR to get the MQTT messaging working. Then we can tackle the motor aspect.

It looks like from the logging the ESP module receives the MQTT commands as needed right?

Looking at your flow I am not sure I understand what it is trying to do. Does your ESP module send feed back back after it accepts a MQTT command?