Cayenne integration: Where is my payload?

If the node always sends the same data, do you feel LPP is that much easier than lora-serialization? I’d prefer something like the latter to be integrated in the payload functions. Arduino side:

LoraMessage message;
message.addTemperature(-1.45)
    .addHumidity(30.10)
    .addUint16(3900) // anything, like maybe voltage
    .addLatLng(-33.905052, 151.26641); // et cetera

Decoder (if the library would be integrated in TTN; right now one needs to first copy/paste it into the Decoder function manually):

function Decoder(bytes, port) {
  // Define the order in which the fields are sent, and their
  // names in the JSON output
  return decode(bytes, 
      [temperature, humidity, uint16, latLng], 
      ['temp', 'humidity', 'battery', 'location']);
}

That’s 12 bytes for the application payload (with the 13 bytes LoRaWAN header: total of 24), whereas LPP would then use an additional 11 bytes (including 3 for the altitude which on roads is hardly useful).

One could even do smart things with bits to tell if data is skipped (rather than using 16 bits for each field).


Well, currently 2 more, as it sends 8 bytes for coordinates while 6 would suffice.

@arjanvanb thanks the lora-serialization library indeed does solve many of my issues, thanks for the explanation of the the size difference also.

But… if it is working correctly at the myDevices side as I haven’t tested, the major bonus of using the LPP is that the UI is generated for you, adhere to the LPP and myDevices supposedly will expose the data for the UI automatically… this is the closest I’ve seen to a interoperable standard I’ve seen in my brief experience in low powered data. I believe whole heartily that this should be the direction forward.

Cheers

I was able to get things up and running by including https://github.com/Zenseio/CayenneLPP and adjusting the example a bit. Works with https://github.com/tijnonlijn/RFM-node

Here is a sample sketch using a DHT 11 temp sensor.

2 Likes

I’ll go for a decoder solution on the TTN Backend. Since then it doesn’t matter how I transmit the data over the air. If I use the STM Stack it’s not so easy to implement a Arduino Stack, if i use a board running python and the microchip module, i need to reemplement the whole Arduino library.

3 Likes

That would be great indeed. Unfortunately, the payload functions expect an object as the result. When just trying to return an array of (modified) bytes, one cannot save the Decoder function:

function Decoder(bytes, port) {
  return bytes;
}

Error(“Could not dry-run uplink on Handler: Decoder not valid: does not return an object”)

So, even if the payload functions are executed before the integration is invoked (I don’t know for Cayenne; they are certainly called for the Data Storage integration), then currently one cannot enhance/convert the node’s payload into a Cayenne LPP.

@JDP @eptak @dittrich @AdamJP @christopherdro I just integrated CayenneLPP in TheThingsNetwork Arduino library v2.5.0, soon available from Arduino Library Manager.

See documentation here: https://www.thethingsnetwork.org/docs/devices/arduino/api/cayennelpp.html, and example here: https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/CayenneLPP/CayenneLPP.ino

Next is to have a JavaScript library that we can preload for payload functions, but for use with Cayenne this is already handy.

@joscha @arjanvanb see my comment on the lora-serialization library here: https://github.com/TheThingsNetwork/sdk/pull/19#issuecomment-286408287. Happy to work with you guys on integrating this too.

5 Likes

Wow awesome work, thanks!

Great work TTN ! Thanks for pushing Cayenne LPP !
Per the JS decoder function, we are going to open source ou Cayenne LPP decoder.
We’ll be able to provide you the code then :slight_smile:

2 Likes

Hi All, great discussion and great reads on Cayenne LPP.
Thank you so much…

I tried to combine the TTN Build your own Sensor Workshop, with an implementation of Cayenne LPP.
I think the payload looks ok, but Cayenne does not accept it, since on the dashboard I only see the RSSI and SNR.

Question:
Is there an cayenne LPP Decoder online available that I can feed my byte string and then see what I did wrong? :slight_smile:

// Cayenne LPP Byte definition
// https://github.com/myDevicesIoT/cayenne-docs/blob/master/docs/LORA.md

// Cayenne LPP Payload buildup
// https://hansboksem.wordpress.com/2017/03/06/sending-sensor-data-through-the-things-network-to-cayenne/

// Lora TTN via LMIC and bmp280 code
// https://github.com/galagaking/ttn_nodeworkshop/blob/master/ttn_bmp280_abp.ino

// Edzo’s First LoRa TTN Cayenne LPP Implementation
// https://github.com/edzob/loraNode/blob/master/sketch_20170406_lora.ino

old
// Byte string in the Lora TTN Payload
// 036700E9046800057328163C94100F141E3D6F08

1 Like

It’s not too hard to manually decode this? I run into problems using the documentation:

03 67 00E9            67 = temperature
04 68 00              68 = humidity
05 73 2816            73 = barometer
3C 94 100F141E3D6F08  94 = unknown type?

(My guess is that you’re missing xx 88 at the start of the last section, for GPS location. Any online decoder would fail as well, so is of little help…)

@arjanvanb Thanks for the hint.

I first build a hardcoded message with the existing code
and then used the example functions to build up payload with the sensor data
and now it works! :slight_smile:

I needed some reading on Hex Decimals and and Byte Array… and learned a lot.
Thanks for the nudge into the right direction :slight_smile:

Code on github is updated.

Hi,

I have a TTN/Cayenne device integration. This device has a DHT11 sensor and the payload is in LPP format.
The application data in the TTN Console looks fine to me: 036700C804684400
channel 03, type 67, tempvalue: 20C and channel 04, type 68, humvalue: 34%

My problem; I only see the RSI and SNR widget in Cayenne and reading the answers in previous posts there must be something wrong with my payload but I have no idea. Anyone else?

1 Like

That should be one byte, not two, for the value. But you’re sending 04 68 4400.

1 Like

Thanks Arjan, that is exactly what played in my mind.
At the moment I’ve no access to the code but I’ll try to remove the last byte.

int16_t val;
uint8_t channel;
byte buffer[8];
uint8_t cursor = 0;

val = temperature;
val = temperature * 10;
channel = 0x03;
buffer[cursor++] = 0x03;
buffer[cursor++] = LPP_TEMPERATURE;
buffer[cursor++] = val >> 8;
buffer[cursor++] = val;

val = humidity;
channel = 0x04;
buffer[cursor++] = channel;
buffer[cursor++] = LPP_RELATIVE_HUMIDITY;
buffer[cursor++] = humidity * 2;

// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F(“OP_TXRXPEND, not sending”));
} else {
// Prepare upstream data transmission at the next possible time.
//LMIC_setTxData2(1, buffer, sizeof(buffer)/sizeof(buffer[0]), 0);
LMIC_setTxData2(1, buffer, 7, 0); //brute force

1 Like

…or:

byte buffer[7];
...
LMIC_setTxData2(1, buffer, sizeof(buffer)/sizeof(buffer[0]), 0);

…or better yet:

byte buffer[20]; // any maximum size your payload might need
...
buffer[cursor++] = ...
buffer[cursor++] = ...
LMIC_setTxData2(1, buffer, cursor, 0);
1 Like

I’d really like to know this as well. Cayenne seems like a great tool and i want to use it but use more efficient payloads. The channel is inferred from the node ID, node sensor has a fixed structure so there is no need to repeat the meta data for the sensor data every time etc.

Hi Johan

Im trying to use your example code on a 32u4 Lora feather with thing works. few questions if you dont mind.

TTN OTAA

  • Are you not missing the DEV EUI input?
  • is the input(s) straight copy and past from TTN like so or does it need to be reveresed the same as the LMIC stuff?
  • const char *appEui = “70B3D57EF0004C11”;
  • const char *appKey = “0000110220330440550660770880990A”;

I have installed your library, copied your example changed the two keys and uploaded the code but i see not registration attemps in TTN or any data flowing.

Thank you
Johann

The example in TheThingsNetwork Arduino library are specifically for Arduinos with the Microchip RN2xx3 module. With the 32u4 LoRa feather I’d suggest using LMiC. And then, indeed, you need to reverse the byte order.

Hi,
I’m also having trouble getting my data to Cayenne. Can you guys help me with what I’m doing wrong? (I know it’s not the prettiest code)

    void do_send(osjob_t* j) {
  // Check if there is not a current TX/RX job running
  if (LMIC.opmode & OP_TXRXPEND) {
    // Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    // Read distance
    int distance = readDistance();
    mydata[0] = (uint8_t)distance;

  //  LMIC_setTxData2(1, mydata, sizeof(mydata), 0);

    // Cayenne LPP Protocal Definition
#define LPP_DIGITAL_OUTPUT         1     
    // Init declaration
    uint8_t val;
    uint8_t channel;
    byte buffer[8];
    uint8_t cursor = 0;

    // set Sensor Barometric Pressure into payload
    val = mydata;
    channel = 0x04;
    {
    
    buffer[cursor++] = channel; 
    buffer[cursor++] = LPP_DIGITAL_OUTPUT; 
    buffer[cursor++] = val; 

    return cursor;
}
   
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
      Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
      // Prepare upstream data transmission at the next possible time.
      LMIC_setTxData2(1, buffer, sizeof(buffer) / sizeof(buffer[0]), 0);

      //Serial output of message
      Serial.println(F("Sending: "));
      for (byte b = 0; b < (sizeof(buffer) / sizeof(buffer[0])); b++) {
        Serial.print(buffer[b]);

      }
      // Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.

  }
}