Run through a sequence of commands in order

This should be simple I think, but I am just not getting it. I have a sequence of operations to perform with a delay between each operation.

[ { "index": 1,"channel": 31, "level": 1, "delay": 2 }, { "index": 2,"channel": 35, "level": 1, "delay": 120 }, { "index": 3,"channel": 35, "level": 0, "delay": 2 }, { "index": 4,"channel": 36, "level": 1, "delay": 120 }, { "index": 5,"channel": 36, "level": 0, "delay": 2 }, { "index": 6,"channel": 33, "level": 1, "delay": 120 }, { "index": 7,"channel": 33, "level": 0, "delay": 2 }, { "index": 8,"channel": 31, "level": 0, "delay": 2 } ]

The flow looks like this:


Split the Sequence into separate messages, fill a msg.delay parameter which the variable delay will use, and then print each message.

And the content of the flow:

[{"id":"6243997b.f97288","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"acb0202b.01c01","type":"delay","z":"6243997b.f97288","name":"Variable Delay","pauseType":"delayv","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":700,"y":80,"wires":[["d838f6b5.c42358"]]},{"id":"2e46b9c2.3c88c6","type":"inject","z":"6243997b.f97288","name":"Sequence","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"[{\"index\":1,\"channel\":31,\"level\":1,\"delay\":2},{\"index\":2,\"channel\":35,\"level\":1,\"delay\":120},{\"index\":3,\"channel\":35,\"level\":0,\"delay\":2},{\"index\":4,\"channel\":36,\"level\":1,\"delay\":120},{\"index\":5,\"channel\":36,\"level\":0,\"delay\":2},{\"index\":6,\"channel\":33,\"level\":1,\"delay\":120},{\"index\":7,\"channel\":33,\"level\":0,\"delay\":2},{\"index\":8,\"channel\":31,\"level\":0,\"delay\":2}]","payloadType":"json","x":170,"y":80,"wires":[["fcbb279a.fb3068"]]},{"id":"d838f6b5.c42358","type":"debug","z":"6243997b.f97288","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":890,"y":80,"wires":[]},{"id":"e9f83c3f.22184","type":"function","z":"6243997b.f97288","name":"Fill msg.delay","func":"msg.delay = msg.payload.delay\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":80,"wires":[["acb0202b.01c01"]]},{"id":"fcbb279a.fb3068","type":"split","z":"6243997b.f97288","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":true,"addname":"","x":330,"y":80,"wires":[["e9f83c3f.22184"]]}]

There are two problems with this - first the output order of the messages is sorted which I do not want, the sequence in the input should be left alone. Then the delay between the messages is not being respected. I am assuming it is in seconds, but did test *1000 in case it is ms.

Can someone help me along? Thank you in advance.

On the delay, remember this is not a delay between messages (if you selected Delay Each Message), but a delay for each message. So, for example, if you set the delay to 10 seconds then fed in 5 messages one after the other in quick succession, then the first one will be sent 10 seconds after it was received, and the second will also be sent 10 seconds after it was received, but since it was received only fractions of a second after the first one was received then it will be passed on only fractions of a second after the first one was passed on. If you want to spread messages out then use Rate Limit mode.

On the ordering have you checked to see the order coming out of the split to see if it is what you expect?
[Edit] Possibly the variable delay you are passing in with the messages is causing them to overtake one another, given the fact that the delay node is not working the way you expected.
[Further Edit] In fact looking at your debug output you can see that is exactly what is happening. The messages with a two millisecond delay follow each other (presumably two milliseconds after the inject fires) and the 120 millisecond delayed messages all appear 120 milliseconds later. The delay is in msec as specified in the nodes help text.

Hi Colin, many thanks - you are indeed right about the sorting - the split node is emitting everything in the correct order, it is the delay that is not doing what I want. As a workaround I can achieve what I need by changing the input table into cumulative delays, but maintaining this would be inconvenient.

Modifying the delay to 'rate limit' then separates the messages, but only by a fixed amount, not by a time specified in msg.delay. Any further clues about how this could be done?

there are times when a simple function node is probably the way to go... maybe something like

[{"id":"f6e3025f.2b54d","type":"inject","z":"e8de29e3.0371c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[ { \"index\": 1,\"channel\": 31, \"level\": 1, \"delay\": 2 }, { \"index\": 2,\"channel\": 35, \"level\": 1, \"delay\": 120 }, { \"index\": 3,\"channel\": 35, \"level\": 0, \"delay\": 2 }, { \"index\": 4,\"channel\": 36, \"level\": 1, \"delay\": 120 }, { \"index\": 5,\"channel\": 36, \"level\": 0, \"delay\": 2 }, { \"index\": 6,\"channel\": 33, \"level\": 1, \"delay\": 120 }, { \"index\": 7,\"channel\": 33, \"level\": 0, \"delay\": 2 }, { \"index\": 8,\"channel\": 31, \"level\": 0, \"delay\": 2 } ]","payloadType":"json","x":100,"y":280,"wires":[["2a1a3a38.dc8e56"]]},{"id":"2a1a3a38.dc8e56","type":"function","z":"e8de29e3.0371c8","name":"","func":"var totalDelay = 0;\n\nfor (var i=0; i < msg.payload.length; i++) {\n    totalDelay = totalDelay + msg.payload[i].delay * 1000;\n    setTimeout(function(m) {\n        node.send({payload:m});\n    }, totalDelay, msg.payload[i]);\n}\n\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":300,"y":280,"wires":[["86a39ab5.2ef5a8"]]},{"id":"86a39ab5.2ef5a8","type":"debug","z":"e8de29e3.0371c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":510,"y":280,"wires":[]}]

Many thanks - that looks like it may do the trick. My Javascript is pretty close to zero but the logic is easy enough to follow.

A final big thank you to @dceejay and @Colin. Your solutions really helped. I rewrote the Javascript to send the message and then wait - this keeps the wait-after-send which is a bit cleaner. Should anyone need it you can find here:

[{"id":"d2458496.314588","type":"function","z":"e971d0b3.233c1","name":"sendNodeAndWait","func":"var i = 0;\n\nsendNodeAndWait()\n\nfunction sendNodeAndWait() {\n    if (i == msg.payload.length) { return null; }\n    node.send({payload:msg.payload[i]});\n    setTimeout(sendNodeAndWait, msg.payload[i].delay * 1000);\n    i += 1;\n}\n\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":330,"y":360,"wires":[["cf5bbe91.68daf"]]}]

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.