1 large strng from Arduino, 3 msgs from Function, 3 Outputs?

Hi all,

Sending from Arduino the data from a sensor (ACS712) in 1 single string. It contains 3 "topic" and "payload", values separates with ":" and between the 3 topics ";"

Serial.println ("Analog:"+String(acs712)+";"+"Mv:"+ String(mv)+";"+"Amperage:"+String(amperage)); 

On receiving on Node-Red, it goes through a Function that first will give an array containing the variables

var myVars=msg.payload.split(";");

Once I have the 3 variables in an array, I split this again with variable name and the value payload

var result={};
myVars.forEach(function(v){
    var parts=v.split(":");
    result [parts[0]]=parts[1];
})
msg.payload=result; 

Next, I split them again to have an array with "topic" and "payload"
https://groups.google.com/forum/#!topic/node-red/GS6RknsLG4k

var keys=Object.keys(msg.payload);
var msgs=keys.map(function(key){
    return {topic: key , payload: msg.payload[key]};
}); 

And then, return msgs array

return [msgs];

What I am trying to get is 3 outputs from those arrays. What I am getting is 1 output with 3 msgs.
I tried to add the Switch function and use the msg.parts.index and then the "0,1,2" outputs but it is not working.
Any ideas of how I can get this 3 outputs from my Function?
Thanks,

Aside from why you need this, why didn't you just make a JSON string with data and then upon receipt at node red, you'd have access to the properties by simply running it through a JSON node.

Serial.println ("{'Analog' : "+String(acs712)+",'Mv' :"+ String(mv)+", 'Amperage' : "+String(amperage) + "}")

No need to do any splits and fully dynamic/future proof/extensible

Secondly, if you have already got the data in to an array, just set 3 outputs on the function and create/send 3 msgs?

Just trying to gauge some results on the dashboard. Still practicing so I started from the basics and from what I get directly from the arduino, with no JSON or MQTT... so I can practice and get into the grips of the node red basics. That is why I am trying to get a simple string and do the convertions/splits to get to different outputs.
Also, the researched above functions are dynamic as it creates as many msgs/topics as you sent.

I tried to add the below function to create the 3 outputs msgs, but it gives a function error
TypeError: msg.payload.split is not a function

var output=msg.payload.split(";");
var msg1={payload:(output[0])};
var msg2={payload:(ouput[1])};
var msg3={payload:(output[2])};

return [msg1,msg2,msg3];

After not working the above, I read that it might be the case to use an array function, so I tried the second option to produce 3 outputs, but neither worked.
TypeError: Cannot read property 'split' of undefined

var output=msg.payload[0].split(";");
var msg1={payload:(output[0])};
var msg2={payload:(ouput[1])};
var msg3={payload:(output[2])};

return [msg1,msg2,msg3];

The total function is the below, but not working:no_mouth:

var myVars=msg.payload.split(";");
var result={};
myVars.forEach(function(v){
    var parts=v.split(":");
    result [parts[0]]=parts[1];
})
msg.payload=result;

var keys=Object.keys(msg.payload);
var msgs=keys.map(function(key){
    return {topic: key , payload: msg.payload[key]};
})

var output=msg.payload[0].split(";");
var msg1={payload:(output[0])};
var msg2={payload:(ouput[1])};
var msg3={payload:(output[2])};

return [msg1,msg2,msg3];

Any ideas pls?

What does the debug output look like (from the first node - the data source).

This is the first debug from Arduino
image

And this is what I get from the second debug after passing the Function and deleting the last section of the code...

var myVars=msg.payload.split(";");
var result={};
myVars.forEach(function(v){
    var parts=v.split(":");
    result [parts[0]]=parts[1];
})
msg.payload=result;

var keys=Object.keys(msg.payload);
var msgs=keys.map(function(key){
    return {topic: key , payload: msg.payload[key]};
})

//var output=msg.payload[0].split(";");
//var msg1={payload:(output[0])};
//var msg2={payload:(ouput[1])};
//var msg3={payload:(output[2])};

return [msg];

image

Try this:

let m = msg.payload
let s = m.split(';')
let out =[]
for(x=0;x<s.length;x++){
    parts = s[x].split(':')
    out.push({payload:{[parts[0]]:parseFloat(parts[1])}})
}

return out

Thanks...
If I only use your function, the payload is an object and cannot gauge them on the graph...

let m = msg.payload;
let s = m.split(";");
let out = [];
for (x=0;x<s.length;x++){
    parts = s[x].split(":")
    out.push({payload:{[parts[0]]:parseFloat(parts[1])}})
}

return out;

image
image

Steve's suggestion above is the sensible way to do this. IE send a json string and then just parse it.

1 Like

If I add your code to the original one, I got the error:

"TypeError: m.split is not a function"

var myVars=msg.payload.split(";");
var result={};
myVars.forEach(function(v){
    var parts=v.split(":");
    result [parts[0]]=parts[1];
})
msg.payload=result;

var keys=Object.keys(msg.payload);
var msgs=keys.map(function(key){
    return {topic: key , payload: msg.payload[key]};
});

let m = msg.payload;
let s = m.split(";");
let out = [];
for (x=0;x<s.length;x++){
    parts = s[x].split(":")
    out.push({payload:{[parts[0]]:parseFloat(parts[1])}})
}

return out;

I understand why and how but...
Your code will not handle nested objects and is your own format. JSON is an EMCA/RFC standard & pretty much built in to JavaScript.
I've done what you're doing in post projects. Once I used JSON I've never went back to manual parsing.
But it is entirely your decision.
...
To send multiple msg, use either 3 outputs and ...

return [msg1, msg2, msg3]

Alternatively set the function to 1 output and do this

return [[msg1,msg2,msg3]]

Or more verbosity...

node.send(msg1)
node.send(msg2)
node.send(msg3)
return null

Note, if you are sending this to a graph you likely need to set topic differently per message (as the graph help says)

Don’t add my code, replace it.
And in the graph use {{msg.payload.Analog}} etc

Thanks, both methods work...the Original and the bakman2!!! I was using the {{value}} rather than the {{msg.payload}} on the graph.
I will stick to the original as I get "topic" and "payload". On the bakman2, only could get "payload"

Original:

var myVars=msg.payload.split(";");
var result={};
myVars.forEach(function(v){
    var parts=v.split(":");
    result [parts[0]]=parts[1];
})
msg.payload=result;

var keys=Object.keys(msg.payload);
var msgs=keys.map(function(key){
    return {topic: key , payload: msg.payload[key]};
});
return msgs;

image

And the bakman2 version: I believe you could also get 'topic" and "payload" separately, but couldn't.

let m = msg.payload;
let s = m.split(";");
let out = [];
for (x=0;x<s.length;x++){
    parts = s[x].split(":")
    out.push({payload:{[parts[0]]:parseFloat(parts[1])}})
}

return out;

image

let m = msg.payload;
let s = m.split(";");
let out = [];
for (x=0;x<s.length;x++){
    parts = s[x].split(":")
    out.push({topic:[parts[0]], payload:parseFloat(parts[1]})
}

return out;

This would work.

Then for the label use {{msg.topic}} and for the value {{msg.payload}}