Add payload to LoRa TX command


(Sequitur) #1

I try to add the payload (temperature and humidity), which are in byte-format, to a char that contains the command: "mac tx uncnf 1 ".

The payload is a bytearray of 4 bytes:

payload[0] = highByte(temperature);  // value 8
payload[1] = lowByte(temperature);   // value 6
payload[2] = highByte(humidity);        // value 24
payload[3] = lowByte(humidity);         // value 232

I want to send the payload to my gateway using this code:

char Cmd = "mac tx uncnf 1 ";
Cmd += payload;
loraSerial.println(Cmd); // Serial port of the RB2483

The data is send but in my TTN console the value 79 is displayed which is not what I send. Probably something goes wrong when I concat the cmd and the payload but not being a C++ programmer I don't know how this should be done. Can someone point out what I am doing wrong?

Thanks in advance,
Anne


(Hylke Visser) #3

Have you considered using a payload format that is already built into our Arduino library?

TheThingsMessage:

CayenneLPP:


(Sequitur) #4

Yes, I did, and I do have a working version based on the TTN Library. But: I want to create my own version without using any library, just based on LoRa mac commands. This version is working too, it;s just the payload that gets corrupted (so it seems). This is my complete code:

/*******************************************************************************
 * Copyright (c) 2017 A.A. Hondema
 *
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and 
 * redistribution.
 * 
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 * 
 * Board  : TheThingsUno
 * LoRa   : RN2483
 * File   : Arduino\libraries\TheThingsNetwork\examples\LoRaSensor
 * TTN    : Yes
 * Device : ttn-000002
 * Remarks: Using LoRa commands only (no library)
 *******************************************************************************/

#include <DHT.h>

#define debugSerial Serial
#define loraSerial Serial1

// DTH sensor
#define DHTPIN 3                        // Digital pin for DHT22
#define DHTTYPE DHT22                   // DHT Type (DHT11, DHT21, DHT22)
DHT dht(DHTPIN, DHTTYPE);               // Initialize DHT

byte msgCount = 0;                      // Count of outgoing messages
float h = 0;                            // Humidity
float t = 0;                            // Temperature
bool debug = true;                      // Debug to serial

byte payload[4] = {0};                  // Current payload

// Scheduling
unsigned long SensorTimer = 0;          // Used for scheduling events
unsigned long SensorInterval = 300000;  // Interval for reading sensor
unsigned long LedTimer = 0;             // Used for scheduling events
unsigned long LedInterval = 1000;       // Interval for LED

void setup()
{  
  // initialize digital pin LED_BUILTIN as an output.
  // pinMode(13, OUTPUT) has the same result.
  pinMode(LED_BUILTIN, OUTPUT);
  
  loraSerial.begin(57600);
  debugSerial.begin(9600);

  // Start DHT
  dht.begin();

  // Wait a maximum of 10s for Serial Monitor
  while (!debugSerial && millis() < 10000)
    ;

  loraReset();
  loraKeys();
  loraInit();
  loraSave();
  loraJoin();
}

void loop() 
{
  if ((unsigned long)(millis() - SensorTimer) >= SensorInterval || SensorTimer == 0)
  {
    // Get sensor data
    getSensorData();

    // Send data to Lora
    sendSensorData();

    SensorTimer = millis();
  }

  if ((unsigned long)(millis() - LedTimer) >= LedInterval || LedTimer == 0)
  {
    LedTimer = millis();
    toggleLed();
  }
}

/*
 * DHT22 sensor functions
 */
void getSensorData()
{
  printDebug(1, "-- GET SENSOR DATA");
  
  // Reading temperature or humidity takes about 250 milliseconds
  h = dht.readHumidity();
  h = h - 8; // value from sensor is too high
  
  // Read temperature as Celsius (default): Fahrenheit = dht.readTemperature(false) 
  t = dht.readTemperature();
 
  // Did we get sensor data?
  if (isnan(h) || isnan(t)) 
  {
    printDebug(1, "Failed to read data from DHT sensor!");
    return;
  }

  // Compute heat index (Gevoelstemperatuur) in Celsius (isFahreheit = false)
  // The heat index (HI) or humiture is an index that combines air temperature 
  // and relative humidity, in shaded areas, as an attempt to determine 
  // the human-perceived equivalent temperature, as how hot it would feel if 
  // the humidity were some other value in the shade. The result is also known 
  // as the "felt air temperature" or "apparent temperature". For example, when 
  // the temperature is 32  C (90  F) with 70% relative humidity, the heat index 
  // is 41  C (106  F). This heat index temperature has an implied (unstated) 
  // humidity of 20%. This is the value of relative humidity for which the heat 
  // index formula indicates 41  C feels like 41  C. A heat index temperature of 
  // 32  C has an implied relative humidity of 38%. (taken from Wikipedia)
  //
  //  Celsius    Notes
  //  27,32 C    Caution: fatigue is possible with prolonged exposure and activity. 
  //             Continuing activity could result in heat cramps.
  //  32,41 C    Extreme caution: heat cramps and heat exhaustion are possible. 
  //             Continuing activity could result in heat stroke.
  //  41,54 C    Danger: heat cramps and heat exhaustion are likely; heat stroke is 
  //             probable with continued activity.
  //  over 54 C  Extreme danger: heat stroke is imminent.
  
  float hidx = dht.computeHeatIndex(t, h, false);

  printDebug(0, "Temperature: ");
  printDebug(0, String(t));
  printDebug(1, " *C ");
  printDebug(0, "Humidity: ");
  printDebug(0, String(h));
  printDebug(1, " %\t");
  printDebug(0, "Heat index: ");
  printDebug(0, String(hidx));
  printDebug(1, " *C ");
}

void sendSensorData()
{
  printDebug(1, "-- SEND SENSOR DATA");
  printDebug(1, "-- RN2483 LoRaSensor - The Things Uno");
      
  // Prepare payload, create integers
  uint16_t humidity = h * 100;
  uint16_t temperature = t * 100;

  // Payload = temperature + humidity
  //String Payload = String(temperature) + String(humidity);
  // loraSend(Payload();

  payload[0] = highByte(temperature);
  payload[1] = lowByte(temperature);
  payload[2] = highByte(humidity);
  payload[3] = lowByte(humidity);

  loraSend(Payload);
}

/*
 * Lora functions
 */

// Reset the RN2483
void loraReset()
{

  // Reset the LoRaWAN stack and initialize for the selected band
  printDebug(1, "-- RESET");
  loraCmd("mac reset 868");
  wait(2);
  loraResponse();

  printDebug(1, "-- INIT RADIO");
  loraCmd("radio set mod lora"); // lora
  loraCmd("radio set freq 868100000"); // 869525000
  loraCmd("radio set sf sf7"); // sf9
  loraCmd("radio set bw 125"); // 125
  loraCmd("radio set crc on");
  loraCmd("radio set cr 4/5"); // 4/5
  loraCmd("radio set prlen 8"); // 8
  loraCmd("radio set pwr 14"); // 14
  loraCmd("radio set sync 34"); 
}

// Set the Keys
void loraKeys()
{
  printDebug(1, "-- INIT KEYS");
  
  loraCmd("mac set deveui XXX");   // ORIGINAL VALUES REPLACED
  loraCmd("mac set appeui XXX");
  loraCmd("mac set devaddr XXX");
  loraCmd("mac set appkey XXX");
  loraCmd("mac set nwkskey XXX");
  loraCmd("mac set appskey XXX");
}

// Initialize the RN2483
void loraInit()
{
  printDebug(1, "-- INIT RN2483");

  // TTN does not support Adaptive Data Rate
  // ADR is only needed in limited scenarios that is why it is disabled
  loraCmd("mac set adr off");

  // Switch off automatic replies, only one max_rx per tx can be received
  loraCmd("mac set ar off");

  // TTN uses a non-default RX2 window freq. and SF
  loraCmd("mac set rx2 3 869525000");

  // Set the min-max datarate allowed  
  loraCmd("mac set ch drrange 1 0 6");

  // For RN2483: pwridx=1
  loraCmd("mac set pwridx 1");

  // The dutyCycle value that needs to be configured can be
  // obtained from the actual duty cycle X (in percentage)
  // using the following formula: <dutyCycle> = (100/X) - 1
  //
  //  10% -> 9
  //  1% -> 99
  //  0.33% -> 299
  //  8 channels, total of 1% duty cycle:
  //  0.125% per channel -> 799
  loraCmd("mac set ch dcycle 3 799");

  // Frequency
  loraCmd("mac set ch freq 3 868100000");

  // Set the min-max datarate allowed  
  loraCmd("mac set ch drrange 3 0 5");

  // Dispable the default channels
  loraCmd("mac set ch status 0 off");
  loraCmd("mac set ch status 1 off");
  loraCmd("mac set ch status 2 off");

  // Only use channel 3
  loraCmd("mac set ch status 3 on");

  // Number of retransmissions for an uplink confirmed packet
  loraCmd("mac set retx 7");

  // Set datarate to 5 (SF7) (12-7=5)
  loraCmd("mac set dr 5");
 
}

// Save the Lora settings
void loraSave() {
  // Save the settings
  loraCmd("mac save"); 
  wait(5);
  loraResponse();
}

// Join the TTN network
void loraJoin()
{
  printDebug(1, "-- JOIN");
  loraCmd("mac join abp");
}

**// Send data**

** void loraSend(byte payload)**
** {**
** String Cmd = "mac tx uncnf 1 ";**
** Cmd += payload;**
** loraCmd(Cmd);**

** // SF12 = 4 sec, SF7 = 2 sec**
** wait(4);**

** // Get the second response**
** loraResponse();**
** }**

// Send command to RN2483
void loraCmd(String cmd)
{

  // Clear the serial buffer
  //clearBuffer();
  
  // Show the command in the monitor
  printDebug(0, cmd);
  printDebug(0, ": ");

  // Execute the command
  loraSerial.println(cmd);

  // Get the response
  loraResponse();
}

// Read the response from the RN2483
void loraResponse()
{
    // Get the response
  delay(100);
  while (loraSerial.available())
  {
    if (debug) debugSerial.write(loraSerial.read());
  }
}

// Clear the serial buffer
void clearBuffer()
{
while (loraSerial.available())
  {
    loraSerial.read();
  }
}

/* 
 *  Supporting functions 
*/

// Wait
void wait(int interval)
{
  // Wait for <interval> seconds
  for (int i = 0; i < interval; i++)
  {
    toggleLed();
    delay(1000);
  }
}

// Toggle the led
void toggleLed()
{
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

// Debug info
void printDebug(bool type, String text)
{
  if ((debug) && (debugSerial))
  {
    switch (type) 
    {
      case 0:
        debugSerial.print(text);
        break;
      case 1:
        debugSerial.println(text);
        break;
    }
  }
}

(Jac Kersing) #5

The RN modules require ASCII commands with the data in HEX format. You are trying to add binary data to the string. So define cmd to be 25 characters and use something like

sprintf(cmd,"mac tx uncnf 1 %02x%02x%02x%02x", highByte(temperature), lowByte(temperature), highByte(humidity), lowByte(humidity));

(Sequitur) #6

Hi Jack,

I managed to get it working yesterday evening using this code:

  loraSerial.print("mac tx uncnf 1 ");
  loraSerial.print(highByte(temperature), HEX);
  loraSerial.print(lowByte(temperature), HEX);
  loraSerial.print(highByte(humidity), HEX);
  loraSerial.println(lowByte(humidity), HEX);

But I prefer your solution. Thanks!

Anne


(Sequitur) #7

Hi again,

I implemented your solution and altered my code a bit. This what it looks like now: a LoRa program based on LoRaWAN commands, not using any library. I wrote it to better understand how the LoRaWAN commands work...

Thanks for your help!

/*******************************************************************************
 * Copyright (c) 2017 A.A. Hondema
 *
 * Permission is hereby granted, free of charge, to anyone obtaining a copy of 
 * this document and accompanying files, to do whatever they want with them 
 * without any restriction, including, but not limited to, copying, modification 
 * and redistribution.
 * 
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 * 
 * Board  : TheThingsUno
 * LoRa   : RN2483
 * File   : Arduino\libraries\TheThingsNetwork\examples\LoRaSensor
 * TTN    : Yes
 * Device : ttn-000001
 * Remarks: Using LoRa commands only (no library)
 *******************************************************************************/

#include <DHT.h>

#define debugSerial Serial
#define loraSerial Serial1

// DTH sensor
#define DHTPIN 3                        // Digital pin for DHT22
#define DHTTYPE DHT22                   // DHT Type (DHT11, DHT21, DHT22)
DHT dht(DHTPIN, DHTTYPE);               // Initialize DHT
float h = 0;                            // Humidity
float t = 0;                            // Temperature

// LED
#define LEDPIN 13                       // Buildin LED pin

// LoRa
byte msgCount = 0;                      // Count of outgoing messages

// Use debugging?
bool debug = true;                      // Debug to serial

// Scheduling
unsigned long SensorTimer = 0;          // Used for scheduling events
unsigned long SensorInterval = 300000;  // Interval for reading sensor
unsigned long LedTimer = 0;             // Used for scheduling events
unsigned long LedInterval = 1000;       // Interval for LED

void setup()
{  
  // initialize digital pin 13 as an output.
  pinMode(LEDPIN, OUTPUT);
  
  loraSerial.begin(57600);
  debugSerial.begin(9600);

  // Start DHT
  dht.begin();

  // Wait a maximum of 10s for Serial Monitor
  while (!debugSerial && millis() < 10000)
    ;

  // Set and Initialize LoRa
  loraReset();
  loraInitRadio();
  loraKeys();
  loraInitRN2483();
  loraSave();
  loraJoin();
}

void loop() 
{
  // Sensortimer loop
  if ((unsigned long)(millis() - SensorTimer) >= SensorInterval || SensorTimer == 0)
  {
    // Get sensor data
    getSensorData();

    // Send data to Lora
    sendSensorData();

    SensorTimer = millis();
  }

  // LED loop
  if ((unsigned long)(millis() - LedTimer) >= LedInterval || LedTimer == 0)
  {
    toggleLed();

    LedTimer = millis();
  }
}

/*
 * DHT22 sensor functions
 */
void getSensorData()
{
  printDebug(1, "-- GET SENSOR DATA");
  
  // Reading temperature or humidity takes about 250 milliseconds
  h = dht.readHumidity();
  h = h - 15; // value from sensor is too high: subtract 15 to correct
  
  // Read temperature as Celsius (default): Fahrenheit = dht.readTemperature(false) 
  t = dht.readTemperature();
 
  // Did we get sensor data?
  if (isnan(h) || isnan(t)) 
  {
    printDebug(1, "Failed to read data from DHT sensor!");

    // No data read: set to 0
    h = 0;
    t = 0;
  }

  // Compute heat index (Gevoelstemperatuur) in Celsius (isFahreheit = false)
  // The heat index (HI) or humiture is an index that combines air temperature 
  // and relative humidity, in shaded areas, as an attempt to determine 
  // the human-perceived equivalent temperature, as how hot it would feel if 
  // the humidity were some other value in the shade. The result is also known 
  // as the "felt air temperature" or "apparent temperature". For example, when 
  // the temperature is 32  C (90  F) with 70% relative humidity, the heat index 
  // is 41  C (106  F). This heat index temperature has an implied (unstated) 
  // humidity of 20%. This is the value of relative humidity for which the heat 
  // index formula indicates 41  C feels like 41  C. A heat index temperature of 
  // 32  C has an implied relative humidity of 38%. (taken from Wikipedia)
  //
  //  Celsius    Notes
  //  27,32 C    Caution: fatigue is possible with prolonged exposure and activity. 
  //             Continuing activity could result in heat cramps.
  //  32,41 C    Extreme caution: heat cramps and heat exhaustion are possible. 
  //             Continuing activity could result in heat stroke.
  //  41,54 C    Danger: heat cramps and heat exhaustion are likely; heat stroke is 
  //             probable with continued activity.
  //  over 54 C  Extreme danger: heat stroke is imminent.
  
  float hidx = dht.computeHeatIndex(t, h, false);

  printDebug(0, "Temperature: ");
  printDebug(0, String(t));
  printDebug(1, " *C ");
  printDebug(0, "Humidity: ");
  printDebug(0, String(h));
  printDebug(1, " %\t");
  printDebug(0, "Heat index: ");
  printDebug(0, String(hidx));
  printDebug(1, " *C ");
}

void sendSensorData()
{
  printDebug(1, "-- SEND SENSOR DATA");
  printDebug(1, "-- RN2483 LoRaSensor - The Things Uno");
      
  loraSend();
}

/*
 * Lora functions
 */

// Reset the RN2483
void loraReset()
{

  // Reset the LoRaWAN stack and initialize for the selected band
  printDebug(1, "-- RESET");
  
  loraCmd("mac reset 868");
  wait(2);
  loraResponse();
}

void loraInitRadio() 
{
  printDebug(1, "-- INIT RADIO");
  
  loraCmd("radio set mod lora"); // lora
  loraCmd("radio set freq 868100000"); // 869525000
  loraCmd("radio set sf sf7"); // sf9
  loraCmd("radio set bw 125"); // 125
  loraCmd("radio set crc on");
  loraCmd("radio set cr 4/5"); // 4/5
  loraCmd("radio set prlen 8"); // 8
  loraCmd("radio set pwr 14"); // 14
  loraCmd("radio set sync 34"); 
}

// Set the Keys
void loraKeys()
{
  printDebug(1, "-- INIT KEYS");
  
  loraCmd("mac set deveui 0004A30B001B6A50");
  loraCmd("mac set appeui 70B3D57EF0006783");
  loraCmd("mac set devaddr 26011D89");
  loraCmd("mac set appkey C6669615A03AF6476DB255A6ED670F47");
  loraCmd("mac set nwkskey 5CDDEEC541C8E1ABF3395F8DE2592383");
  loraCmd("mac set appskey 407A8722D3CE5294531597BEC5B50F91");
}

// Initialize the RN2483
void loraInitRN2483()
{
  printDebug(1, "-- INIT RN2483");

  // TTN does not support Adaptive Data Rate
  // ADR is only needed in limited scenarios that is why it is disabled
  loraCmd("mac set adr off");

  // Switch off automatic replies, only one max_rx per tx can be received
  loraCmd("mac set ar off");

  // TTN uses a non-default RX2 window freq. and SF
  loraCmd("mac set rx2 3 869525000");

  // Set the min-max datarate allowed  
  loraCmd("mac set ch drrange 1 0 6");

  // For RN2483: pwridx=1
  loraCmd("mac set pwridx 1");

  // The dutyCycle value that needs to be configured can be
  // obtained from the actual duty cycle X (in percentage)
  // using the following formula: <dutyCycle> = (100/X) - 1
  //
  //  10% -> 9
  //  1% -> 99
  //  0.33% -> 299
  //  8 channels, total of 1% duty cycle:
  //  0.125% per channel -> 799
  loraCmd("mac set ch dcycle 3 799");

  // Frequency
  loraCmd("mac set ch freq 3 868100000");

  // Set the min-max datarate allowed  
  loraCmd("mac set ch drrange 3 0 5");

  // Disable the default channels, sending to single channel gateway!
  loraCmd("mac set ch status 0 off");
  loraCmd("mac set ch status 1 off");
  loraCmd("mac set ch status 2 off");

  // Only use channel 3
  loraCmd("mac set ch status 3 on");

  // Number of retransmissions for an uplink confirmed packet
  loraCmd("mac set retx 7");

  // Set datarate to 5 (SF7) (12-7=5)
  loraCmd("mac set dr 5");
 
}

// Save the Lora settings
void loraSave() {
  printDebug(1, "-- SAVE");
  loraCmd("mac save"); 
  wait(5);
  loraResponse();
}

// Join the TTN network
void loraJoin()
{
  printDebug(1, "-- JOIN");
  loraCmd("mac join abp");
}

// Send data
void loraSend()
{

  // Prepare payload, create integers
  uint16_t humidity = h * 100;
  uint16_t temperature = t * 100;

  // Create LoRa TX command
  char cmd[25];
  sprintf(cmd,"mac tx uncnf 1 %02x%02x%02x%02x", highByte(temperature), lowByte(temperature), highByte(humidity), lowByte(humidity));
  loraCmd(String(cmd));

  // SF12 = 4 sec, SF7 = 2 sec
  wait(2);

  // Get the second response (tx ok)
  loraResponse();
}

// Send command to RN2483
void loraCmd(String cmd)
{

  // Clear the serial buffer
  //clearBuffer();
  
  // Show the command in the monitor
  printDebug(0, cmd);
  printDebug(0, ": ");

  // Execute the command
  loraSerial.println(cmd);

  // Get the response
  loraResponse();
}

// Read the response from the RN2483
void loraResponse()
{
    // Get the response
  delay(100);
  while (loraSerial.available())
  {
    if (debug) debugSerial.write(loraSerial.read());
  }
}

// Clear the serial buffer
void clearBuffer()
{
while (loraSerial.available())
  {
    loraSerial.read();
  }
}

/* 
 *  Supporting functions 
 */

// Wait
void wait(int interval)
{
  // Wait for <interval> seconds
  for (int i = 0; i < interval; i++)
  {
    toggleLed();
    delay(1000);
  }
}

// Toggle the led
void toggleLed()
{
  digitalWrite(LEDPIN, !digitalRead(LEDPIN));
}

// Debug info
void printDebug(bool type, String text)
{
  if ((debug) && (debugSerial))
  {
    switch (type) 
    {
      case 0:
        debugSerial.print(text);
        break;
      case 1:
        debugSerial.println(text);
        break;
    }
  }
}

(Jayarams) #8

Hi Sequitur,
I need to fetch the temperature and light sensor data.
and put the data in,
while (1)
{
LORAWAN_Mainloop();
}
to send every 10 seconds to my server app.
How to get the GPIO12 and GPIO13 (temp. and light) data using the code.
From your post,
payload[0] = highByte(temperature); // value 8
payload[1] = lowByte(temperature); // value 6
payload[2] = highByte(humidity); // value 24
payload[3] = lowByte(humidity); // value 232

How the temp and light values readed in payload[0],[1],[2],[3].
And how can send the combined information as data from MOTE rn2483 using "mac tx uncnf 1".

Thanks,
JayaramS


(Sequitur) #9

Hi JayaramS,

As you can see in my code, the temperature and humidity are retrieved from a DHT22 sensor using this code:

/*
 * DHT22 sensor functions
 */
void getSensorData()
{
  printDebug(1, "-- GET SENSOR DATA");
  
  // Reading temperature or humidity takes about 250 milliseconds
  h = dht.readHumidity();
  h = h - 15; // value from sensor is too high: subtract 15 to correct
  
  // Read temperature as Celsius (default): Fahrenheit = dht.readTemperature(false) 
  t = dht.readTemperature();
 
  // Did we get sensor data?
  if (isnan(h) || isnan(t)) 
  {
    printDebug(1, "Failed to read data from DHT sensor!");

    // No data read: set to 0
    h = 0;
    t = 0;
  }
}

(Teacher) #10

Hello,
Am I right to assume your code only works for the RN2483 chip? Also I know how to find the appskey but what is the appkey?


#11

App Key is used in combination with OTAA
App_key


(Teacher) #12

Thank you.