Help converting string to key/value object

Hope everyone is well! Was hoping you may be able to help me with this or point me in the right direction!
I'm trying to extract data from my emfit QS.
I can HTTP GET request it and I get this back in the payload as a string

payload: string
SER=001803<br>
TS=1611481080<br>
TS_R=91663<br>
PRES=1<br>
HR=0<br>
HR_DM=0<br>
RR=0.0<br>
RR_DM=0<br>
ACT=4<br>
ACT_DM=0<br>
FW=t120 v2.2.1
<br>
END=1<br>

I would ideally like to extract these all into key pairs to feed into my home assistant. Maybe even msg.PRES, msg.SER etc. I've tried playing around with the split node and it kind of works but keeps them all as strings still.

Any help would be greatly appreciated :slight_smile:

string split is probably best bet.

Split on <br> then loop the array and split on =

e.g...

image

const lines = msg.payload.split("<br>");
let result = {};

for (let i = 0; i < lines.length ; i++) {
    const line = lines[i].trim();
    if(!line) continue;
    let parts = line.split("=");
    if(parts.length != 2) continue;
    let key = parts[0].trim();
    let val = parts[1].trim();
    if(isNumeric(val)) val = Number(val)
    result[key] = val;
}

msg.payload = result;
return msg;

function isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

(though SER is probably the serial number so should remain as a string )

1 Like

Ah, missed the leading zeros.

Revised...

const lines = msg.payload.split("<br>");
let result = {};

for (let i = 0; i < lines.length ; i++) {
    const line = lines[i].trim();
    if(!line) continue;
    let parts = line.split("=");
    if(parts.length != 2) continue;
    let key = parts[0].trim();
    let val = parts[1].trim();
    if(key != "SER" && isNumeric(val)) val = Number(val)
    result[key] = val;
}

msg.payload = result;
return msg;

function isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}
1 Like

That works perfectly, thank you so much!! World needs more people like you!!
I will spend some time learning/understanding your code as well, it is much appreciated!!
I can now connect multiple sensor output nodes to that with the each of the different paths of the key/pairs.
Thank you again for your rapid response!

In Node-RED, there are always many ways to restructure your data. My favorite is to use a JSONata expression inside a change node, like so:

Using the Expression Test tab with your data, you can see the results in real-time as you type the expression in the window above -- very nice!

Although the expressions are very powerful, the lambda syntax of the language itself can be a bit puzzling to read... Here is a short description of what this expression does:

payload.$split('<br>').[$split('=')] {
    $[0]: $[0] in ['SER', 'FW'] ? $[1]
        : $[0] = 'TS' ? $fromMillis($number($[1])*1000)
        : $number($[1])
}
  • Line 1: split the payload into an array of "key=value" strings, and then split each of those strings into a 2-element array of ["key", "value"] pairs
  • Lines 1 - 5: from the opening { to closing } is the body of a single output object, with:
  • Line 2: field name pulled from the first pair element $[0], with 'SER' and 'FW' field values being the string in the second pair element $[1]
  • Line 3: if the field name is 'TS' then multiply the value of secs. by 1000 to get millis, and convert to a datetime value
  • Line 4: for all other field names, just get the numeric value of the string

Most people would stick with plain Javascript for maintainability, but I just wanted to show an alternative, which I think is worth learning. Hope this helps more than it confuses!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.