Duplicate nodes dynamiquely

Hello
i made a small Weather station application
my idea is to read from TCP, the information should look like that: “stationname,firstmesure,secondmesure,thirdmesure”.
now in the flow, there should be 3 charts to show the measurements received from the TCP, but there must be much charts as the number of stations.

I think i can do this by creating lot of tabs (or groups), and in each tab (or group) there must be the same content of the other tab, the difference is that when the TCP read the info, it should send the data to the correct chart.

i couldn’t make it and need help.

this is my flow code:

[{"id":"456ce3eb.038f9c","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"b45d9e90.f7efb","type":"ui_chart","z":"456ce3eb.038f9c","name":"","group":"10ddc440.6242dc","order":2,"width":"6","height":"4","label":"","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":550,"y":160,"wires":[[],[]]},{"id":"b5c9b25b.5654d","type":"tcp in","z":"456ce3eb.038f9c","name":"","server":"server","host":"","port":"51","datamode":"stream","datatype":"utf8","newline":"\\n","topic":"","base64":false,"x":50,"y":320,"wires":[["d9a881a5.38b95","41d06c60.5062c4"]]},{"id":"e19a3435.efdad8","type":"ui_chart","z":"456ce3eb.038f9c","name":"","group":"16259666.f7561a","order":3,"width":"6","height":"4","label":"","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":570,"y":260,"wires":[[],[]]},{"id":"902c65b8.257588","type":"ui_chart","z":"456ce3eb.038f9c","name":"","group":"45e8f89.7680708","order":4,"width":"6","height":"4","label":"","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":390,"y":320,"wires":[[],[]]},{"id":"d9a881a5.38b95","type":"split","z":"456ce3eb.038f9c","name":"","splt":",","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":70,"y":240,"wires":[["c848a8f7.2a1458"]]},{"id":"c848a8f7.2a1458","type":"switch","z":"456ce3eb.038f9c","name":"","property":"parts.index","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":230,"y":180,"wires":[[],["26e7056d.faf0ea"],["25f6b027.2d93c"],["442b32b1.0e00cc"]],"outputLabels":["station name","temperature","humidity","rain"]},{"id":"41d06c60.5062c4","type":"csv","z":"456ce3eb.038f9c","name":"To csv format","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\r\\n","temp":"Temperature,Humidity,Rain","skip":"0","x":150,"y":420,"wires":[["cf90cc55.41356"]]},{"id":"cf90cc55.41356","type":"file","z":"456ce3eb.038f9c","name":"Save to file","filename":"measurements.csv","appendNewline":true,"createDir":false,"overwriteFile":"false","x":370,"y":420,"wires":[]},{"id":"b6b9227a.432e4","type":"ui_text","z":"456ce3eb.038f9c","group":"b5419d55.fdc67","order":0,"width":"4","height":"1","name":"","label":"Total Stations","format":"{{msg.payload}}","layout":"row-spread","x":420,"y":500,"wires":[]},{"id":"d2321a54.ab0428","type":"ui_text","z":"456ce3eb.038f9c","group":"b5419d55.fdc67","order":0,"width":0,"height":0,"name":"","label":"Station","format":"{{msg.payload}}","layout":"row-spread","x":270,"y":560,"wires":[]},{"id":"cf05468d.f8c188","type":"ui_text","z":"456ce3eb.038f9c","group":"b5419d55.fdc67","order":0,"width":0,"height":0,"name":"","label":"Last connected","format":"{{msg.payload}}","layout":"row-spread","x":490,"y":580,"wires":[]},{"id":"4dce5f73.3ff72","type":"ui_gauge","z":"456ce3eb.038f9c","name":"","group":"10ddc440.6242dc","order":0,"width":"5","height":"4","gtype":"gage","title":"","label":"degree","format":"{{value}}°","min":0,"max":"70","colors":["#00b500","#e6e600","#ca3838"],"seg1":"13","seg2":"30","x":550,"y":100,"wires":[]},{"id":"26e7056d.faf0ea","type":"switch","z":"456ce3eb.038f9c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"nnull"},{"t":"nnull"}],"checkall":"true","repair":false,"outputs":2,"x":420,"y":160,"wires":[["4dce5f73.3ff72"],["b45d9e90.f7efb"]]},{"id":"bb49d451.c7c418","type":"ui_gauge","z":"456ce3eb.038f9c","name":"","group":"16259666.f7561a","order":0,"width":"5","height":"4","gtype":"gage","title":"","label":"","format":"{{value}}","min":0,"max":"70","colors":["#00b500","#e6e600","#ca3838"],"seg1":"13","seg2":"30","x":570,"y":220,"wires":[]},{"id":"25f6b027.2d93c","type":"switch","z":"456ce3eb.038f9c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"nnull"},{"t":"nnull"}],"checkall":"true","repair":false,"outputs":2,"x":410,"y":220,"wires":[["bb49d451.c7c418"],["e19a3435.efdad8"]]},{"id":"8b999ad8.686b88","type":"ui_gauge","z":"456ce3eb.038f9c","name":"","group":"45e8f89.7680708","order":0,"width":"5","height":"4","gtype":"gage","title":"","label":"","format":"{{value}}","min":0,"max":"70","colors":["#00b500","#e6e600","#ca3838"],"seg1":"13","seg2":"30","x":390,"y":280,"wires":[]},{"id":"442b32b1.0e00cc","type":"switch","z":"456ce3eb.038f9c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"nnull"},{"t":"nnull"}],"checkall":"true","repair":false,"outputs":2,"x":250,"y":300,"wires":[["8b999ad8.686b88"],["902c65b8.257588"]]},{"id":"10ddc440.6242dc","type":"ui_group","z":"","name":"Temperature","tab":"b62215db.2882d8","disp":true,"width":"6","collapse":false},{"id":"16259666.f7561a","type":"ui_group","z":"","name":"Humidity","tab":"b62215db.2882d8","order":2,"disp":true,"width":"6","collapse":false},{"id":"45e8f89.7680708","type":"ui_group","z":"","name":"Rain","tab":"b62215db.2882d8","order":3,"disp":true,"width":"6","collapse":false},{"id":"b5419d55.fdc67","type":"ui_group","z":"","name":"Dashboard","tab":"300b4099.db267","order":1,"disp":true,"width":"6","collapse":false},{"id":"b62215db.2882d8","type":"ui_tab","z":"","name":"Constantine","icon":"dashboard","order":2},{"id":"300b4099.db267","type":"ui_tab","z":"","name":"Weather Station","icon":"dashboard","order":1}]

Do you know how many stations there will be, or is that list variable?

If you know ahead of time that there are say 8 stations with three measurements for each, then you can define 8x3 groups of gauges in the usual dashboard format. However, if either the number of stations or measurements will be changing over time, you would need a way to dynamically render the grid of widgets. This is not currently possible with the standard dashboard widgets. However, there are at least 3 techniques that I’ve used in the past to do similar responsive dashboards:

  1. Create a single dashboard to show all the measurements for a single station (if the measurement types do not change). Then add a dropdown list of all the stations (this list can grow over time). Whichever station is selected has its data shown on the existing guages/charts. This is simpler to set up, and the widgets already exist as dashboard nodes.

  2. Use the Angular ng-repeat directive to create the same number of widgets as are defined in the incoming data array. This requires a good understanding of how to build Angular v2 applications, but gives you a lot of control over the layout and interaction with the data. The biggest problem is that you will also need to roll your own gauge/chart widgets, using other js charting libraries (e.g. plotly, d3js, dygraph, google, highcharts, etc). You may be able to reuse the chartjs library that is already used by node-red-dashboard. The main advantage to writing this Angular code inside ui_template nodes is that the msg communication between your flows and your code is handled for you.

  3. Use another “dashboard” framework, served up by the node-red-contrib-uibuilder project. This means that you are essentially writing the entire application using whatever reactive UI framework you like (e.g. d3, vue, moon, riotjs, reactjs, etc). UIBuilder simply manages the websocket communication between the backend flows, and the front-end app code. Again, how you choose to draw the widgets is up to you.

Also, please edit your original post to put your flow’s JSON into a code block – it’s easier to read, and keeps discourse from changing your quotes to smart-quotes (which makes your json invalid). To create a code block, simply place a line with three backtics before and after your json text.

2 Likes