How can i build a random delayed trigger loop?

#1

hello,
i have the intention to fill a chart with random data.
it shall simulate if people done a task it appear in a chart.
i have no sucecss with inject & delay node. (at least my chart looks linear slope)
i need a trigger that send a message random between 1-10 minutes and after the delay
it create a new random delay and send new message all day long.

0 Likes

#2

Try this :slight_smile:

[{"id":"5e55e393.3c7b3c","type":"delay","z":"6c2991c6.f2285","name":"","pauseType":"delayv","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"5","randomLast":"10","randomUnits":"seconds","drop":false,"x":520,"y":360,"wires":[["c4c706c8.3fa4c8","a0367298.d3914"]]},{"id":"7abe9d2b.6ca824","type":"inject","z":"6c2991c6.f2285","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":300,"y":300,"wires":[["a0367298.d3914"]]},{"id":"c4c706c8.3fa4c8","type":"debug","z":"6c2991c6.f2285","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":730,"y":360,"wires":[]},{"id":"a0367298.d3914","type":"change","z":"6c2991c6.f2285","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"$floor($random()*600000)","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$floor($random()*10)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":300,"wires":[["5e55e393.3c7b3c"]]}]

2 Likes

#3

thank you, i build it in

0 Likes

#4

Nice, but I would suggest a reset input, just in case you don't really want it to run forever.

[{"id":"81fa9f84.c2ef3","type":"change","z":"f3a075a0.2b2ae","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":120,"wires":[["3fac4536.38e1d2"]]},{"id":"3fac4536.38e1d2","type":"delay","z":"f3a075a0.2b2ae","name":"","pauseType":"delayv","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"5","randomLast":"10","randomUnits":"seconds","drop":false,"x":540,"y":120,"wires":[["3d9011e2.9a279e","3888711f.dad256"]]},{"id":"16d5b50f.05f7bb","type":"inject","z":"f3a075a0.2b2ae","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":320,"y":60,"wires":[["3888711f.dad256"]]},{"id":"3d9011e2.9a279e","type":"debug","z":"f3a075a0.2b2ae","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":770,"y":120,"wires":[]},{"id":"3888711f.dad256","type":"change","z":"f3a075a0.2b2ae","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"$floor($random()*600000)","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$floor($random()*10)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":60,"wires":[["3fac4536.38e1d2"]]},{"id":"aad6f390.80961","type":"inject","z":"f3a075a0.2b2ae","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":120,"wires":[["81fa9f84.c2ef3"]]}]
``
0 Likes

#5

I just tried to stay in scope of issue. For full solution I think there is much more needed of course.

0 Likes

#6

thanks for the reset hint.

my current solution:

[{"id":"3716c275.fcba66","type":"subflow","name":"jobs simulation","info":"","category":"","in":[{"x":100,"y":120,"wires":[{"id":"d8b4ec33.0ea608"}]}],"out":[{"x":1180,"y":240,"wires":[{"id":"b93c39d1.206018","port":0}]}]},{"id":"b93c39d1.206018","type":"delay","z":"3716c275.fcba66","name":"","pauseType":"random","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"5","randomLast":"45","randomUnits":"seconds","drop":false,"x":980,"y":240,"wires":[["d8b4ec33.0ea608"]]},{"id":"d8b4ec33.0ea608","type":"delay","z":"3716c275.fcba66","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":240,"y":120,"wires":[["e1e866a1.ee1a"]]},{"id":"cf70b3a4.37554","type":"function","z":"3716c275.fcba66","name":"working hours","func":"var d = new Date();\nvar h = d.getHours();\nif (msg.do=="yes") {\n if (h>=8 && h<=17){\n } else {\n msg.do=="no" \n }\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":600,"y":260,"wires":[["2330084b.7b17d"]]},{"id":"e1e866a1.ee1a","type":"function","z":"3716c275.fcba66","name":"work days","func":"var d = new Date();\n// 0 Sunday\n// 1 Monday\n// 2 Tuesday\n// 3 Wednesday\n// 4 Thursday\n// 5 Friday\n// 6 Saturday\nvar day = d.getDay();\nif (day>=1 && day<=6){\n msg.do="yes";\n} else {\n msg.do="no";\n}\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":260,"wires":[["cf70b3a4.37554"]]},{"id":"2330084b.7b17d","type":"switch","z":"3716c275.fcba66","name":"","property":"do","propertyType":"msg","rules":[{"t":"eq","v":"no","vt":"str"},{"t":"eq","v":"yes","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":770,"y":260,"wires":[["d8b4ec33.0ea608"],["b93c39d1.206018"]],"outputLabels":["no","yes"]},{"id":"33cd4306.9cbb14","type":"comment","z":"3716c275.fcba66","name":"jobs simulation","info":"created by M.Rauch 10/2018\n\nit have a clock\nthen the work days are checked\nthen the working hours are checked\nif not at work the clock ticks\nif at work then the delay simulate a task\n","x":120,"y":40,"wires":[]}]

0 Likes

#7

In case anyone is still interested, this flow will generate the sort of random events that @MarkusR wants, using only a single function node and no feedback loop. It also illustrates what a pain JavaScript can be (at least for me) when what you want is synchronous execution. I was already working on something similar, so it was worth the effort, but if anyone can suggest less ugly code I would be grateful.

[{"id":"13c7f4da.98d3bb","type":"function","z":"9b4deac7.469e4","name":"","func":"const minDelay = 1, maxDelay =5; // seconds\nvar run = context.get('state') || false;\nif (msg.topic.toLowerCase() === 'control') {\n    run = ! run;\n}\ncontext.set('state',run);\nnode.status({fill:(run) ? 'green':'red'});\nif (run) {\n    randomDelay(maxDelay,minDelay);\n    node.status({fill:'green',text:delay.toFixed(2)});\n}\n\nfunction randomDelay(max,min) {\n    delay = Math.random() * (max - min) + min;\n    setTimeout(sendMessages,1000 * delay);\n    msg.delay = delay;\n    return delay;\n}\n\nfunction sendMessages() {\n    node.send(msg);\n    run = context.get('state');\n    if (run) {\n        randomDelay(maxDelay,minDelay);\n        node.status({fill:'green',text:delay.toFixed(2)});\n    }\n}\n","outputs":1,"noerr":0,"x":530,"y":500,"wires":[["f2d3395f.8d1ad8"]]},{"id":"48ab97b.5d78868","type":"inject","z":"9b4deac7.469e4","name":"start/stop","topic":"control","payload":"random trigger","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":400,"y":500,"wires":[["13c7f4da.98d3bb"]]},{"id":"f2d3395f.8d1ad8","type":"debug","z":"9b4deac7.469e4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":650,"y":500,"wires":[]}]
0 Likes

#8

Here is a way of refactoring the loop to make it a bit neater.

[{"id":"f6d5dfd7.84ec5","type":"function","z":"6dc690a3.1abc88","name":"","func":"const minDelay = 1, maxDelay =5; // seconds\nvar run = context.get('state') || false;\nif (msg.topic.toLowerCase() === 'control') {\n    run = ! run;\n}\ncontext.set('state',run);\nnode.status({fill:(run) ? 'green':'red'});\n\nvar msgToSend = null;\nloop();\nreturn null;\n\nfunction loop() {\n    if (context.get('state')) {\n        node.send(msgToSend);\n        msgToSend = msg;\n        let delay = Math.random() * (maxDelay - minDelay) + minDelay;\n        setTimeout(loop,1000 * delay);\n        node.status({fill:'green',text:delay.toFixed(2)});\n    }\n}\n","outputs":1,"noerr":0,"x":320,"y":209,"wires":[["9e9ea6e4.a82078"]]},{"id":"7defb913.a1ebe","type":"inject","z":"6dc690a3.1abc88","name":"start/stop","topic":"control","payload":"random trigger","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":209,"wires":[["f6d5dfd7.84ec5"]]},{"id":"9e9ea6e4.a82078","type":"debug","z":"6dc690a3.1abc88","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":440,"y":209,"wires":[]}]
0 Likes

#9

also posted here HTTP GET request for data and post to website

0 Likes

#10

You could use a dsm node:

[{"id":"a26cd0b7.90aef","type":"dsm","z":"66646ca8.e97654","name":"random trigger","sm_config":"{\n    \"currentState\": \"stopped\",\n    \"states\": {\n        \"stopped\": {\n            \"start\": \"running\"\n        },\n        \"running\": {\n            \"running\": \"running\",\n            \"stop\": \"stopped\"\n        }\n    },\n    \"data\": {\n        \"minDelay\": 1,\n        \"maxDelay\": 5\n    },\n    \"methods\": {\n        \"start\": [\n            \"resume('running', msg);\"\n        ],\n        \"running\": [\n            \"sm.delay = Math.random() * (sm.data.maxDelay - sm.data.minDelay) + sm.data.minDelay;\",\n            \"msg.delay = 'delay '+ sm.delay.toFixed(2);\",\n            \"timeout.delay = setTimeout(function() {\",\n            \"   node.send(msg);\",\n            \"   resume('running',msg);\",\n            \"},sm.delay*1000);\"\n        ],\n        \"stop\": [\n            \"clearTimeout(timeout.delay);\",\n            \"msg.delay = 'stopped';\"\n        ],\n        \"onTransition\": [\n            \"output = false;\"\n        ],\n        \"status\": {\n            \"fill\": {\n                \"get\": \"sm.currentState === 'running' ? 'green' : 'red';\"\n            },\n            \"shape\": \"dot\",\n            \"text\": {\n                \"get\": \"msg.delay;\"\n            }\n        }\n    }\n}","x":330,"y":320,"wires":[["fdb8b530.787a38"]]},{"id":"c78a24cc.f507f8","type":"inject","z":"66646ca8.e97654","name":"start","topic":"start","payload":"random trigger","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":320,"wires":[["a26cd0b7.90aef"]]},{"id":"fdb8b530.787a38","type":"debug","z":"66646ca8.e97654","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":490,"y":320,"wires":[]},{"id":"894976da.9dfca8","type":"inject","z":"66646ca8.e97654","name":"stop","topic":"stop","payload":"random trigger","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":360,"wires":[["a26cd0b7.90aef"]]}]
0 Likes

Node-red-contrib-dsm
#11

@Colin, thanks! That certainly is neater -- and just the sort of help I'll need if I am ever going to get really comfortable with JavaScript. I have coded in at least a dozen high-level languages since the mid-1970's, and JS may not be the most difficult or opaque, but somehow I find it the most annoying...

0 Likes

#12

@cflurin That's a really nice solution to the problem. At one time, finite state machines were my bread and butter, so I've looked for opportunities to use your node. Unfortunately, I haven't done much with it for a couple of reasons. One is the learning curve associated with the JSON objects used for programming the node, and the other is that in debugging it is sometimes hard to see the connection between JS error messages and syntax errors in the configuration. I think I will give it another try.

BTW, have you considered developing an edit window that would let the user define the states and transition table with text entry boxes and pull-down menus? Perhaps actions could then be entered simply as blocks of JS code. All this would still be translated into JSON in the background, but the ui might be more accessible to a beginner.

0 Likes

#13

@drmibell: Thanks for your feedback, your answer is dsm specific, so I moved to node-red-contrib-dsm Node-red-contrib-dsm

0 Likes