We are struggling with this for quite a while now. I found a cool way here by @dceejay (see first example flow below). However, because we are using link in
and link out
nodes, the messages arrive in wrong order at the delay node and the loop does not restart. And I am not sure about the switch node either (if it’s deterministic). But without link nodes it worked well.
[{"id":"13bbb7508b3bb572","type":"switch","z":"3dfe0c63f0cf19d7","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"reset","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":440,"y":300,"wires":[["b987a4a6e324e26a"],["f5fc3d878dd4c32f"]]},{"id":"d49fa8ce1f5bca4f","type":"function","z":"3dfe0c63f0cf19d7","name":"reset","func":"msg.topic = \"should come after reset\";\nreturn [[{reset: true, topic: \"reset\"},msg]];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":300,"wires":[["13bbb7508b3bb572"]]},{"id":"49fdbec74d480310","type":"inject","z":"3dfe0c63f0cf19d7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":200,"y":300,"wires":[["d49fa8ce1f5bca4f"]]},{"id":"b987a4a6e324e26a","type":"link out","z":"3dfe0c63f0cf19d7","name":"reset timer","links":["c2038469c0ba3306"],"x":555,"y":250,"wires":[]},{"id":"c2038469c0ba3306","type":"link in","z":"3dfe0c63f0cf19d7","name":"reset timer","links":["b987a4a6e324e26a"],"x":675,"y":250,"wires":[["987e20e6877a3177","c7af6cf407200e12"]]},{"id":"987e20e6877a3177","type":"delay","z":"3dfe0c63f0cf19d7","name":"","pauseType":"delayv","timeout":"2.5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":870,"y":350,"wires":[["12910a1494edce46"]]},{"id":"f5fc3d878dd4c32f","type":"change","z":"3dfe0c63f0cf19d7","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"2500","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":350,"wires":[["987e20e6877a3177","c7af6cf407200e12"]]},{"id":"c7af6cf407200e12","type":"debug","z":"3dfe0c63f0cf19d7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":860,"y":250,"wires":[]},{"id":"12910a1494edce46","type":"function","z":"3dfe0c63f0cf19d7","name":"do something","func":"return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050,"y":350,"wires":[["987e20e6877a3177"]]}]
Our current solution (see second example flow below): We just use an extra delay node to make sure, the reset command arrives first (before the restart message). I am sure there's a more elegant and shorter way. The reset procedure gets quite complicated because we do have three delay nodes in our loop (with dynamic delay time).
[{"id":"d98df5cb5546faf3","type":"switch","z":"3dfe0c63f0cf19d7","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"reset","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":360,"y":640,"wires":[["f263ba15d8efa8bb"],["122585f51bb77468"]]},{"id":"2c208884d3b86217","type":"function","z":"3dfe0c63f0cf19d7","name":"reset","func":"msg.topic = \"should come after reset\";\nreturn [[{payload: \"blub\", topic: \"reset\"},msg]];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":640,"wires":[["d98df5cb5546faf3"]]},{"id":"b1b58aecb8d9920a","type":"inject","z":"3dfe0c63f0cf19d7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":120,"y":640,"wires":[["2c208884d3b86217"]]},{"id":"f263ba15d8efa8bb","type":"link out","z":"3dfe0c63f0cf19d7","name":"reset timer","links":["9daedb40f8e87c45"],"x":465,"y":590,"wires":[]},{"id":"9daedb40f8e87c45","type":"link in","z":"3dfe0c63f0cf19d7","name":"reset timer","links":["f263ba15d8efa8bb"],"x":615,"y":590,"wires":[["1688e141bdbbc996"]]},{"id":"5a60a576632f60e8","type":"delay","z":"3dfe0c63f0cf19d7","name":"","pauseType":"delayv","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":990,"y":640,"wires":[["607f32fae5f53c3f","d43a8864b16c4803"]]},{"id":"1688e141bdbbc996","type":"change","z":"3dfe0c63f0cf19d7","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":590,"wires":[["5a60a576632f60e8","607f32fae5f53c3f"]]},{"id":"122585f51bb77468","type":"delay","z":"3dfe0c63f0cf19d7","name":"delay restart (15)","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":540,"y":690,"wires":[["95eb9c2c66e8b992"]]},{"id":"95eb9c2c66e8b992","type":"change","z":"3dfe0c63f0cf19d7","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"2500","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":690,"wires":[["5a60a576632f60e8"]]},{"id":"607f32fae5f53c3f","type":"debug","z":"3dfe0c63f0cf19d7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1160,"y":590,"wires":[]},{"id":"d43a8864b16c4803","type":"function","z":"3dfe0c63f0cf19d7","name":"do something","func":"return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1190,"y":640,"wires":[["5a60a576632f60e8"]]}]
We even got rid of the loop and used a node called node-red-contrib-controltimer
. However, that node does not allow dynamic delays (yet). So back to square one.
We would be happy if someone could guide us in the right direction. Feel free to ask questions if something is unclear.