Javascript equivalent for ShiftNumTableElements

I want to build an array in a Node Red function block, similar to the technique in PacControl using the command ShiftNumTableElements. I am reading a float variable from the S2 Controller, which represents the weight of a tank, and from this array I want to perform various calculations such as rate of depletion from the tank, etc.

[{"id":"b569cff6.885ac8","type":"inject","z":"c97af0fa.6fb9","name":"","topic":"","payload":"","payloadType":"date","repeat":"10","crontab":"","once":false,"onceDelay":0.1,"x":473,"y":283,"wires":[["98c5637a.61f638"]]},{"id":"98c5637a.61f638","type":"pac-read","z":"c97af0fa.6fb9","device":"31b5623c.c2558e","dataType":"float-variable","tagName":"WT4101_Final","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"","topicType":"none","name":"","x":673,"y":289,"wires":[["4fbb0564.b4ce9c"]]},{"id":"5ee4f3dc.f1b194","type":"debug","z":"c97af0fa.6fb9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1027,"y":290,"wires":[]},{"id":"4fbb0564.b4ce9c","type":"function","z":"c97af0fa.6fb9","name":"","func":"var feed_tank_wt = msg.payload; //the new feed tank wieght from the opto controller\nvar tank_wtarray = []; //array holding the feed tank wieghts\nvar feed_rate;\n\ntank_wtarray.unshift(feed_tank_wt);\n\n//feed_rate = tank_wtarray[30] - tank_wtarray[0];\n\nmsg.payload = tank_wtarray;\n\nreturn msg;","outputs":1,"noerr":0,"x":870,"y":289,"wires":[["5ee4f3dc.f1b194"]]},{"id":"31b5623c.c2558e","type":"pac-device","z":"","address":"10.0.4.10","protocol":"http"}]

Please see flow attached. I am using the javascript “unshift” command to enter a new value at element zero of the array. However the values do not shift from there, and I continue to see only one value at 0?

Capture

Can anyone with javascript experience provide some insight on this? thanks, much appreciated. Also I realize i can do this in the S2 controller, however it is running a process and I do not want to restart it right now.

This is happening because when the code runs it creates a new, empty array each and every time, it adds one value, then returns that list of just one value. For your values to build up you’ll need a persistent array that will keep values between injects (but not between deployments).
This is no problem though, really easy two-line fix since you can use “context”, “flow”, and “global” to set and get values within a node, flow, or entire Node-RED instance respectively. If you’re interested you can find more details here: nodered.org/docs/user-guide/writing-functions.

Here’s a code snippet that should get it working:

var feed_tank_wt = msg.payload; //the new feed tank weight from the opto controller
var tank_wtarray = context.get("tank_wtarray")||[]; //array holding the feed tank wieghts
var feed_rate;

tank_wtarray.unshift(feed_tank_wt);

//feed_rate = tank_wtarray[30] - tank_wtarray[0];

msg.payload = tank_wtarray;
context.set("tank_wtarray", tank_wtarray);

return msg;

Happy coding!

1 Like

Thanks so much for that solution. My next question, this will then build an array of infinite length, yes? I am going to be using 360 elements (inject every 10 seconds for an hour of values) with a new/recent value at element zero and the old one dropping off at the end. How can I accomplish this? thanks,

I think I found the answer to my question:
I need to use
array.length = 359
to define the length of the array.
thanks for your input

1 Like

That solution will definitely work, just be aware that when the array is not full it will have a bunch of “null” values at the end, which can cause errors if you read them by mistake. As long as you account for those you should be fine!


If the null values are causing any issues you can pop off the extra array entries instead, so that the array only ever has valid values in it:
if(tank_wtarray.length > max) tank_wtarray.pop();