Cayenne LPP Decoder in NodeJS

Hello all,

I am looking for an existing library to decode Cayenne LPP with NodeJS. So far very few success.

There is a Go implementation that can be converted there:

And a project that promise encoder and decoder but committed only the encoder part:

Is anyone already working on this topic or should I start it?

1 Like

I created a quick and dirty decoder for our devices. Note: I’m a NodeJS newbie and this hasn’t been thoroughly tested, but it’s at least a start.

NodeJS Cayenne LPP Decoder

Thanks, looks pretty good.

Maybe I can do minor editing of your code so we can add it to a fork of the CayenneLPP-Node project with some tests.

We would then have a first release of a encoder/decoder.

Tell me if it’s ok for you. I can handle this next week.

Hi! @crapougnax. I am also working cayenne lpp format and was looking for decoder library. Were you able to do it?

Hi,

Yes I published a NodeJS module some time ago. You can see it there : https://www.npmjs.com/package/@crapougnax/cayennelpp

The source code is there: https://github.com/crapougnax/cayennelpp

I am using it with another piece of code to listen to new message, decode them and store in an InfluxDB database. (see https://github.com/crapougnax/ttn2influx)

It is yet to be converted into a module too.

Hi @crapougnax! how do I integrate it to my code to decode the payload of the sensor i’m using. And i have a separate function defined as below:

     function decode(payload, port) {
    var result = new Object();
    .
    .
    return result;
    }

My Payload is an array of bytes, Port is integer.
I want to return them as an object of [key:value] pairs.

Use the example from the git repo:

const decoder = new LPPEncoder(buffer)
decoder.decode()
const temperature1 = decoder.getChannel(1).temperature

You can also do a decoder.getChannels() to retrieve all the decoded channels data.

I’m trying this but I’m getting the following error.

import {LPPEncoder, LPPDecoder} from '@crapougnax/cayennelpp'
const buffer = '026700F0'
const decoder =new LPPEncoder(buffer);
decoder.decode()
const temperature1 = decoder.getChannel(2).temperature;
return temperature1;
console.log(temperature1);

error:

   at Module._compile (internal/modules/cjs/loader.js:718:23)
   at Object.Module._extensions..js (internal/modules/cjs/loader.js:785:10)
   at Module.load (internal/modules/cjs/loader.js:641:32)
   at Function.Module._load (internal/modules/cjs/loader.js:556:12)
   at Function.Module.runMain (internal/modules/cjs/loader.js:837:10)
   at internal/main/run_main_module.js:17:11

If you want to use the decoder, you have to instantiate a decoder and not an encoder. :wink:

Try:

const decoder = new LPPDecoder(buffer);

I was wondering the same thing! but then its
'const decoder = new LPPEncoder(buffer);'
in the the example.

My mistake then. I’ll fix that when I have the chance.

@crapougnax. It is still throwing the same error. How do I pass my value(hex encoded) that has to be decoded to the buffer.

@crapougnax! This is my driver decoder for a sensor which cayenne lpp format. I want to use your library in my driver. Initially tried only for temperature but was not able to achieve it. My payload is received in Base-64 and i’m converting it into hex string to use at certain places, and returning the values. How should I integrate your library here.

var hexpayload = '';
function decode(payload, port) {
    var result = new Object();
    // Convert received payload (Base-64) into hex payload //
    Object.keys(payload).forEach(function(key) {
        thishex = Number(payload[key]).toString(16);
        thishex = thishex.length < 2 ? "" + "0" + thishex : thishex;
        hexpayload += thishex;
    });
    result.RawPayload = hexpayload;

    if (payload[0] == 1) {
        result.PayloadTtype = 'Recalibrate Response'; // dataType 1 //
        result.Status = (payload[2] == 0) ? 'Failed' : 'Successful';
    } else if (payload[0] == 2) {
        result.PayloadTtype = 'Temperature'; // dataType 103 //
        result.Value = (parseInt(hexpayload.slice(4), 16).toString(10)) / 10 + 'C';
    } else if (payload[0] == 3) {
        result.PayloadTtype = 'Battery'; // dataType 2 //
        result.Battery = (parseInt(hexpayload.slice(4), 16).toString(10)) / 100 + 'V';
    } else if (payload[0] == 21) {
        result.PayloadTtype = 'Parking Status'; // dataType 102 //
        result.ParkingStatus = (payload[2] == 0) ? 'Occupied' : 'Vacant';
    } else if (payload[0] == 28) {
        result.PayloadTtype = 'Deactivate Response'; //dataType 1 //
        result.ParkingStatus = (payload[2] == 0) ? 'Not Done' : 'Done';
    } else if (payload[0] == 33) {
        result.PayloadTtype = 'Vehicle Count'; // dataType 0 //
        if (payload[2] > 80) {
            payload[2] %= 80; //Sensor Reboot due to exceeding limit
            result.Count = payload[2];
        } else {
            result.Count = payload[2];
        }
    }else {
        result.PayloadTtype = 'Invalid-Payload';
    }
    return {
        "result": result,
        "port": port
    }
}

This is how I use it to decode and push data to InfluxDB, as you can see, nothing fancy:

import { data } from 'ttn'
import { LPPDecoder } from '@crapougnax/cayennelpp'
import { ttnConfig } from '../config'
import { influxWriter } from './writers'

data(ttnConfig.appID, ttnConfig.accessKey)
  .then((client) => {
    console.log(Date.now(), 'Connected to TTN MQTT server')
    const decoder = new LPPDecoder()
    client.on('uplink', (devID, payload) => {
      console.log(Date.now(), 'Received uplink from ', devID)
      decoder.decode(payload.payload_raw)
      influxWriter(decoder, devID)
    })
  })
  .catch((err) => {
    console.error(err)
    process.exit(1)
  })

The two of you are talking different use cases. @crapougnax is using a stand alone program where @Hemanth it trying to integrate the code into the decoder function hosted at TTN. From memory the later does not allow importing foreign code to protect the shared resources against rogue code.

@kersing. How can I use the cayenne lpp library to decode a payload sent from the sensor which is cayenne encoded. The decode function i’m using is the body of the driver from the thingsHub platform.