Need help optimising flow and Chart output


Hi, your post was very clear, included correct formatting, examples, and indicated you tried stuff before asking so i felt inclined to to try and help you.

NOTE: there are many ways to skin a cat & others will have other ideas. This is just one.

Screen shots...


The flow...
[{"id":"e99d400c.6ac15","type":"tab","label":"Flow 3","disabled":false,"info":""},{"id":"d1da66ed.8ed4f8","type":"function","z":"e99d400c.6ac15","name":"matrix red on","func":"msg.payload = \"4,0,red,4,1,red,4,2,red,4,3,red,5,0,red,5,1,red,5,2,red,5,3,red,6,0,red,6,1,red,6,2,red,6,3,red,7,0,red,7,1,red,7,2,red,7,3,red\";\nmsg.topic = \"A\";\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":80,"wires":[["eefa2946.5b3d08"]]},{"id":"ef34d559.e4a878","type":"switch","z":"e99d400c.6ac15","name":"A or B or other","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"!AIVDM,1,1,,A,","vt":"str"},{"t":"cont","v":"!AIVDM,1,1,,B,","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":280,"y":100,"wires":[["d1da66ed.8ed4f8"],["2dd5498a.db6576"],["5503f0a6.0505c","1d88b922.cfa7f7"]]},{"id":"5503f0a6.0505c","type":"function","z":"e99d400c.6ac15","name":"matrix red off","func":"msg.payload = \"4,0,off,4,1,off,4,2,off,3,off,5,0,off,5,1,off,5,2,off,5,3,off,6,0,off,6,1,off,6,2,off,6,3,off,7,0,off,7,1,off,7,2,off,7,3,off\";\nmsg.topic = \"\";\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":160,"wires":[[]]},{"id":"2dd5498a.db6576","type":"function","z":"e99d400c.6ac15","name":"matrix green on","func":"msg.payload = \"0,4,green,0,5,green,0,6,green,0,7,green,1,4,green,1,5,green,1,6,green,1,7,green,2,4,green,2,5,green,2,6,green,2,7,green,3,4,green,3,5,green,3,6,green,3,7,green\";\nmsg.topic = \"B\";\nreturn msg;","outputs":1,"noerr":0,"x":500,"y":120,"wires":[["eefa2946.5b3d08"]]},{"id":"1d88b922.cfa7f7","type":"function","z":"e99d400c.6ac15","name":"matrix green off","func":"msg.payload = \"0,4,off,0,5,off,0,6,off,0,7,off,1,4,off,1,5,off,1,6,off,1,7,off,2,4,off,2,5,off,2,6,off,2,7,off,3,4,off,3,5,off,3,6,off,3,7,off\";\nmsg.topic = \"\";\nreturn msg;","outputs":1,"noerr":0,"x":500,"y":200,"wires":[[]]},{"id":"daa58ccf.31e4a","type":"udp in","z":"e99d400c.6ac15","name":"","iface":"","port":"10110","ipv":"udp4","multicast":"false","group":"","datatype":"utf8","x":100,"y":100,"wires":[["ef34d559.e4a878"]]},{"id":"e64cb1a3.843cb","type":"comment","z":"e99d400c.6ac15","name":"listen for Channel A and B messages","info":"","x":190,"y":40,"wires":[]},{"id":"98e87438.0b9f58","type":"comment","z":"e99d400c.6ac15","name":"switch LED matrix on/off depending on Channel","info":"","x":600,"y":40,"wires":[]},{"id":"682d9713.9e3188","type":"inject","z":"e99d400c.6ac15","name":"A","topic":"","payload":"!AIVDM,1,1,,A,","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":160,"wires":[["ef34d559.e4a878"]]},{"id":"7c475136.306fb","type":"inject","z":"e99d400c.6ac15","name":"B","topic":"","payload":"!AIVDM,1,1,,B,","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":200,"wires":[["ef34d559.e4a878"]]},{"id":"eefa2946.5b3d08","type":"function","z":"e99d400c.6ac15","name":"log counts A and B in flow contect store","func":"if(msg.topic !== \"A\" && msg.topic !== \"B\"){\n return null;//halt flow\n} \n//set the payload to the memory value stored in flow contect\n//note: as we verified above that msg.topic is definitely A or B\n//we simply get from flow contect using msg.topic\nmsg.payload = flow.get(msg.topic) || 0; // if value is empty, ||0 will set it to 0 (like a default)\nmsg.payload += 1;//increment the value \nflow.set(msg.topic, msg.payload);//update the value in flow store\nreturn msg;//return the message\n","outputs":1,"noerr":0,"x":780,"y":100,"wires":[[]]},{"id":"90bc0552.721448","type":"function","z":"e99d400c.6ac15","name":"get & reset counts A and B","func":"var msgA = {};\nmsgA.topic = \"A\";\nmsgA.payload = flow.get(msgA.topic) || 0; // if value is empty, ||0 will set it to 0 (like a default)\n\nvar msgB = {};\nmsgB.topic = \"B\";\nmsgB.payload = flow.get(msgB.topic) || 0; // if value is empty, ||0 will set it to 0 (like a default)\n\n//store prev counters\nflow.set(\"A_Prev\",msgA.payload);\nflow.set(\"B_Prev\",msgB.payload);\n//reset counters\nflow.set(\"A\",0);\nflow.set(\"B\",0);\n\n//for learning purposes, i return 2 objects on 2 outputs\n//we could skip this by using 2 node.send(msg) if we wanted \nreturn [msgA, msgB];","outputs":2,"noerr":0,"x":400,"y":360,"wires":[["c0288161.721c3"],["c0288161.721c3"]]},{"id":"c0288161.721c3","type":"ui_chart","z":"e99d400c.6ac15","name":"","group":"4680bb7c.986364","order":0,"width":"0","height":"0","label":"","chartType":"line","legend":"true","xformat":"auto","interpolate":"step","nodata":"","dot":false,"ymin":"0","ymax":"","removeOlder":"1","removeOlderPoints":"","removeOlderUnit":"86400","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":670,"y":360,"wires":[[]]},{"id":"beaa55c1.fd55e8","type":"inject","z":"e99d400c.6ac15","name":"Every minute","topic":"","payload":"true","payloadType":"bool","repeat":"60","crontab":"","once":true,"onceDelay":0.1,"x":140,"y":360,"wires":[["90bc0552.721448"]]},{"id":"cc2cfba3.3669e8","type":"comment","z":"e99d400c.6ac15","name":"Trigger chart update every minute","info":"","x":170,"y":320,"wires":[]},{"id":"4680bb7c.986364","type":"ui_group","z":"","name":"AIS Message Count","tab":"e1ead9a8.b76758","order":1,"disp":true,"width":"6","collapse":false},{"id":"e1ead9a8.b76758","type":"ui_tab","z":"","name":"AIS","icon":"dashboard","order":6,"disabled":false,"hidden":false}]


Hi Steve,
and thank you so much. That is a lot more than expected!

Now I need to work my way through your nodes and see how you had things done. That will be the fun part :slight_smile:

Just deployed and noticed that you split into A/B in the chart. That is not necessary as I want the total amount of messages (A+B). In real life there are these two channels just for the purpose of providing more bandwidth. Imagine a main port like Hongkong or wherever with hundreds if not thousands of ships. Each one sending an AIS message every 3 to 30 seconds. For the receiver it doesn't matter whether it was from channel A or B.

Another thing I discovered is that both LEDs (red and green) stays lit with your flow. Not sure what's going on, but will look into it. edit: my fault. For debug purposes I disconnected the off function nodes...display works fine.


Hi yeah - I was not 100% sure of your final intent (some assumptions were made) .

The changes I made were mostly academic & for showing you alternative methods.

Mainly I wanted to show you how the graph can be populated.

From what I've seen from you I am sure you can integrate what I did with your work & get it going pretty quickly & easily.

Key points I tried to make were...

  • using topics
  • use of flow context
  • use of function nodes with multiple outputs
  • how to populate graph

Let us know if you get stuck.


oh and in case you dont know of it, check out the right hand side bar in particular the Context Data - here you can see what value things are.



Thanks again very much!

The intent is only for learning. Sorry if I was not clear enough.
And no better way than to learn from others, how they do it or how they solve problems.

I must admit I've never heard of flow context, but I can see and understand how it works. When I discovered node-red I really thought it is all plug'n play. Wire a few nodes and there you go. How wrong I was :wink: But thats the fun of it. Finally I have a lot of ideas how to make real use of NR.


Sorry I should have said 'set msg.reset to msg.payload' like this:


zenofmud, not your fault. But a better understanding of this sure will help me.

When I set msg.reset to msg.payload per your example, it sends 0 (as was injected) to the output. The other way around is undefined.


I've always found the SET confusing - it sets the top item to what ever the bottom item is. So it is setting msg.reset' to what evermsg.payload' contains. I probably should have set set msg.reset to 0 because - if you read the info on the node you will see:

It's possible to control the counter with incoming msg properties:

  • msg.increment : counter will be incremented by the given value.
  • msg.decrement : counter will be decremented by the given value.
  • msg.reset : resets the counter to it's initial count, or to the given value, when it's a number.


Indeed, very confusing with the change node. I read that too that msg.reset could be a number and so I accepted 0 to be valid. But is not. As soon as I set msg.reset to 1 or any other number, it works.

Ugh, hard bread. But we finally got there :slight_smile: Thanks very much, zenofmud!


did you mke sure to send the number 0 and not the letter 0. i.e. This:

and not this:


Note the a/z vrs 0/9 for the type


Of course, I did and always verified the output to be a number. It accepts 0, but 0 doesn't reset the counter node.

Here is how it will reset. Please notice that once it resets the counter, it starts counting 1 twice. Means the counter does not start at 0. I cannot explain this as I'm too much of a novice in these things. But sure someone can. Or maybe a bug in the counter node?



Which counter node are you using (node-red-contrib-something probably)?


It's the node-red-contrib-counter.


About msg.reset the readme says " msg.reset : resets the counter to it's initial count, or to the given value, when it's a number." The emboldening is mine. Look at what value you have given for msg.reset. The counter is reset to that value.


@colin - it looks like there is a bug when msg.reset is set to zero. In that case it doesn't reset the counter. I'm going to take a look at the node and see if I can see why


Yup there is a bug! in the code it does this

            // handle reset
            if( msg.hasOwnProperty("reset") && msg.reset ) {
                node.count = typeof msg.reset === "number" ? msg.reset : node.init;

the problem is that if msg.reset containg a zero the if statement will always fail because msg.reset evaluate to false. the code should be

            // handle reset
            if( msg.hasOwnProperty("reset") &&  typeof msg.reset === "number" ) {
                node.count = typeof msg.reset === "number" ? msg.reset : node.init;

I will create a PR for this
@Stefanie in the meantime you can fix this in the code yourself if you are daring :stuck_out_tongue_winking_eye:
If you are on a Pi:

  1. open a terminal window
  2. enter nano $HOME/.node-red/node_modules/node-red-contrib-counter/counter.js
  3. use the down arrow to scroll down until you find the code above.
  4. make the change and press ctrl-x the y then the enter key
  5. restart NR and giveit a whirl

NOTE: I updated this code to the correct fix, my original fix only worked it the msg.reset was 0 but it can be any number.


The flow posted sets msg.reset to 1. Which also is not correct.


I set it to 1 as an example only.


Haha, I certainly will when I‘m back home Wednesday :innocent:


@Colin you're right, the if statement needs to be

if( msg.hasOwnProperty("reset") &&  typeof msg.reset === "number" ) {

@Stefanie - use this code instead