...and what about a State Machine Node?

1,041 views
Skip to first unread message

Lorenzo Maiorfi

unread,
Jan 20, 2014, 10:24:20 AM1/20/14
to node...@googlegroups.com
Hi.

I think it would be really very useful to have a node providing a state machine model, where input messages could be processed as events/triggers and where output messages could be emitted while entering into, or exiting from a state or transitioning between two states. Maybe a hierarchical state machine model would be even more interesting.

What do you think about that? Is there any js open library that provides state-machine features?

Thanks!

Nicholas Humfrey

unread,
Jan 20, 2014, 12:32:32 PM1/20/14
to node...@googlegroups.com, node...@googlegroups.com
Yes, I was thinking something like that would be useful.

In particular, I was interested in being able to toggle a bi-state machine based on any input.

Sent from my phone
--
http://nodered.org
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Dave C-J

unread,
Jan 20, 2014, 1:36:37 PM1/20/14
to node...@googlegroups.com

There are some full on bundles around eg - https://github.com/wheeyls/stateMachine 
though I think it will need some thought how to best wrap to make it "work" visually. 
I would think either you have one  node - but it would be somewhat complex with lots of hidden internal state... or you have bunch of "nodelets" that represent each state.
To me the latter would be more visual and easier to understand  - but i suspect we can build that from existing function nodes.

I'll have a play and see - any thoughts/ideas appreciated.... If we do need a "state" node then we can create one.

Lorenzo Maiorfi

unread,
Jan 21, 2014, 5:07:08 AM1/21/14
to node...@googlegroups.com
From a "behavioral" point of view a single node representing the whole state machine seems more appropriate to me. Concerning visual appeal of node configuration, schema editing of state machine model could easily be done also by mean of a simple script (mimicking choosen library api).

As a use case scenario, think to a node-red flow providing logic for canonical example of traffic light (here you can find an example implementation http://www.stateworks.com/active/download/intersection.jpg), where traffic light lamps driving is made through mqtt (retained) publications, with several "actuator" devices acting as subscribers.

Concerning choosen JS library, maybe one should consider projects implementing hierarchical state machines, but I did't searched online for them yet: do you know whether something similar to Stateless (https://code.google.com/p/stateless/) or StatelessJ (for Java) has ever been published for javascript?

Thanks!

Lorenzo Maiorfi

unread,
Jan 21, 2014, 5:37:38 AM1/21/14
to node...@googlegroups.com
https://github.com/hyperandroid/Automata and http://statejs.org/ both seem good candidates in order to provide hierarchical FSM features.


On Monday, January 20, 2014 7:36:37 PM UTC+1, Dave C-J wrote:

Artem Pastukhov

unread,
Oct 14, 2015, 6:19:47 AM10/14/15
to Node-RED
Any news?

Marcio Braga

unread,
Oct 16, 2015, 4:15:31 PM10/16/15
to Node-RED
Maybe something like this:

You enter the state machine by event "ev_enter" and sets it to "state 0".
At this point only events ev1 and ev2 works.
If you trigger ev1, you change to "state 1", that also starts another state machine and sets it to "state 1.1".
Now events ev4 and ev5 are the ones working.
And so on ...

Does it makes sense ?

Marcio Braga

unread,
Oct 16, 2015, 4:25:08 PM10/16/15
to Node-RED
We also need something to indicate where we are ...


Marcio Braga

unread,
Oct 16, 2015, 4:34:43 PM10/16/15
to Node-RED
Each State-node has at least 2 fields to write JavaScript code: one for Status Enter and another for Status Exit.

Mike Biddell

unread,
Oct 17, 2015, 12:00:44 PM10/17/15
to Node-RED
It would be great if the state machine allowed you to opt to activate/de-activate 'tabs'

Cory Guynn

unread,
Apr 20, 2016, 8:45:19 AM4/20/16
to Node-RED
Hi guys, 

Reviving this thread. I am trying to build a state machine for my InternetOfLEGO.com project. I will have various sensors to detect a LEGO train and built a WiFi controller (NodeMCU) to control the engine. The goal is to have several trains, running their own program but also are aware of other trains/obstacles on the track. 

As I started wiring this in Node-RED, I realized it was a real challenge. The primary issue was the lack of a logic gate to store a msg (command) until a sensor is either detected or not detected, depending on the use case. 
By leveraging the context variables, I was able to build this myself using function nodes.

Now that I have two logic gates, I can combine them to build a state machine (or close to it).




Logic Gates
[{"id":"73f9d9ad.89fc38","type":"debug","z":"494c2f6c.48306","name":"Gate 1","active":true,"console":"false","complete":"true","x":690,"y":140,"wires":[]},{"id":"3f6ffcb9.fa7604","type":"inject","z":"494c2f6c.48306","name":"Sensor A - on","topic":"SensorA","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":140,"wires":[["d58d43bd.3de9a"]]},{"id":"a3ef5079.789fb","type":"inject","z":"494c2f6c.48306","name":"Sensor A - off","topic":"SensorA","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":180,"wires":[["d58d43bd.3de9a"]]},{"id":"c7189620.d3c018","type":"inject","z":"494c2f6c.48306","name":"Command","topic":"myCommand","payload":"{\"command\":{\"motor\":1024}}","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":100,"wires":[["a1dac285.eacff"]]},{"id":"e6ea36e6.650008","type":"inject","z":"494c2f6c.48306","name":"Sensor B - on","topic":"SensorB","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":240,"wires":[["d58d43bd.3de9a"]]},{"id":"f8b3c798.ea3f28","type":"inject","z":"494c2f6c.48306","name":"Sensor B - off","topic":"SensorB","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":280,"wires":[["d58d43bd.3de9a"]]},{"id":"a1dac285.eacff","type":"function","z":"494c2f6c.48306","name":"message","func":"var newMsg = {}\nnewMsg.payload = msg;\nnewMsg.topic = \"message\";\nreturn newMsg;","outputs":1,"noerr":0,"x":320,"y":100,"wires":[["12cf4611.c17f5a"]]},{"id":"cb75020.a8935","type":"function","z":"494c2f6c.48306","name":"state ","func":"// save state\ncontext.state = context.state || {};\ncontext.state[msg.topic] = msg.payload;\n\n// check all states status\nvar sensors = 0;\nvar keys = Object.keys(context.state);\nfor (var i = 0; i < keys.length; i++) {\n    sensors += context.state[keys[i]];\n}\n\n/*\nif (sensors < 1){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"safe: \"+sensors}); \n    return context.msg;\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"unsafe: \"+sensors});\n}\n*/\n\nnode.status({fill:\"gray\",shape:\"ring\",text:\"Sensors: \"+sensors});\nmsg.topic = \"state\";\nmsg.payload = sensors;\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":160,"wires":[["12cf4611.c17f5a"]]},{"id":"12cf4611.c17f5a","type":"function","z":"494c2f6c.48306","name":"Gate: <1","func":"// Store states and msg based on origin\ncontext.state = context.state || 0;\ncontext.msg = context.msg || {};\nswitch(msg.topic){\n    case \"message\":\n        // save original msg\n        context.msg = msg.payload;\n      break;\n      \n    case \"state\":\n        // save state\n        context.state = msg.payload;\n        break;\n}\n\n// LOGIC GATE -- if no sensors active, then send command.\nif(context.state < 1){\n    node.status({fill:\"green\",shape:\"ring\",text:\"Sent: \"+JSON.stringify(context.msg)}); \n    msg.payload = context.msg;\n    // reset msg\n    context.msg = undefined; \n    return msg.payload; // the payload contains the original msg object\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"Waiting: \"+JSON.stringify(context.msg)}); \n}\n        \n//return msg;","outputs":1,"noerr":0,"x":520,"y":140,"wires":[["73f9d9ad.89fc38","377e050f.47050a"]]},{"id":"d58d43bd.3de9a","type":"rbe","z":"494c2f6c.48306","name":"","func":"rbe","gap":"","x":330,"y":240,"wires":[["cb75020.a8935"]]},{"id":"cb72855a.9992f8","type":"debug","z":"494c2f6c.48306","name":"Gate 2","active":true,"console":"false","complete":"true","x":690,"y":420,"wires":[]},{"id":"d99e8d5a.7d2d7","type":"inject","z":"494c2f6c.48306","name":"Sensor A - on","topic":"SensorA","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":420,"wires":[["e95bd8b2.4ab388"]]},{"id":"bc9b62fc.23a7d","type":"inject","z":"494c2f6c.48306","name":"Sensor A - off","topic":"SensorA","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":460,"wires":[["e95bd8b2.4ab388"]]},{"id":"8e9b6bb6.2fe098","type":"inject","z":"494c2f6c.48306","name":"Command","topic":"newCommand","payload":"{\"command\":{\"motor\":1024}}","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":380,"wires":[["377e050f.47050a"]]},{"id":"525199c7.45bf78","type":"inject","z":"494c2f6c.48306","name":"Sensor B - on","topic":"SensorB","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":520,"wires":[["e95bd8b2.4ab388"]]},{"id":"a320dffb.d8f83","type":"inject","z":"494c2f6c.48306","name":"Sensor B - off","topic":"SensorB","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":130,"y":560,"wires":[["e95bd8b2.4ab388"]]},{"id":"377e050f.47050a","type":"function","z":"494c2f6c.48306","name":"message","func":"var newMsg = {}\nnewMsg.payload = msg;\nnewMsg.topic = \"message\";\nreturn newMsg;","outputs":1,"noerr":0,"x":320,"y":380,"wires":[["d45308c5.c02128"]]},{"id":"92f24b6f.35a9f8","type":"function","z":"494c2f6c.48306","name":"state ","func":"// save state\ncontext.state = context.state || {};\ncontext.state[msg.topic] = msg.payload;\n\n// check all states status\nvar sensors = 0;\nvar keys = Object.keys(context.state);\nfor (var i = 0; i < keys.length; i++) {\n    sensors += context.state[keys[i]];\n}\n\n/*\nif (sensors < 1){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"safe: \"+sensors}); \n    return context.msg;\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"unsafe: \"+sensors});\n}\n*/\n\nnode.status({fill:\"gray\",shape:\"ring\",text:\"Sensors: \"+sensors});\nmsg.topic = \"state\";\nmsg.payload = sensors;\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":440,"wires":[["d45308c5.c02128"]]},{"id":"d45308c5.c02128","type":"function","z":"494c2f6c.48306","name":"Gate >= 1","func":"// Store states and msg based on origin\ncontext.state = context.state || 0;\ncontext.msg = context.msg || {};\nswitch(msg.topic){\n    case \"message\":\n        // save original msg\n        context.msg = msg.payload;\n      break;\n      \n    case \"state\":\n        // save state\n        context.state = msg.payload;\n        break;\n}\n\n// LOGIC GATE -- if no sensors active, then send command.\nif(context.state >= 1){\n    node.status({fill:\"green\",shape:\"ring\",text:\"Sent: \"+JSON.stringify(context.msg)}); \n    msg.payload = context.msg;\n    // reset msg\n    context.msg = undefined; \n    return msg.payload; // the payload contains the original msg object\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"Waiting: \"+JSON.stringify(context.msg)}); \n}\n        \n//return msg;","outputs":1,"noerr":0,"x":520,"y":420,"wires":[["cb72855a.9992f8"]]},{"id":"e95bd8b2.4ab388","type":"rbe","z":"494c2f6c.48306","name":"","func":"rbe","gap":"","x":330,"y":520,"wires":[["92f24b6f.35a9f8"]]},{"id":"67c53a04.e4fb54","type":"comment","z":"494c2f6c.48306","name":"Runs command if no sensors active","info":"","x":160,"y":60,"wires":[]},{"id":"e84c3898.03d6e8","type":"comment","z":"494c2f6c.48306","name":"Runs command when at least one sensor is detected","info":"","x":220,"y":340,"wires":[]}]



State Machine idea - Lego Train goes in a loop to then stop at a subway station, but first sets the track switches and ensures there are no other trains on the shared track. I'm using input and debug nodes for the demo, but would eventually attach MQTT or similar endpoints.

[{"id":"52332e6f.c1be3","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"horizonExpress","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":160,"y":160,"wires":[["2498393f.ce2746"]]},{"id":"94e30749.4b6cb8","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"local","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":130,"y":200,"wires":[["2498393f.ce2746"]]},{"id":"2498393f.ce2746","type":"function","z":"7cadc4a0.74ec1c","name":"switch track to subway loop","func":"msg.payload = {\"command\":{\"trackSwitch.a\":\"straight\"}};\nreturn msg;","outputs":1,"noerr":0,"x":160,"y":120,"wires":[["b6e47118.febdc"]]},{"id":"acd42b86.03b128","type":"function","z":"7cadc4a0.74ec1c","name":"train forward","func":"msg.payload = {\"command\":{\"motor\":1024}};\nreturn msg;","outputs":1,"noerr":0,"x":110,"y":380,"wires":[["8564b611.34ae88"]]},{"id":"f0e31ee2.437df","type":"comment","z":"7cadc4a0.74ec1c","name":"check if tracks are occupied","info":"","x":620,"y":120,"wires":[]},{"id":"83872c03.01b48","type":"comment","z":"7cadc4a0.74ec1c","name":"check if tracks are occupied","info":"","x":620,"y":360,"wires":[]},{"id":"1e631817.fc9968","type":"function","z":"7cadc4a0.74ec1c","name":"stop at subway","func":"msg.payload = {\"command\":{\"motor\":0}}\nreturn msg;","outputs":1,"noerr":0,"x":120,"y":580,"wires":[["5d54af4.64fe25"]]},{"id":"9bac8925.0a2918","type":"delay","z":"7cadc4a0.74ec1c","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":100,"y":760,"wires":[["2498393f.ce2746"]]},{"id":"af652839.d48708","type":"comment","z":"7cadc4a0.74ec1c","name":"stop when train detetected at subway","info":"","x":650,"y":580,"wires":[]},{"id":"b6e47118.febdc","type":"function","z":"7cadc4a0.74ec1c","name":"message","func":"var newMsg = {}\nnewMsg.payload = msg;\nnewMsg.topic = \"message\";\nreturn newMsg;","outputs":1,"noerr":0,"x":380,"y":120,"wires":[["2014f560.20d98a"]]},{"id":"2298bc3d.dfa5d4","type":"function","z":"7cadc4a0.74ec1c","name":"state ","func":"// save state\ncontext.state = context.state || {};\ncontext.state[msg.topic] = msg.payload;\n\n// check all states status\nvar sensors = 0;\nvar keys = Object.keys(context.state);\nfor (var i = 0; i < keys.length; i++) {\n    sensors += context.state[keys[i]];\n}\n\n/*\nif (sensors < 1){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"safe: \"+sensors}); \n    return context.msg;\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"unsafe: \"+sensors});\n}\n*/\n\nnode.status({fill:\"gray\",shape:\"ring\",text:\"Sensors: \"+sensors});\nmsg.topic = \"state\";\nmsg.payload = sensors;\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":160,"wires":[["2014f560.20d98a"]]},{"id":"2014f560.20d98a","type":"function","z":"7cadc4a0.74ec1c","name":"Gate: <1","func":"// Store states and msg based on origin\ncontext.state = context.state || 0;\ncontext.msg = context.msg || {};\nswitch(msg.topic){\n    case \"message\":\n        // save original msg\n        context.msg = msg.payload;\n      break;\n      \n    case \"state\":\n        // save state\n        context.state = msg.payload;\n        break;\n}\n\n// LOGIC GATE -- if no sensors active, then send command.\nif(context.state < 1){\n    node.status({fill:\"green\",shape:\"ring\",text:\"Sent: \"+JSON.stringify(context.msg)}); \n    msg.payload = context.msg;\n    // reset msg\n    context.msg = undefined; \n    return msg.payload; // the payload contains the original msg object\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"Waiting: \"+JSON.stringify(context.msg)}); \n}\n        \n//return msg;","outputs":1,"noerr":0,"x":560,"y":160,"wires":[["b8ba9111.e92bc","acd42b86.03b128"]]},{"id":"1bb9bd92.3bf402","type":"rbe","z":"7cadc4a0.74ec1c","name":"","func":"rbe","gap":"","x":270,"y":260,"wires":[["2298bc3d.dfa5d4"]]},{"id":"8b85c1e8.42b3a","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"trackA","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":240,"wires":[["1bb9bd92.3bf402"]]},{"id":"b8ba9111.e92bc","type":"debug","z":"7cadc4a0.74ec1c","name":"subway track switch","active":true,"console":"false","complete":"true","x":780,"y":160,"wires":[]},{"id":"3af4581.02c83a8","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"trackA","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":280,"wires":[["1bb9bd92.3bf402"]]},{"id":"8564b611.34ae88","type":"function","z":"7cadc4a0.74ec1c","name":"message","func":"var newMsg = {}\nnewMsg.payload = msg;\nnewMsg.topic = \"message\";\nreturn newMsg;","outputs":1,"noerr":0,"x":380,"y":380,"wires":[["4a1d760d.f2b038"]]},{"id":"cad742f5.0f6df","type":"function","z":"7cadc4a0.74ec1c","name":"state ","func":"// save state\ncontext.state = context.state || {};\ncontext.state[msg.topic] = msg.payload;\n\n// check all states status\nvar sensors = 0;\nvar keys = Object.keys(context.state);\nfor (var i = 0; i < keys.length; i++) {\n    sensors += context.state[keys[i]];\n}\n\n/*\nif (sensors < 1){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"safe: \"+sensors}); \n    return context.msg;\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"unsafe: \"+sensors});\n}\n*/\n\nnode.status({fill:\"gray\",shape:\"ring\",text:\"Sensors: \"+sensors});\nmsg.topic = \"state\";\nmsg.payload = sensors;\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":420,"wires":[["4a1d760d.f2b038"]]},{"id":"4a1d760d.f2b038","type":"function","z":"7cadc4a0.74ec1c","name":"Gate: <1","func":"// Store states and msg based on origin\ncontext.state = context.state || 0;\ncontext.msg = context.msg || {};\nswitch(msg.topic){\n    case \"message\":\n        // save original msg\n        context.msg = msg.payload;\n      break;\n      \n    case \"state\":\n        // save state\n        context.state = msg.payload;\n        break;\n}\n\n// LOGIC GATE -- if no sensors active, then send command.\nif(context.state < 1){\n    node.status({fill:\"green\",shape:\"ring\",text:\"Sent: \"+JSON.stringify(context.msg)}); \n    msg.payload = context.msg;\n    // reset msg\n    context.msg = undefined; \n    return msg.payload; // the payload contains the original msg object\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"Waiting: \"+JSON.stringify(context.msg)}); \n}\n        \n//return msg;","outputs":1,"noerr":0,"x":560,"y":420,"wires":[["e8e28516.a13d88","1e631817.fc9968"]]},{"id":"f3d08745.e4b7f8","type":"rbe","z":"7cadc4a0.74ec1c","name":"","func":"rbe","gap":"","x":270,"y":480,"wires":[["cad742f5.0f6df"]]},{"id":"99258234.9e2cd","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"trackA","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":460,"wires":[["f3d08745.e4b7f8"]]},{"id":"e8e28516.a13d88","type":"debug","z":"7cadc4a0.74ec1c","name":"train forward","active":true,"console":"false","complete":"true","x":750,"y":420,"wires":[]},{"id":"65917631.90cc08","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"trackA","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":500,"wires":[["f3d08745.e4b7f8"]]},{"id":"5d54af4.64fe25","type":"function","z":"7cadc4a0.74ec1c","name":"message","func":"var newMsg = {}\nnewMsg.payload = msg;\nnewMsg.topic = \"message\";\nreturn newMsg;","outputs":1,"noerr":0,"x":380,"y":580,"wires":[["e3a4c8bb.53dcc8"]]},{"id":"72084afc.5c3bc4","type":"function","z":"7cadc4a0.74ec1c","name":"state ","func":"// save state\ncontext.state = context.state || {};\ncontext.state[msg.topic] = msg.payload;\n\n// check all states status\nvar sensors = 0;\nvar keys = Object.keys(context.state);\nfor (var i = 0; i < keys.length; i++) {\n    sensors += context.state[keys[i]];\n}\n\n/*\nif (sensors < 1){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"safe: \"+sensors}); \n    return context.msg;\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"unsafe: \"+sensors});\n}\n*/\n\nnode.status({fill:\"gray\",shape:\"ring\",text:\"Sensors: \"+sensors});\nmsg.topic = \"state\";\nmsg.payload = sensors;\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":620,"wires":[["e3a4c8bb.53dcc8"]]},{"id":"e3a4c8bb.53dcc8","type":"function","z":"7cadc4a0.74ec1c","name":"Gate >= 1","func":"// Store states and msg based on origin\ncontext.state = context.state || 0;\ncontext.msg = context.msg || {};\nswitch(msg.topic){\n    case \"message\":\n        // save original msg\n        context.msg = msg.payload;\n      break;\n      \n    case \"state\":\n        // save state\n        context.state = msg.payload;\n        break;\n}\n\n// LOGIC GATE -- if no sensors active, then send command.\nif(context.state >= 1){\n    node.status({fill:\"green\",shape:\"ring\",text:\"Sent: \"+JSON.stringify(context.msg)}); \n    msg.payload = context.msg;\n    // reset msg\n    context.msg = undefined; \n    return msg.payload; // the payload contains the original msg object\n}else{\n    node.status({fill:\"red\",shape:\"ring\",text:\"Waiting: \"+JSON.stringify(context.msg)}); \n}\n        \n//return msg;","outputs":1,"noerr":0,"x":560,"y":620,"wires":[["7f5a79e4.e89b68","9bac8925.0a2918"]]},{"id":"ebdeaeb1.1fb3","type":"rbe","z":"7cadc4a0.74ec1c","name":"","func":"rbe","gap":"","x":270,"y":680,"wires":[["72084afc.5c3bc4"]]},{"id":"a643b789.2d7758","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"subway","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":660,"wires":[["ebdeaeb1.1fb3"]]},{"id":"1354f75f.587aa9","type":"inject","z":"7cadc4a0.74ec1c","name":"","topic":"subway","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":140,"y":700,"wires":[["ebdeaeb1.1fb3"]]},{"id":"7f5a79e4.e89b68","type":"debug","z":"7cadc4a0.74ec1c","name":"stop at subway","active":true,"console":"false","complete":"true","x":760,"y":620,"wires":[]},{"id":"c0ee4af1.2b76e8","type":"inject","z":"7cadc4a0.74ec1c","name":"cmd","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":620,"wires":[["1e631817.fc9968"]]},{"id":"573b2a96.b82ed4","type":"inject","z":"7cadc4a0.74ec1c","name":"cmd","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":420,"wires":[["acd42b86.03b128"]]},{"id":"192f4d35.7874a3","type":"comment","z":"7cadc4a0.74ec1c","name":"Action","info":"","x":110,"y":40,"wires":[]},{"id":"8ecbd8ca.a6f8b8","type":"comment","z":"7cadc4a0.74ec1c","name":"Condition","info":"","x":560,"y":40,"wires":[]},{"id":"def4c08e.9c879","type":"comment","z":"7cadc4a0.74ec1c","name":"Output","info":"","x":770,"y":40,"wires":[]}]



So, the real question is:

Does this approach make sense? Are there ways to improve this? Is it worth building a standalone node to build these gates?

Cheers,
Cory

Michael Folkerts

unread,
Jun 1, 2016, 4:27:13 PM6/1/16
to Node-RED
Hey guys,
I wanted to let you know that you can store/edit "state" data within a node's context, which is persistent (unless re-deployed or server is restarted):

Perhaps it is simpler to tackle your problem by taking advantage of this feature (this is what I ended up using). Hope this helps.

Best,
Michael
Reply all
Reply to author
Forward
0 new messages