Project assistance

I am trying to create a trigger in which I can send a downlink message to change the sensitivity of a sensor node. I would like the node to keep sending the battery percentage, but only send; sensor data, and GPS data only when the proper criteria are met. I am having trouble with making an if statement regarding the app data. I have made such a sensitivity setting when I was sending data from node to node, but now that I am sending data to a gateway, I am unsure on how to format this with the case-based uplink system that I am using.

below is the template I am using from the ESP32_LoRaWAN library I’m using

#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: */
uint32_t  license[4] = {0xD5397DF0, 0x8573F814, 0x7A38C73D, 0x48E68607};

/* OTAA para*/
uint8_t DevEui[] = {FILLMEIN };
uint8_t AppEui[] = { FILLMEIN};
uint8_t AppKey[] = { FILLMEIN};

/* ABP para*/
uint8_t NwkSKey[] = {FILLMEIN };
uint8_t AppSKey[] = { FILLMEIN};
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;

#define LEDPin 25  //LED light
void app(uint8_t data)
  // lora_printf("data:%d\r\n",data);
  switch (data)
    case 49:
        pinMode(LEDPin, OUTPUT);
        digitalWrite(LEDPin, HIGH);
    case 50:
        pinMode(LEDPin, OUTPUT);
        digitalWrite(LEDPin, LOW);
    case 51:

String LoRa_data;
void  downLinkDataHandle(McpsIndication_t *mcpsIndication)
  LoRa_data = "";
  lora_printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n", mcpsIndication->RxSlot ? "RXWIN2" : "RXWIN1", mcpsIndication->BufferSize, mcpsIndication->Port);
  lora_printf("+REV DATA:");

  for (uint8_t i = 0; i < mcpsIndication->BufferSize; i++)
    lora_printf("%02X", mcpsIndication->Buffer[i]);
    LoRa_data = LoRa_data + (String)(char)mcpsIndication->Buffer[i];

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 Percentage = map(Voltage, 3.6, 4.2, 0, 100);
  float Perc = ((Percentage * -1) / 3);
  int16_t Battery = (Perc + 0);
  float LatRead =;
  float LonRead = gps.location.lng();
  float AltRead = gps.altitude.feet();
  uint16_t HourRead = gps.time.hour();
  uint16_t MinRead = gps.time.minute();
  uint16_t SecRead = gps.time.second();
  int16_t SensorRead = ads.getLastConversionResults();

  digitalWrite(Vext, HIGH);
  unsigned char *puc;
  appDataSize = 22;
  appData[0] = (int8_t)(SensorRead >> 8);
  appData[1] = (int8_t)SensorRead;

  appData[2] = (int8_t)(Battery >> 8);
  appData[3] = (int8_t)Battery;

  appData[4] = (uint8_t)(HourRead >> 8);
  appData[5] = (uint8_t)HourRead;

  appData[6] = (uint8_t)(MinRead >> 8);
  appData[7] = (uint8_t)MinRead;

  appData[8] = (uint8_t)(SecRead >> 8);
  appData[9] = (uint8_t)SecRead;

  puc = (unsigned char *)(&LatRead);
  appData[10] = puc[0];
  appData[11] = puc[1];
  appData[12] = puc[2];
  appData[13] = puc[3];

  puc = (unsigned char *)(&LonRead);
  appData[14] = puc[0];
  appData[15] = puc[1];
  appData[16] = puc[2];
  appData[17] = puc[3];

  puc = (unsigned char *)(&AltRead);
  appData[18] = puc[0];
  appData[19] = puc[1];
  appData[20] = puc[2];
  appData[21] = puc[3];

  Serial.print(", Lon=");
  Serial.print(", Alt=");
  Serial.print("Time: ");
  Serial.print("Voltage: ");
  Serial.print(", Percentage: ");
  Serial.print("Sensor Reading: ");

// Add your initialization code here
void setup()
  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("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
  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 )
        LoRaWAN.init(loraWanClass, loraWanRegion);
        prepareTxFrame( appPort );
        deviceState = DEVICE_STATE_CYCLE;
        // Schedule next packet transmission
        txDutyCycleTime = appTxDutyCycle + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
        deviceState = DEVICE_STATE_SLEEP;
        LoRaWAN.sleep(loraWanClass, debugLevel);
        deviceState = DEVICE_STATE_INIT;

It seems no one is leaping in to help - probably as you are effectively asking a generic programming question - assuming you are referring to the case statement in the app function, where does it get called?

If you don’t want to send the sensor reading, which is added to the payload in the prepareTxFrame function, that would be the place perhaps for an if statement. But you’ll need a global variable that can be sent from the downLinkDataHandle.

The other thing that’s most likely holding people back is the difference of opinion that tends to arise when we point out that you are sending far far far too frequently - for the law (blue lights, sirens, police, handcuffs, court, fine, jail, that sort of thing) and the Fair Use Policy for TTN. You have 15 seconds, a 22 byte payload would be somewhere between once every 5 minutes and once per hour.

1 Like