Strange Behavior between calling a JS script manually or in a loop

Hi all,
i create a flow with a javascript code that convert a number to binary (6 numbers) and based on 1 or 0 poweron/poweroff 6 switches and wait 3 seconds for 64 cycles (2^6 possibilities) and then reset to 1

All works fine if i manually click on a inject. I create a loop connecting the delay to the js function and it start to work ok for about 5-6 loops and then it start to put random numbers blocking the nodered instance.

Someone can help me to solve?

This is the basic flow

[{"id":"15056c5e.4b8594","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"247a86f7.e101c2","type":"function","z":"15056c5e.4b8594","name":"","func":"var count = context.get('count')||1;\nvar i = context.get('i')||1;\nvar first = context.get('first')||1;\n\n\n//count = i * count;\nif ((count *2) > 62) {\n\ti += 2;\n\tif (i > 64) { i = 2; } //reset\n    count = 1;\n\tcount = i * count;\n    }\n\telse { \n\t    if (first == 1) { \n\t        count = 1; \n\t        first = 2;\n\t    } else { count = count * 2; }}\n\t\nvar res = count.toString(2).padStart(6,\"0\");\n\n// store the value back\t\ncontext.set('count',count);\ncontext.set('i',i);\ncontext.set('first',first);\n\n//LSB\n\nvar msg6 = { payload: res.substring(0, 1) };\nvar msg5 = { payload: res.substring(1, 2) };\nvar msg4 = { payload: res.substring(2, 3) };\nvar msg3 = { payload: res.substring(3, 4) };\nvar msg2 = { payload: res.substring(4, 5) };\nvar msg1 = { payload: res.substring(5, 6) };\n\nvar msgG = { payload: res };\n\nreturn [msg1,msg2,msg3,msg4,msg5,msg6,msgG];","outputs":7,"noerr":0,"x":330,"y":440,"wires":[["5398a974.0f0f98"],["ab5f303.1964f5"],["f12cbac.a0290c8"],["83dfed9d.4f9f8"],["9de792b9.6daf58"],["a9fc7d9.da658"],["f50acfae.30e2"]]},{"id":"25821ee9.c8df72","type":"inject","z":"15056c5e.4b8594","name":"TEST SWITCH - MANUAL MODE","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":620,"wires":[["247a86f7.e101c2"]]},{"id":"5398a974.0f0f98","type":"switch","z":"15056c5e.4b8594","name":"Switch1","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":340,"wires":[["a5ac7616.725e18"]]},{"id":"ab5f303.1964f5","type":"switch","z":"15056c5e.4b8594","name":"Switch2","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":420,"wires":[["a5ac7616.725e18"]]},{"id":"f12cbac.a0290c8","type":"switch","z":"15056c5e.4b8594","name":"Switch3","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":500,"wires":[["a5ac7616.725e18"]]},{"id":"83dfed9d.4f9f8","type":"switch","z":"15056c5e.4b8594","name":"Switch4","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":580,"wires":[["a5ac7616.725e18"]]},{"id":"9de792b9.6daf58","type":"switch","z":"15056c5e.4b8594","name":"Switch5","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":660,"wires":[["a5ac7616.725e18"]]},{"id":"a9fc7d9.da658","type":"switch","z":"15056c5e.4b8594","name":"Switch6","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":540,"y":740,"wires":[["a5ac7616.725e18"]]},{"id":"f50acfae.30e2","type":"debug","z":"15056c5e.4b8594","name":"MSG_ALL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":550,"y":840,"wires":[]},{"id":"a5ac7616.725e18","type":"delay","z":"15056c5e.4b8594","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":880,"y":420,"wires":[["247a86f7.e101c2"]]}]

Thanks to all

A picture is worth a lot when posting a flow. Here is yours but tidied up slightly:

And since the most complex part is your function, you should include that as well to make it easier for busy people to help you:

var count = context.get('count')||1;
var i = context.get('i')||1;
var first = context.get('first')||1;


//count = i * count;
if ((count *2) > 62) {
	i += 2;
	if (i > 64) { i = 2; } //reset
    count = 1;
	count = i * count;
    }
	else { 
	    if (first == 1) { 
	        count = 1; 
	        first = 2;
	    } else { count = count * 2; }}
	
var res = count.toString(2).padStart(6,"0");

// store the value back	
context.set('count',count);
context.set('i',i);
context.set('first',first);

//LSB

var msg6 = { payload: res.substring(0, 1) };
var msg5 = { payload: res.substring(1, 2) };
var msg4 = { payload: res.substring(2, 3) };
var msg3 = { payload: res.substring(3, 4) };
var msg2 = { payload: res.substring(4, 5) };
var msg1 = { payload: res.substring(5, 6) };

var msgG = { payload: res };

return [msg1,msg2,msg3,msg4,msg5,msg6,msgG];

The first time round the loop one message generates 6, then the next time those 6 generate 36, etc. In no time you have millions

Actually, you only need a single switch node here as they all do the same thing.

Also note that you can convert decimal numbers to binary in Javascript using the parsInt(n, 2) function where n is your input.

Actually, I wasn't quite right, the increase is not as rapid as I suggested, but the numbers do go up rapidly. I suggest setting the inject to trigger repeatedly rather than using a loop.

Also recommend to get rid of the loop. Apparently the solution is as easy as counting up to 64 and sending binary digits to the desired output. Can be done with this code inside the function node.

var count = 0;

function createmsg(a) {
    return {payload : a};
}

while (count < 64) {
var res = count.toString(2).padStart(6,"0");
let msg1 = Array.from(res, createmsg);
msg1.push({payload : res});
node.send(msg1);
count = count + 1;
}

return msg;
[{"id":"c9015bd5.24aa58","type":"function","z":"e26818e2.e01738","name":"","func":"var count = 0;\n\nfunction createmsg(a) {\n    return {payload : a};\n}\n\nwhile (count < 64) {\nvar res = count.toString(2).padStart(6,\"0\");\nlet msg1 = Array.from(res, createmsg);\nmsg1.push({payload : res});\nnode.send(msg1);\ncount = count + 1;\n}\n\nreturn msg;","outputs":7,"noerr":0,"x":650,"y":620,"wires":[["8dd6539.079aeb"],["d082e98c.0129b8"],["2a2bfde5.be0e92"],["110b91d8.34e62e"],["da1dcfc2.a15ef"],["b611aefa.5918f"],["1db75054.15ac6"]]},{"id":"606d6f86.fb85a","type":"inject","z":"e26818e2.e01738","name":"TEST SWITCH - MANUAL MODE","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":400,"y":620,"wires":[["c9015bd5.24aa58"]]},{"id":"1db75054.15ac6","type":"debug","z":"e26818e2.e01738","name":"MSG_ALL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":850,"y":760,"wires":[]},{"id":"8dd6539.079aeb","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":520,"wires":[]},{"id":"d082e98c.0129b8","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":560,"wires":[]},{"id":"2a2bfde5.be0e92","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":600,"wires":[]},{"id":"110b91d8.34e62e","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":640,"wires":[]},{"id":"da1dcfc2.a15ef","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":680,"wires":[]},{"id":"b611aefa.5918f","type":"debug","z":"e26818e2.e01738","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":850,"y":720,"wires":[]}]

thanks to all!!!
But my function works well in manual mode. It's not a simple 1-->64 count but is based on an algorithm

0
1
2
4
8
16
32
3
6
12
24
48
5
10
20
40
7
14
28
56
9
18
....

And I convert the int to a binary with 6 numbers that will control 6 switches

When I arrive to 63, the loop restart from 0

IF i call the function manually without closing the loop clicking on "TEST SWITCH - MANUAL MODE" node, all works well I see on debug all the combination and switches goes on and off correctly.

If i close the loop after the delay it start to count correctly but after some correct output it start to write uncorrected numbers, the delay is not respected and other things until the browser crash.

The flow that I attached is a small part of a bigger one, but until I don't solve the issue, all other items are not necessary

This is the bigger flow

As I said the reason it runs away and crashes when you close the loop is that each time round more and more messages get added so they come faster and faster. Note that the delay node as you have it configured delays each message by the specified time, if two messages arrive at the same time they will both be delayed by the time and then released together. If you want to limit the rate the messages go round use Rate Limit mode in the delay node.

Thanks for the info but due i'm a newbie of nodered, it's not clear for me.

You said 3 things:

  • more and more messages get added: Do I need to reset the message queue after the delay? It yes, how?
  • if two messages arrive at the same time they will both be delayed by the time and then released together: This is correct in my mind due i need to open or close the switches in the same time
  • limit the rate: I read the documentation about but it's not clear for me what change in the loop.

Thanks for the big help

Firstly do you realise that more and more messages get added each time round the loop?
Secondly Is that the intended operation?
Thirdly, why is it not appropriate just to trigger it from an inject node set to inject once every three seconds?

  1. No I'm not able to understand, I think that msg payload is set everytime and it doesn't keep the "history"
  2. My needed operation is to generate a message for every round, wait 3 seconds, generate a message, wait, and so on until i switch off the main switch (not present in this flow but it's on the correct bigger flow)
  3. :roll_eyes: not understand

tnx

  1. For the first point, from the initial start you trigger it using the inject node. Your function node then generates 6 messages which is sends to its 6 outputs. Those then go into the Switch nodes. Some of those messages get blocked and some get passed. Suppose, for example, that two get passed on. These will then both arrive at the delay at virtually the same time and will be queued there. Three seconds later they are released one after the other in quick succession, and both of them will get fed round to your function node again. The first one will get actioned and will send another six messages, then the second will get actioned and will send yet another six. So now each switch has two messages to action. All the switch nodes will service their messages and pass on an increasing number of messages. So each time round you have up to six times the number of messages as you did the last time. In a short space of time you have thousands of messages waiting to be serviced and node red clogs up.

  2. As you can see your current flow does not generate one message every three seconds, it generates many more than that.

  3. If you open the inject node you will see that it has an option to generate an initial message and then a message at a defined period, so if you set that to three seconds then it will generate a message every three seconds and you can open the loop in your flow and let the inject node run it. If you want to be able to stop and start it then you can use node-red-contrib-simple-gate to interrupt the flow using your master switch.

Ok, now is more clear, I make some test with your information and then i will give a feedback.

Hi all,
i make some test and via inject node it works, but.... Ho i can make the same via an events node?

Is that a Home Assistant node? I don't know anything about HA?

yes it's an HA node
btw I solved the issue and now it works like a charm, now i need to clean the JS code but it's another story

Thanks all for the support

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