Read a variable in an array of object without variable name

Hello,

I am new at this forum and maybe someone have already ask these question, but i can't find the right answer.

I have a array of objects and I would like to read the right variable on the right place.

What you see on the left is de "Tijdstip" and "Temperatuur" variable, the "Tijdstip" is always the same name but the "Temperatuur" name is sometimes different.

To show this data in de line graph I would like to read the "Tijdstip" and the variable(s) that are also available.

I hope you will understand my question and you can help me out.

You'll need to recode your function completely. The reason being is because with Javascript, you can construct your data structure on the fly rather than having to do it all at once. I could show you how to rewrite this function, but there may be an easier way. To figure that out, we'll need some information.

  1. What does your flow look like?
  2. What are you using to display your data? The chart node in Dashboard?
  3. What does the raw input look like? Is it that full array like what you show in the debug output or is it an individual pair of timestamp and temperature? My guess is the full array.

For the quick fixes, there are a few things you could change. First off, you only need to declare array variables at one level deep.

let data1 = [];

You can easily add another level of array by simply assigning the array to a position in the original.

let temp = [1, 2, 3, 4, 5];
ley data1 = [];
data1[0] = temp;

Next, I wouldn't work with a lot of different arrays. I would instead make an array of objects like what you're receiving. Just assign the value to the object identifier. Also, if you use the keyword of in your for loop, you can use it in this way because it actually takes that position of msg.payload and assigns it to x:

let temp = {};  //Declare an empty object
let data = [];  //Declare an empty variable
for(let x of msg.payload){  //Assign each position of msg.payload to x and then process it
    temp["label"] = x.Tijdstip;  //Assign the timestamp to the label
    temp["Sensor1"] = x.Sensor1;  //Assign sensor 1 to the Sensor1 property
    temp["Sensor2"] = x.Sensor2;  //And so on
    temp["Sensor3"] = x.Sensor3;
    temp["Sensor4"] = x.Sensor4;
    data.push(temp);  //Add the newly created object to the array
}

When that whole block is completed, you have an array of objects where the object label property has a value of the timestamp and the sensor properties have the values of the readings. Again, this is just based off of what you've provided. It all depends on what your input and output need to be in order to use your data that will dictate what needs to happen in your function. If you can clarify that, you'll definitely get a better answer that will help out a lot more.

Thanks for the quick response @madhouse.

I am quite new with Javascript and Node-Red, so I must learn a lot of new things.

I will try your examples and what you suggest.

Node-red is control on a PLC (weidmueller UC20) with connected analog sensors, but the sensors will not always on the same input of the PLC, so I have tried to make a dynamic logging tool for logging the data of the sensors. The data of each sensor will be place with the actual time and correct name on the SD card of the PLC. With the dashboard we can open and show the data on the screen in a line graph.

Here are my flow(s):

[{"id":"288b8093.84499","type":"tab","label":"Files","disabled":false,"info":""},{"id":"1b46711c.36755f","type":"inject","z":"288b8093.84499","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"string"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":120,"wires":[["f3f6e723.158a08"]]},{"id":"d8c34461.bd2778","type":"debug","z":"288b8093.84499","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":100,"wires":[]},{"id":"4f5db71a.626968","type":"comment","z":"288b8093.84499","name":"SD Card File Browser","info":"","x":120,"y":60,"wires":[]},{"id":"5802319f.e1104","type":"function","z":"288b8093.84499","name":"Format data","func":"msg.options = [];\nfor (var i=0; i<msg.payload.length; i++) {\n    obj = {};\n    obj [msg.payload[i].name]=msg.payload[i].name;\n    msg.options.push(obj);\n}\nmsg.payload={};\nreturn msg;","outputs":1,"noerr":0,"x":590,"y":160,"wires":[["eef70c85.448f8"]]},{"id":"2eef2e74.325762","type":"template","z":"288b8093.84499","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<table width=\"100%\">\n    <tr><th>File Name</th><th>Size</th><th>Created</th><th>Changed</th></tr>\n    {{#payload}}\n        <tr>\n            <td><a href=\"/red/download?filename={{name}}\" target=\"blank\">{{fname}}</a></td>\n            <td>{{stat.size}}</td>\n            <td>{{stat.created}}</td>\n            <td>{{stat.changed}}</td>\n        </tr>\n    {{/payload}}\n</table>\n","output":"str","x":820,"y":220,"wires":[["a1ba22bc.8a352"]]},{"id":"cc85cf75.0551f","type":"function","z":"288b8093.84499","name":"Convert timestamps","func":"\nfor (var i=0; i<msg.payload.length; i++) {\n    msg.payload[i].stat.created = msg.payload[i].stat.created.toISOString().slice(0, 19).replace('T', ' ');\n    msg.payload[i].stat.changed = msg.payload[i].stat.changed.toISOString().slice(0, 19).replace('T', ' ');\n    msg.payload[i].stat.accessed = msg.payload[i].stat.accessed.toISOString().slice(0, 19).replace('T', ' ');\n    msg.payload[i].stat.statusChanged = msg.payload[i].stat.statusChanged.toISOString().slice(0, 19).replace('T', ' ');\n    msg.payload[i].fname = msg.payload[i].name.replace(/^.*(\\\\|\\/|\\:)/, '');\n}\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":220,"wires":[["2eef2e74.325762"]]},{"id":"7a30e131.3ab18","type":"function","z":"288b8093.84499","name":"Save selection","func":"// Save the file name selected from the dropdown in the flow context\nflow.set(\"fileselected\", msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":1020,"y":160,"wires":[[]]},{"id":"4580f3e7.258ccc","type":"function","z":"288b8093.84499","name":"Get filename","func":"// Get the filename from the flow context\nlet filename = flow.get(\"fileselected\");\n\n// check, if the filename is undefined that means it does not exist yet, nothing is selected yet\n// return: do not output anything\nif (filename===undefined) {\n    return;\n}\n\n// return the filename to the file-in node to delete\nmsg.filename = filename;\n\n// and delete the context/selection as we are deleting the file as well\nflow.set(\"fileselected\");\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":320,"wires":[["928b635a.e4512"]]},{"id":"928b635a.e4512","type":"file","z":"288b8093.84499","name":"Delete file","filename":"","appendNewline":true,"createDir":false,"overwriteFile":"delete","encoding":"none","x":460,"y":320,"wires":[["f3f6e723.158a08"]]},{"id":"95a6b885.c4e078","type":"http in","z":"288b8093.84499","name":"","url":"/download","method":"get","upload":false,"swaggerDoc":"","x":150,"y":380,"wires":[["eb9b4b79.9a2888"]]},{"id":"c2ff398b.e2c488","type":"http response","z":"288b8093.84499","name":"","statusCode":"","headers":{},"x":940,"y":380,"wires":[]},{"id":"eb9b4b79.9a2888","type":"function","z":"288b8093.84499","name":"Get the file name","func":"msg.filename = msg.req.query.filename;\nmsg.contentdisposition = \"attachment; filename=\\\"\" + msg.req.query.filename.replace(/^.*(\\\\|\\/|\\:)/, '') + \"\\\"\";\nreturn msg;","outputs":1,"noerr":0,"x":400,"y":380,"wires":[["fb3511a4.a7baa"]]},{"id":"fb3511a4.a7baa","type":"file in","z":"288b8093.84499","name":"","filename":"","format":"","chunk":false,"sendError":false,"encoding":"none","x":590,"y":380,"wires":[["d2400b86.0a7258"]]},{"id":"d2400b86.0a7258","type":"change","z":"288b8093.84499","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"text/csv","tot":"str"},{"t":"set","p":"headers.Content-Disposition","pt":"msg","to":"contentdisposition","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":380,"wires":[["c2ff398b.e2c488"]]},{"id":"5c190aeb.7bef74","type":"comment","z":"288b8093.84499","name":"Autologger ","info":"","x":80,"y":620,"wires":[]},{"id":"24c92f55.fc08d","type":"function","z":"288b8093.84499","name":"Filename generator","func":"// Get the current time and convert it to text\nvar now = new Date();\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Generate out file name pattern\nmsg.fname = \"logging_\"+ yyyy + mm + dd + \".csv\";\n// Full filename with path for the file node later\nmsg.filename = \"/run/media/mmcblk0p1/\"+ msg.fname;\n\n// We save the current payload into a different place on the msg object\nmsg.filecontent = msg.payload;\n\n// We are passing the file name search pattern to fs node to tell us if the file exists or not\nmsg.payload = {\"pattern\":msg.fname};\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.fname});\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":196,"y":787,"wires":[["35c6d0f7.c0b01"]]},{"id":"1836e6c2.b5c749","type":"switch","z":"288b8093.84499","name":"","property":"$count(msg.payload)","propertyType":"jsonata","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":536,"y":787,"wires":[["31da97fb.5b9428"],["62e86e59.f3b59"]]},{"id":"84fa66a.5893598","type":"csv","z":"288b8093.84499","name":"","sep":";","hdrin":"","hdrout":"all","multi":"one","ret":"\\n","temp":"","skip":"0","strings":true,"include_empty_strings":false,"include_null_values":false,"x":1190,"y":760,"wires":[["b305d747.4639c8"]]},{"id":"b305d747.4639c8","type":"file","z":"288b8093.84499","name":"","filename":"","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":1336,"y":767,"wires":[[]]},{"id":"7f99918a.27e0c","type":"csv","z":"288b8093.84499","name":"","sep":";","hdrin":"","hdrout":"none","multi":"one","ret":"\\n","temp":"","skip":"0","strings":true,"include_empty_strings":false,"include_null_values":false,"x":1190,"y":800,"wires":[["b305d747.4639c8"]]},{"id":"31da97fb.5b9428","type":"change","z":"288b8093.84499","name":"Get file content","rules":[{"t":"set","p":"payload","pt":"msg","to":"filecontent","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":760,"wires":[["6904d180.18353"]]},{"id":"62e86e59.f3b59","type":"change","z":"288b8093.84499","name":"Get file content","rules":[{"t":"set","p":"payload","pt":"msg","to":"filecontent","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":800,"wires":[["4941746b.54fb5c"]]},{"id":"d743ed09.0b366","type":"comment","z":"288b8093.84499","name":"Graph the data","info":"","x":126,"y":1072,"wires":[]},{"id":"9a41fa60.3a05d8","type":"function","z":"288b8093.84499","name":"Get filename","func":"// Get the filename from the flow context\nlet filename = flow.get(\"fileselected\");\n\n// check, if the filename is undefined that means it does not exist yet, nothing is selected yet\n// return: do not output anything\nif (filename===undefined) {\n    return;\n}\n\n// return the filename to the file-in node to delete\nmsg.filename = filename;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":370,"y":1120,"wires":[["652cec50.f88e54"]]},{"id":"652cec50.f88e54","type":"file in","z":"288b8093.84499","name":"","filename":"","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":540,"y":1117,"wires":[["c3cea279.83c91"]]},{"id":"c3cea279.83c91","type":"csv","z":"288b8093.84499","name":"","sep":";","hdrin":true,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":true,"include_empty_strings":false,"include_null_values":false,"x":690,"y":1117,"wires":[["fd32e5f6.ae37e8","df393d88.a130f"]]},{"id":"150a8568.bc258b","type":"inject","z":"288b8093.84499","name":"Every 10min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1160,"wires":[["9a41fa60.3a05d8"]]},{"id":"6904d180.18353","type":"change","z":"288b8093.84499","name":"timestamp to time","rules":[{"t":"set","p":"payload.Tijdstip","pt":"msg","to":"time","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":890,"y":760,"wires":[["207d51ce.c7d1ae"]]},{"id":"4941746b.54fb5c","type":"change","z":"288b8093.84499","name":"Timestamp to time","rules":[{"t":"set","p":"payload.Tijdstip","pt":"msg","to":"time","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":890,"y":800,"wires":[["e9d7323a.ce38a8"]]},{"id":"f27b11a4.8acdf","type":"function","z":"288b8093.84499","name":"Set data","func":"msg.payload = { \n    [global.get(\"AI00.name\")]: global.get(\"AI00.value\"), \n    [global.get(\"AI01.name\")]: global.get(\"AI01.value\"),\n    [global.get(\"AI02.name\")]: global.get(\"AI02.value\"),\n    [global.get(\"AI03.name\")]: global.get(\"AI03.value\")};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":613,"y":698,"wires":[["6c219724.5f8d18"]]},{"id":"dd4bb6e.cf31448","type":"ui_chart","z":"288b8093.84499","name":"","group":"6939346c.3cdb8c","order":1,"width":0,"height":0,"label":"File data","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1500","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"86400","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":1220,"y":1117,"wires":[[]]},{"id":"a1ba22bc.8a352","type":"ui_template","z":"288b8093.84499","group":"f14bc46d.61ef78","name":"","order":5,"width":0,"height":0,"format":"<div ng-bind-html=\"msg.payload\" height=\"400\" style=\"height: 400px;\"><br/>\n</div>\n\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":1000,"y":220,"wires":[[]]},{"id":"eef70c85.448f8","type":"ui_dropdown","z":"288b8093.84499","name":"File Selector","label":"","tooltip":"","place":"Select a file","group":"f14bc46d.61ef78","order":4,"width":0,"height":0,"passthru":false,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"","topicType":"str","className":"","x":790,"y":160,"wires":[["7a30e131.3ab18"]]},{"id":"a44db5d6.5d2b28","type":"ui_button","z":"288b8093.84499","name":"","group":"f14bc46d.61ef78","order":1,"width":0,"height":0,"passthru":false,"label":"Refresh","tooltip":"","color":"","bgcolor":"","className":"","icon":"refresh","payload":"","payloadType":"str","topic":"","topicType":"str","x":140,"y":160,"wires":[["f3f6e723.158a08"]]},{"id":"756b5c80.2e1554","type":"ui_button","z":"288b8093.84499","name":"","group":"f14bc46d.61ef78","order":3,"width":0,"height":0,"passthru":false,"label":"Delete","tooltip":"","color":"","bgcolor":"","className":"","icon":"delete","payload":"","payloadType":"str","topic":"","topicType":"str","x":110,"y":320,"wires":[["4580f3e7.258ccc"]]},{"id":"67615f6d.285b3","type":"ui_button","z":"288b8093.84499","name":"","group":"f14bc46d.61ef78","order":2,"width":0,"height":0,"passthru":false,"label":"Graph","tooltip":"","color":"","bgcolor":"","className":"","icon":"show_chart","payload":"","payloadType":"str","topic":"","topicType":"str","x":190,"y":1117,"wires":[["9a41fa60.3a05d8"]]},{"id":"950f805f.eb259","type":"debug","z":"288b8093.84499","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1230,"y":1160,"wires":[]},{"id":"fd32e5f6.ae37e8","type":"function","z":"288b8093.84499","name":"","func":"let dataLabels = [];\nlet data1 = [[]];\nlet data2 = [[]];\nlet data3 = [[]];\nlet data4 = [[]];\nfor (let X in msg.payload) \n{\n    dataLabels[X] = msg.payload[X].Tijdstip;\n    data1[0][X] = msg.payload[X].Geleidbaarheid;\n    data2[0][X] = msg.payload[X].Druk;\n    data3[0][X] = msg.payload[X].Sensor3;\n    data4[0][X] = msg.payload[X].Sensor4;\n}\n\n\n\nvar m={\n     \"series\": [\"Sensor1\",\"sensor2\",\"sensor3\",\"sensor4\"],                    // Legenda \n    \"data\": [data1[0],data2[0],data3[0],data4[0]],                 // Waarde van staafdiagram y-as\n    \"labels\": dataLabels                         // Momenten van data X-as\n};\n\nreturn {payload:[m]};","outputs":1,"noerr":0,"initialize":"","finalize":"","x":960,"y":1120,"wires":[["950f805f.eb259","dd4bb6e.cf31448"]]},{"id":"3606fd3c.c9b3b2","type":"function","z":"288b8093.84499","name":"Filename generator","func":"// Get the current time and convert it to text\nvar now = new Date();\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Generate out file name pattern\nmsg.fname = \"logging_\"+ yyyy + mm + \".csv\";\n// Full filename with path for the file node later\nmsg.filename = \"/run/media/mmcblk0p1/\"+ msg.fname;\n\n// We save the current payload into a different place on the msg object\nmsg.filecontent = msg.payload;\n\n// We are passing the file name search pattern to fs node to tell us if the file exists or not\nmsg.payload = {\"pattern\":msg.fname};\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.fname});\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":190,"y":920,"wires":[["c07881d6.073e3"]]},{"id":"5ba2ec41.5250f4","type":"inject","z":"288b8093.84499","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":860,"wires":[["3606fd3c.c9b3b2"]]},{"id":"d683b176.78a9e","type":"function","z":"288b8093.84499","name":"Set data","func":"msg.payload = {\n    \n    \"pattern\" : \"logging_\"+ msg.payload + \".csv\",\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":920,"wires":[["3896c5fe.148baa"]]},{"id":"b54fa671.282c18","type":"switch","z":"288b8093.84499","name":"","property":"$count(msg.payload)","propertyType":"jsonata","rules":[{"t":"eq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":930,"y":920,"wires":[["4bc1e4a0.81e55c"]]},{"id":"4d09ca5e.3ecf54","type":"file","z":"288b8093.84499","name":"Delete file","filename":"","appendNewline":true,"createDir":false,"overwriteFile":"delete","encoding":"none","x":1260,"y":920,"wires":[["482daecf.ff94d"]]},{"id":"4bc1e4a0.81e55c","type":"function","z":"288b8093.84499","name":"Set data","func":"msg.filename = msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1100,"y":920,"wires":[["4d09ca5e.3ecf54"]]},{"id":"644fbccd.dcfce4","type":"link in","z":"288b8093.84499","name":"Refresh","links":["482daecf.ff94d"],"x":135,"y":220,"wires":[["f3f6e723.158a08"]]},{"id":"482daecf.ff94d","type":"link out","z":"288b8093.84499","name":"","links":["644fbccd.dcfce4"],"x":1375,"y":920,"wires":[]},{"id":"df393d88.a130f","type":"debug","z":"288b8093.84499","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1030,"y":1240,"wires":[]},{"id":"f3f6e723.158a08","type":"fs-file-lister","z":"288b8093.84499","name":"","start":"/run/media/mmcblk0p1/","pattern":"*.*","folders":"*","hidden":true,"lstype":"files","path":true,"single":true,"depth":0,"stat":true,"showWarnings":true,"x":340,"y":140,"wires":[["d8c34461.bd2778","5802319f.e1104","cc85cf75.0551f"]]},{"id":"35c6d0f7.c0b01","type":"fs-file-lister","z":"288b8093.84499","name":"","start":"/run/media/mmcblk0p1/","pattern":"","folders":"*","hidden":true,"lstype":"files","path":true,"single":true,"depth":0,"stat":true,"showWarnings":true,"x":386,"y":787,"wires":[["1836e6c2.b5c749"]]},{"id":"3896c5fe.148baa","type":"fs-file-lister","z":"288b8093.84499","name":"","start":"/run/media/mmcblk0p1/","pattern":"","folders":"*","hidden":true,"lstype":"files","path":true,"single":false,"depth":0,"stat":false,"showWarnings":true,"x":780,"y":920,"wires":[["b54fa671.282c18"]]},{"id":"120d8a3f.a92596","type":"moment","z":"288b8093.84499","name":"","topic":"","input":"payload","inputType":"msg","inTz":"Europe/London","adjAmount":"2","adjType":"hours","adjDir":"subtract","format":"LLL","locale":"C","output":"time","outputType":"msg","outTz":"Europe/Amsterdam","x":413,"y":698,"wires":[["f27b11a4.8acdf"]]},{"id":"c07881d6.073e3","type":"moment","z":"288b8093.84499","name":"","topic":"","input":"payload","inputType":"msg","inTz":"Europe/Amsterdam","adjAmount":"1","adjType":"years","adjDir":"subtract","format":"YYYYMM","locale":"C","output":"payload","outputType":"msg","outTz":"Europe/Amsterdam","x":420,"y":920,"wires":[["d683b176.78a9e"]]},{"id":"1eaa5e7d.760822","type":"inject","z":"288b8093.84499","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":700,"wires":[["120d8a3f.a92596"]]},{"id":"207d51ce.c7d1ae","type":"function","z":"288b8093.84499","name":"","func":"\n\nmsg.columns = \"Tijdstip,\"+msg.name1+\",\"+msg.name2+\",\"+msg.name3+\",\"+msg.name4+\",\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1060,"y":760,"wires":[["84fa66a.5893598"]]},{"id":"6c219724.5f8d18","type":"change","z":"288b8093.84499","name":"","rules":[{"t":"set","p":"name1","pt":"msg","to":"AI00.name","tot":"global"},{"t":"set","p":"name2","pt":"msg","to":"AI01.name","tot":"global"},{"t":"set","p":"name3","pt":"msg","to":"AI02.name","tot":"global"},{"t":"set","p":"name4","pt":"msg","to":"AI03.name","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":700,"wires":[["24c92f55.fc08d"]]},{"id":"e9d7323a.ce38a8","type":"function","z":"288b8093.84499","name":"","func":"\n\nmsg.columns = \"Tijdstip,\"+msg.name1+\",\"+msg.name2+\",\"+msg.name3+\",\"+msg.name4+\",\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1060,"y":800,"wires":[["7f99918a.27e0c"]]},{"id":"26a582fa.c19396","type":"inject","z":"288b8093.84499","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"one\":1,\"two\":2},{\"three\":3,\"four\":4}]","payloadType":"json","x":250,"y":1320,"wires":[["b60fd602.e8f418"]]},{"id":"b60fd602.e8f418","type":"function","z":"288b8093.84499","name":"","func":"msg.payload = Object.keys(msg.payload[0]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":1320,"wires":[["540f088.66ac2f8"]]},{"id":"540f088.66ac2f8","type":"debug","z":"288b8093.84499","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":810,"y":1320,"wires":[]},{"id":"6939346c.3cdb8c","type":"ui_group","z":"","name":"Bestand","tab":"b5e5ffd5.e6021","order":3,"disp":true,"width":20,"collapse":true,"className":""},{"id":"f14bc46d.61ef78","type":"ui_group","z":"","name":"Buttons","tab":"b5e5ffd5.e6021","order":1,"disp":false,"width":"8","collapse":false,"className":""},{"id":"b5e5ffd5.e6021","type":"ui_tab","z":"","name":" File","icon":"fa-file-excel-o","order":3,"disabled":false,"hidden":false}]
[{"id":"ce4bb0dd.a8435","type":"tab","label":"Sensor 1","disabled":false,"info":""},{"id":"b41fafca.5b9e2","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"AI00_Name","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":100,"wires":[["d637e4c5.2563a8","2caba41f.e07d84"]]},{"id":"e204f7c0.01bed8","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"payload.online","pt":"msg","to":"true","tot":"bool"},{"t":"set","p":"payload.name","pt":"msg","to":"AI00_Name","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":180,"wires":[["af4ba3de.072a6"]]},{"id":"ba6e762c.adfa98","type":"switch","z":"ce4bb0dd.a8435","name":"","property":"AI00_Name","propertyType":"flow","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":230,"y":180,"wires":[["e7721a61.8ff888"]]},{"id":"e6a527fc.801118","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"AI00","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1200,"y":180,"wires":[["72064ba4.9c14bc"]]},{"id":"59d23704.70b618","type":"uc-iodataIn","z":"ce4bb0dd.a8435","mode":"wi_single_variable","variable":"AI00","name":"","pollInterval":"2000","pollIntervalBase":"s","x":80,"y":180,"wires":[["ba6e762c.adfa98"],[]]},{"id":"7e1981ef.f7a45","type":"ui_dropdown","z":"ce4bb0dd.a8435","name":"","label":"","tooltip":"","place":"Kies sensor","group":"abcb8328.96141","order":4,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"Temperatuur","value":"Temperatuur","type":"str"},{"label":"Geleidbaarheid","value":"Geleidbaarheid","type":"str"},{"label":"Flow","value":"Flow","type":"str"},{"label":"Druk","value":"Druk","type":"str"},{"label":"Leeg","value":false,"type":"bool"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":80,"y":100,"wires":[["b41fafca.5b9e2"]]},{"id":"ddcf891c.9af918","type":"ui_text","z":"ce4bb0dd.a8435","group":"abcb8328.96141","order":3,"width":6,"height":1,"name":"","label":"Sensor 1","format":"","layout":"row-spread","className":"","x":80,"y":60,"wires":[]},{"id":"be946f9a.e78cb","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"AI00.online","pt":"global","to":"false","tot":"bool"},{"t":"set","p":"AI00.value","pt":"global","to":"0","tot":"num"},{"t":"set","p":"AI00.name","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1200,"y":100,"wires":[[]]},{"id":"d637e4c5.2563a8","type":"switch","z":"ce4bb0dd.a8435","name":"","property":"AI00_Name","propertyType":"flow","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":550,"y":100,"wires":[["be946f9a.e78cb"]]},{"id":"af4ba3de.072a6","type":"function","z":"ce4bb0dd.a8435","name":"","func":"var value; \n\nvalue = msg.payload.value.toFixed(2);\n\nmsg.payload.value = parseFloat(value);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1000,"y":180,"wires":[["e6a527fc.801118"]]},{"id":"33986851.57283","type":"ui_text_input","z":"ce4bb0dd.a8435","name":"","label":"Min","tooltip":"","group":"abcb8328.96141","order":7,"width":3,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"topic","sendOnBlur":true,"className":"","topicType":"msg","x":90,"y":400,"wires":[["ee599125.399f18"]]},{"id":"95a468f9.ea9d4","type":"ui_text_input","z":"ce4bb0dd.a8435","name":"","label":"Max","tooltip":"","group":"abcb8328.96141","order":8,"width":3,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"topic","sendOnBlur":true,"className":"","topicType":"msg","x":90,"y":360,"wires":[["bb69ee8b.ad4448"]]},{"id":"bb69ee8b.ad4448","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"AI00.Max","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":360,"wires":[[]]},{"id":"ee599125.399f18","type":"change","z":"ce4bb0dd.a8435","name":"","rules":[{"t":"set","p":"AI00.Min","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":400,"wires":[[]]},{"id":"e7721a61.8ff888","type":"change","z":"ce4bb0dd.a8435","name":"Limits","rules":[{"t":"set","p":"minout","pt":"msg","to":"AI00.Min","tot":"global"},{"t":"set","p":"maxout","pt":"msg","to":"AI00.Max","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":180,"wires":[["64274f03.d31188"]]},{"id":"64274f03.d31188","type":"function","z":"ce4bb0dd.a8435","name":"Scale for colour","func":"var maxin = 27648;\nvar minin = 0;\nvar maxout = flow.get(\"AI00.Max\");\nvar minout = flow.get(\"AI00.Min\");\nvar X = parseInt(msg.payload.value);\n\nif (msg.payload < minin)\n{\n    msg.payload = 0;\n    return msg;\n}\nvar value = parseFloat((((maxout - minout) / (maxin - minin) * ( X - minin)) + minout));\n\nmsg.payload.value = value;\nmsg.payload.Max = maxout;\nmsg.payload.Min = minout;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":560,"y":180,"wires":[["e204f7c0.01bed8","5f9b6057.091398","c8180dab.5ee6a8"]]},{"id":"8e53a9b5.2fee8","type":"ui_text","z":"ce4bb0dd.a8435","group":"38acb3ef.21ae24","order":1,"width":0,"height":0,"name":"","label":"Sensor 1","format":"{{msg.name}}","layout":"col-center","className":"","x":1240,"y":360,"wires":[]},{"id":"707583ce.97b974","type":"ui_gauge","z":"ce4bb0dd.a8435","name":"","group":"38acb3ef.21ae24","order":2,"width":0,"height":0,"gtype":"gage","title":"","label":"","format":"{{value | number:1}} ","min":0,"max":"100","colors":["#005cb3","#e6b400","#ca3838"],"seg1":"","seg2":"","className":"","x":1230,"y":400,"wires":[]},{"id":"c8180dab.5ee6a8","type":"function","z":"ce4bb0dd.a8435","name":"","func":"\nmsg = {ui_control:{min:msg.payload.Min}};\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1020,"y":400,"wires":[["707583ce.97b974"]]},{"id":"5f9b6057.091398","type":"function","z":"ce4bb0dd.a8435","name":"","func":"\nmsg = {ui_control:{max:msg.payload.Max}};\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1020,"y":360,"wires":[["707583ce.97b974"]]},{"id":"72064ba4.9c14bc","type":"change","z":"ce4bb0dd.a8435","name":"Sensor 1","rules":[{"t":"set","p":"payload","pt":"msg","to":"AI00.value","tot":"global"},{"t":"set","p":"name","pt":"msg","to":"AI00.name","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":1020,"y":280,"wires":[["8e53a9b5.2fee8","707583ce.97b974"]]},{"id":"f95b453c.b2d438","type":"function","z":"ce4bb0dd.a8435","name":"Style Gauge","func":"var name = msg.payload;\n\nif (name == \"Druk\"){\n    msg.ui_control = \n    {\n    \"gtype\": \"donut\",\n    \"options\":{\n        \"circleColor\": msg.circleColor, \n        \"textColor\": msg.textColor, \n        \"waveTextColor\": msg.waveTextColor, \n        \"waveColor\": msg.waveColor, \n        \"circleThickness\":0.06, \n        \"textVertPosition\":0.4, \n        \"waveHeight\":0.08, \n        \"waveCount\":3,\n        \"label\": \"mbar\",\n                }\n    }\n    \n}else if (name == \"Temperatuur\"){   \n    msg.ui_control = \n    {\n        \"gtype\": \"gage\",\n        \"options\":{\n        \"label\": \"°c\",\n                }\n    }\n} else if (name ==\"Geleidbaarheid\"){\n    msg.ui_control =\n    {\n        \"gtype\": \"donut\",\n        \"options\":{\n        \"label\": \"µS\",\n                }\n        \n    }\n} else if (name ==\"Flow\"){\n    msg.ui_control =\n    {\n        \"gtype\": \"gage\",\n        \"options\":{\n        \"label\": \"m/s\",\n                }\n        \n    }\n} else {\n    msg.ui_control =\n    {\n        \"gtype\": \"\",\n        \"options\":{\n        \"label\": \"\",\n        \"max\": 0,\n                }\n    }\n    msg.name = \"empty\";\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1010,"y":320,"wires":[["707583ce.97b974","8e53a9b5.2fee8"]]},{"id":"2caba41f.e07d84","type":"link out","z":"ce4bb0dd.a8435","name":"Flow_Name","links":["b5ffb334.371da8"],"x":525,"y":40,"wires":[]},{"id":"b5ffb334.371da8","type":"link in","z":"ce4bb0dd.a8435","name":"","links":["2caba41f.e07d84"],"x":895,"y":280,"wires":[["f95b453c.b2d438"]]},{"id":"abcb8328.96141","type":"ui_group","z":"","name":"Settings","tab":"58a80602.fb5da8","order":1,"disp":true,"width":19,"collapse":false,"className":""},{"id":"38acb3ef.21ae24","type":"ui_group","z":"","name":"Sensor 1","tab":"b8864e65.57ebf","order":2,"disp":true,"width":"10","collapse":true,"className":""},{"id":"58a80602.fb5da8","type":"ui_tab","z":"","name":"Sensoren","icon":"perm_data_setting","order":3,"disabled":false,"hidden":false},{"id":"b8864e65.57ebf","type":"ui_tab","z":"","name":" Dashboard","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Ok. So for the file graphing section, you're reading in a CSV file and trying to assign the properties to the actual values. My guess is you're trying to use the header names for the actual data to graph? If so, you may not need the function you're attempting to use. At least, not in the way you're attempting to use it. Can you provide an example of the file you're reading from and what you expect to see on the graph? I think I know where you're going. Now I just need to know what's coming in so I can match it up to what you need out.

Hello madhouse,

I appreciate your help with my problem.

Underneath is the raw data of the CSV file. The header depends on the selected sensor in the dashboard:
image

I would like to show as following with the correct name at top of the graph:

First of all, if I've ever said anything about not knowing my German, it shows how much I also don't know Dutch. Sorry... :slight_smile:

That shouldn't be too hard to work with. I don't have any good CSV files to work with right now, so I can't build a good function for you yet. What is the output you get of this debug node when you load a file?
image
I'm imagining it would look something like an array of objects that look like (using your example above):

[{"Tijdstip":"March 8, 2022 4:47 AM", "Geleidbarrheid":136,.72},{"Tijdstip":"March 8, 2022 4:47 AM", "Geleidbarrheid":136,.72},{"Tijdstip":"March 8, 2022 4:47 AM", "Geleidbarrheid":136,.72},{"Tijdstip":"March 8, 2022 4:47 AM", "Geleidbarrheid":136,.72}]

If that's the case, you can get the unique column names from this:

var colNames = Object.keys(msg.payload[0]);

This would make colNames equal to:

["Tijdstip","Geleibaarheid"]
//or possibly...
["Tijdstip","Geleibaarheid",undefined,undefined,undefined]

Most likely the first. But it all depends on what the debug shows as to what will actually go into your array. Then you just have to pull what you want to see in your chart based on the title you're trying to get to. That way you can title your chart.

I have a good idea of how to send stuff to the chart so you get all of the columns in the file represented in one chart, but that now depends on what your CSV node output looks like. Let me know what comes out and I can show you how to build a way to display it on your chart.

Hello madhouse,

I get the following array in the debug node block you ask for:
image

I have tried with the Object.keys function, and you are correct! :slight_smile:

Now I get the collum names like so:
image

That is what I was looking for, now I must write the function again for setting the columns name + data for the right file for the graph node.

I have tried earlier with the Object.keys function but it won't work, so maybe I did something wrong.

Great thanks.

Welcome. Just let us know if you get stuck on something else and we'll help however we can!

Hello madhouse,

I am still interesting in your way of making this possible.

Will you share you idea how to give the graph node the right content?

Thanks in advance.

Sure. There's just one more thing I need to know. Is the timestamp (Tijdstip) stored as the actual text or is it stored as a number and converted to text?

Nevermind. I just went back and looked at the raw data you posted earlier. But that still leaves a question. How important is it to include Tijdstip on the chart?

Hello,

I take the actual year,month,day,hour,minute of the the moment and save this as string in the payload. After that I save the string in the CSV file.

It is a history of the measuring of the sensors so it would be very nice to see when the sensor(s) have measure the data.

It is a history for every day and, I would like to make an option in the future to start logging and stop logging, so node-red is not always logging like now and collect a lot of data.

The time or (tijdstip) ( maybe i have to write my code in English next time :slight_smile: ) have to be on the x-axis. I would also like to have in the future an easy filtering option for the x-axis for specified time, so it is easy to find the right data on the right time.

Ok. While this isn't a project killer, it makes things more difficult. Is it possible with your setup to store the "epoch time" instead of the date and time string? If you're using Node-Red to store the time, this is a very easy change. If the PLC is storing the time and you're getting it that way, it may not be... Epoch time is the time since a certain point in time, generally in something like seconds or milliseconds (Javascript uses milliseconds).

This makes me think you're having Node-Red gather and store all the data and that it's not something the PLC itself is storing, correct?

Both of these become much simpler if we store the epoch time instead of a date/time string. If at anytime you need to convert the epoch time into something human readable, you simply use this:

someVariable = someTimeVariable.toLocaleString("en-US");

Mine uses "en-US" because it formats it to US based time. All you have to do is substitute the locale, like "da-DK" for Denmark (making assumptions with Dutch, sorry if incorrect). This will convert the epoch time (current or stored) to a date/time string in the locale format and store it in a variable. You could eliminate the variable assignment and use it in a function to simply display the time in the locale date/time format.

What changing to epoch time does though is make it so you can compare times without trying to convert strings, which is not a quick solution in Javascript. Also, since the chart node uses epoch time, it makes it a very simple matter to pass the time to the chart and have everything formatted nicely without doing any conversions. It will do the date/time conversion for you and display it on the chart.

Is that a possibility with your flow?

Hello Madhouse,

:thinking: A lot of options, but it is very interesting to learn new things.

The epoch time is really an option if it is easier to implement and for adding to the graph maybe I have to use this instead of a long string text.

The PLC has a global variable list but not a historical logging function, therefore I use the node-red with the dashboard to easily showing this data.

The controller I use is the following type:
1334950000 UC20-WL2000-AC | WeidmĂĽller Product Catalogue (weidmueller.com)

Have you considered the option of using a time series database such as influx rather than using CSV files? If you want sophisticated graphs with the ability to select timeranges etc then influx integrates easily with Grafana to give you much better capabilities than you will ever get doing it yourself.

Yes, it is much easier. Instead of parsing your timestamp to store, you can just send it directly through to Tijdstip. When you reference it, you can simply compare times like regular numbers and order it based on such. And like I said, you can get a human readable date/time with a single command. Not only that, but you can pass the value directly into other nodes like the chart node because it can use that value directly.

Colin makes a good point here, though it depends on your setup. Using databases makes it so you can pull values directly into objects without any conversion in between. You can also pull individual columns instead of trying to parse an entire CSV for a specific series of values. Not much of an issue, but something to think about. I would make sure your setup is working the way you want before adding in something like databases, just to make sure you know it's working first. But that's up to you. CSV files also give you portability, which means you can take it to any system and open it. You may not be able to get to your database from every system.

If you have the time stored as an epoch, you can simply do this with the function once the values are passed in:

var myKeys = Object.keys(msg.payload[0]);
delete myKeys[0];
for(let x of msg.payload){
    for(let y of myKeys){
        node.send({topic:y, payload:x[y], timestamp:x.Tijdstip});
    }
}

To explain briefly what's happening, here's the breakdown.

  1. Payload comes in and we pull all the column names as keys.
  2. We remove the Tijdstip key since that's not a data point.
  3. We start a for loop to loop through each timestamp set of data. This includes the data for every column in that timestamp.
  4. We start an inner for loop to loop through each column of data using the keys we created earlier.
  5. In each inner loop, we send out a particular data point with three things. The topic tells us what column we're looking at (series on the chart). The payload is the actual data point (y axis). And the timestamp gives us our x axis.
  6. The inner loop goes through each column (series) and plots the data point for that timestamp and column. When that finishes, the loop ends and the next timestamp worth of data is pulled and parsed.

In the end, we should have several data points from several series worth of data. In order to plot a certain time period, you can simply put in an if statement around the node.send function to see if the Tidjstip value is between the lower and upper bounds you set. If it is, it sends the data point to the chart. If not, nothing is added.

I'm not actually sure if that will work (I don't have a data set and my instance of Node-Red can't add other flows right now), but I expect it should. Try it out and let me know what you end up with.

Hello madhouse,

It works quite well, but with the code you write the function node send every find data to the graph node.

At the end of the loop he finally send the filled array with the data.

I think it is because of the node.send function but I don't know exactly how it's works.