Help with contexts please

Hi there, I'm new to Node-Red, I'm having fun ! :blush: $

Please advice : I'm trying to create a programmable and resettable timer. I'm using the node-red-contrib-loop-processing nodes.

image

The counter works, but if I use the inject node a second time (to restart the counter) I see that there is actually a second counter running. I understand that it is related to a second _msgid and that I should create a global or flow variable but I don't understand how.

Could someone put me on the right track ?

Thanks

Matthieu

can you post your flow code please?


that would be great
Johannes

Sure, thanks !

Here you are :

[{"id":"bab1d11c.c9df7","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"27bad9ee.78950e","type":"inject","z":"bab1d11c.c9df7","name":"","topic":"","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":270,"y":260,"wires":[["e69d0cba.2a1168"]]},{"id":"36c3bd3f.70bf42","type":"delay","z":"bab1d11c.c9df7","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":620,"y":340,"wires":[["e69d0cba.2a1168"]]},{"id":"b7650339.95175","type":"ui_text","z":"bab1d11c.c9df7","group":"232a7e45.e895ea","order":1,"width":0,"height":0,"name":"","label":"Counter = ","format":"{{msg.payload}}","layout":"row-spread","x":740,"y":200,"wires":[]},{"id":"4444d80f.c7693","type":"debug","z":"bab1d11c.c9df7","name":"DONE","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":730,"y":260,"wires":[]},{"id":"e69d0cba.2a1168","type":"while-loop","z":"bab1d11c.c9df7","name":"","condi":"msg.payload == 0","x":510,"y":260,"wires":[["2735fb45.ca497c","b7650339.95175"],["4444d80f.c7693"]]},{"id":"2735fb45.ca497c","type":"change","z":"bab1d11c.c9df7","name":"decrement payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload - 1","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":340,"wires":[["36c3bd3f.70bf42"]]},{"id":"232a7e45.e895ea","type":"ui_group","name":"Group 1","tab":"6efc8e67.a67ff8","order":1,"disp":true,"width":6},{"id":"6efc8e67.a67ff8","type":"ui_tab","name":"Tab 2","icon":"dashboard","order":1}]

Try this, just after the inject node, add a change node and set global.counter to 0

Thanks ! I guess you mean setting global.counter to msg.payload ?

I tried this :

[{"id":"bab1d11c.c9df7","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"27bad9ee.78950e","type":"inject","z":"bab1d11c.c9df7","name":"","topic":"","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":240,"wires":[["c51871cc.9de9a"]]},{"id":"36c3bd3f.70bf42","type":"delay","z":"bab1d11c.c9df7","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":620,"y":340,"wires":[["e69d0cba.2a1168"]]},{"id":"b7650339.95175","type":"ui_text","z":"bab1d11c.c9df7","group":"232a7e45.e895ea","order":1,"width":0,"height":0,"name":"","label":"Counter = ","format":"{{msg.payload}}","layout":"row-spread","x":880,"y":180,"wires":[]},{"id":"4444d80f.c7693","type":"debug","z":"bab1d11c.c9df7","name":"DONE","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":730,"y":260,"wires":[]},{"id":"e69d0cba.2a1168","type":"while-loop","z":"bab1d11c.c9df7","name":"","condi":"global.counter == 0","x":510,"y":260,"wires":[["2735fb45.ca497c","dfb489e0.84369"],["4444d80f.c7693"]]},{"id":"2735fb45.ca497c","type":"change","z":"bab1d11c.c9df7","name":"decrement counter","rules":[{"t":"set","p":"counter","pt":"global","to":"gobal.counter - 1","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":340,"wires":[["36c3bd3f.70bf42"]]},{"id":"c51871cc.9de9a","type":"change","z":"bab1d11c.c9df7","name":"msg.payload --> global.counter","rules":[{"t":"set","p":"counter","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":240,"wires":[["e69d0cba.2a1168"]]},{"id":"dfb489e0.84369","type":"change","z":"bab1d11c.c9df7","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"counter","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":180,"wires":[["b7650339.95175","acde071e.1280d8"]]},{"id":"acde071e.1280d8","type":"debug","z":"bab1d11c.c9df7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":900,"y":140,"wires":[]},{"id":"232a7e45.e895ea","type":"ui_group","name":"Group 1","tab":"6efc8e67.a67ff8","order":1,"disp":true,"width":6},{"id":"6efc8e67.a67ff8","type":"ui_tab","name":"Tab 2","icon":"dashboard","order":1}]

But it looks like global.counter is not even created.

Nope, set global.counter to 0
Screen Shot 2020-03-25 at 5.11.27 AM
this should reset the counter used the loop node

Thanks @zenofmud ! It works ! How did you know that this variable was used by the while loop node ?

Saw it to late that @zenofmud already answered your question . But have a look at a different approach using a function node i wrote in the mean time anyway:

[{"id":"e55319fd.75bac","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":780,"wires":[["f07ada4b.c33cb8"]]},{"id":"c1fd7048.fbcb48","type":"delay","z":"f954564f.03e718","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":520,"y":840,"wires":[["f07ada4b.c33cb8"]]},{"id":"f07ada4b.c33cb8","type":"function","z":"f954564f.03e718","name":"decrement","func":"const previouspayload = context.get(\"previous_payload\");\nif(msg.topic == \"start\" && msg.payload != previouspayload){\n    msg.topic = \"counting\";\n    context.set(\"startvalue\", msg.payload);\n    context.set(\"previous_payload\", msg.payload);\n    context.set(\"newcount\", true);\n    return [msg, msg];\n} else if(msg.topic == \"counting\" && msg.payload > 1){\n    const startvalue = context.get(\"startvalue\");\n    const newcount = context.get(\"newcount\");\n    let countvalue = previouspayload;\n    if(newcount && msg.payload != countvalue) return null;\n    context.set(\"newcount\", false);\n    msg.payload = countvalue - 1;\n    context.set(\"previous_payload\", msg.payload);\n    return [msg, msg];\n} else if(msg.payload == 1){\n    msg.payload = \"finished\";\n    return [msg, null];\n}","outputs":2,"noerr":0,"x":510,"y":780,"wires":[["c3bf3c62.ac62a"],["c1fd7048.fbcb48"]]},{"id":"c3bf3c62.ac62a","type":"debug","z":"f954564f.03e718","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":780,"wires":[]},{"id":"ccff5a19.ae50c8","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"11","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":840,"wires":[["f07ada4b.c33cb8"]]},{"id":"ee085092.8ec72","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"16","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":720,"wires":[["f07ada4b.c33cb8"]]}]

you can throw any number with a msg.topic of start at this and it will countdown. It will start a new countdown if it receives a new number with a start topic and only ever does one count at a time.
Best regards Johannes

Actually my solution doesn't work. The author of the node should impliment some way to break out of the node (I added an RFE to the GitHub of the node)

1 Like

I added a stop function to mine

[{"id":"e55319fd.75bac","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"22","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":570,"y":700,"wires":[["f07ada4b.c33cb8"]]},{"id":"c1fd7048.fbcb48","type":"delay","z":"f954564f.03e718","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":860,"y":760,"wires":[["f07ada4b.c33cb8"]]},{"id":"f07ada4b.c33cb8","type":"function","z":"f954564f.03e718","name":"decrement","func":"const previouspayload = context.get(\"previous_payload\");\nconst stop = context.get(\"stop\") || false;\nif(msg.payload == \"stop\"){\n    context.set(\"stop\", true);\n    return [msg, null];\n} else if(msg.topic == \"start\" && msg.payload != previouspayload){\n    msg.topic = \"counting\";\n    context.set(\"startvalue\", parseFloat(msg.payload));\n    context.set(\"previous_payload\", parseFloat(msg.payload));\n    context.set(\"newcount\", true);\n    context.set(\"stop\", false);\n    return [msg, msg];\n} else if(msg.topic == \"counting\" && msg.payload > 1 && !stop){\n    const startvalue = context.get(\"startvalue\");\n    const newcount = context.get(\"newcount\");\n    let countvalue = previouspayload;\n    if(newcount && msg.payload != countvalue) return null;\n    context.set(\"newcount\", false);\n    msg.payload = countvalue - 1;\n    context.set(\"previous_payload\", msg.payload);\n    return [msg, msg];\n} else if(msg.payload == 1 && !stop){\n    msg.payload = \"finished\";\n    return [msg, null];\n}","outputs":2,"noerr":0,"x":850,"y":700,"wires":[["c3bf3c62.ac62a"],["c1fd7048.fbcb48"]]},{"id":"c3bf3c62.ac62a","type":"debug","z":"f954564f.03e718","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1110,"y":700,"wires":[]},{"id":"ccff5a19.ae50c8","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"11","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":570,"y":760,"wires":[["f07ada4b.c33cb8"]]},{"id":"ee085092.8ec72","type":"inject","z":"f954564f.03e718","name":"","topic":"start","payload":"16","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":570,"y":640,"wires":[["f07ada4b.c33cb8"]]},{"id":"9b97d08b.29d83","type":"inject","z":"f954564f.03e718","name":"","topic":"","payload":"stop","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":570,"y":820,"wires":[["f07ada4b.c33cb8"]]}]

if you send a msg.payload of "stop" the running counter will be stopped

1 Like

Thanks so much both of you ! I'll use your function node @JGKK :blush: I like to avoid function nodes for readability but in this case this looks the way to go.

1 Like

Here is one with ui:


[{"id":"c1fd7048.fbcb48","type":"delay","z":"f954564f.03e718","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":460,"y":760,"wires":[["f07ada4b.c33cb8"]]},{"id":"f07ada4b.c33cb8","type":"function","z":"f954564f.03e718","name":"decrement","func":"const previouspayload = context.get(\"previous_payload\");\nconst stop = context.get(\"stop\") || false;\nif(msg.payload == \"stop\"){\n    context.set(\"stop\", true);\n    msg.payload = \"stopped\";\n    return [msg, null];\n} else if(msg.topic == \"start\" && msg.payload != previouspayload){\n    msg.topic = \"counting\";\n    context.set(\"previous_payload\", parseFloat(msg.payload));\n    context.set(\"newcount\", true);\n    context.set(\"stop\", false);\n    return [msg, msg];\n} else if(msg.topic == \"counting\" && msg.payload > 1 && !stop){\n    const newcount = context.get(\"newcount\");\n    let countvalue = previouspayload;\n    if(newcount && msg.payload != countvalue) return null;\n    context.set(\"newcount\", false);\n    msg.payload = countvalue - 1;\n    context.set(\"previous_payload\", msg.payload);\n    return [msg, msg];\n} else if(msg.payload == 1 && !stop){\n    msg.payload = \"finished\";\n    return [msg, null];\n}","outputs":2,"noerr":0,"x":450,"y":700,"wires":[["757c3701.47806"],["c1fd7048.fbcb48"]]},{"id":"78a83b75.26d8c4","type":"ui_numeric","z":"f954564f.03e718","name":"","label":"set start count","tooltip":"","group":"d619b4d0.780aa8","order":1,"width":0,"height":0,"wrap":false,"passthru":false,"topic":"","format":"{{msg.payload}}","min":0,"max":"100","step":1,"x":160,"y":580,"wires":[["463c0cad.ce804c"]]},{"id":"c99a569d.8a0998","type":"ui_button","z":"f954564f.03e718","name":"","group":"d619b4d0.780aa8","order":2,"width":0,"height":0,"passthru":false,"label":"start countdown","tooltip":"","color":"","bgcolor":"","icon":"","payload":"startcount","payloadType":"flow","topic":"start","x":160,"y":700,"wires":[["f07ada4b.c33cb8","1ac5dad4.5007ed"]]},{"id":"463c0cad.ce804c","type":"change","z":"f954564f.03e718","name":"","rules":[{"t":"set","p":"startcount","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":580,"wires":[[]]},{"id":"757c3701.47806","type":"ui_text","z":"f954564f.03e718","group":"d619b4d0.780aa8","order":3,"width":0,"height":0,"name":"","label":"Countdown","format":"{{msg.payload}}","layout":"row-spread","x":630,"y":700,"wires":[]},{"id":"1ac5dad4.5007ed","type":"change","z":"f954564f.03e718","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":640,"wires":[["78a83b75.26d8c4"]]},{"id":"cdc32fdf.291988","type":"ui_button","z":"f954564f.03e718","name":"","group":"d619b4d0.780aa8","order":4,"width":0,"height":0,"passthru":false,"label":"Stop countdown","tooltip":"","color":"","bgcolor":"","icon":"","payload":"stop","payloadType":"str","topic":"","x":170,"y":780,"wires":[["f07ada4b.c33cb8"]]},{"id":"d619b4d0.780aa8","type":"ui_group","z":"","name":"Countdown","tab":"b2566dcf.0415","order":2,"disp":true,"width":"6","collapse":false},{"id":"b2566dcf.0415","type":"ui_tab","z":"","name":"Countdown","icon":"dashboard","order":2,"disabled":false,"hidden":false}]
2 Likes