Help with delay

I am monitoring main power status in a remote place (using a GSM internet connection) and want that if the power outage takes more than a certain delay, a messages is issued. The system has a battery backup so messages still will be sent even if mains are down. My flow example should issue a debug message if a change in payload was detected AND within 5 seconds it has not been reverted back. However it does the opposite, if the payload is reverted back within 5 seconds, it issues a debug. Is this a matter of threading? In the example I've changed the MQTT input by INSERTs, and I'm only using 1 of the three topics which finally should be handled by the flow.

[{"id":"9e5bdacf.6dbba","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"672bef53.d7db1","type":"change","z":"9e5bdacf.6dbba","name":"convert value (up/down to 1/0)","rules":[{"t":"change","p":"payload","pt":"msg","from":"up","fromt":"str","to":"1","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"down","fromt":"str","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":120,"wires":[["47f998e0.8fb31"]]},{"id":"901ea457.178658","type":"function","z":"9e5bdacf.6dbba","name":"Detect changed power status","func":"// define the date the power status change was detected\nvar Trigger_time = new Date();\n\n// fill the previous-state value if this node is run the first time\nif (msg.topic == \"fase1\") {\n    if (context.previous_1 === null) {context.previous_1=msg.payload; return null;}\n}\nif (msg.topic == \"fase2\") {\n    if (context.previous_2 === null) {context.previous_2=msg.payload; return null;}\n}\nif (msg.topic == \"fase3\") {\n    if (context.previous_3 === null) {context.previous_3=msg.payload; return null;}\n}\n\n// pass the message through if it was changed\nif (msg.topic == \"fase1\" && msg.payload !== context.previous_1) {\n    //msg.previous_state=context.previous_1\n    context.previous_1=msg.payload;\n    msg.triggertime=Trigger_time;\n    msg.triggerphase=1;\n    return msg;\n} \nif (msg.topic == \"fase2\" && msg.payload !== context.previous_2) {\n    //msg.previous_state=context.previous_2\n    context.previous_2=msg.payload;\n    msg.triggertime=Trigger_time;\n    msg.triggerphase=2;\n    return msg;\n} \nif (msg.topic == \"fase3\" && msg.payload !== context.previous_3) {\n    //msg.previous_state=context.previous_3\n    context.previous_3=msg.payload; \n    msg.triggertime=Trigger_time;\n    msg.triggerphase=3;\n    return msg;\n} \n\n","outputs":1,"noerr":0,"x":660,"y":180,"wires":[["5d5885a2.6b8b64"]],"info":"This function should pass through messages only if the payload has \nchanged compared to the previous message with the same topic.\n\n"},{"id":"5d5885a2.6b8b64","type":"delay","z":"9e5bdacf.6dbba","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":600,"y":240,"wires":[["3eb8e0b0.91ab"]]},{"id":"2ab09f68.4239e8","type":"function","z":"9e5bdacf.6dbba","name":"block if power is up before end of delay","func":"// if msg.status = raw, set the current value of the device and return nothing\nif (msg.msgstatus == \"raw\") {\n    if(msg.topic == \"fase1\") {context.current_1 = msg.payload; return null;}\n    if(msg.topic == \"fase2\") {context.current_2 = msg.payload; return null;}\n    if(msg.topic == \"fase3\") {context.current_3 = msg.payload; return null;}\n}\n\nif(msg.msgstatus == \"delayed\" ) { \n    if(msg.topic == \"fase1\" && msg.payload === context.current_1) { // the delayed message and the latest value seems to be the same\n        return null; // no need to report\n    } \n    if(msg.topic == \"fase2\" && msg.payload === context.current_2) { // the delayed message and the latest value seems to be the same\n        return null; // no need to report\n    } \n    if(msg.topic == \"fase3\" && msg.payload === context.current_3) { // the delayed message and the latest value seems to be the same\n        return null; // no need to report\n    } \n    // the current payload and the delayed payload are (still) different so a message should be sent\n    return msg;\n}\n\n","outputs":1,"noerr":0,"x":690,"y":360,"wires":[["3daca799.dc8eb8"]]},{"id":"3daca799.dc8eb8","type":"debug","z":"9e5bdacf.6dbba","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1010,"y":360,"wires":[]},{"id":"47f998e0.8fb31","type":"change","z":"9e5bdacf.6dbba","name":"set msgstatus = raw","rules":[{"t":"set","p":"msgstatus","pt":"msg","to":"raw","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":180,"wires":[["2ab09f68.4239e8","901ea457.178658"]]},{"id":"3eb8e0b0.91ab","type":"change","z":"9e5bdacf.6dbba","name":"set msgstatus = delayed","rules":[{"t":"set","p":"msgstatus","pt":"msg","to":"delayed","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":300,"wires":[["2ab09f68.4239e8"]]},{"id":"878a1a3c.c04828","type":"inject","z":"9e5bdacf.6dbba","name":"up","topic":"fase1","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":100,"wires":[["672bef53.d7db1"]]},{"id":"deb20734.0c1d8","type":"inject","z":"9e5bdacf.6dbba","name":"down","topic":"fase1","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":140,"wires":[["672bef53.d7db1"]]}]

The idea is that the function 'block if power is up before end of delay' immediately after a messages ('fase1') arrives stores an updated value representing the current power status (1=up). Simultaneously the function 'Detect change in power status' gets the same message and feeds it to the first function after 5 seconds. There the current status is compared with the delayed message. If they are the same (nothing has changed the last 5 seconds) nothing should be done (return null). If there is a difference (i.e. a new message has arrived with another payload), a messages is passed through to the debug node. If the message is the same, it can also mean that it has changed back and forth within the delay of 5 seconds.
I can't find out why it does not work....

Do you mean "delay" in the literal sense ? The delay node will simply send the message 5 seconds later.

You use the correct word in the function nodes: trigger. The trigger node will help you out here.
I think you can get rid of that complicated contraption with contexts and comparisons by simply using the trigger node.

Hi.

I don't know if this will be of any help.

It isn't I want to "one up" on you, but this is a quick little flow I made.

Ok, it doesn't have the smarts yours has with date/time stamping message, but I am sure you get the idea.

By the way:
That change node - just after the two inject nodes - why?
Just have the up and down buttons inject 1 and 0.

Anyway, that doesn't matter.

Here is my small flow.

[{"id":"22709bd6.adca5c","type":"inject","z":"45831579.1d4494","name":"Up","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":490,"wires":[["fe1fdf6.4b3bea"]]},{"id":"eb09bd5f.0a2928","type":"inject","z":"45831579.1d4494","name":"Down","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":540,"wires":[["fe1fdf6.4b3bea"]]},{"id":"fe1fdf6.4b3bea","type":"trigger","z":"45831579.1d4494","op1":"","op2":"Down","op1type":"nul","op2type":"str","duration":"5","extend":false,"units":"s","reset":"1","bytopic":"all","name":"","x":250,"y":520,"wires":[["4c150237.b0cebc"]]},{"id":"4c150237.b0cebc","type":"debug","z":"45831579.1d4494","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":500,"y":520,"wires":[]}]

(edit)

I'm not (now) sure that is going to work/do what you want.

I was posting to another thread and found I posted what I wanted to go in there here.
So, I maybe posted that code here rather than there.

But, as I know: I may be wrong, and it was meant for here.

This is how I would approach it. Instead of the debug node you can add whatever logic is needed

[{"id":"ce983ec3.2be9f","type":"change","z":"40dc3432.ef2acc","name":"convert value (up/down to 1/0)","rules":[{"t":"change","p":"payload","pt":"msg","from":"up","fromt":"str","to":"1","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"down","fromt":"str","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":660,"wires":[["8b737dd0.a9cea"]]},{"id":"bb8cb2ca.213","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase1","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":540,"wires":[["ce983ec3.2be9f"]]},{"id":"5f995455.bc2c9c","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase1","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":580,"wires":[["ce983ec3.2be9f"]]},{"id":"8b737dd0.a9cea","type":"switch","z":"40dc3432.ef2acc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":400,"y":750,"wires":[["3d5c5a88.7b1cb6"],["8ba6ac78.234b"]]},{"id":"8ba6ac78.234b","type":"trigger","z":"40dc3432.ef2acc","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"5","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":630,"y":800,"wires":[["22408810.b6a9b8"]]},{"id":"3d5c5a88.7b1cb6","type":"change","z":"40dc3432.ef2acc","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":730,"wires":[["8ba6ac78.234b","22408810.b6a9b8"]]},{"id":"22408810.b6a9b8","type":"debug","z":"40dc3432.ef2acc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":880,"y":760,"wires":[]},{"id":"1251d25f.a75e4e","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase2","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":640,"wires":[["ce983ec3.2be9f"]]},{"id":"d24f9d8.7bfd86","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase2","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":680,"wires":[["ce983ec3.2be9f"]]},{"id":"2eeb7e64.0dc922","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase3","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":740,"wires":[["ce983ec3.2be9f"]]},{"id":"7b4764b1.969e6c","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase3","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":780,"wires":[["ce983ec3.2be9f"]]},{"id":"fc07e4b9.879168","type":"comment","z":"40dc3432.ef2acc","name":"Three-phase power monitor","info":"","x":210,"y":480,"wires":[]}]

Or this one, if you would like to suppress duplicate messages

[{"id":"ce983ec3.2be9f","type":"change","z":"40dc3432.ef2acc","name":"convert value (up/down to 1/0)","rules":[{"t":"change","p":"payload","pt":"msg","from":"up","fromt":"str","to":"1","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"down","fromt":"str","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":640,"wires":[["8b737dd0.a9cea"]]},{"id":"bb8cb2ca.213","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase1","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":520,"wires":[["ce983ec3.2be9f"]]},{"id":"5f995455.bc2c9c","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase1","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":560,"wires":[["ce983ec3.2be9f"]]},{"id":"8b737dd0.a9cea","type":"switch","z":"40dc3432.ef2acc","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":390,"y":750,"wires":[["3d5c5a88.7b1cb6"],["8ba6ac78.234b"]]},{"id":"8ba6ac78.234b","type":"trigger","z":"40dc3432.ef2acc","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"5","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":620,"y":790,"wires":[["aacf96e5.5a2428"]]},{"id":"3d5c5a88.7b1cb6","type":"change","z":"40dc3432.ef2acc","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":710,"wires":[["8ba6ac78.234b","dbf3e1e2.7dc86"]]},{"id":"22408810.b6a9b8","type":"debug","z":"40dc3432.ef2acc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":870,"y":870,"wires":[]},{"id":"1251d25f.a75e4e","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase2","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":620,"wires":[["ce983ec3.2be9f"]]},{"id":"d24f9d8.7bfd86","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase2","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":660,"wires":[["ce983ec3.2be9f"]]},{"id":"2eeb7e64.0dc922","type":"inject","z":"40dc3432.ef2acc","name":"up","topic":"fase3","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":720,"wires":[["ce983ec3.2be9f"]]},{"id":"7b4764b1.969e6c","type":"inject","z":"40dc3432.ef2acc","name":"down","topic":"fase3","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":760,"wires":[["ce983ec3.2be9f"]]},{"id":"fc07e4b9.879168","type":"comment","z":"40dc3432.ef2acc","name":"Three-phase power monitor","info":"","x":200,"y":460,"wires":[]},{"id":"aacf96e5.5a2428","type":"rbe","z":"40dc3432.ef2acc","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":870,"y":790,"wires":[["22408810.b6a9b8"]]},{"id":"dbf3e1e2.7dc86","type":"change","z":"40dc3432.ef2acc","name":"","rules":[{"t":"delete","p":"reset","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":880,"y":710,"wires":[["aacf96e5.5a2428"]]}]

Dear all, thanks for thinking with me. I've tested all options. The last suggestion of krambriw comes closest to what I need. Translated in words:

  1. if up (1) is sent, nothing happens. Switch 1 sends the msg to change:set msg.reset, which resets the trigger, change:delete msg.reset converts msg back to original and msg is fed to rbe, rbe does nothing as long as up is sent repeatedly
  2. if down (0) is sent (after signal has been up), switch 1 sends the msg to the trigger, which holds it for 5 seconds. If nothing happens, it is unmodified passed through to rbe, which senses a change and forwards msg to debug
  3. if, after down, within 5 seconds, up is sent again change:msg.reset sends reset to trigger (which cancelles the down msg) and forwards up to change:delete msg.reset so the msg which arrives at rbe does not trigger a 'change'.

I've made a small modification (I love functions :wink: ):

[{"id":"dbfe1c6f.7a7c08","type":"change","z":"9e5bdacf.6dbba","name":"convert value (up/down to 1/0)","rules":[{"t":"change","p":"payload","pt":"msg","from":"up","fromt":"str","to":"1","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"down","fromt":"str","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":1440,"wires":[["184d3646.729e9a"]]},{"id":"c5570ee4.6b5d4","type":"inject","z":"9e5bdacf.6dbba","name":"up","topic":"fase1","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1320,"wires":[["dbfe1c6f.7a7c08"]]},{"id":"2db849c6.1562ce","type":"inject","z":"9e5bdacf.6dbba","name":"down","topic":"fase1","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1360,"wires":[["dbfe1c6f.7a7c08"]]},{"id":"184d3646.729e9a","type":"switch","z":"9e5bdacf.6dbba","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":510,"y":1520,"wires":[["e84c6d9c.ef39b8"],["c8af9838.b09bc"]]},{"id":"c8af9838.b09bc","type":"trigger","z":"9e5bdacf.6dbba","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"2","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":760,"y":1580,"wires":[["bad13db0.b3c6e8"]]},{"id":"28d289dc.748fe6","type":"debug","z":"9e5bdacf.6dbba","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1210,"y":1540,"wires":[]},{"id":"e84c6d9c.ef39b8","type":"function","z":"9e5bdacf.6dbba","name":"Send up to trigger and reset down","func":"const msgn = RED.util.cloneMessage(msg);\nmsgn.reset = true;\n\nreturn [msg, msgn];","outputs":2,"noerr":0,"x":780,"y":1500,"wires":[["bad13db0.b3c6e8"],["c8af9838.b09bc"]]},{"id":"bad13db0.b3c6e8","type":"rbe","z":"9e5bdacf.6dbba","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1070,"y":1540,"wires":[["28d289dc.748fe6"]]},{"id":"1942df3e.802859","type":"inject","z":"9e5bdacf.6dbba","name":"up","topic":"fase2","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1420,"wires":[["dbfe1c6f.7a7c08"]]},{"id":"55e36ed5.fac3a","type":"inject","z":"9e5bdacf.6dbba","name":"down","topic":"fase2","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1460,"wires":[["dbfe1c6f.7a7c08"]]},{"id":"1df6f7cb.01fff","type":"inject","z":"9e5bdacf.6dbba","name":"up","topic":"fase3","payload":"up","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1520,"wires":[["dbfe1c6f.7a7c08"]]},{"id":"3679476e.6fcad8","type":"inject","z":"9e5bdacf.6dbba","name":"down","topic":"fase3","payload":"down","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":1560,"wires":[["dbfe1c6f.7a7c08"]]}]

And actually, instead of the trigger also a delay can be used, but trigger may be cleaner as you can define what happens if new messages arrive. I'm not sure however if this is important in this case.

Thanks again!

This is purely academic, the flow below is even leaner, just using "standard" nodes. In your flow, the function node does the same of course but it is not really necessary to use a function node unless for other unknown reasons

You also don't need the set msg.reset as you can tell the trigger to use a payload of 1 to reset..

1 Like

Oh yes, of course, very nice tuning indeed!!!