Add Single String to msg.payload so csv output prints as title of messages?

Hi, i'm trying to figure out how to basically just automatically inject a string that kind of acts like a title to the messages below based on which dash button someone presses.
so basically if they press the 2kV start button it writes to the excel file as the data comes through "2kV Test Readings" then the msg payload / timestamp that came before in the flow... but it seems my attempt just stops outputting to file if i have the title adding function in place. quite stuck.

to elaborate, i only want the 'title' to occupy 1 cell each time the start is pressed, so if someone presses start and gets 1 batch of readings it is at the top. if they press start and let 4 batches of readings write to file i still only want it to be at the top once... unless they press stop and start again...

here's my flow:

[{"id":"11abe06410824819","type":"tab","label":"Voltage monitor test","disabled":false,"info":"","env":[]},{"id":"e485991ccf3e0822","type":"serial in","z":"11abe06410824819","name":"ESP_RX","serial":"6929e66dfb37b765","x":80,"y":320,"wires":[["fd8076b5fc07bbe3","d1156230815e2561","f9cfdd32067a70ed"]]},{"id":"8d630393845bd583","type":"ui_text","z":"11abe06410824819","group":"5d58b87e2056344d","order":1,"width":6,"height":3,"name":"Date and Time","label":"","format":"{{msg.payload}}","layout":"row-left","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1440,"y":20,"wires":[]},{"id":"4bfbe73e0ce0a23d","type":"function","z":"11abe06410824819","name":"add time","func":"msg.payload = new Date().toString() +'\\n'+\" \"+',' +msg.payload;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":340,"wires":[["8ae3077d1e35d6f7","646f21230c7c34d8"]]},{"id":"245ca36fe017d921","type":"file","z":"11abe06410824819","name":"OUTPUT FILE","filename":"C:\\Users\\223131446\\documents\\ESP_NOW_testfile.csv","filenameType":"str","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":1460,"y":560,"wires":[[]]},{"id":"d1156230815e2561","type":"debug","z":"11abe06410824819","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":140,"y":40,"wires":[]},{"id":"dad545f1b5f6476c","type":"function","z":"11abe06410824819","name":"payload buffer","func":"// Get the cycle var from this node's context store or set to 0 if it doesn't yet exist\nlet cycle = context.get('cycle') ?? 0\n\n// Get the data buffer or an empty array if not exists yet\nconst databuff = context.get('databuff') ?? []\n\n// Add the new data to the buffer\ndatabuff.push(msg.payload)\n\n// Increment the cycle count\ncycle++\n\nif (cycle >= 5) {\n    // Output the buffer (join the array as a string)\n    node.send({payload: databuff.join('')})\n    // reset the buffer\n    context.set('databuff', [])\n    // reset the counter\n    context.set('cycle', 0)\n} else {\n    context.set('databuff', databuff)\n    context.set('cycle', cycle)\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":520,"wires":[["245ca36fe017d921"]]},{"id":"8ae3077d1e35d6f7","type":"function","z":"11abe06410824819","name":"Message parser","func":"var outputs = [];\nvar values = msg.payload.split(\",\");\nfor(var v in values){\n    outputs.push({payload:values[v]});\n}\nreturn outputs;","outputs":21,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":220,"wires":[["8d630393845bd583"],["70cd1f1ccbd09caf"],["b4d7d97c77eaa853"],["8a48bf7f69cbd11a"],["1774b8ac7e7e9d7b"],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]},{"id":"70cd1f1ccbd09caf","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":1,"width":4,"height":1,"name":"B1 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":60,"wires":[]},{"id":"b4d7d97c77eaa853","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":2,"width":4,"height":1,"name":"B2 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":100,"wires":[]},{"id":"480a77aad8b034ce","type":"delay","z":"11abe06410824819","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"10","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":120,"y":680,"wires":[[]]},{"id":"fd8076b5fc07bbe3","type":"q-gate","z":"11abe06410824819","name":"2kV Write Blocker","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","queueCmd":"queue","defaultCmd":"default","triggerCmd":"trigger","flushCmd":"flush","resetCmd":"reset","peekCmd":"peek","dropCmd":"drop","statusCmd":"status","maxQueueLength":"100","keepNewest":false,"qToggle":false,"persist":true,"storeName":"memory","x":510,"y":260,"wires":[["4bfbe73e0ce0a23d"]]},{"id":"039f4d8694d72753","type":"ui_button","z":"11abe06410824819","name":"2kVStart","group":"fb9a3225602c434e","order":2,"width":3,"height":2,"passthru":false,"label":"Start Receiving Data","tooltip":"","color":"","bgcolor":"green","className":"","icon":"","payload":"open","payloadType":"str","topic":"control","topicType":"str","x":340,"y":120,"wires":[["fd8076b5fc07bbe3"]]},{"id":"0f4ca1545306e50a","type":"ui_button","z":"11abe06410824819","name":"2kV Stop","group":"fb9a3225602c434e","order":3,"width":3,"height":2,"passthru":true,"label":"Stop Receiving Data","tooltip":"","color":"","bgcolor":"red","className":"","icon":"","payload":"close","payloadType":"str","topic":"control","topicType":"str","x":340,"y":160,"wires":[["fd8076b5fc07bbe3"]]},{"id":"8a48bf7f69cbd11a","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":3,"width":4,"height":1,"name":"B3 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":140,"wires":[]},{"id":"b804165a13928094","type":"debug","z":"11abe06410824819","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":860,"y":60,"wires":[]},{"id":"1774b8ac7e7e9d7b","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":4,"width":4,"height":1,"name":"B4 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":180,"wires":[]},{"id":"f9cfdd32067a70ed","type":"q-gate","z":"11abe06410824819","name":"4kV Write Blocker","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","queueCmd":"queue","defaultCmd":"default","triggerCmd":"trigger","flushCmd":"flush","resetCmd":"reset","peekCmd":"peek","dropCmd":"drop","statusCmd":"status","maxQueueLength":"100","keepNewest":false,"qToggle":false,"persist":true,"storeName":"memory","x":510,"y":480,"wires":[[]]},{"id":"8f32978ecfef8149","type":"ui_button","z":"11abe06410824819","name":"4kV Stop","group":"fb9a3225602c434e","order":6,"width":3,"height":2,"passthru":true,"label":"Stop Receiving Data","tooltip":"","color":"","bgcolor":"red","className":"","icon":"","payload":"close","payloadType":"str","topic":"control","topicType":"str","x":320,"y":360,"wires":[["f9cfdd32067a70ed"]]},{"id":"4c93f806372b1bba","type":"ui_button","z":"11abe06410824819","name":"4kV Start","group":"fb9a3225602c434e","order":5,"width":3,"height":2,"passthru":false,"label":"Start Receiving Data","tooltip":"","color":"","bgcolor":"green","className":"","icon":"","payload":"open","payloadType":"str","topic":"control","topicType":"str","x":320,"y":320,"wires":[["f9cfdd32067a70ed"]]},{"id":"646f21230c7c34d8","type":"function","z":"11abe06410824819","name":"2kV Title","func":"","outputs":1,"timeout":0,"noerr":0,"initialize":"var title;\nvar data;\ndata = msg.payload;\ntitle = \"2kV Test Readings\";\nmsg.payload = title + data;\nreturn msg;\n","finalize":"","libs":[],"x":920,"y":520,"wires":[["dad545f1b5f6476c","b804165a13928094"]]},{"id":"9ce84772b81d7467","type":"ui_spacer","z":"11abe06410824819","name":"spacer","group":"fb9a3225602c434e","order":4,"width":3,"height":1},{"id":"6929e66dfb37b765","type":"serial-port","name":"Nano IN","serialport":"COM5","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"},{"id":"5d58b87e2056344d","type":"ui_group","name":"Timestamp:","tab":"f95d506942394920","order":3,"disp":true,"width":"6","collapse":false,"className":""},{"id":"e926a6330eaa482e","type":"ui_group","name":"Voltage Readings","tab":"f95d506942394920","order":4,"disp":true,"width":"16","collapse":false,"className":""},{"id":"fb9a3225602c434e","type":"ui_group","name":"Control Panel","tab":"f95d506942394920","order":1,"disp":true,"width":"3","collapse":false,"className":""},{"id":"f95d506942394920","type":"ui_tab","name":"Home","icon":"fa-bolt","disabled":false,"hidden":false}]

my plan is to have a title per type of button pressed. any help is appreciated even if it's just pointing me to a solution to once append a string to a payload automatically

i would just like to point out if i put the code into 'On 'Message' it works. but it puts the test title every single message payload.

e.g.:

[{"id":"11abe06410824819","type":"tab","label":"Voltage monitor test","disabled":false,"info":"","env":[]},{"id":"e485991ccf3e0822","type":"serial in","z":"11abe06410824819","name":"ESP_RX","serial":"6929e66dfb37b765","x":80,"y":320,"wires":[["fd8076b5fc07bbe3","d1156230815e2561","f9cfdd32067a70ed"]]},{"id":"8d630393845bd583","type":"ui_text","z":"11abe06410824819","group":"5d58b87e2056344d","order":1,"width":6,"height":3,"name":"Date and Time","label":"","format":"{{msg.payload}}","layout":"row-left","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1440,"y":20,"wires":[]},{"id":"4bfbe73e0ce0a23d","type":"function","z":"11abe06410824819","name":"add time","func":"msg.payload = new Date().toString() +'\\n'+\" \"+',' +msg.payload;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":340,"wires":[["8ae3077d1e35d6f7","646f21230c7c34d8"]]},{"id":"245ca36fe017d921","type":"file","z":"11abe06410824819","name":"OUTPUT FILE","filename":"C:\\Users\\223131446\\documents\\ESP_NOW_testfile.csv","filenameType":"str","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":1460,"y":560,"wires":[[]]},{"id":"d1156230815e2561","type":"debug","z":"11abe06410824819","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":140,"y":40,"wires":[]},{"id":"dad545f1b5f6476c","type":"function","z":"11abe06410824819","name":"payload buffer","func":"// Get the cycle var from this node's context store or set to 0 if it doesn't yet exist\nlet cycle = context.get('cycle') ?? 0\n\n// Get the data buffer or an empty array if not exists yet\nconst databuff = context.get('databuff') ?? []\n\n// Add the new data to the buffer\ndatabuff.push(msg.payload)\n\n// Increment the cycle count\ncycle++\n\nif (cycle >= 5) {\n    // Output the buffer (join the array as a string)\n    node.send({payload: databuff.join('')})\n    // reset the buffer\n    context.set('databuff', [])\n    // reset the counter\n    context.set('cycle', 0)\n} else {\n    context.set('databuff', databuff)\n    context.set('cycle', cycle)\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":520,"wires":[["245ca36fe017d921","b804165a13928094"]]},{"id":"8ae3077d1e35d6f7","type":"function","z":"11abe06410824819","name":"Message parser","func":"var outputs = [];\nvar values = msg.payload.split(\",\");\nfor(var v in values){\n    outputs.push({payload:values[v]});\n}\nreturn outputs;","outputs":21,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":220,"wires":[["8d630393845bd583"],["70cd1f1ccbd09caf"],["b4d7d97c77eaa853"],["8a48bf7f69cbd11a"],["1774b8ac7e7e9d7b"],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]},{"id":"70cd1f1ccbd09caf","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":1,"width":4,"height":1,"name":"B1 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":60,"wires":[]},{"id":"b4d7d97c77eaa853","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":2,"width":4,"height":1,"name":"B2 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":100,"wires":[]},{"id":"480a77aad8b034ce","type":"delay","z":"11abe06410824819","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"10","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":120,"y":680,"wires":[[]]},{"id":"fd8076b5fc07bbe3","type":"q-gate","z":"11abe06410824819","name":"2kV Write Blocker","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","queueCmd":"queue","defaultCmd":"default","triggerCmd":"trigger","flushCmd":"flush","resetCmd":"reset","peekCmd":"peek","dropCmd":"drop","statusCmd":"status","maxQueueLength":"100","keepNewest":false,"qToggle":false,"persist":true,"storeName":"memory","x":510,"y":260,"wires":[["4bfbe73e0ce0a23d"]]},{"id":"039f4d8694d72753","type":"ui_button","z":"11abe06410824819","name":"2kVStart","group":"fb9a3225602c434e","order":2,"width":3,"height":2,"passthru":false,"label":"Start Receiving Data","tooltip":"","color":"","bgcolor":"green","className":"","icon":"","payload":"open","payloadType":"str","topic":"control","topicType":"str","x":340,"y":120,"wires":[["fd8076b5fc07bbe3"]]},{"id":"0f4ca1545306e50a","type":"ui_button","z":"11abe06410824819","name":"2kV Stop","group":"fb9a3225602c434e","order":3,"width":3,"height":2,"passthru":true,"label":"Stop Receiving Data","tooltip":"","color":"","bgcolor":"red","className":"","icon":"","payload":"close","payloadType":"str","topic":"control","topicType":"str","x":340,"y":160,"wires":[["fd8076b5fc07bbe3"]]},{"id":"8a48bf7f69cbd11a","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":3,"width":4,"height":1,"name":"B3 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":140,"wires":[]},{"id":"b804165a13928094","type":"debug","z":"11abe06410824819","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1380,"y":440,"wires":[]},{"id":"1774b8ac7e7e9d7b","type":"ui_text","z":"11abe06410824819","group":"e926a6330eaa482e","order":4,"width":4,"height":1,"name":"B4 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1420,"y":180,"wires":[]},{"id":"f9cfdd32067a70ed","type":"q-gate","z":"11abe06410824819","name":"4kV Write Blocker","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","queueCmd":"queue","defaultCmd":"default","triggerCmd":"trigger","flushCmd":"flush","resetCmd":"reset","peekCmd":"peek","dropCmd":"drop","statusCmd":"status","maxQueueLength":"100","keepNewest":false,"qToggle":false,"persist":true,"storeName":"memory","x":510,"y":480,"wires":[[]]},{"id":"8f32978ecfef8149","type":"ui_button","z":"11abe06410824819","name":"4kV Stop","group":"fb9a3225602c434e","order":6,"width":3,"height":2,"passthru":true,"label":"Stop Receiving Data","tooltip":"","color":"","bgcolor":"red","className":"","icon":"","payload":"close","payloadType":"str","topic":"control","topicType":"str","x":320,"y":360,"wires":[["f9cfdd32067a70ed"]]},{"id":"4c93f806372b1bba","type":"ui_button","z":"11abe06410824819","name":"4kV Start","group":"fb9a3225602c434e","order":5,"width":3,"height":2,"passthru":false,"label":"Start Receiving Data","tooltip":"","color":"","bgcolor":"green","className":"","icon":"","payload":"open","payloadType":"str","topic":"control","topicType":"str","x":320,"y":320,"wires":[["f9cfdd32067a70ed"]]},{"id":"646f21230c7c34d8","type":"function","z":"11abe06410824819","name":"2kV Title","func":"var title;\nvar data;\ndata = msg.payload;\ntitle = \"2kV Test Readings\";\nmsg.payload = title + '\\n'+ data ;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"\n","finalize":"","libs":[],"x":920,"y":520,"wires":[["dad545f1b5f6476c"]]},{"id":"9ce84772b81d7467","type":"ui_spacer","z":"11abe06410824819","name":"spacer","group":"fb9a3225602c434e","order":4,"width":3,"height":1},{"id":"6929e66dfb37b765","type":"serial-port","name":"Nano IN","serialport":"COM5","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"},{"id":"5d58b87e2056344d","type":"ui_group","name":"Timestamp:","tab":"f95d506942394920","order":3,"disp":true,"width":"6","collapse":false,"className":""},{"id":"e926a6330eaa482e","type":"ui_group","name":"Voltage Readings","tab":"f95d506942394920","order":4,"disp":true,"width":"16","collapse":false,"className":""},{"id":"fb9a3225602c434e","type":"ui_group","name":"Control Panel","tab":"f95d506942394920","order":1,"disp":true,"width":"3","collapse":false,"className":""},{"id":"f95d506942394920","type":"ui_tab","name":"Home","icon":"fa-bolt","disabled":false,"hidden":false}]


i literally just want 2kV Test Readings to print in first row, until someone presses stop -> start, again...

i attempted using a combination of an IF type function and the inject node, but couldnt quite get it to work right. also tried a for loop but that would completely brick my flow for some reason

Hi @Boerwors

Sorry no one has responded yet.

But I feel you may have over engineered the solution (applogies if not)

But a better approach maybe using the CSV Node?

[{"id":"b90596e4a94f9523","type":"inject","z":"7be0fa384bab46bd","name":"Start (Heading)","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"2kV Test Readings\",\"\",\"\",\"\",\"\"]","payloadType":"json","x":260,"y":200,"wires":[["a830b34f8455f071"]]},{"id":"a830b34f8455f071","type":"csv","z":"7be0fa384bab46bd","name":"","sep":",","hdrin":"","hdrout":"none","multi":"one","ret":"\\r\\n","temp":"","skip":"0","strings":true,"include_empty_strings":true,"include_null_values":true,"x":470,"y":260,"wires":[["5ca1b7eb672faee5"]]},{"id":"8a6716ddc31f1d9d","type":"inject","z":"7be0fa384bab46bd","name":"Each Reading","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[$random(),$random(),$random(),$random()]","payloadType":"jsonata","x":230,"y":340,"wires":[["a830b34f8455f071"]]},{"id":"5ca1b7eb672faee5","type":"file","z":"7be0fa384bab46bd","name":"","filename":"Some-path","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":710,"y":260,"wires":[[]]}]

hi marcus, no worries :slight_smile:

as for using the CSV node i'm a bit hesitant to use it as my serial input brings in e.g. 4 readings as a single message that is internally parsed on the arduino with ',' and \t...

would the CSV node not bugger this up? also is there a way to control the inject node by using the button that i have in the flow? in a sort of roundabout way i think i solved it. since i only want the title to be written to the top row when the start button is pressed, could i use the message that the start button sends to open the blocking gate, to also trigger a function that returns the title message once? i've made some updates to the flow but its now so large i cant add it to the reply

to tack on a secondary question: could you point me to any guidance docs on how to add stylization to the written CSV file? similar to yours where the top row is filled etc...

If each row is already formatted (to represent each column)
Use the split & join nodes to create an array of the columns for the CSV node

you can set the delimiter in the CSV Node

See below for revision 2

[{"id":"0212b0f88459ef06","type":"inject","z":"7be0fa384bab46bd","name":"Create Header","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":240,"wires":[["f1f9e78327d5f81c"]]},{"id":"99d3ceead8531fdb","type":"csv","z":"7be0fa384bab46bd","name":"","sep":",","hdrin":"","hdrout":"none","multi":"one","ret":"\\r\\n","temp":"","skip":"0","strings":true,"include_empty_strings":true,"include_null_values":true,"x":670,"y":240,"wires":[["9af9c8e3dc25a7f7"]]},{"id":"da47ca1c65b653ba","type":"inject","z":"7be0fa384bab46bd","name":"Preformatted Readings","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Value 1,Value 2,Value 3, Value 4","payloadType":"str","x":180,"y":320,"wires":[["87f6a7d5e121cfa2"]]},{"id":"9af9c8e3dc25a7f7","type":"file","z":"7be0fa384bab46bd","name":"","filename":"/Users/marcusdavies/Documents/test.csv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":920,"y":240,"wires":[[]]},{"id":"87f6a7d5e121cfa2","type":"split","z":"7be0fa384bab46bd","name":"","splt":",","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":390,"y":320,"wires":[["ba90fe9a085d627f"]]},{"id":"ba90fe9a085d627f","type":"join","z":"7be0fa384bab46bd","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"4","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":530,"y":320,"wires":[["99d3ceead8531fdb"]]},{"id":"f1f9e78327d5f81c","type":"change","z":"7be0fa384bab46bd","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[[\"2kV Test Readings\",\"\",\"\",\"\",\"\"],[$moment(),\"\",\"\",\"\",\"\"]]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":240,"wires":[["99d3ceead8531fdb"]]}]

This is my place holder and should be replaced by another action according to your needs
the formatted readings inject - will be the serial output for example

This is just the Numbers (excel) app for OSX, its styled by the application, not the file - CSV can't be styled unless its an excel file

Once the start button is pressed (Creates the start header for the batch)
just block further messages from it, until one presses stop, and then re-opens the gate

1 Like

thanks for the help marcus i will try your solution out and see how it fits :slight_smile:

1 Like

hello again, i tried it but it doesn't seem to work. since my last reply i've also noticed that i've changed the data to be parsed by \t only, so no commas now. so coming out of serial is just the Values. then i add current time to the top end of that msg.payload with a function. i'm fine with the time being every single time the values come through because they're time logged anyway.

is it then possible to get just the title at the top? when it's all just separated by tabs. i'm intrigued by using this CSV node as it may make the excel sheet look nicer and open up the ability to have individual columnheaders.

i've included a snapshot of one part of my current flow where i'm still having this problem:

[{"id":"7bfc1276c35b6509","type":"tab","label":"Flow 2","disabled":false,"info":"","env":[]},{"id":"972375677a4ce17f","type":"group","z":"7bfc1276c35b6509","name":"FULL HEAT TEST DASH FLOW","style":{"stroke":"#000000","label":true},"nodes":["553b074c63e322cd","84f2ec6a764f5aa3","ec67b399c180e6e0","bf8c5a72052dc995","6128f83772ac870f","67e42f9c2cff1d59","43ebe42ba3ef66f6","433c8b3b77203411","e0555b63417f4fe7","37d0bb8b1ae64669","0acc4e3a7c4b5d7b","6fc641777086432b","0052f74badf54e9b","12685748df941f03","235ee89a7b4d3084","b11078f7e2c006f1","645d29fb43471c2e","62589ab3f0ca9572","164c3e5b969108b1","be74fb718f082b5d","10493f2c714f7076","af2c081e45aeea4f","15e2d6cbe81f1be7"],"x":614,"y":79,"w":1692,"h":582},{"id":"553b074c63e322cd","type":"function","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"Message parser","func":"var display = [];\nvar values = msg.payload.split(\"\\t\");\nfor(var v in values){\n    display.push({payload:values[v]});\n}\nreturn display;","outputs":21,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1740,"y":320,"wires":[["84f2ec6a764f5aa3"],["ec67b399c180e6e0"],["bf8c5a72052dc995"],["6128f83772ac870f"],["67e42f9c2cff1d59"],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]},{"id":"84f2ec6a764f5aa3","type":"ui_text","z":"7bfc1276c35b6509","g":"972375677a4ce17f","group":"08809e5c2942d6fc","order":1,"width":6,"height":3,"name":"Date and Time","label":"","format":"{{msg.payload}}","layout":"row-left","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":1920,"y":120,"wires":[]},{"id":"ec67b399c180e6e0","type":"ui_text","z":"7bfc1276c35b6509","g":"972375677a4ce17f","group":"3541e8bfb78c4f57","order":1,"width":4,"height":1,"name":"B1 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":2220,"y":120,"wires":[]},{"id":"bf8c5a72052dc995","type":"ui_text","z":"7bfc1276c35b6509","g":"972375677a4ce17f","group":"3541e8bfb78c4f57","order":2,"width":4,"height":1,"name":"B2 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":2220,"y":160,"wires":[]},{"id":"6128f83772ac870f","type":"ui_text","z":"7bfc1276c35b6509","g":"972375677a4ce17f","group":"3541e8bfb78c4f57","order":3,"width":4,"height":1,"name":"B3 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":2220,"y":200,"wires":[]},{"id":"67e42f9c2cff1d59","type":"ui_text","z":"7bfc1276c35b6509","g":"972375677a4ce17f","group":"3541e8bfb78c4f57","order":4,"width":4,"height":1,"name":"B4 Out","label":"","format":"{{msg.payload}}","layout":"row-spread","className":"","style":true,"font":"","fontSize":16,"color":"#000000","x":2220,"y":240,"wires":[]},{"id":"43ebe42ba3ef66f6","type":"link in","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"FULL DASH","links":["e0555b63417f4fe7"],"x":1615,"y":300,"wires":[["553b074c63e322cd"]]},{"id":"433c8b3b77203411","type":"function","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"add time","func":"msg.payload = new Date().toString() +'\\n'+\"\\t \"+msg.payload;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":340,"wires":[["e0555b63417f4fe7"]]},{"id":"e0555b63417f4fe7","type":"link out","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"FULL_TO_DASH","mode":"link","links":["b11078f7e2c006f1","43ebe42ba3ef66f6"],"x":1165,"y":320,"wires":[]},{"id":"37d0bb8b1ae64669","type":"ui_button","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"Start","group":"267b3b26d23a38e6","order":1,"width":3,"height":2,"passthru":false,"label":"Start Receiving Data","tooltip":"","color":"","bgcolor":"green","className":"","icon":"","payload":"open","payloadType":"str","topic":"control","topicType":"str","x":690,"y":220,"wires":[["62589ab3f0ca9572","10493f2c714f7076","235ee89a7b4d3084"]]},{"id":"0acc4e3a7c4b5d7b","type":"ui_button","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"Stop","group":"267b3b26d23a38e6","order":4,"width":3,"height":2,"passthru":true,"label":"Stop Receiving Data","tooltip":"","color":"","bgcolor":"red","className":"","icon":"","payload":"close","payloadType":"str","topic":"control","topicType":"str","x":690,"y":260,"wires":[["10493f2c714f7076"]]},{"id":"6fc641777086432b","type":"file","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"OUTPUT FILE","filename":"C:\\Users\\223131446\\documents\\ESP_NOW_testfile.xls","filenameType":"str","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":2040,"y":620,"wires":[[]]},{"id":"0052f74badf54e9b","type":"function","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"payload buffer","func":"// Get the cycle var from this node's context store or set to 0 if it doesn't yet exist\nlet cycle = context.get('cycle') ?? 0\n\n// Get the data buffer or an empty array if not exists yet\nconst databuff = context.get('databuff') ?? []\n\n// Add the new data to the buffer\ndatabuff.push(msg.payload)\n\n// Increment the cycle count\ncycle++\nif (msg.payload===\"Heat Test Readings:\") {\n    context.set('cycle', [])\n}\n\nif (cycle >= 5) {\n    // Output the buffer (join the array as a string)\n    node.send({payload: databuff.join('')})\n    // reset the buffer\n    context.set('databuff', [])\n    // reset the counter\n    context.set('cycle', 0)\n} else {\n    context.set('databuff', databuff)\n    context.set('cycle', cycle)\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1560,"y":560,"wires":[["12685748df941f03"]]},{"id":"12685748df941f03","type":"delay","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":1790,"y":620,"wires":[["af2c081e45aeea4f"]]},{"id":"235ee89a7b4d3084","type":"debug","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"debug 6","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":860,"y":180,"wires":[]},{"id":"b11078f7e2c006f1","type":"link in","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"FILE_WRITE_IN","links":["e0555b63417f4fe7"],"x":1325,"y":600,"wires":[["0052f74badf54e9b"]]},{"id":"645d29fb43471c2e","type":"link in","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"FULL IN","links":["2c8fff0752bb70f1"],"x":685,"y":360,"wires":[["10493f2c714f7076"]]},{"id":"62589ab3f0ca9572","type":"link out","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"RESET TITLE","mode":"link","links":["164c3e5b969108b1"],"x":835,"y":240,"wires":[]},{"id":"164c3e5b969108b1","type":"link in","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"RESET_TITLE_IN","links":["62589ab3f0ca9572"],"x":1145,"y":560,"wires":[["be74fb718f082b5d"]]},{"id":"be74fb718f082b5d","type":"function","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"Add Title","func":"var title = \"Heat Test Readings:\";\nmsg.payload = title + '\\n';\n\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1320,"y":540,"wires":[["0052f74badf54e9b"]]},{"id":"10493f2c714f7076","type":"q-gate","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"FULL Write Blocker","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","queueCmd":"queue","defaultCmd":"default","triggerCmd":"trigger","flushCmd":"flush","resetCmd":"reset","peekCmd":"peek","dropCmd":"drop","statusCmd":"status","maxQueueLength":"100","keepNewest":false,"qToggle":false,"persist":true,"storeName":"memory","x":830,"y":360,"wires":[["433c8b3b77203411"]]},{"id":"af2c081e45aeea4f","type":"debug","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1980,"y":520,"wires":[]},{"id":"15e2d6cbe81f1be7","type":"change","z":"7bfc1276c35b6509","g":"972375677a4ce17f","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[[\"2kV Test Readings\",\"\",\"\",\"\",\"\"],[$moment(),\"\",\"\",\"\",\"\"]]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1020,"y":480,"wires":[[]]},{"id":"08809e5c2942d6fc","type":"ui_group","name":"Timestamp:","tab":"f95d506942394920","order":2,"disp":true,"width":"6","collapse":false,"className":""},{"id":"3541e8bfb78c4f57","type":"ui_group","name":"Voltage Readings","tab":"f95d506942394920","order":3,"disp":true,"width":20,"collapse":false,"className":""},{"id":"267b3b26d23a38e6","type":"ui_group","name":"Heat Test Control","tab":"f95d506942394920","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"f95d506942394920","type":"ui_tab","name":"HEAT TEST DASHBOARD","icon":"whatshot","order":1,"disabled":false,"hidden":false}]

just to add, my above flow doesn't have your example in it, in a secondary test area i've tried modifying it to just for \t instead of commas but it doesnt like it... unfortunately i'm still a noob to Node-red and JS.

I fancy a challenge :sweat_smile: ...

so you want :

  • A Button that will add a "Start" header and allows preformatted rows of data to follow it.
  • No more start Header until it has been stopped
  • The rows of data are column separated with a tab?
  • Each row received - is the prefomatted row (4 columns) - passed in as a single string?

i'm glad for that then aha.

  • yes, in your previous example this will be was triggers the injection if you will (currently im using the dashboard based start button as the source of the press
  • kind of? in short i'm trying to get the header that is created by the start function to append to the beginning of the msg payload that contains the pre-formatted info.
    *yes
    *yes
    here's an example output to excel that i currently get:

the problem with that is because it forces the title in as the first message, the 5 message buffer only then outputs 4 actual data messages. then the next buffer packet is the correct 5.

does that make sense? i'm really bad at explaining these problems sometimes so apologies.

one thing i toyed with but couldn't get it to work is to reset the buffer counter based on the information received in msg.payload... but it never actually reset it:

i managed to get a crude working version!!!:

however i am 100% open to making it more elegant :slight_smile: i am still looking to learn better ways of coding instead of my brute force approach to coding haha

this is basically the output i was looking for:

apologies for the many replies, but to re-iterate i would like to do it via your suggestion of using the CSV node because then it means i can take the board ID out of the data cells and hard code them into node-red as the column headers

Working on it...

1 Like

thank you again for taking the time to help / effectively teach me this marcus; i really appreciate it mate :slight_smile:

1 Like

OK - not sure I have this right
I had a few strange glitches with the split node (I think it has a ring buffer of some kind)
so used a Function node to address it

This uses all native nodes to block the Start if already started + doesn't write to the CSV unless started

and it uses tab as the delimiter

[{"id":"7bfc1276c35b6509","type":"tab","label":"CSV","disabled":false,"info":"","env":[]},{"id":"03c9c0616c672829","type":"inject","z":"7bfc1276c35b6509","name":"Start Batch","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":220,"wires":[["5e9222632ba1334e"]]},{"id":"4e5849be7752ca47","type":"comment","z":"7bfc1276c35b6509","name":"Replace with Start Button Pressed event","info":"","x":200,"y":180,"wires":[]},{"id":"ce9e5217f32843f8","type":"inject","z":"7bfc1276c35b6509","name":"Serial Row","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Value 1\tValue 2\tValue 3\tValue 4","payloadType":"str","x":120,"y":360,"wires":[["b3d3c7247052f86b"]]},{"id":"ce54001e098a57e6","type":"comment","z":"7bfc1276c35b6509","name":"Replace with serial input","info":"","x":150,"y":320,"wires":[]},{"id":"3ccc0f7cc0b78546","type":"change","z":"7bfc1276c35b6509","name":"","rules":[{"t":"set","p":"started","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":220,"wires":[["d492314b5a670940"]]},{"id":"5e9222632ba1334e","type":"switch","z":"7bfc1276c35b6509","name":"Not Started?","property":"started","propertyType":"flow","rules":[{"t":"false"},{"t":"null"}],"checkall":"true","repair":false,"outputs":2,"x":450,"y":220,"wires":[["3ccc0f7cc0b78546"],["3ccc0f7cc0b78546"]]},{"id":"795960c49f6c5518","type":"comment","z":"7bfc1276c35b6509","name":"Replace with Stop Button Pressed event","info":"","x":200,"y":460,"wires":[]},{"id":"ffcdcd5d59e8b750","type":"inject","z":"7bfc1276c35b6509","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":500,"wires":[["81c2379d0ea67134"]]},{"id":"81c2379d0ea67134","type":"change","z":"7bfc1276c35b6509","name":"","rules":[{"t":"set","p":"started","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":500,"wires":[[]]},{"id":"bf3167a5aa971165","type":"csv","z":"7bfc1276c35b6509","name":"","sep":"\\t","hdrin":"","hdrout":"none","multi":"one","ret":"\\r\\n","temp":"","skip":"0","strings":true,"include_empty_strings":true,"include_null_values":true,"x":590,"y":640,"wires":[["be18bb8c452ef282"]]},{"id":"be18bb8c452ef282","type":"file","z":"7bfc1276c35b6509","name":"","filename":"/Users/marcusdavies/Documents/Test.csv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":910,"y":640,"wires":[[]]},{"id":"368c0794da18eb4c","type":"inject","z":"7bfc1276c35b6509","name":"On Start Up","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":100,"wires":[["2afa3d1da87c5f3a"]]},{"id":"736f27152da7eb26","type":"link in","z":"7bfc1276c35b6509","name":"link in 1","links":["fcab9a3611ea143b","d72516572e8c2694","c847e5c58cde0c9b"],"x":65,"y":640,"wires":[["49412ebf550e8a93"]]},{"id":"fcab9a3611ea143b","type":"link out","z":"7bfc1276c35b6509","name":"link out 1","mode":"link","links":["736f27152da7eb26"],"x":635,"y":100,"wires":[]},{"id":"d72516572e8c2694","type":"link out","z":"7bfc1276c35b6509","name":"link out 2","mode":"link","links":["736f27152da7eb26"],"x":1115,"y":220,"wires":[]},{"id":"f0e01029efaf89fb","type":"comment","z":"7bfc1276c35b6509","name":"Sets the top level header when deployed","info":"","x":200,"y":60,"wires":[]},{"id":"d492314b5a670940","type":"function","z":"7bfc1276c35b6509","name":"Set Batch Header","func":"msg.payload = `${new Date()}\t\t\t\t`\nreturn msg","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":220,"wires":[["d72516572e8c2694"]]},{"id":"c847e5c58cde0c9b","type":"link out","z":"7bfc1276c35b6509","name":"link out 3","mode":"link","links":["736f27152da7eb26"],"x":815,"y":360,"wires":[]},{"id":"c0899d814360eab8","type":"comment","z":"7bfc1276c35b6509","name":"Sink to CSV","info":"","x":110,"y":600,"wires":[]},{"id":"2afa3d1da87c5f3a","type":"function","z":"7bfc1276c35b6509","name":"Set File Header","func":"msg.payload = '2kV Test Readings\t\t\t\t'\nreturn msg","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":100,"wires":[["fcab9a3611ea143b"]]},{"id":"06effc064c18e04b","type":"function","z":"7bfc1276c35b6509","name":"Pad Column","func":"msg.payload += '\t'\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":360,"wires":[["c847e5c58cde0c9b"]]},{"id":"49412ebf550e8a93","type":"function","z":"7bfc1276c35b6509","name":"Split to Columns","func":"msg.payload = msg.payload.split('\t')\nreturn msg","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":640,"wires":[["bf3167a5aa971165"]]},{"id":"b3d3c7247052f86b","type":"switch","z":"7bfc1276c35b6509","name":"Started?","property":"started","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":440,"y":360,"wires":[["06effc064c18e04b"]]}]

hmmm that looks grand, i'll have to give it a try over the weekend / monday to understand / integrate it. but just from the node structure it looks like it will work :slight_smile: thanks man

1 Like

hi again marcus, sorry about the delay its been a tumultuous week.

in regards to the flow, i just have a question about the pad column function: "what is it actually doing? is it just defining the msg.payload as a tab entry?

Hi @Boerwors

I think that function block can be removed, I think I left it in there in error.
it was to ensure the values align, but I think its redudnent.

Example, if you wanted to shift the values 1 column to the right

msg.payload = `	${msg.payload}`
return msg;

The above is hiding the fact there is a tab, but there is (as below)

If you wanted to see non printable characters

https://www.soscisurvey.de/tools/view-chars.php