If/Else statements failing

Hi All,

Firstly, apologies for the newbie questions. I suspect this is a straightforward solution but I've not been able to find it yet.

I have a number of sensors and am using a existing github repository for the javascript decoder code.
My understanding is that this could be simply copied into a function node and the bytes would be mapped to the fields as required.

However, any of the code with If/else if statements fails to work for me

Here is an example, the msg_version, seq_num and device_time all are decoded but as soon as it hits the if statement it appears that nothing further is decoded.

function uintToInt(uint, nbit) {
    nbit = +nbit || 32;
    if (nbit > 32) throw new Error('uintToInt only supports ints up to 32 bits');
    uint <<= 32 - nbit;
    uint >>= 32 - nbit;
    return uint;
}

function Decoder(bytes, port) {
    var decoded = {};
    
    decoded.msg_version = bytes[1];
    decoded.seq_num = bytes[2];
    decoded.device_time = (bytes[3] << 24) | (bytes[4] << 16 ) | (bytes[5] << 8) | bytes[6];

    if (bytes[0] === 0x00) {
        decoded.msg_type = 'install request';
        decoded.nonce = (bytes[7] << 24) | (bytes[8] << 16 ) | (bytes[9] << 8) | bytes[10];
        decoded.battery_voltage = (bytes[11] << 8) | bytes[12];
        decoded.sensor1_temp = (((bytes[13] << 8) | bytes[14]) - 270) / 10;
        decoded.sensor2_temp = (((bytes[15] << 8) | bytes[16]) - 270) / 10;
        decoded.sensor3_temp = (((bytes[17] << 8) | bytes[18]) - 270) / 10;
        decoded.fw_version = bytes[19].toString() + '.' + bytes[20].toString() + '.' + bytes[21].toString();
        decoded.reset_reason = (bytes[22] << 8) | bytes[23];
    } else if (bytes[0] == 0x02) {
        decoded.msg_type = 'install response';
        decoded.error = bytes[7];
    } else if (bytes[0] == 0x03) {
        decoded.msg_type = 'temperature report';
        // doesn't handle historical data!!!
        decoded.sensor1_min_temp = uintToInt(bytes[7], 8);
        decoded.sensor1_max_temp = uintToInt(bytes[8], 8);
        decoded.sensor1_flow_count = bytes[9];
        decoded.sensor1_compliant = bytes[10];
        
        decoded.sensor2_min_temp = uintToInt(bytes[11], 8);
        decoded.sensor2_max_temp = uintToInt(bytes[12], 8);
        decoded.sensor2_flow_count = bytes[13];
        decoded.sensor2_compliant = bytes[14];
        
        decoded.sensor3_min_temp = uintToInt(bytes[15], 8);
        decoded.sensor3_max_temp = uintToInt(bytes[16], 8);
        decoded.sensor3_flow_count = bytes[17];
        decoded.sensor3_compliant = bytes[18];
    } else if (bytes[0] == 0x05) {
        decoded.msg_type = 'scald message';
        decoded.sensor = bytes[7];
        decoded.temperature = uintToInt(bytes[8], 8);
    } else if (bytes[0] == 0x06) {
        decoded.msg_type = 'freeze message';
        decoded.sensor = bytes[7];
        decoded.temperature = uintToInt(bytes[8], 8);
    } else if (bytes[0] == 0x08) {
        decoded.msg_type = 'sensor error';
        decoded.sensor1_error = bytes[7];
        decoded.sensor2_error = bytes[8];
        decoded.sensor3_error = bytes[9];
    } else if (bytes[0] == 0x09) {
        decoded.msg_type = 'internal error';
        decoded.error_number = (bytes[7] << 8) || bytes[8];
        decoded.file_name = bytes.slice(9, 41).toString();
        decoded.line_num = (bytes[41] << 8) || bytes[42];
    }

    return decoded;
}

// this will allow the decoder to be used in NodeRed accepting data from Kerlink Wanesy
var tempPayload = Decoder(Buffer.from(msg.payload.payload, 'hex'), msg.payload.fPort);
tempPayload.devEUI = msg.payload.endDevice.devEui;
msg.payload = tempPayload;
if (msg.payload.msg_type == 'install request') {
    // create downlink header
    var downlink = "0102" + ('0'+msg.payload.seq_num.toString(16)).substr(-2);
    // add epoch
    downlink += Math.round((new Date()).getTime() / 1000).toString(16);
    // add nonce
    downlink += ('0'+msg.payload.nonce.toString(16)).substr(-8);
    downlink += "07"; // days to resend install request
    downlink += "03"; // flags, scald and freeze on. History off.
    downlink += "3C"; // scald threshold, 60deg
    downlink += "FB"; // freeze temp, -5deg
    downlink += "000F"; // report period, 15 mins
    downlink += "01"; // sensor 1 config - hot outlet
    downlink += "03"; // sensor 2 config - cold outlet
    downlink += "00"; // sensor 1 config - disabled
    msg.downlink = downlink.toUpperCase(); // used in the API call for a downlink
    msg.deveui = msg.payload.devEUI; // used in the API call for a downlink
    return [ null, msg ];
} else {
    return [ msg, null ];
}

Appreciate any suggestions. Be gentle, I'm new to this and I clearly need to up my javascript knowledge.

Thanks

Welcome to the forums @mattuns

First thing I spotted - this isn't a typo no?
Buffer.from(msg.payload.payload, 'hex')

Or does the payload have a payload?

If that is by design,
A sample payload that is going into the block will be helpful?

Use the debug node to check what is being sent (and to provide a sample payload)

Thanks for the quick reply.

Apologies, I should have included the payload

{"applicationID":"2","applicationName":"WaveTrend_Water_Temp","data":"AATfZSbQt14pMJwL6gOTAbn//wAIAAEAAA==","devEUI":"3836323062397e04","deviceName":"wavetrend_water","fCnt":4,"fPort":1,"rxInfo":[{"altitude":0,"latitude":0,"loRaSNR":12.8,"longitude":0,"mac":"24e124fffef552be","name":"Local Gateway","rssi":-76,"time":"2023-10-11T15:49:10.340644Z"}],"time":"2023-10-11T15:49:10.340644Z","txInfo":{"adr":true,"codeRate":"4/5","dataRate":{"bandwidth":125,"modulation":"LORA","spreadFactor":7},"frequency":868100000}}

I actually spotted that myself and ended up commenting out the whole downlink section, replacing with

msg.payload=Decoder(msg.payload)
return msg;

As previous, this gives me msg_version, seq_num and device_time but nothing after the If statement is decoded.

My code, modified from the original looks like

function uintToInt(uint, nbit) {
    nbit = +nbit || 32;
    if (nbit > 32) throw new Error('uintToInt only supports ints up to 32 bits');
    uint <<= 32 - nbit;
    uint >>= 32 - nbit;
    return uint;
}

function Decoder(bytes, fport) 
{
    var decoded = {};
    decoded.msg_version = bytes[1];
    decoded.seq_num = bytes[2];
    decoded.device_time = (bytes[3] << 24) | (bytes[4] << 16) | (bytes[5] << 8) | bytes[6];
    if (bytes[0] === 0x00) 
    {
        decoded.msg_type = 'install request';
        decoded.nonce = (bytes[7] << 24) | (bytes[8] << 16) | (bytes[9] << 8) | bytes[10];
        decoded.battery_voltage = (bytes[11] << 8) | bytes[12];
        decoded.sensor1_temp = (((bytes[13] << 8) | bytes[14]) - 270) / 10;
        decoded.sensor2_temp = (((bytes[15] << 8) | bytes[16]) - 270) / 10;
        decoded.sensor3_temp = (((bytes[17] << 8) | bytes[18]) - 270) / 10;
        decoded.fw_version = bytes[19].toString() + '.' + bytes[20].toString() + '.' + bytes[21].toString();
        decoded.reset_reason = (bytes[22] << 8) | bytes[23];
    } 
    else if (bytes[0] == 0x02) 
    {
        decoded.msg_type = 'install response';
        decoded.error = bytes[7];
    } 
    else if (bytes[0] == 0x03) 
    {
        decoded.msg_type = 'temperature report';
        // doesn't handle historical data!!!
        decoded.sensor1_min_temp = uintToInt(bytes[7], 8);
        decoded.sensor1_max_temp = uintToInt(bytes[8], 8);
        decoded.sensor1_flow_count = bytes[9];
        decoded.sensor1_compliant = bytes[10];

        decoded.sensor2_min_temp = uintToInt(bytes[11], 8);
        decoded.sensor2_max_temp = uintToInt(bytes[12], 8);
        decoded.sensor2_flow_count = bytes[13];
        decoded.sensor2_compliant = bytes[14];

        decoded.sensor3_min_temp = uintToInt(bytes[15], 8);
        decoded.sensor3_max_temp = uintToInt(bytes[16], 8);
        decoded.sensor3_flow_count = bytes[17];
        decoded.sensor3_compliant = bytes[18];
    } 
    else if (bytes[0] == 0x05) 
    {
        decoded.msg_type = 'scald message';
        decoded.sensor = bytes[7];
        decoded.temperature = uintToInt(bytes[8], 8);
    }
     else if (bytes[0] == 0x06) 
    {
        decoded.msg_type = 'freeze message';
        decoded.sensor = bytes[7];
        decoded.temperature = uintToInt(bytes[8], 8);
    } else if (bytes[0] == 0x08) 
    {
        decoded.msg_type = 'sensor error';
        decoded.sensor1_error = bytes[7];
        decoded.sensor2_error = bytes[8];
        decoded.sensor3_error = bytes[9];
    } else if (bytes[0] == 0x09) 
    {
        decoded.msg_type = 'internal error';
        decoded.error_number = (bytes[7] << 8) || bytes[8];
        decoded.file_name = bytes.slice(9, 41).toString();
        decoded.line_num = (bytes[41] << 8) || bytes[42];
    }

    return decoded;
}

msg.payload=Decoder(msg.payload)
return msg;

Maybe try this?

msg.payload = Decoder(Buffer.from(msg.payload.data,'base64'))

It seems (I could be wrong), the good stuff is in a data property and is encoded using base64

EDIT
it would seem so?
image

1 Like

Thanks again Marcus,

This has worked - amazing!
I did actually try using msg.payload.data in earlier attempts but without the Buffer.from it just errored out so I guess it didn't like base64

I still cant use the downlink code but at this time I just need to report the data so its not required.

Really appreciate the help!

Matthew

1 Like

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