TTN counter not incrementing with ttgo

Hi everyone, I have a sketch used for an ultrasonic sensor using a ttgo. For some reason, when it sends the uplink (say every 10 min), the counter on ttn doesn’t increment? Any thoughts as to why this is occuring? Everything else seems ok…
Interestingly I also get a downlink with every uplink, so perhaps it’s resetting every time?
Here’s the sketch…

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <Ultrasonic.h>
#include <esp_system.h>

/* define macros */
#define uS_TO_S_FACTOR  1000000   /* conversion factor for micro seconds to seconds */
#define TX_INTERVAL     1       /* time ESP32 will go to sleep (in minutes) */
#define MAX_LIMIT       10
float Vbat_Vsol = 3.3;
float STEP_Cnt = 4096;
float V_Trim = 20;
float R_01 = 6800;    //Battery Resistor 1
float R_02 = 8200;    //Battery Resistor 2
float R_03 = 15000;    //Solar Resistor 1
float R_04 = 8200;    //Solar Resistor 2

/* pin mapping */
#define VBAT_PIN    36
#define SWITCH_PIN  23
#define Trigger_Pin 25
#define Echo_Pin 34
#define DIAG_LED 0


/* global variables */
Ultrasonic ultrasonic(Trigger_Pin, Echo_Pin);
static osjob_t sendJob;
RTC_DATA_ATTR uint32_t txInterval = TX_INTERVAL;

/* time tick */
int startSend;
int finishSend;
int timeToSend;

void IRAM_ATTR resetModule() {
  ets_printf("Watchdog timed out - reboot\n");
  delay(5000);
  esp_restart();
}

// LoRaWAN NwkSKey, network session key (msb)
static const PROGMEM u1_t NWKSKEY[16] = };

// LoRaWAN AppSKey, application session key (msb)
static const u1_t PROGMEM APPSKEY[16] = };

// 0x then paste devadress in hex format
// The library converts the address to network byte order as needed.
static const u4_t DEVADDR = 0x ; // <-- Change this address for every node!

// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in arduino-lmic/project_config/lmic_project_config.h,
// otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 18,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = LMIC_UNUSED_PIN,
  /* if DIO2 is not connected, dio2 as unused, otherwise 32 */
  .dio = {
    /*dio0*/ 26,
    /*dio1*/ 33,
    /*dio2*/ LMIC_UNUSED_PIN
  }
};

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;
    /*
      || This event is defined but not used in the code. No
      || point in wasting codespace on it.
      ||
      || 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.print(F("Received "));
        Serial.print("\t");
        Serial.print(LMIC.dataLen);
        Serial.print("\t");
        Serial.println(F(" bytes of payload"));
        

        /* receive downlink */

        if (LMIC.dataLen == 5) {
          Serial.println("[INFO] Downlink is available");

          /* get packet information */
          uint8_t header = LMIC.frame[LMIC.dataBeg + 0];
          uint8_t cmd = LMIC.frame[LMIC.dataBeg + 1];
          uint16_t dat = 256 * LMIC.frame[LMIC.dataBeg + 2] + LMIC.frame[LMIC.dataBeg + 3];
          uint8_t tail = LMIC.frame[LMIC.dataBeg + 4];

          /*
             analyze downlink {0x55, cmd, dat0, dat1, 0xFF}
             @cmd: {set interval - 01, reboot - 02}
             @dat: 2 byte data
          */
          if (header == 0x55 && tail == 0xFF) {
            if (cmd == 0x01) {
              Serial.println("[INFO] Received CHANGE_TX_INTERVAL request");
              txInterval = dat;
            }
            else {
              Serial.println("[INFO] Received REBOOT request");
              resetModule();
            }
          }
        }
      }

      /* turn off PCB power */
      digitalWrite(SWITCH_PIN, LOW);
      Serial.println("***");
      Serial.println("[INFO] Turning off PCB power");


      // Schedule next transmission
                os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);

      finishSend = millis();
      timeToSend = (finishSend - startSend) / 1000;

      Serial.printf("[INFO] The board was awake for %d seconds this time\n", timeToSend);
      Serial.printf("[INFO] Going to sleep now for %d seconds\n", txInterval);
      Serial.println("***\n\n");
      Serial.flush();

    esp_sleep_enable_timer_wakeup(txInterval * 60 * uS_TO_S_FACTOR);
    esp_deep_sleep_start();
    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;
    /*
      || This event is defined but not used in the code. No
      || point in wasting codespace on it.
      ||
      || case EV_SCAN_FOUND:
      ||    Serial.println(F("EV_SCAN_FOUND"));
      ||    break;
    */
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    default:
      Serial.print(F("Unknown event: "));
      Serial.println((unsigned) ev);
      break;
  }
}

void do_send(osjob_t* j) {
  /* check if there is not a current TX/RX job running */
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println("[INFO] TX/RX was Busy, last msg not yet sent");
  }
  else {

    /* prepare upstream data transmission at the next possible time. */
    Serial.println("[INFO] Reading sensors and building payload\n");

    digitalWrite(SWITCH_PIN, LOW);   /* select Battery channel */
    delay(1000);                       /* small delay for settling */
    float vbat_a = analogRead(VBAT_PIN) / STEP_Cnt * Vbat_Vsol;
    int vbat = (vbat_a / (R_02 / (R_02 + R_01)) * 100) + V_Trim;
    //    Serial.println(analogRead(VBAT_PIN));
    //    Serial.println(vbat_a);
    //    Serial.println(vbat);

    /* Do all the required steps
      ->1. Read A/D Channel
      2. Scale to Vref for count proportion
      3. Apply external resistor scaling for Vbat
      4. Covert to mV*/

    digitalWrite(SWITCH_PIN, HIGH);
    /* select Solar channel */
    delay(1000);

    float vsol_a = analogRead(VBAT_PIN) / STEP_Cnt * Vbat_Vsol;
    int vsol = (vsol_a / (R_04 / (R_03 + R_04)) * 100);
    //    Serial.println(analogRead(VBAT_PIN));
    //    Serial.println(vsol_a);
    //    Serial.println(vsol);

    int level = ultrasonic.read();

    Serial.printf("[INFO] Level is: %d\n", level);

    byte payload[6];
    payload[0] = highByte(vbat);
    payload[1] = lowByte(vbat);
    payload[2] = highByte(level);
    payload[3] = lowByte(level);
    payload[4] = highByte(vsol);
    payload[5] = lowByte(vsol);

    /* prepare upstream data transmission at the next possible time */
    LMIC_setTxData2(1, payload, sizeof(payload), 0);
    Serial.println("[INFO] Packet queued");
  }
}

void setup() {
  /* serial initialize */
  pinMode(DIAG_LED, OUTPUT);
  digitalWrite(DIAG_LED, LOW);

  
  Serial.begin(115200);
  //  Serial2.begin(115200, SERIAL_8N1, 18, 17);
  while (!Serial);
  Serial.println("[INFO] Starting");

  /* pin configuration */
  pinMode(SWITCH_PIN, OUTPUT);
  pinMode(Trigger_Pin, OUTPUT);
  pinMode(Echo_Pin, INPUT);
  digitalWrite(SWITCH_PIN, LOW);   /* Turn on PCB power */
  delay(1000);



  /* timer started */
  startSend = millis();

  /* LMIC init */
  os_init();

  /* reset the MAC state */
  /* session and pending data transfers will be discarded */
  LMIC_reset();

  /* let LMIC compensate for +/- 1% clock error */
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
  LMIC_selectSubBand(1);

  // Set static session parameters. Instead of dynamically establishing a session
  // by joining the network, precomputed session parameters are be provided.
#ifdef PROGMEM
  // On AVR, these values are stored in flash and only copied to RAM
  // once. Copy them to a temporary buffer here, LMIC_setSession will
  // copy them into a buffer of its own again.
  uint8_t appskey[sizeof(APPSKEY)];
  uint8_t nwkskey[sizeof(NWKSKEY)];
  memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
  memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
  LMIC_setSession (0x13, DEVADDR, nwkskey, appskey);
#else
  // If not running an AVR with PROGMEM, just use the arrays directly
  LMIC_setSession (0x13, DEVADDR, NWKSKEY, APPSKEY);
#endif

  // Disable link check validation
  LMIC_setLinkCheckMode(0);


  // Start job
  do_send(&sendjob);
}

void loop() {

  os_runloop_once();

}

Moderator reformatted: How to do it yourself

1 Like

Do you mean the Frames up on the device console page?

Yep, exactly, here’s a screenshot. Sorry I should have added it in the original post…
image

Are you using confirmed uploads? Maybe the confirmation is not received by the node.

If that’s the case, I assume there would be a line in the code that I could be directed to to modify?
I’m not particularly good at the code, tend to plagiarise existing code to get things working.

Your node is going to sleep likely in a way that (because it is an ESP chip) results in loosing all program state. LoRaWAN nodes absolutely must retain local state between transmissions.

Doing a low power node on an ESP will be quite tricky; you’ll need to spend a very very large amount of time reading through all of the details in the several existing threads on this.

There really isn’t any option but to either wade through that, or switch to a more traditional MCU which ordinary state-retaining sleep modes.