Payloads for mutiple sensors using Lora module with LMIC Library

Hi there,

I am working on a project based on Lora module for smart plant using Single channel Gateway and Lora shield and Arduino Uno from Dragino. I am using LPP format for sending Lora packet to Application server. So far, I am able only to send Temp and Humidity.
I need your help to add send two more values ( soil moisture and illuminace sensors).
Temp. and hum. have sent via 0x67 and 0x68 and data types respectively. what is the Data Type for soil moisture ?
another question I need also to queue Downlink msg to control relay module?
I have attached my sketch

Best regards
Mohamad Shawa

`// Import libraries 
#include <dht.h>
#include <lmic.h>
#include <hal/hal.h>

// Create an instance of the dht class, define pin and variables
dht DHT;
#define DHT11_PIN A0
static float dhtData, temp, humid;

// APPEUI - 64-bit application identifier. Must be in little-endian format, so least-significant-byte first. 
// LoRa App Server acts as a default join-server currently, (regardless of the AppEUI value), 
// the AppEUI / JoinEUI (two names, same field) does not matter.
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);} 

// DEVEUI - unique 64-bit end-device identifier. Must be in little-endian format. 
// Can be genereted by Chirsptack's Application server or use own.
static const u1_t PROGMEM DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // --> Unique for each end-node
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} 

// APPKEY - AES-128 root key unique for the end-device. Must be in big endian format.
// Used to derive the session keys NwkSKey and AppSKey specific for that end-device to encrypt 
// and verify network communication and application data. Can be genereted by Chirsptack's Application server or use own.
static const u1_t PROGMEM APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // --> Unique for each end-node
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}

// Setting Cayenne LPP format. Need to choose a channel (optional) and data type for each of the sensors' data. 
// More info about a format here: https://developers.mydevices.com/cayenne/docs/lora/
static uint8_t LPP_data[7] = {0x01,0x67,0x00,0x00,0x02,0x68,0x00}; //0x01,0x02 is Data Channel,0x67,0x68 is Data Type

// Per job control struct, which identifies the job and stores context information.
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty cycle limitations).
const unsigned TX_INTERVAL = 30;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 9,
    .dio = {2, 6, 7},
};

// Application’s callback function which prints Events via Serial.
void onEvent (ev_t ev) {
    Serial.print(os_getTime());
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Serial.println(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            Serial.println(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            Serial.println(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            Serial.println(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            Serial.println(F("EV_JOINING"));
            break;
        case EV_JOINED:
            Serial.println(F("EV_JOINED"));
            break;
        case EV_RFU1:
            Serial.println(F("EV_RFU1"));
            break;
        case EV_JOIN_FAILED:
            Serial.println(F("EV_JOIN_FAILED"));
            break;
        case EV_REJOIN_FAILED:
            Serial.println(F("EV_REJOIN_FAILED"));
            break;
        case EV_TXCOMPLETE:
            Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if (LMIC.txrxFlags & TXRX_ACK)
              Serial.println(F("Received ack"));
            if (LMIC.dataLen) {
              Serial.println(F("Received "));
              Serial.println(LMIC.dataLen);
              Serial.println(F(" bytes of payload"));
            }
            // Schedule next transmission in TX_INTERVAL time.
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            break;
        case EV_LOST_TSYNC:
            Serial.println(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            Serial.println(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Serial.println(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            Serial.println(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            Serial.println(F("EV_LINK_ALIVE"));
            break;
         default:
            Serial.println(F("Unknown event"));
            break;
    }
}

// Read temperature and humidity values from a sensor and encode to Cayanne LPP format.
void dhtTem()
{
       int16_t tem_LPP;
       dhtData = DHT.read11(DHT11_PIN);
       temp = DHT.temperature;      
       humid = DHT.humidity;
       
       // Each data type has different data size and data resolution per bit
       tem_LPP=temp * 10; // Data Resolution per bit is 0.1°C MSB.
       LPP_data[2] = tem_LPP>>8;
       LPP_data[3] = tem_LPP;
       LPP_data[6] = humid *2; // Data Resolution per bit is 0.5%.

}

// Read sensor value and make data ready for transmission.
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 sensor values put data to Cayanne LPP format. 
        dhtTem();
        // Prepare upstream data transmission at the next possible time.
        LMIC_setTxData2(1, LPP_data, sizeof(LPP_data), 0);
        Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.
}

// Called when a sketch starts to initialize variables, pin modes, start using libraries, etc. 
// Only run once, after each powerup or reset of the Arduino board.
void setup() {
    Serial.begin(9600);
    Serial.println(F("Starting"));

    // Initialize the run-time environment 
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();
    // Start job
    do_send(&sendjob);
}

// Loops consecutively, allowing the program to change and respond.
void loop() {
    // Execute run-time jobs from the timer and from the run queues. Returns after dispatching the first available job.
    os_runloop_once();
}

there is no soil moisture data type. you need to send the data on analog sensor datatype.

Hi @shramik_salgaonkar ,
thank you for your reply. as I assume sending packet on channel number five and the format supposed to be like this:
0x05, 0x03, 0x00, 0x00 ??
I have tried but, it doesn’t work !! and gives![lpp cayenne|690x339] random values
am I wrong?

0x03 is analog output. you need to use 0x02 for analog input.

1 Like