I have a sensor that is one of my end devices. It sends the GPS location, altitude, time and the feedback of a geophone (ground sensor) to my gateway. The end device is a Heltec ESP32 LoRaWAN microcontroller. I’m really struggling with the decoder. I’ve seen a lot of documentation using the decoder for temperature and humidity sensors but I’m not really sure on how to apply it to my project.
Arduino Sketch
#include <ESP32_LoRaWAN.h>
#include "Arduino.h"
//Include the needed libraries for the ADS and the GPS module
#include <Wire.h>//I2C library
#include <Adafruit_ADS1X15.h>//ADS library
#include "TinyGPS++.h"//Gps module library
//Define the BAND frequency
#define BAND 915E6//set BAND to US which is 915E6 or 915MHz
//Declare your objects which are the GPS module and the ADS1115 in which we can read the geophone inputs
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data
Adafruit_ADS1115 ads;/* Use this for the 16-bit version */
//Declare the global variables
int value = analogRead(A0);
float Voltage;
float Perc;
int16_t SensorRead;
float LatRead;
float LonRead;
float AltRead;
int HourRead;
int MinRead;
int SecRead;
/*license for Heltec ESP32 LoRaWan, quary your ChipID relevant license: http://resource.heltec.cn/search */
uint32_t license[4] = {0xD5397DF0, 0x8573F814, 0x7A38C73D, 0x48E68607};
/* OTAA para*/
uint8_t DevEui[] = { 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x04, 0xC7, 0x25 };
uint8_t AppEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t AppKey[] = { 0x00, 0x5C, 0xC0, 0x9F, 0x5D, 0x71, 0x4F, 0xE1, 0x0D, 0xAC, 0x21, 0x7D, 0xC4, 0xB3, 0x43, 0x40};
/* ABP para*/
uint8_t NwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda, 0x85 };
uint8_t AppSKey[] = { 0x00, 0x5C, 0xC0, 0x9F, 0x5D, 0x71, 0x4F, 0xE1, 0x0D, 0xAC, 0x21, 0x7D, 0xC4, 0xB3, 0x43, 0x40 };
uint32_t DevAddr = ( uint32_t )0x007e6ae1;
/*LoraWan channelsmask, default channels 0-7*/
uint16_t userChannelsMask[6] = { 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
/*LoraWan Class, Class A and Class C are supported*/
DeviceClass_t loraWanClass = CLASS_A;
/*the application data transmission duty cycle. value in [ms].*/
uint32_t appTxDutyCycle = 15000;
/*OTAA or ABP*/
bool overTheAirActivation = true;
/*ADR enable*/
bool loraWanAdr = true;
/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = true;
/* Application port */
uint8_t appPort = 2;
/*!
Number of trials to transmit the frame, if the LoRaMAC layer did not
receive an acknowledgment. The MAC performs a datarate adaptation,
according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
to the following table:
Transmission nb | Data Rate
----------------|-----------
1 (first) | DR
2 | DR
3 | max(DR-1,0)
4 | max(DR-1,0)
5 | max(DR-2,0)
6 | max(DR-2,0)
7 | max(DR-3,0)
8 | max(DR-3,0)
Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
the datarate, in case the LoRaMAC layer did not receive an acknowledgment
*/
uint8_t confirmedNbTrials = 8;
/*LoraWan debug level, select in arduino IDE tools.
None : print basic info.
Freq : print Tx and Rx freq, DR info.
Freq && DIO : print Tx and Rx freq, DR, DIO0 interrupt and DIO1 interrupt info.
Freq && DIO && PW: print Tx and Rx freq, DR, DIO0 interrupt, DIO1 interrupt and MCU deepsleep info.
*/
uint8_t debugLevel = LoRaWAN_DEBUG_LEVEL;
/*LoraWan region, select in arduino IDE tools*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
static void prepareTxFrame( uint8_t port )
{
/*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in "commissioning.h".
appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE.
if enabled AT, don't modify LORAWAN_APP_DATA_MAX_SIZE, it may cause system hanging or failure.
if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be modified, the max value is reference to lorawan region and SF.
for example, if use REGION_CN470,
the max value for different DR can be found in MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in "RegionCN470.h".
*/
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
float Voltage = value * 5.0 / 1023;
float Perc = map(Voltage, 3.6, 4.2, 0, 100);
float LatRead = gps.location.lat();
float LonRead = gps.location.lng();
float AltRead = gps.altitude.feet();
int HourRead = gps.time.hour();
int MinRead = gps.time.minute();
int SecRead = gps.time.second();
int16_t SensorRead = ads.getLastConversionResults();
digitalWrite(Vext, HIGH);
unsigned char *puc;
puc = (unsigned char *)(&Voltage);
appDataSize = 34;
appData[0] = puc[0];
appData[1] = puc[1];
appData[2] = puc[2];
appData[3] = puc[3];
puc = (unsigned char *)(&Perc);
appData[4] = puc[0];
appData[5] = puc[1];
appData[6] = puc[2];
appData[7] = puc[3];
puc = (unsigned char *)(&LatRead);
appData[8] = puc[0];
appData[9] = puc[1];
appData[10] = puc[2];
appData[11] = puc[3];
puc = (unsigned char *)(&LonRead);
appData[12] = puc[0];
appData[13] = puc[1];
appData[14] = puc[2];
appData[15] = puc[3];
puc = (unsigned char *)(&AltRead);
appData[16] = puc[0];
appData[17] = puc[1];
appData[18] = puc[2];
appData[19] = puc[3];
puc = (unsigned char *)(&HourRead);
appData[20] = puc[0];
appData[21] = puc[1];
appData[22] = puc[2];
appData[23] = puc[3];
puc = (unsigned char *)(&MinRead);
appData[24] = puc[0];
appData[25] = puc[1];
appData[26] = puc[2];
appData[27] = puc[3];
puc = (unsigned char *)(&SecRead);
appData[28] = puc[0];
appData[29] = puc[1];
appData[30] = puc[2];
appData[31] = puc[3];
puc = (unsigned char *)(&SensorRead);
appData[32] = puc[0];
appData[33] = puc[1];
appData[34] = puc[2];
appData[35] = puc[3];
Serial.print("Lat=");
Serial.print(LatRead);
Serial.print(", Lon=");
Serial.print(LonRead);
Serial.print(", Alt=");
Serial.println(AltRead);
Serial.print("Time: ");
Serial.print(HourRead);
Serial.print(":");
Serial.print(MinRead);
Serial.print(":");
Serial.println(SecRead);
Serial.print("Voltage: ");
Serial.print(Voltage);
Serial.print(", Percentage: ");
Serial.println(Perc);
Serial.print("Sensor Reading: ");
Serial.println(SensorRead);
}
// Add your initialization code here
void setup()
{
Serial.begin(115200);
while (!Serial);
SPI.begin(SCK, MISO, MOSI, SS);
Mcu.init(SS, RST_LoRa, DIO0, DIO1, license);
deviceState = DEVICE_STATE_INIT;
Serial2.begin(115200, SERIAL_8N1, 2, 17);
//serial_connection.begin(115200);//This opens up communications to the GPS
Serial.println("Hello!");
Serial.println("Single-ended readings from AIN0 with >3.0V comparator");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)");
Serial.println("Comparator Threshold: 1000 (3.000V)");
// ADS1015 ADS1115
// ------- -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
//ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
//ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
ads.begin();
ads.setGain(GAIN_FOUR);
if (!ads.begin()) {
Serial.println("Failed to initialize ADS.");
while (1);
}
// Setup 3V comparator on channel 0
ads.startComparator_SingleEnded(0, 1000);
}
// The loop function is called in an endless loop
void loop()
{
switch ( deviceState )
{
case DEVICE_STATE_INIT:
{
#if(LORAWAN_DEVEUI_AUTO)
LoRaWAN.generateDeveuiByChipID();
#endif
LoRaWAN.init(loraWanClass, loraWanRegion);
break;
}
case DEVICE_STATE_JOIN:
{
LoRaWAN.join();
break;
}
case DEVICE_STATE_SEND:
{
prepareTxFrame( appPort );
LoRaWAN.send(loraWanClass);
deviceState = DEVICE_STATE_CYCLE;
break;
}
case DEVICE_STATE_CYCLE:
{
// Schedule next packet transmission
txDutyCycleTime = appTxDutyCycle + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
LoRaWAN.cycle(txDutyCycleTime);
deviceState = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SLEEP:
{
LoRaWAN.sleep(loraWanClass, debugLevel);
break;
}
default:
{
deviceState = DEVICE_STATE_INIT;
break;
}
}
}
and below is the decoder I’m using
Decoder
function Decoder(bytes, port) {
var voltage = (bytes[0] << 8) | bytes[1];
var perc = (bytes[1] << 8) | bytes[3];
var lat = (bytes[4] << 8) | bytes[5];
var lon = (bytes[4] << 8) | bytes[7];
var alt = (bytes[8] << 8) | bytes[9];
var hour = (bytes[0] << 8) | bytes[1];
var min = (bytes[2] << 8) | bytes[3];
var sec = (bytes[4] << 8) | bytes[5];
var sensor1 = (bytes[4] << 8) | bytes[7];
return {
voltage: voltage,
perc: perc,
lat: lat,
lon: lon,
alt: alt,
hour: hour,
min: min,
sec: sec,
sensor1: sensor1,
}
}
Please help, thank you!