Sending Data from file in node to a dashboard table

I want to send data from file in node to ui table node for a display in node-red dashboard. How can I go about doing that?

As a general piece of advice, when you want to ask a question, pause and think about whether you are providing enough information.

You question current says you want to send data from a file to a table. Based on that information all we can say is wire the File In node in to a Function node, reformat your data, then pass it to a ui_template node containing an appropriate template or use https://flows.nodered.org/node/node-red-node-ui-table.

But you will then immediately ask how to reformat the data, and we'll say "we don't know because you haven't shared your data" and so on through the day.

You direct messaged me this question earlier and you did provide more information there. I asked you to post it publicly because I don't have time for one-on-one support today.

I know from the direct message you sent me that you want to display the data we spent a lot of yesterday helping you to reformat the numbers in - Parsing the scientific numbers to general numbers format

I asked you yesterday if you wanted to do anything with the individual values, or just replace the numbers in the text directly. You said you just wanted to replace the numbers in the text

Now you say you want to display them in a table. Had you mentioned that in yesterday's thread then I wouldn't have wasted my time giving you an answer that is not needed today.

So the task is to change the Function node I provided to extract the individual Fxyz values. Do you want any of the information from the first few lines of the text? Or is it just the F values from the second half of the file?

How can I resolve this issue

Hi. You're gonna have to be more explicit.

  1. Are you trying to use firebase?
  2. Do you want to use firebase?
  3. Have you imported a flow - that might have a firebase node in it?

As for what you want to do with the data, it looks like CSV data try putting a CSV node after the file in node then feed that to debug to see if you get data as expected.

Yes, I have imported flow that has firebase because the discussion seemed relevant

`[{"id":"c7e84e4f.2fcce","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"c80ee3b6.e3a8e","type":"function","z":"c7e84e4f.2fcce","name":"SQL - Select","func":"var select = {topic: \"SELECT * FROM NDBD\"};\nreturn select;\n","outputs":1,"noerr":0,"x":112,"y":235,"wires":[["5ae108cf.0a1588"]]},{"id":"5ae108cf.0a1588","type":"firebird","z":"c7e84e4f.2fcce","firebirddb":"63e7940.44abf6c","name":"BancoDados","x":283,"y":237,"wires":[["e3ed9800.4db168","8ae74f3f.4b261"]]},{"id":"b8b78526.adc458","type":"inject","z":"c7e84e4f.2fcce","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":132,"y":139,"wires":[["c80ee3b6.e3a8e"]]},{"id":"e3ed9800.4db168","type":"ui_template","z":"c7e84e4f.2fcce","group":"8c5b38db.78eea8","name":"Mostra Tabela","order":3,"width":"24","height":"6","format":"<div layout=\"row\" layout-align=\"start center\">\n    <span flex><b>Data</b></span> \n    <span flex><b>Hora</b></span>\n    <span flex><b>Set Point Ar1</b></span> \n    <span flex><b>Set Point Ar2</b></span>\n    <span flex><b>Temperatura Ar1</b></span>\n    <span flex><b>Temperatura Ar2</b></span>\n</div>\n<div layout=\"row\" layout-align=\"start center\" ng-repeat=\"x in msg.payload | limitTo:20\">\n    <span flex>{{x.DATA}}</span>\n    <span flex style=\"color: green\">{{x.HORA}}</span>    \n    <span flex style=\"color: red\">{{x.SETPOINTAR1}}</span>\n    <span flex>{{x.SETPOINTAR2}}</span>\n    <span flex>{{x.TEMPERATURAAR1}}</span>\n    <span flex>{{x.TEMPERATURAAR2}}</span>\n    \n</div>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":569,"y":123,"wires":[[]]},{"id":"8ae74f3f.4b261","type":"debug","z":"c7e84e4f.2fcce","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":679,"y":245,"wires":[]},{"id":"63e7940.44abf6c","type":"Firebirddatabase","z":"","host":"localhost","port":"3050","db":"C:\\NodeRed\\BancoDados\\NODEREDBD.FDB"},{"id":"8c5b38db.78eea8","type":"ui_group","z":"","name":"Default","tab":"1e230577.890d2b","disp":true,"width":"24","collapse":false},{"id":"1e230577.890d2b","type":"ui_tab","z":"","name":"TESTE","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

@Steve-Mcl, Do you know how I can fix the error?

Yes, but the answer depends on answering my questions.

There are many here who can help but if you are not concise it'll be difficult.

Just to summarise the options you can either:

  1. install the missing firebase node - search on flows.nodered.org to find which module provides that node
  2. or delete the firebase node you just imported. It may be in the Configuration Nodes sidebar tab listed as 'unknown'

No, It was just try I have imported a flow where firebase is used

Then follow what @knolleary said - point no. 2

Look at the flows and side bar for unknown node, delete, deploy.

Yep. Click it, press delete on keyboard. Deploy.

I did this, see image below, but I would like reformat the template to two columns and 14 rows. Any ideas

Yeah, plenty but again, without details I have no idea.

Firstly, you cant just poke your data into a CSV then into a template node & expect magic to happen.
I think you are trying to run before learning to walk TBH.
you really should spend some time here before moving on - i cant stress enough how much that section will help you.

That said, what comes out of the csv node?

Put a debug node BEFORE and AFTER the CSV (with the option "complete object" set on both debug nodes) - see what you get - see if thats doing what you expect before even attempting to display on dashboard.

You're welcome, NOTE AGAIN: I cant stress enough - read it - you will understand why I ask for the next bit...

Can you do what I asked?...

... screen shot the debug output (expand all parts of the debug msg) and post them both here.

I have parsed these number to general format i.e., F1 100.22 etc thanks to Mr @knolleary. So now I want to find away of sending what comes out of the function node to a table in a dashboard

In addition to @Steve-Mcl's suggestion of reading the documentation, i would highly recommend watching this full playlist of video's

I have managed to mimic the "sending command" example I find in the node-red-node-ui-table.
Modified it to the following screenshot with this flow

[{"id":"6aa7f187.9d891","type":"tab","label":"Flow 8","disabled":false,"info":""},{"id":"2aed37b5.a8b688","type":"ui_table","z":"6aa7f187.9d891","group":"5275919d.8e4a9","name":"","order":0,"width":"17","height":"4","columns":[{"field":"id","title":"id","width":"","align":"right","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"timestamp","title":"Timestamp","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"reconciled mesurement","title":"Reconciled Mesurement","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"text","title":"Error diference","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"standard deviation","title":"Standard Deviation","width":"","align":"left","formatter":"plaintext","formatterParams":{"target":"_blank"}}],"outputs":1,"cts":true,"x":770,"y":160,"wires":[["80dd5f3b.5ac2e","6322beea.6d17d"]]},{"id":"80dd5f3b.5ac2e","type":"debug","z":"6aa7f187.9d891","name":"response from ui-table","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1020,"y":160,"wires":[]},{"id":"7f852240.5f16e4","type":"inject","z":"6aa7f187.9d891","name":"Init 6 rows","topic":"","payload":"6","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":154,"y":188,"wires":[["5f413c76.2b94bc"]]},{"id":"5f413c76.2b94bc","type":"function","z":"6aa7f187.9d891","name":"table with n rows as array","func":"var numberOfRows = msg.payload;\nflow.set(\"lastId\",numberOfRows);\nmsg.payload=[];\nfor (let i=1; i<=numberOfRows; i++) {\n    msg.payload.push({\"id\":i,\"timestamp\":Date.now(),\"text\":\"Standard_Deviation value\"+i})\n}\nreturn msg;","outputs":1,"noerr":0,"x":425,"y":154,"wires":[["2aed37b5.a8b688","66fbd793.f8eed8","6322beea.6d17d"]]},{"id":"ffac5bf6.66fbb8","type":"comment","z":"6aa7f187.9d891","name":"update ui-table by passing the complete tableData as array","info":"","x":287,"y":103,"wires":[]},{"id":"66fbd793.f8eed8","type":"debug","z":"6aa7f187.9d891","name":"addRow","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":375,"y":205,"wires":[]},{"id":"6322beea.6d17d","type":"function","z":"6aa7f187.9d891","name":"table recorder","func":"var status = {fill:\"red\",shape:\"ring\",text:\"an error occured\"};\nvar success = (msg.topic && msg.topic===\"success\") || false;\nvar tableData = flow.get(\"tableData\");\nif (tableData === undefined) {\n    tableData = [];\n    flow.set(\"tableData\",tableData);\n}\n\n// find the index for a row in tableData for a given index (id)\nfunction checkIndex(id) {\n    let matchRow=-1\n    tableData.forEach(function (row,index){\n        if (row.id === id){\n            matchRow=index;\n            return matchRow;\n        }\n    })\n    return matchRow;\n}\n\n// flat merge one row \nfunction mergeRow(dest,source) {\n    Object.keys(source).forEach(function(key) {\n        dest[key]=source[key];\n    })\n}\n\n//merge or add one or many rows into tableData \nfunction mergeData(newData,toTop) {\n    newData.forEach(function (item,index) {\n        node.warn([\"findIndex\",item]);\n        let row=checkIndex(item.id);\n        if (row<0) { // row do not existst in tableData\n            if (toTop) {\n                tableData.push(item);\n                status.text+=\"newRow @ top\";\n            } else {\n                tableData.unshift(item);\n                status.text+=\"newRow @ bottom\";\n            }\n            return;\n        } else { // row exists so update\n            mergeRow(tableData[row],item);\n            status.text+=\"row updated\";\n            return;\n        }\n        if (status.text!==\"\") node.status(status);\n    });\n}\n\nswitch (typeof msg.payload){\n    case \"string\":\n        node.warn([\"[table recorder] \",(typeof msg.payload),msg.payload]);\n        switch (msg.payload){\n            case \"change\":\n                status={fill:\"green\",shape:\"dot\",text:\"table restored \"+tableData.length+\" rows\"};\n                msg.payload=tableData;\n                break;\n        }\n        break;\n    case \"object\":\n        node.warn([\"[table recorder] \",(typeof msg.payload),msg.payload]);\n        if (Array.isArray(msg.payload)) { // replace all tableData\n            status={fill:\"green\",shape:\"dot\",text:\"table replaced \"+msg.payload.length+\" rows\"};\n            tableData=RED.util.cloneMessage(msg.payload); \n        } else {\n            switch (msg.payload.command) { // clearData does not return a promise!\n                case \"clearData\":\n                    status={fill:\"green\",shape:\"dot\",text:\"clearData: done\"};\n                    tableData=[];\n                    flow.set(\"lastId\",0);\n                    break;                \n            }\n        }\n        break;\n    default: // likely a msg fom a ui-table command or callback\n        if (msg.hasOwnProperty(\"topic\")&&\n            msg.hasOwnProperty(\"ui_control\") && \n            msg.ui_control.hasOwnProperty(\"callback\") &&\n            msg.hasOwnProperty(\"return\")) { // message originates from a ui-table callback\n            if (success) {\n                switch(msg.return.command) {\n                    case \"addRow\":\n                        status.text=\"addRow: \";\n                        mergeData(msg.return.arguments[0],msg.return.arguments[1]);\n                        status.shape=\"dot\";\n                        break;\n                    case \"updateOrAddData\":\n                        status.text=\"updateOrAddData: \";\n                        mergeData(msg.return.arguments[0]);\n                        break;\n                    case \"deleteRow\":\n                        let row=checkIndex(msg.return.arguments[0]);\n                        tableData.splice(row,1);\n                        status.shape=\"dot\";\n                        status.text=\"deleteRow: \"+row+\" deleted\";\n                        break;\n                    default:\n                        status={fill:\"yellow\",shape:\"dot\",text:msg.return.command + \" unknown!\"};\n                        break;         \n                }\n            } else {\n                status.text=msg.topic+\" \"+msg.error;\n            }\n        }\n        break;\n}\nif (success) status.fill=\"green\";\nflow.set(\"tableData\",tableData);\nnode.status(status);\nreturn msg;","outputs":1,"noerr":0,"x":1080,"y":300,"wires":[["2aed37b5.a8b688"]],"icon":"font-awesome/fa-database","info":"# simple ui-table handler\n## abstract\nUsing ui-table with commands offer the hole flexibilty of tabulator. The table can be manipulated down to cell level.\nAs the ui-table node only passes the commands to tabulator and receives promises back the node does not hold the table data. If the data should be available after refresh, tab change, new connections the flow is responsible to cache the data and all the manipulations.\nThis node takes care of most simple data manipulation commands and holds a copy of the data in `flow.context.tabledata`\n\n## details\n\n### row index (id)\n\nTo identify a [row a index](http://tabulator.info/docs/4.5/data#overview) column has to be defined. This colum defaults to `id` but can be changed by specifing a **field** by using `msg.ui_control`. In this example the row index is a simple counter adding up by one if a new line is added.\n\n### addRow command\n\n[details @ tabulator addRow docs](http://tabulator.info/docs/4.5/update#alter-add)\n\nYou can add a row by sending the `addRow` command. You can decide if the row adds on the top or at the bottom of table.\n\n### addOrUpdate command\n\n[details @ tabulator addOrUpdate docs](http://tabulator.info/docs/4.5/update#alter-update)\n\nTo update data the best way is to use the `addOrUpdate` command. If the row indetified by the index is not exeisting a new row will be added automatically\n\n### deleteRow command\n\n[details @ tabulator deleteRow docs](http://tabulator.info/docs/4.5/update#row)\n\nDelete one or more rows (passing an array always results in \"row not found error\"! I think there is an issue in tabulator)\n\n### clearData\n\n[details @ tabulator clearData docs](http://tabulator.info/docs/4.5/update#alter-empty)\n\nunfortunately this command (currently) do not send a promise back! So we have to pass it directly to the table handler"},{"id":"b65fb2d7.e2a2d","type":"ui_ui_control","z":"6aa7f187.9d891","name":"","events":"all","x":780,"y":280,"wires":[["6322beea.6d17d"]]},{"id":"d9cb1d5d.d7458","type":"function","z":"6aa7f187.9d891","name":"clearData","func":"\nmsg.payload={\n    command:\"clearData\",\n    arguments: [],\n    returnPromise: true\n}\nreturn msg;","outputs":1,"noerr":0,"x":400,"y":320,"wires":[["a75fa725.6d4eb8","2aed37b5.a8b688","6322beea.6d17d"]],"info":"# clear data\n\nunfortunately this command (currently) do not send a promise back! So we have to pass it directly to the table handler"},{"id":"99c4061a.65cf1","type":"inject","z":"6aa7f187.9d891","name":"clear","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":340,"wires":[["d9cb1d5d.d7458"]]},{"id":"72024cb8.f707ec","type":"comment","z":"6aa7f187.9d891","name":"Erase all data by using clearData command","info":"","x":250,"y":240,"wires":[]},{"id":"a75fa725.6d4eb8","type":"debug","z":"6aa7f187.9d891","name":"clearData","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":420,"y":380,"wires":[]},{"id":"59345176.871548","type":"inject","z":"6aa7f187.9d891","name":"change","topic":"","payload":"change","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":810,"y":340,"wires":[["6322beea.6d17d"]]},{"id":"2197bee7.b209ba","type":"ui_button","z":"6aa7f187.9d891","name":"","group":"6eb2a5.27c0255c","order":1,"width":0,"height":0,"passthru":false,"label":"Update","tooltip":"init table by passing the hole table array (default way)","color":"","bgcolor":"","icon":"","payload":"6","payloadType":"num","topic":"","x":154,"y":154,"wires":[["5f413c76.2b94bc"]]},{"id":"5427903f.e2b478","type":"ui_button","z":"6aa7f187.9d891","name":"","group":"6eb2a5.27c0255c","order":7,"width":0,"height":0,"passthru":false,"label":"clear","tooltip":"clear all table data","color":"","bgcolor":"","icon":"","payload":"","payloadType":"date","topic":"","x":150,"y":280,"wires":[["d9cb1d5d.d7458"]]},{"id":"a4255c12.fc045","type":"ui_text","z":"6aa7f187.9d891","group":"6eb2a5.27c0255c","order":9,"width":0,"height":0,"name":"","label":"status","format":"{{status.text}}","layout":"col-center","x":1170,"y":500,"wires":[]},{"id":"6d1e109d.23ebf","type":"status","z":"6aa7f187.9d891","name":"","scope":["6322beea.6d17d"],"x":1000,"y":500,"wires":[["a4255c12.fc045"]]},{"id":"5f255802.ff636","type":"ui_button","z":"6aa7f187.9d891","name":"","group":"6eb2a5.27c0255c","order":8,"width":0,"height":0,"passthru":false,"label":"refresh (change)","tooltip":"Same as ui-control sending a change message","color":"","bgcolor":"","icon":"","payload":"change","payloadType":"str","topic":"","x":1100,"y":420,"wires":[["6322beea.6d17d"]]},{"id":"5fa0418b.dd5b4","type":"inject","z":"6aa7f187.9d891","name":"format table","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":500,"wires":[["207a59a5.36f3b6"]]},{"id":"fe0b57cb.2e4728","type":"comment","z":"6aa7f187.9d891","name":"Format Table using ui_control","info":"","x":200,"y":380,"wires":[]},{"id":"da83f888.b22b4","type":"debug","z":"6aa7f187.9d891","name":"clearData","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":800,"y":500,"wires":[]},{"id":"c16a2992.00629","type":"ui_button","z":"6aa7f187.9d891","name":"","group":"6eb2a5.27c0255c","order":7,"width":0,"height":0,"passthru":false,"label":"format table","tooltip":"Formats the table using msg.ui_control","color":"","bgcolor":"","icon":"","payload":"","payloadType":"date","topic":"","x":150,"y":420,"wires":[["207a59a5.36f3b6"]]},{"id":"207a59a5.36f3b6","type":"change","z":"6aa7f187.9d891","name":"","rules":[{"t":"set","p":"ui_control","pt":"msg","to":"{\"customHeight\":18,\"tabulator\":{\"layout\":\"fitColumns\",\"movableColumns\":false,\"index\":\"id\",\"columns\":[{\"title\":\"ID\",\"field\":\"id\",\"formatter\":\"text\",\"headerTooltip\":\"id number act as row index\"},{\"formatterParams\":{\"outputFormat\":\"HH:mm:ss.SSS\",\"inputFormat\":\"x\",\"invalidPlaceholder\":\"(unknown)\"},\"title\":\"Timestamp\",\"field\":\"timestamp\",\"formatter\":\"datetime\",\"headerTooltip\":\"timestamp of last change\"},\"title\":\"Reconciled Mesurement\",\"field\":\"\",\"formatter\":\"\",\"headerTooltip\":\"reconciled mesurement of last change\"},{\"title\":\"Error difference\",\"field\":\"text\",\"headerTooltip\":\"last cause of reboot (provided by http json request)\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":440,"wires":[["da83f888.b22b4","2aed37b5.a8b688","1110367a.440bea"]]},{"id":"1110367a.440bea","type":"change","z":"6aa7f187.9d891","name":"change","rules":[{"t":"delete","p":"ui_control","pt":"msg"},{"t":"set","p":"payload","pt":"msg","to":"change","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":440,"wires":[["6322beea.6d17d"]]},{"id":"5275919d.8e4a9","type":"ui_group","z":"","name":"Heat Exchanger Example","tab":"fcc61d13.672c7","disp":true,"width":"17","collapse":false},{"id":"6eb2a5.27c0255c","type":"ui_group","z":"","name":"commands","tab":"fcc61d13.672c7","disp":true,"width":"6","collapse":false},{"id":"fcc61d13.672c7","type":"ui_tab","z":"","name":"Heat Exchanger Example","icon":"fa-table","disabled":false,"hidden":false}]


My goal is now is to update the table with the right data. I have created a flow for the data I want to work with and it looks like this screenshot

with this follow

`[{"id":"57dded67.4f2584","type":"tab","label":"Flow 5","disabled":false,"info":""},{"id":"83ccee1e.161cc","type":"inject","z":"57dded67.4f2584","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":260,"y":1020,"wires":[["ead8cd61.1334a8"]]},{"id":"ead8cd61.1334a8","type":"exec","z":"57dded67.4f2584","command":"C:\\\\IMPL\\\\HeatExchanger.bat","addpay":false,"append":"","useSpawn":"true","timer":"","oldrc":false,"name":"","x":480,"y":1020,"wires":[["38594113.893e66"],["fd3d1849.d2595"],["4c429df5.e97124"]]},{"id":"38594113.893e66","type":"debug","z":"57dded67.4f2584","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","x":819,"y":960,"wires":[]},{"id":"fd3d1849.d2595","type":"debug","z":"57dded67.4f2584","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","x":819,"y":1020,"wires":[]},{"id":"4c429df5.e97124","type":"debug","z":"57dded67.4f2584","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","x":819,"y":1080,"wires":[]},{"id":"a43987c4.046948","type":"file in","z":"57dded67.4f2584","name":"","filename":"C:\\IMPL\\HeatExchanger\\MassBalancing.dta","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":450,"y":100,"wires":[["cb140895.60a848"]]},{"id":"2e2863ae.cf303c","type":"debug","z":"57dded67.4f2584","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":950,"y":100,"wires":[]},{"id":"152a6280.2afede","type":"inject","z":"57dded67.4f2584","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":100,"wires":[["a43987c4.046948"]]},{"id":"cb140895.60a848","type":"function","z":"57dded67.4f2584","name":"","func":"msg.payload = msg.payload.replace(/(-?\\d+\\.\\d+E[-+]\\d+)/g,\nfunction(v) { return Number(v) })\nreturn msg;","outputs":1,"noerr":0,"x":730,"y":100,"wires":[["2e2863ae.cf303c"]]}]` 

I would appreciate some guidance on how I can update the `ui table` 
with data from the function node that reads a `file in` from node

I have managed to find a solution - thanks to each and every one of you!.

@Munier It would be great for the rest of us if you could explain what you did / how you did it, so we could learn without having to ask the same question you did, please.

1 Like

Hi Micheal,

I have done a couple of things to display dashboard that contains the on-line results of
a software I am using wherein a particular timestamp using
either snapshot or time-aggregated Tagname (ID) process
variable data is used to show the raw measurement,
reconciled value, revision or adjustment (raw –
reconciled), standard-deviation of the revision (squareroot
of its reconciled variance) and corresponding grosserror
detection statistics we call vetistic.

I would be happy to share with you what I have done do you want me to post the flow I have used?