Dragino LoRa shield with LMIC and 1-Wire sensor problem

Hi everyone :hugs:

It feels like I’ve read every post in this forum about ABP and still I cannot find the answer of my problem. The code is attached below, don’t worry because of some german comments in it.

My problem

I’m transmitting the temperature value and part of the address (for identification in backend) of six DS18B20 sensors. My payload isn’t optimized and a bit too large, according to the TTN console 49 bytes. With spreading factor 7 and a interval of 12 minutes I should be inside fair use policy.
Everything works fine for 1 to 2 hours (not always the same) and then it slows down to a 70min interval. After weeks of usage it even slows down to a 3 or 4 hours interval.

Stuff I’m using

My question

I have some guesses where my slow down comes from, but I’m far from shure where my problem comes from. Is it a…

  • duty cycle limitation? But increasing Interval didn’t change anything and airtime calculator looks fine to me (even thought payload size could be optimized).
  • memory leakage? It’s my first contact with C, I’m a Javascript coder :innocent:
  • millis() overflow problem? So any idea how to solve?

If I reset the node everything starts working again for two hours… :man_shrugging:t2:

Background

  • I tried to overwrite with X the privacy related stuff, I hope I didn’t remove values you wanted to see. :shushing_face:
  • The sensors get used in our farm to monitor the cherry trees. So we can try to protect them from frost in spring (yes, I’m a bit stressed :see_no_evil::wink:).

The code

Arduino node code
/*******************************************************************************
   Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
   Copyright (c) 2018 Terry Moore, MCCI

   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.

   This example sends a valid LoRaWAN packet with payload "Hello,
   world!", using frequency and encryption settings matching those of
   the The Things Network.

   This uses ABP (Activation-by-personalisation), where a DevAddr and
   Session keys are preconfigured (unlike OTAA, where a DevEUI and
   application key is configured, while the DevAddr and session keys are
   assigned/generated in the over-the-air-activation procedure).

   Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
   g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
   violated by this sketch when left running for longer)!

   To use this sketch, first register your application and device with
   the things network, to set or generate a DevAddr, NwkSKey and
   AppSKey. Each device should have their own unique values for these
   fields.

   Do not forget to define the radio type correctly in
   arduino-lmic/project_config/lmic_project_config.h or from your BOARDS.txt.

 *******************************************************************************/

// References:
// [feather] adafruit-feather-m0-radio-with-lora-module.pdf

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// OneWire-Instanz anlegen
OneWire oneWire(24);// Die Sensoren werden mit PIN 24 verbunden

// DS18B20-Instanz anlegen
DallasTemperature ds18b20(&oneWire);
int deviceCount;

int redLED = 28;

// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed.
static const u4_t DEVADDR = 0xXXXXXXXX ; // <-- 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) { }

uint8_t mydata[] = "xyz500xyz500xyz500xyz500xyz500xyz500";
static osjob_t sendjob;

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

// Pin mapping
// Adapted for Feather M0 per p.10 of [feather]
const lmic_pinmap lmic_pins = {
  .nss = 10,                       // chip select on feather (rf95module) CS
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 9,                       // reset pin
  .dio = {2, 6, 7}, // assumes external jumpers [feather_lora_jumper]
  // DIO1 is on JP1-1: is io1 - we connect to GPO6
  // DIO1 is on JP5-3: is D2 - we connect to GPO5
};



double temp[6]; // 6 Temperaturfühler
char temp_buffer[6][6];
void writeTempToTempBuffer() {
  // Lese von allen Temp-Sensoren und befülle das Char-Array
  ds18b20.requestTemperatures();
  Serial.println("Temperaturwerte: ");
  // Gebe Zeit für die Messung!
  delay(1000);

  for (int i = 0; i < 6; i++) {
    String tempString;
    char tempChar[3];
    String deviceString;
    DeviceAddress  deviceAddr;

    temp[i] = -50; // Standardwert setzen
    temp[i] = ds18b20.getTempCByIndex(i);
    if (temp[i] == 85.0) { // Fehler beim Lesen des Sensors, erneuter Versuch
      Serial.print("Lesefehler bei Sensor "); Serial.print(i); Serial.println(" . Versuche es erneut.");
      temp[i] = ds18b20.getTempCByIndex(i);
    }
    if (temp[i] < -49 || temp[i] > 49) { // ungültige Werte
      temp[i] = -50; // Standardwert setzen
    }

    // Standardwert setzen
    if (i < deviceCount) {
      ds18b20.getAddress(deviceAddr, i);
      for (uint8_t ij = 0; ij < 8; ij++)
      {
        deviceString += String(deviceAddr[ij], HEX);
      }
      deviceString = deviceString.substring(4, 7);
    } else {
      deviceString = "yyy";
    }
    Serial.print("Sensor "); Serial.print(deviceString); Serial.print("(#"); Serial.print(i); Serial.print("): ");
    Serial.print(temp[i]); Serial.print("°C ("); Serial.print(ds18b20.getTempCByIndex(i)); Serial.println("), ");

    temp[i] = temp[i] + 50; // 50 dazurechnen, um immer positive Werte zu haben
    temp[i] = temp[i] * 10; // *10, um Dezimalwert wegzumachen
    // dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER);
    dtostrf (temp[i], 3, 0, tempChar);
    // Alles ins Char-Array schreiben
    (deviceString + String(tempChar)).toCharArray(temp_buffer[i], 7);
  }
}

void prepareData() {
  writeTempToTempBuffer();

  // Das cheiben Zeugs mit dem char-Array...
  int q = 0;
  for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 6; j++) {
      mydata[q] = temp_buffer[i][j];
      q++;
    }
  }

}

void blinkRedLED (int count) {
  for (int i = 0; i < count; i++) {
    digitalWrite(redLED, LOW);
    delay(500);
    digitalWrite(redLED, HIGH);
    delay(500);
  }
}



void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.print("|");
  Serial.print((unsigned long)(os_getTime() / OSTICKS_PER_SEC));
  Serial.print("s: ");
  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)"));

      // LED blinken lassen bei Übermittlung => HIGH == aus (minusgeschaltet)
      blinkRedLED(deviceCount);

      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
      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;
    /*
      || 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;
    case EV_SCAN_FOUND:
      Serial.println(F("EV_SCAN_FOUND"));
      break;
    case EV_TXCANCELED:
      Serial.println(F("EV_TXCANCELED"));
      break;
    case EV_RXSTART:
      Serial.println(F("EV_RXSTART"));
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println(F("EV_JOIN_TXCOMPLETE"));
      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(F("OP_TXRXPEND, not sending"));
  } else {

   // Präpariere Daten für das senden
    prepareData();
    delay(500);

    // Prepare upstream data transmission at the next possible time.
    LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
    Serial.println(F("Packet queued"));

    // Show TX channel (channel numbers are local to LMIC)
    Serial.print("Send, txCnhl: ");
    Serial.println(LMIC.txChnl);

    // Zeige länge und Daten
    Serial.print("Length: ");
    Serial.print(sizeof(mydata));
    Serial.print("; Data: '");
    for (int q = 0; q < sizeof(mydata); q++)  {
      Serial.print(char(mydata[q]));
    }
    Serial.print("'");
    Serial.println();
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
  //    pinMode(13, OUTPUT);
  pinMode(redLED, OUTPUT);
  digitalWrite(redLED, HIGH); // HIGH == LED ausgeschaltet

  while (!Serial); // wait for Serial to be initialized
  Serial.begin(115200);
  delay(100);     // per sample code on RF_95 test
  Serial.println(F("Starting"));

  // DS18B20-Instanz starten
  ds18b20.begin();

  // Genauigkeit festlegen
  //    Mode  Resol     Reading time
  //    9     0.5°C     93.75 ms
  //    10    0.25°C    187.5 ms
  //    11    0.125°C   375 ms
  //    12    0.0625°C  750 ms

  // Bleibt im EEPROM gespeichert, muss deshalb
  // nur bei neuem Sensor ausgeführt werden
  //ds18b20.setResolution(11); //TODO: remove

  // Lese von allen Temp-Sensoren und befülle das Char-Array
  ds18b20.requestTemperatures();
  // Gebe Zeit für die Messung!
  delay(1000);
  // Zähle die Geräte auf dem Bus
  deviceCount = ds18b20.getDS18Count();
  Serial.print(deviceCount); Serial.println(" Sensor(en) gefunden.");



#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);  //Relax RX timing window


  // Disable link check validation
  LMIC_setLinkCheckMode(0);


  // 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

#if defined(CFG_eu868)
  // Set up the channels used by the Things Network, which corresponds
  // to the defaults of most gateways. Without this, only three base
  // channels from the LoRaWAN specification are used, which certainly
  // works, so it is good for debugging, but can overload those
  // frequencies, so be sure to configure the full frequency range of
  // your network here (unless your network autoconfigures them).
  // Setting up channels should happen after LMIC_setSession, as that
  // configures the minimal channel set.
  LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
  LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
  // TTN defines an additional channel at 869.525Mhz using SF9 for class B
  // devices' ping slots. LMIC does not have an easy way to define set this
  // frequency and support for class B is spotty and untested, so this
  // frequency is not configured here.
#elif defined(CFG_us915)
  // NA-US channels 0-71 are configured automatically
  // but only one group of 8 should (a subband) should be active
  // TTN recommends the second sub band, 1 in a zero based count.
  // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
  LMIC_selectSubBand(1);
#endif

  // disable all channels except 0, because I'm using a single channel gateway
  for (int channel = 1; channel < 9; ++channel) {
    LMIC_disableChannel(channel);
  }

  // TTN uses SF9 for its RX2 window.
  LMIC.dn2Dr = DR_SF9;

  // Set data rate and transmit power for uplink
  LMIC_setDrTxpow(DR_SF7, 14);

  // Start job
  do_send(&sendjob);
}

void loop() {
  unsigned long now;
  now = millis();
  if ((now & 512) != 0) {
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(13, LOW);
  }

  os_runloop_once();

}
lmic_project_config.h file
// project-specific definitions
#define CFG_eu868 1
//#define CFG_us915 1
//#define CFG_au921 1
//#define CFG_as923 1
// #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP	/* for as923-JP */
//#define CFG_in866 1
#define CFG_sx1276_radio 1
//#define LMIC_USE_INTERRUPTS

#define DISABLE_JOIN
#define DISABLE_PING
#define DISABLE_BEACONS
Output of the TTN console
{
  "gw_id": "eui-XXXXXXXXXXXXXXXX",
  "payload": "QNwRASaAAAABX1LSvPH1P2O+1PT9IZgaB2Hy/68aBo05c9EbeDf412mUUgbEHnj7gQ==",
  "lora": {
    "spreading_factor": 7,
    "bandwidth": 125,
    "air_time": 97536000
  },
  "coding_rate": "4/5",
  "timestamp": "2019-03-27T16:51:29.043Z",
  "rssi": -67,
  "snr": 9,
  "dev_addr": "XXXXXXXX",
  "frequency": 868100000
}
1 Like

my first guess… it’s a one wire / spi timing conflict
change temp sensor for an I2C one and remove one wire lib

a temp sensor node with an arduino MEGA + HAT… really ? battery powered too ?

1 Like

Or remove the sensor code altogether and repeat the experiment with hardcoded values? (The default uint8_t mydata[] = "xyz500xyz500xyz500xyz500xyz500xyz500"; might be good enough for that.)

Also: do you see gaps (missing values) in the uplink counter values? Can you tell from some serial logging if the device is trying to send at the expected times?

that’s probably faster

my first guess … it’s a one wire / spi timing conflict
change temp sensor for an I2C one and remove one wire lib

Ok, never thought about this one, thank you! I would be happy if I don’t have to change sensors, it was quite a work to find a waterproof, interchangeable solution for outdoor use. :see_no_evil: But shure, if that’s the problem it has to be done.
Do you have a link at hand that tells me more about that kind of problems?

a temp sensor node with an arduino MEGA + HAT… really ? battery powered too ?

Well, we have 230V Power in the orchard :man_shrugging:t2::wink:. So I was totaly lazy in terms of power consumption. The mega is primary because of my bad skills, with the uno and the used libraries I didn’t have enough RAM. I know, shame on me… :see_no_evil:

Or remove the sensor code altogether and repeat the experiment with hardcoded values?

Sounds so obvious to debug this way, but I completly forgot that! I will try that this night and tell you the results. I was completly focused on duty cycle problems…

Also: do you see gaps (missing values) in the uplink counter values? Can you tell from some serial logging if the device is trying to send at the expected times?

No, there are no gaps, it’s not even trying to send. I had it on Serial console for quite a time now (example attached).

Example serial console output
18:28:12.511 -> Temperaturwerte: 
18:28:13.561 -> Sensor 10f(#0): 21.37°C (21.37), 
18:28:13.636 -> Sensor 5ce(#1): 20.87°C (20.87), 
18:28:13.779 -> Sensor 368(#2): 21.25°C (21.25), 
18:28:13.957 -> Sensor b17(#3): 21.12°C (21.12), 
18:28:14.201 -> Sensor fd5(#4): 21.25°C (21.25), 
18:28:14.461 -> Sensor 87b(#5): 21.25°C (21.25), 
18:28:15.062 -> 138117584|2209s: EV_TXSTART
18:28:15.098 -> Packet queued
18:28:15.098 -> Send, txCnhl: 0
18:28:15.098 -> Length: 37; Data: '10f7145ce709368713b17711fd571387b713'
18:28:16.179 -> 138185710|2210s: EV_RXSTART
18:28:17.147 -> 138247954|2211s: EV_RXSTART
18:28:20.850 -> 138478381|2215s: EV_TXCOMPLETE (includes waiting for RX windows)
18:40:29.234 -> Temperaturwerte: 
18:40:29.234 -> Sensor 10f(#0): 20.62°C (20.62), 
18:40:29.234 -> Sensor 5ce(#1): 20.37°C (20.37), 
18:40:29.234 -> Sensor 368(#2): 20.75°C (20.75), 
18:40:29.234 -> Sensor b17(#3): 20.37°C (20.37), 
18:40:29.876 -> Sensor fd5(#4): 20.50°C (20.50), 
18:40:29.876 -> Sensor 87b(#5): 20.50°C (20.50), 
18:40:44.345 -> 184036356|2944s: EV_TXSTART
18:40:44.345 -> Packet queued
18:40:44.345 -> Send, txCnhl: 0
18:40:44.345 -> Length: 37; Data: '10f7065ce704368708b17704fd570587b705'
18:40:44.345 -> 184104418|2945s: EV_RXSTART
18:40:44.345 -> 184166661|2946s: EV_RXSTART
18:40:44.345 -> 184452848|2951s: EV_TXCOMPLETE (includes waiting for RX windows)
18:52:48.986 -> Temperaturwerte: 
18:52:48.986 -> Sensor 10f(#0): 20.12°C (20.12), 
18:52:48.986 -> Sensor 5ce(#1): 19.87°C (19.87), 
18:52:48.986 -> Sensor 368(#2): 20.37°C (20.37), 
18:52:48.986 -> Sensor b17(#3): 19.87°C (19.87), 
18:52:48.986 -> Sensor fd5(#4): 20.00°C (20.00), 
18:52:48.986 -> Sensor 87b(#5): 20.00°C (20.00), 
18:52:48.986 -> 230010823|3680s: EV_TXSTART
18:52:48.986 -> Packet queued
18:52:48.986 -> Send, txCnhl: 0
18:52:48.986 -> Length: 37; Data: '10f7015ce699368704b17699fd570087b700'
18:52:48.986 -> 230078885|3681s: EV_RXSTART
18:52:48.986 -> 230141130|3682s: EV_RXSTART
18:53:07.497 -> 230335090|3685s: EV_TXCOMPLETE (includes waiting for RX windows)
19:05:03.489 -> Temperaturwerte: 
19:05:03.489 -> Sensor 10f(#0): 20.37°C (20.37), 
19:05:03.489 -> Sensor 5ce(#1): 20.00°C (20.00), 
19:05:03.489 -> Sensor 368(#2): 20.50°C (20.50), 
19:05:03.489 -> Sensor b17(#3): 20.12°C (20.12), 
19:05:03.489 -> Sensor fd5(#4): 20.25°C (20.25), 
19:05:03.489 -> Sensor 87b(#5): 20.25°C (20.25), 
19:05:03.489 -> Packet queued
19:05:03.489 -> Send, txCnhl: 0
20:04:33.070 -> Length: 37; Data: '10f7045ce700368705b17701fd570387b703'
20:04:33.070 -> 230620280|3689s: EV_TXSTART
20:04:33.531 -> 230688340|3691s: EV_RXSTART
20:04:38.481 -> 230750586|3692s: EV_RXSTART
20:04:39.661 -> 231058600|3696s: EV_TXCOMPLETE (includes waiting for RX windows)
20:16:46.119 -> Temperaturwerte: 
20:16:47.122 -> Sensor 10f(#0): 20.87°C (20.87), 
20:16:47.229 -> Sensor 5ce(#1): 20.37°C (20.37), 
20:16:47.379 -> Sensor 368(#2): 20.75°C (20.75), 
20:16:47.557 -> Sensor b17(#3): 20.62°C (20.62), 
20:16:47.809 -> Sensor fd5(#4): 20.75°C (20.75), 
20:16:48.056 -> Sensor 87b(#5): 20.75°C (20.75), 
20:16:48.665 -> Packet queued
20:16:48.665 -> Send, txCnhl: 0
20:16:48.665 -> Length: 37; Data: '10f7095ce704368708b17706fd570887b708'

For tests with the sensors, I’d also add a debug statement before starting the measurements. Like the additional first line and some Serial.flush() in:

  Serial.println("Requesting measurements");
  Serial.flush();
  ds18b20.requestTemperatures();
  Serial.println("Temperaturwerte: ");
  Serial.flush();

The serial log shows a long time between 19:05 and 20:04, but then it’s okay again for 20:16? And are the subsequent 4 lines (which are not shown) also in the 20:16 range? Or is the end of the log the point where things take a long time (again)?

Looking at the serial output, I’d run the original code with some more logging tonight, rather than the test without the sensor code…

So, last night I removed the sonsor code and with hardcoded values it worked without any problems, so I can say TTN and LoRa aren’t the problem. Must be something with reading temperatures and sending them. Do you have any recommandation where I can start learning about these kind of problems? Probably you have a good link at hand. :blush:

Throught today I changed the code like @arjanvanb suggested. It also stopped working after about one hour. Do you see something special in the console output? For me it looks like before… :man_shrugging:t2:

console output with sensors attached, with Serial.flush() in it
06:21:55.044 -> Starting
06:21:56.688 -> 6 Sensor(en) gefunden.
06:21:56.724 -> Requesting measurements
06:21:57.045 -> Temperaturwerte: 
06:21:58.106 -> Sensor 10f(#0): 19.00°C (19.00), 
06:21:58.211 -> Sensor 5ce(#1): 18.50°C (18.50), 
06:21:58.359 -> Sensor 368(#2): 19.00°C (19.00), 
06:21:58.542 -> Sensor b17(#3): 18.75°C (18.75), 
06:21:58.758 -> Sensor fd5(#4): 18.87°C (18.87), 
06:21:59.048 -> Sensor 87b(#5): 18.87°C (18.87), 
06:21:59.631 -> 291183|4s: EV_TXSTART
06:21:59.631 -> Packet queued
06:21:59.631 -> Send, txCnhl: 0
06:21:59.631 -> Length: 37; Data: '10f6905ce685368690b17688fd568987b689'
06:22:00.725 -> 359292|5s: EV_RXSTART
06:22:01.742 -> 421536|6s: EV_RXSTART
06:22:06.665 -> 731041|11s: EV_TXCOMPLETE (includes waiting for RX windows)
06:34:12.959 -> Requesting measurements
06:34:13.329 -> Temperaturwerte: 
06:34:14.372 -> Sensor 10f(#0): 19.00°C (19.00), 
06:34:14.445 -> Sensor 5ce(#1): 18.50°C (18.50), 
06:34:14.597 -> Sensor 368(#2): 19.00°C (19.00), 
06:34:14.785 -> Sensor b17(#3): 18.75°C (18.75), 
06:34:15.010 -> Sensor fd5(#4): 18.87°C (18.87), 
06:34:15.278 -> Sensor 87b(#5): 18.87°C (18.87), 
06:34:15.880 -> 46289232|740s: EV_TXSTART
06:34:15.918 -> Packet queued
06:34:15.918 -> Send, txCnhl: 0
06:34:15.918 -> Length: 37; Data: '10f6905ce685368690b17688fd568987b689'
06:34:17.000 -> 46357287|741s: EV_RXSTART
06:34:17.985 -> 46419533|742s: EV_RXSTART
06:34:21.057 -> 46611129|745s: EV_TXCOMPLETE (includes waiting for RX windows)
06:46:27.333 -> Requesting measurements
06:46:27.695 -> Temperaturwerte: 
06:46:28.717 -> Sensor 10f(#0): 19.12°C (19.12), 
06:46:28.836 -> Sensor 5ce(#1): 18.62°C (18.62), 
06:46:28.952 -> Sensor 368(#2): 19.00°C (19.00), 
06:46:29.150 -> Sensor b17(#3): 18.87°C (18.87), 
06:46:29.392 -> Sensor fd5(#4): 19.00°C (19.00), 
06:46:29.666 -> Sensor 87b(#5): 19.00°C (19.00), 
06:46:30.272 -> 92169327|1474s: EV_TXSTART
06:46:30.272 -> Packet queued
06:46:30.272 -> Send, txCnhl: 0
06:46:30.272 -> Length: 37; Data: '10f6915ce686368690b17689fd569087b690'
06:46:31.376 -> 92237386|1475s: EV_RXSTART
06:46:32.359 -> 92299631|1476s: EV_RXSTART
06:46:36.548 -> 92562587|1481s: EV_TXCOMPLETE (includes waiting for RX windows)
06:58:42.866 -> Requesting measurements
06:58:43.190 -> Temperaturwerte: 
06:58:44.259 -> Sensor 10f(#0): 19.25°C (19.25), 
06:58:44.340 -> Sensor 5ce(#1): 18.62°C (18.62), 
06:58:44.497 -> Sensor 368(#2): 19.12°C (19.12), 
06:58:44.690 -> Sensor b17(#3): 18.87°C (18.87), 
06:58:44.887 -> Sensor fd5(#4): 19.12°C (19.12), 
06:58:45.154 -> Sensor 87b(#5): 19.00°C (19.00), 
06:58:45.806 -> 138120792|2209s: EV_TXSTART
06:58:45.806 -> Packet queued
06:58:45.806 -> Send, txCnhl: 0
06:58:45.806 -> Length: 37; Data: '10f6935ce686368691b17689fd569187b690'
06:58:46.894 -> 138188916|2211s: EV_RXSTART
06:58:47.865 -> 138251160|2212s: EV_RXSTART
06:58:51.625 -> 138485355|2215s: EV_TXCOMPLETE (includes waiting for RX windows)
07:10:57.919 -> Requesting measurements
07:10:58.277 -> Temperaturwerte: 
07:10:59.296 -> Sensor 10f(#0): 19.25°C (19.25), 
07:10:59.409 -> Sensor 5ce(#1): 18.75°C (18.75), 
07:10:59.529 -> Sensor 368(#2): 19.25°C (19.25), 
07:10:59.727 -> Sensor b17(#3): 19.00°C (19.00), 
07:10:59.957 -> Sensor fd5(#4): 19.12°C (19.12), 
07:11:00.226 -> Sensor 87b(#5): 19.12°C (19.12), 
07:11:00.841 -> 184043563|2944s: EV_TXSTART
07:11:00.841 -> Packet queued
07:11:00.841 -> Send, txCnhl: 0
07:11:00.841 -> Length: 37; Data: '10f6935ce688368693b17690fd569187b691'
07:11:01.933 -> 184111623|2945s: EV_RXSTART
07:11:02.909 -> 184173868|2946s: EV_RXSTART
07:11:06.000 -> 184367042|2949s: EV_TXCOMPLETE (includes waiting for RX windows)
07:23:12.295 -> Requesting measurements
07:23:12.652 -> Temperaturwerte: 
07:23:13.707 -> Sensor 10f(#0): 19.50°C (19.50), 
07:23:13.790 -> Sensor 5ce(#1): 18.87°C (18.87), 
07:23:13.947 -> Sensor 368(#2): 19.25°C (19.25), 
07:23:14.107 -> Sensor b17(#3): 19.25°C (19.25), 
07:23:14.350 -> Sensor fd5(#4): 19.37°C (19.37), 
07:23:14.629 -> Sensor 87b(#5): 19.25°C (19.25), 
07:23:15.221 -> 229925252|3678s: EV_TXSTART
07:23:15.259 -> Packet queued
07:23:15.259 -> Send, txCnhl: 0
07:23:15.259 -> Length: 37; Data: '10f6955ce689368693b17693fd569487b693'
07:23:16.332 -> 229993317|3679s: EV_RXSTART
07:23:17.344 -> 230055560|3680s: EV_RXSTART
07:23:20.475 -> 230251874|3684s: EV_TXCOMPLETE (includes waiting for RX windows)
07:35:26.770 -> Requesting measurements
07:35:27.092 -> Temperaturwerte: 
07:35:28.150 -> Sensor 10f(#0): 19.62°C (19.62), 
07:35:28.229 -> Sensor 5ce(#1): 19.00°C (19.00), 
07:35:28.378 -> Sensor 368(#2): 19.50°C (19.50), 
07:35:28.553 -> Sensor b17(#3): 19.37°C (19.37), 
07:35:28.796 -> Sensor fd5(#4): 19.62°C (19.62), 
07:35:29.090 -> Sensor 87b(#5): 19.50°C (19.50), 
07:35:29.678 -> Packet queued
07:35:29.678 -> Send, txCnhl: 0
07:35:29.678 -> Length: 37; Data: '10f6965ce690368695b17694fd569687b695'
08:35:01.677 -> 230534710|3688s: EV_TXSTART
08:35:02.775 -> 230602771|3689s: EV_RXSTART
08:35:03.769 -> 230665017|3690s: EV_RXSTART
08:35:08.442 -> 230957761|3695s: EV_TXCOMPLETE (includes waiting for RX windows)
08:47:14.757 -> Requesting measurements
08:47:15.088 -> Temperaturwerte: 
08:47:16.158 -> Sensor 10f(#0): 21.62°C (21.62), 
08:47:16.239 -> Sensor 5ce(#1): 20.62°C (20.62), 
08:47:16.381 -> Sensor 368(#2): 21.25°C (21.25), 
08:47:16.568 -> Sensor b17(#3): 21.37°C (21.37), 
08:47:16.794 -> Sensor fd5(#4): 21.50°C (21.50), 
08:47:17.063 -> Sensor 87b(#5): 21.37°C (21.37), 
08:47:17.689 -> Packet queued
08:47:17.689 -> Send, txCnhl: 0
08:47:17.689 -> Length: 37; Data: '10f7165ce706368713b17714fd571587b714'
09:46:48.300 -> 231144190|3698s: EV_TXSTART
09:46:49.418 -> 231212254|3699s: EV_RXSTART
09:46:50.405 -> 231274498|3700s: EV_RXSTART
09:46:54.896 -> 231556198|3704s: EV_TXCOMPLETE (includes waiting for RX windows)
09:59:01.246 -> Requesting measurements
09:59:01.590 -> Temperaturwerte: 
09:59:02.642 -> Sensor 10f(#0): 27.62°C (27.62), 
09:59:02.757 -> Sensor 5ce(#1): 26.12°C (26.12), 
09:59:02.877 -> Sensor 368(#2): 27.25°C (27.25), 
09:59:03.063 -> Sensor b17(#3): 27.75°C (27.75), 
09:59:03.311 -> Sensor fd5(#4): 27.25°C (27.25), 
09:59:03.583 -> Sensor 87b(#5): 27.12°C (27.12), 
09:59:04.186 -> Packet queued
09:59:04.186 -> Send, txCnhl: 0
09:59:04.186 -> Length: 37; Data: '10f7765ce761368773b17778fd577387b771'
10:58:35.187 -> 231753669|3708s: EV_TXSTART
10:58:36.281 -> 231821732|3709s: EV_RXSTART
10:58:37.280 -> 231883976|3710s: EV_RXSTART
10:58:40.569 -> 232089993|3713s: EV_TXCOMPLETE (includes waiting for RX windows)
11:10:46.932 -> Requesting measurements
11:10:47.258 -> Temperaturwerte: 
11:10:48.322 -> Sensor 10f(#0): 32.13°C (32.13), 
11:10:48.402 -> Sensor 5ce(#1): 31.25°C (31.25), 
11:10:48.557 -> Sensor 368(#2): 27.37°C (27.37), 
11:10:48.716 -> Sensor b17(#3): 32.75°C (32.75), 
11:10:48.951 -> Sensor fd5(#4): 32.25°C (32.25), 
11:10:49.256 -> Sensor 87b(#5): 32.50°C (32.50), 
11:10:49.856 -> Packet queued
11:10:49.856 -> Send, txCnhl: 0
11:10:49.856 -> Length: 37; Data: '10f8215ce813368774b17828fd582387b825'
12:10:21.923 -> 232363146|3717s: EV_TXSTART
12:10:23.010 -> 232431207|3718s: EV_RXSTART
12:10:24.016 -> 232493452|3719s: EV_RXSTART
12:10:28.048 -> 232747941|3723s: EV_TXCOMPLETE (includes waiting for RX windows)
12:22:34.375 -> Requesting measurements
12:22:34.727 -> Temperaturwerte: 
12:22:35.792 -> Sensor 10f(#0): 25.25°C (25.25), 
12:22:35.870 -> Sensor 5ce(#1): 25.37°C (25.37), 
12:22:36.032 -> Sensor 368(#2): 24.00°C (24.00), 
12:22:36.225 -> Sensor b17(#3): 25.50°C (25.50), 
12:22:36.464 -> Sensor fd5(#4): 25.37°C (25.37), 
12:22:36.739 -> Sensor 87b(#5): 25.50°C (25.50), 
12:22:37.310 -> Packet queued
12:22:37.310 -> Send, txCnhl: 0
12:22:37.310 -> Length: 37; Data: '10f7535ce754368740b17755fd575487b755'
13:22:08.536 -> 232972624|3727s: EV_TXSTART
13:22:09.628 -> 233040752|3728s: EV_RXSTART
13:22:10.652 -> 233102996|3729s: EV_RXSTART
13:22:13.733 -> 233296560|3732s: EV_TXCOMPLETE (includes waiting for RX windows)
13:34:20.046 -> Requesting measurements
13:34:20.386 -> Temperaturwerte: 
13:34:21.426 -> Sensor 10f(#0): 24.25°C (24.25), 
13:34:21.540 -> Sensor 5ce(#1): 24.00°C (24.00), 
13:34:21.692 -> Sensor 368(#2): 23.37°C (23.37), 
13:34:21.876 -> Sensor b17(#3): 24.25°C (24.25), 
13:34:22.113 -> Sensor fd5(#4): 24.25°C (24.25), 
13:34:22.383 -> Sensor 87b(#5): 24.25°C (24.25), 
13:34:22.972 -> Packet queued
13:34:22.972 -> Send, txCnhl: 0
13:34:22.972 -> Length: 37; Data: '10f7435ce740368734b17743fd574387b743'
14:33:55.133 -> 233582102|3737s: EV_TXSTART
14:33:56.227 -> 233650230|3738s: EV_RXSTART
14:33:57.237 -> 233712474|3739s: EV_RXSTART
14:34:01.981 -> 234009959|3744s: EV_TXCOMPLETE (includes waiting for RX windows)
14:46:08.308 -> Requesting measurements
14:46:08.663 -> Temperaturwerte: 
14:46:09.712 -> Sensor 10f(#0): 23.25°C (23.25), 
14:46:09.793 -> Sensor 5ce(#1): 22.87°C (22.87), 
14:46:09.950 -> Sensor 368(#2): 22.75°C (22.75), 
14:46:10.142 -> Sensor b17(#3): 23.12°C (23.12), 
14:46:10.344 -> Sensor fd5(#4): 23.25°C (23.25), 
14:46:10.620 -> Sensor 87b(#5): 23.25°C (23.25), 
14:46:11.239 -> Packet queued
14:46:11.239 -> Send, txCnhl: 0
14:46:11.239 -> Length: 37; Data: '10f7335ce729368728b17731fd573387b733'
15:45:41.704 -> 234191579|3747s: EV_TXSTART
15:45:42.789 -> 234259707|3748s: EV_RXSTART
15:45:43.803 -> 234321951|3749s: EV_RXSTART
15:45:47.820 -> 234573269|3753s: EV_TXCOMPLETE (includes waiting for RX windows)
15:57:54.130 -> Requesting measurements
15:57:54.477 -> Temperaturwerte: 
15:57:55.535 -> Sensor 10f(#0): 22.50°C (22.50), 
15:57:55.610 -> Sensor 5ce(#1): 22.12°C (22.12), 
15:57:55.771 -> Sensor 368(#2): 22.12°C (22.12), 
15:57:55.965 -> Sensor b17(#3): 22.25°C (22.25), 
15:57:56.194 -> Sensor fd5(#4): 22.37°C (22.37), 
15:57:56.447 -> Sensor 87b(#5): 22.37°C (22.37), 
15:57:57.061 -> Packet queued
15:57:57.061 -> Send, txCnhl: 0
15:57:57.061 -> Length: 37; Data: '10f7255ce721368721b17723fd572487b724'

I’m really impressed of your fast and good help, thank you very much!

No, there wasn’t any additional output, this was end of log. That’s the point where waiting starts (probably you can see it better in the console output above).

Ah, I missed that the long time between 19:05 and 20:04 clearly started after taking the measurements, and after calling LMIC_setTxData2 and some more logging:

// Präpariere Daten für das senden
prepareData();
delay(500);

// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
Serial.println(F("Packet queued"));

// Show TX channel (channel numbers are local to LMIC)
Serial.print("Send, txCnhl: ");
Serial.println(LMIC.txChnl);

// Zeige länge und Daten
Serial.print("Length: ");
Serial.print(sizeof(mydata));
Serial.print("; Data: '");
for (int q = 0; q < sizeof(mydata); q++)  {
  Serial.print(char(mydata[q]));
}
Serial.print("'");
Serial.println();

Like, from the new logs with the blank line added by me:

07:35:29.090 -> Sensor 87b(#5): 19.50°C (19.50), 
07:35:29.678 -> Packet queued
07:35:29.678 -> Send, txCnhl: 0
07:35:29.678 -> Length: 37; Data: '10f6965ce690368695b17694fd569687b695'

08:35:01.677 -> 230534710|3688s: EV_TXSTART
08:35:02.775 -> 230602771|3689s: EV_RXSTART
08:35:03.769 -> 230665017|3690s: EV_RXSTART
08:35:08.442 -> 230957761|3695s: EV_TXCOMPLETE (includes waiting for RX windows)

(Beware: in your earlier log, the “Length: 37” line was printed or captured an hour late too, at 20:04:33.070, while the “Send” line was then captured at 19:05:03.489. Adding flush() ensures that the log is always printed right away.)

As things are fine without the sensor code, I’d assume it’s not the single-channel setup that is to blame. Enabling LMIC debugging might still be useful, of course.

While reading the sensors LMIC cannot do any of its housekeeping for almost 3 seconds:

07:35:26.770 -> Requesting measurements
07:35:27.092 -> Temperaturwerte: 
07:35:28.150 -> Sensor 10f(#0): 19.62°C (19.62), 
07:35:28.229 -> Sensor 5ce(#1): 19.00°C (19.00), 
07:35:28.378 -> Sensor 368(#2): 19.50°C (19.50), 
07:35:28.553 -> Sensor b17(#3): 19.37°C (19.37), 
07:35:28.796 -> Sensor fd5(#4): 19.62°C (19.62), 
07:35:29.090 -> Sensor 87b(#5): 19.50°C (19.50), 
07:35:29.678 -> Packet queued

I wonder if those 3 seconds make it fail to detect some overflow, but it seems its overflow detection is much more resilient than that, and only needs to be triggered once every 30 minutes or so:

Still then, if you really don’t have any other ideas, then maybe adding a few calls to os_runloop_once(); in the measurement code might help. (But I’d focus on the possible 1-Wire/SPI issues.)

But all above does not address the following:

Not my cup of tea, but more wild ideas:

  • Maybe using the recommended OneWire 2 helps?

    One Wire Library

    OneWire 2 - I recommend you use OneWire 2, a spiritual successor to the original OneWire library. PJRC has developed this library to fix many of the original bugs found in OneWire. If you find OneWire to be unreliable I would highly recommend this drop-in replacement.

  • Maybe one can explicitly pause/disable 1-Wire after taking the measurements?

By the way, what is port 13 used for?

if ((now & 512) != 0) {
  digitalWrite(13, HIGH);
}
else {
  digitalWrite(13, LOW);
}

Hmmm, the os_getTime() timestamps that onEvent prints are weird.

For the first hour, time increases just fine (about 734 seconds difference between two transmissions), and EV_TXSTART is logged right after LMIC_setTxData2 is invoked, before the next log lines. But then after an hour (the "millis overflow, which happens after approx 71 minutes" as mentioned above?) the printed timestamps increase with much smaller steps of about 10 seconds, and LMIC_setTxData2 is just queueing the transmission.

06:34:15.278 -> Sensor 87b(#5): 18.87°C (18.87), 
06:34:15.880 -> 46289232|740s: EV_TXSTART
06:34:15.918 -> Packet queued
...
06:46:29.666 -> Sensor 87b(#5): 19.00°C (19.00), 
06:46:30.272 -> 92169327|1474s: EV_TXSTART
06:46:30.272 -> Packet queued
...
06:58:45.154 -> Sensor 87b(#5): 19.00°C (19.00), 
06:58:45.806 -> 138120792|2209s: EV_TXSTART
06:58:45.806 -> Packet queued
...
07:11:00.226 -> Sensor 87b(#5): 19.12°C (19.12), 
07:11:00.841 -> 184043563|2944s: EV_TXSTART
07:11:00.841 -> Packet queued
...
07:23:14.629 -> Sensor 87b(#5): 19.25°C (19.25), 
07:23:15.221 -> 229925252|3678s: EV_TXSTART
07:23:15.259 -> Packet queued
...
07:35:29.090 -> Sensor 87b(#5): 19.50°C (19.50), 
07:35:29.678 -> Packet queued
07:35:29.678 -> Send, txCnhl: 0
07:35:29.678 -> Length: 37; Data: '10f6965ce690368695b17694fd569687b695'
08:35:01.677 -> 230534710|3688s: EV_TXSTART
...
08:47:17.063 -> Sensor 87b(#5): 21.37°C (21.37), 
08:47:17.689 -> Packet queued
08:47:17.689 -> Send, txCnhl: 0
08:47:17.689 -> Length: 37; Data: '10f7165ce706368713b17714fd571587b714'
09:46:48.300 -> 231144190|3698s: EV_TXSTART
...
09:59:03.583 -> Sensor 87b(#5): 27.12°C (27.12), 
09:59:04.186 -> Packet queued
09:59:04.186 -> Send, txCnhl: 0
09:59:04.186 -> Length: 37; Data: '10f7765ce761368773b17778fd577387b771'
10:58:35.187 -> 231753669|3708s: EV_TXSTART
...
11:10:49.256 -> Sensor 87b(#5): 32.50°C (32.50), 
11:10:49.856 -> Packet queued
11:10:49.856 -> Send, txCnhl: 0
11:10:49.856 -> Length: 37; Data: '10f8215ce813368774b17828fd582387b825'
12:10:21.923 -> 232363146|3717s: EV_TXSTART

That makes me wonder how that could be caused by 1-Wire/SPI. Or if the single-channel setup or some other LMIC error is to blame after all, for which the sensor-less code should have shown the same problem, which it did not.

You might add trying another LMIC library to your lists of tests. (Like the abandoned https://github.com/matthijskooijman/arduino-lmic …)

" millis overflow, which happens after approx 71 minutes"

This question is about an Arduino Mega, so millis() shouldn’t actually overflow for some 49 days.

It’s micros() which overflows in a bit over an hour. And because LMIC wants sub-millisecond timing, it likely uses that.

The situations is quite different on the ports of Arduino to some other hardware; the ESP32 port for example millis() overflows quite quickly, or at least used to (it is divided on access from a much faster counter, due to how they do coordination between the two cores)

Additionally the original question here said the time to failure was variable.


the printed timestamps increase with much smaller steps of about 10 seconds, and LMIC_setTxData2 is just queueing the transmission.

Another thing that’s really useful to do when debugging time-related issues is to run node debug logs through a serial terminal which adds its own approximate timestamps - that’s very easy to hack together with something like pyserial, for example. If there’s any concern of the embedded timestamps not incrementing monotonically you can even have the python code process those and flag discrepancies.

1 Like

@martin_schilliger, can you confirm that? In the two logs, the last good transmissions seem to be at 3680s: EV_TXSTART and 3678s: EV_TXSTART.

As an aside: I also wonder if tempChar should have length 4 rather than 3, to allow for a null-terminator. But I doubt that’s causing issues after running for some time

char tempChar[3];
dtostrf (temp[i], 3, 0, tempChar);
1 Like

Your support is great, thank you!!

Ah, that looked crazy for me too, didn’t know that this is the reason, thank you!

Could it be the delay() after it, that causes problems? I’ll try to remove it.

I’ll take a look at this :blush:

Just a red LED :wink:

That was my first try, looking throught all the different LMIC libraries I found. The problem was the same everywhere. But I didn’t try the to look into the sensors. Will do that the next days.

I thought that, but it’s not true. It’s working in the right interval for exactly 71min and then it uses a 71min interval. I just haven’t found the regularity before YOU named it.

What’s next

You gave me a bunch of ideas to try, I will do that and come back with new console logs and knowledge. Thank you for the support so far!
I think I need some time to try all of them, but now it’s too late in the evening. :sleeping:

I’ll keep this thread up to date. :hugs:

I doubt it. A total of 3 seconds doesn’t feel like a problem if timers overflow only after an hour. But if you ever run the test code without the sensors again, maybe you can add some delay to mimic that. But it’s not the first thing I’d suspect to be the culprit.

Just in case you didn’t know: loop is calling os_runloop_once() all the time, and only in very few occasions it got work to do. So, I’d assume it has plenty of time to detect any overflow…

Quickly browsing the LMIC code I also don’t see it using any SPI when not actually doing anything LoRa-related. But again: not my expertise, and as the sensor-less code works, 1-Wire/SPI surely is a suspect, even when it seems the code is failing when neither is actively used.

I’d at least try to enable debug in LMIC. And check if sending, say, every 5 minutes still breaks things after around 71 minutes? Even though the sensor-less code worked, it might also be nice to see if using all 8 channels helps; you won’t receive 7/8th of the messages, but the serial log will still show what’s going on. (The duty cycle code that determines when the next transmission is allowed, is EU868 specific.)

Why don’t you:

  • Add debug print to the functions that obtain the lmic time from the hosting platform, print both the raw platform time and the derived OS time.

  • Run the node against a serial capture program (previously mentioned pyserial idea) which does its own timestamping

FWIW, you can run LMIC with a 1ms timebase despite its compile warnings claiming that will not work; however you may need to increase the variation allowances if you do.

So, my first update

The version of DallasTemperature is v3.8.0, OneWire is on v2.3.4 => as recommended.

And you think that’s better than the timestamps of the arduino console?

Yes it does, I tried values from 0.5min to 30min, everything breaks after 71min. I also tried using all 8 channels (without receiving 7/8th of the message) – no difference.

1 Like

The problem is solved now!

Thank you very much for your support. To be honest, right now I don’t really know what solved it. I changed a few things from the code I first pasted here:

  • removed multiple delay() calls – I believe there the problem began, but I’m testing in the next hours whether re-adding them brings the problem back
  • changed char tempChar[3] to char tempChar[3 + 1] to allow for a null-terminator as @arjanvanb suggested.
  • added multiple calls to os_getTime() to force resync of the timing commands
  • added some Serial.flush() after Serial.print() commands
  • cleaned up double calls to the OneWire library that where present just for debug
  • activated #define LMIC_DEBUG_LEVEL 2, #define LMIC_PRINTF_TO Serial and #define LMIC_FAILURE_TO Serial
  • added waiting for at most 10 seconds for the serial monitor to be attached with while ((!Serial) && (millis() < 10000)) as suggested by @arjanvanb by PM
  • removed unnecessary LED commands

Right now I’m re-adding my bad behaviour to find out what made my code work. I’ll write you back if I find out. :blush:
I also will do some work to reduce payload size, but I first have to figure out how that works. :blush:

working code example
/*******************************************************************************
   Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
   Copyright (c) 2018 Terry Moore, MCCI

   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.

   This example sends a valid LoRaWAN packet with payload "Hello,
   world!", using frequency and encryption settings matching those of
   the The Things Network.

   This uses ABP (Activation-by-personalisation), where a DevAddr and
   Session keys are preconfigured (unlike OTAA, where a DevEUI and
   application key is configured, while the DevAddr and session keys are
   assigned/generated in the over-the-air-activation procedure).

   Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
   g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
   violated by this sketch when left running for longer)!

   To use this sketch, first register your application and device with
   the things network, to set or generate a DevAddr, NwkSKey and
   AppSKey. Each device should have their own unique values for these
   fields.

   Do not forget to define the radio type correctly in
   arduino-lmic/project_config/lmic_project_config.h or from your BOARDS.txt.

 *******************************************************************************/

// References:
// [feather] adafruit-feather-m0-radio-with-lora-module.pdf

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// Temp sensor data wire is plugged into pin 24 on the Arduino
#define ONE_WIRE_BUS 24

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature ds18b20(&oneWire);

int deviceCount;



int redLED = 28;

// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xFE, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed.
static const u4_t DEVADDR = 0xXXXXXXXX ; // <-- 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) { }

uint8_t mydata[] = "xyz500xyz500xyz500xyz500xyz500xyz500";
static osjob_t sendjob;

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

// Pin mapping => Found here by Andreas Spiess: https://www.youtube.com/watch?v=duwUwXt-hs8
// Adapted for Feather M0 per p.10 of [feather]
const lmic_pinmap lmic_pins = {
  .nss = 10,                       // chip select on feather (rf95module) CS
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 9,                       // reset pin
  .dio = {2, 6, 7}, // assumes external jumpers [feather_lora_jumper]
  // DIO1 is on JP1-1: is io1 - we connect to GPO6
  // DIO1 is on JP5-3: is D2 - we connect to GPO5
};



double temp[6]; // normally 6 temperature sensors
char temp_buffer[6][6];
void writeTempToTempBuffer() {
  serialPrintOsTime();
  Serial.println("Requesting measurements");
  Serial.flush();
  ds18b20.requestTemperatures();
  Serial.println("Temperaturwerte: ");
  Serial.flush();

  for (int i = 0; i < 6; i++) {
    String tempString;
    // tempChar should have length 4 rather than 3, to allow for a null-terminator
    char tempChar[3 + 1];
    String deviceString;
    DeviceAddress  deviceAddr;

    temp[i] = -50; // set default value
    temp[i] = ds18b20.getTempCByIndex(i);
    if (temp[i] == 85.0) { // Error reading sensors, try once again
      Serial.print("Reading errer at sensor "); Serial.print(i);
      Serial.println(" . Try again."); Serial.flush();
      temp[i] = ds18b20.getTempCByIndex(i);
    }
    if (temp[i] < -49 || temp[i] > 49) { // bad values, set default value again
      temp[i] = -50;
    }

    // read device address and take 3 characters of it
    if (i < deviceCount) {
      ds18b20.getAddress(deviceAddr, i);
      for (uint8_t ij = 0; ij < 8; ij++)
      {
        deviceString += String(deviceAddr[ij], HEX);
      }
      deviceString = deviceString.substring(4, 7);
    } else {
      deviceString = "yyy";
    }

    Serial.print("Sensor "); Serial.print(deviceString);
    Serial.print("(#"); Serial.print(i); Serial.print("): ");
    Serial.print(temp[i]); Serial.println("°C");
    Serial.flush();

    temp[i] = temp[i] + 50; // add 50 to always stay positive
    temp[i] = temp[i] * 10; // multiply with 10 to remove comma
    // dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER);
    dtostrf (temp[i], 3, 0, tempChar);
    // write everything to char array
    (deviceString + String(tempChar)).toCharArray(temp_buffer[i], 7);
  }
}

void prepareData() {
  writeTempToTempBuffer();

  int q = 0;
  for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 6; j++) {
      mydata[q] = temp_buffer[i][j];
      q++;
    }
  }

}

void blinkRedLED (int count) {
  for (int i = 0; i < count; i++) {
    digitalWrite(redLED, LOW);
    delay(500);
    digitalWrite(redLED, HIGH);
    delay(500);
  }
}

void serialPrintOsTime() {
  Serial.print(os_getTime());
  Serial.print("|");
  Serial.print((unsigned long)(os_getTime() / OSTICKS_PER_SEC));
  Serial.print("s: ");
  Serial.flush();
}


void onEvent (ev_t ev) {
  serialPrintOsTime();
  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)"));

      // LED blinken lassen bei Übermittlung => HIGH == aus (minusgeschaltet)
      blinkRedLED(deviceCount);

      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
      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;
    /*
      || 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;
    case EV_SCAN_FOUND:
      Serial.println(F("EV_SCAN_FOUND"));
      break;
    case EV_TXCANCELED:
      Serial.println(F("EV_TXCANCELED"));
      break;
    case EV_RXSTART:
      Serial.println(F("EV_RXSTART"));
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println(F("EV_JOIN_TXCOMPLETE"));
      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(F("OP_TXRXPEND, not sending"));
  } else {

    // prepare Data for sending
    prepareData();
    serialPrintOsTime();

    // Prepare upstream data transmission at the next possible time.
    LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
    Serial.println(F("Packet queued"));

    // Show TX channel (channel numbers are local to LMIC)
    Serial.print("Send, txCnhl: ");
    Serial.println(LMIC.txChnl);

    // Show length and data of transmission
    Serial.print("Length: ");
    Serial.print(sizeof(mydata));
    Serial.print("; Data: '");
    for (int q = 0; q < sizeof(mydata); q++)  {
      Serial.print(char(mydata[q]));
    }
    Serial.print("'");
    Serial.println();
    Serial.flush();
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
  pinMode(redLED, OUTPUT);
  digitalWrite(redLED, HIGH); // HIGH == LED off

  // Wait at most 10 seconds for the serial monitor to be attached
  while ((!Serial) && (millis() < 10000));

  Serial.begin(115200);
  delay(100);     // per sample code on RF_95 test
  Serial.println(F("Starting"));

  // ds18b20-Instanz starten
  ds18b20.begin();

  // Genauigkeit festlegen
  //    Mode  Resol     Reading time
  //    9     0.5°C     93.75 ms
  //    10    0.25°C    187.5 ms
  //    11    0.125°C   375 ms
  //    12    0.0625°C  750 ms

  // Bleibt im EEPROM gespeichert, muss deshalb
  // nur bei neuem Sensor ausgeführt werden
  //ds18b20.setResolution(11); //TODO: remove!

  // Initial reading of temperatures
  ds18b20.requestTemperatures();

  // Count temperature sensors
  deviceCount = ds18b20.getDS18Count();
  Serial.print(deviceCount); Serial.println(" Sensor(s) found.");
  serialPrintOsTime();



#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);  //Relax RX timing window


  // Disable link check validation
  LMIC_setLinkCheckMode(0);


  // 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

#if defined(CFG_eu868)
  // Set up the channels used by the Things Network, which corresponds
  // to the defaults of most gateways. Without this, only three base
  // channels from the LoRaWAN specification are used, which certainly
  // works, so it is good for debugging, but can overload those
  // frequencies, so be sure to configure the full frequency range of
  // your network here (unless your network autoconfigures them).
  // Setting up channels should happen after LMIC_setSession, as that
  // configures the minimal channel set.
  LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
  LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
  // TTN defines an additional channel at 869.525Mhz using SF9 for class B
  // devices' ping slots. LMIC does not have an easy way to define set this
  // frequency and support for class B is spotty and untested, so this
  // frequency is not configured here.
#elif defined(CFG_us915)
  // NA-US channels 0-71 are configured automatically
  // but only one group of 8 should (a subband) should be active
  // TTN recommends the second sub band, 1 in a zero based count.
  // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
  LMIC_selectSubBand(1);
#endif

  // disable all channels except 0, because I'm using a single channel gateway
  for (int channel = 1; channel < 9; ++channel) {
    LMIC_disableChannel(channel);
  }

  // TTN uses SF9 for its RX2 window.
  LMIC.dn2Dr = DR_SF9;

  // Set data rate and transmit power for uplink
  LMIC_setDrTxpow(DR_SF7, 14);

  // Start job
  do_send(&sendjob);
}

void loop() {
  os_runloop_once();
}
1 Like

I won’t call myself a LoRaWAN expert but I have been fighting the same problems you had. Although I am not using the same hardware as you, my idea was to use a Heltec ESP32 module with 1-wire sensors. I first went through the loop of getting the temperatures when it is my send window but I ran into problems of the dreaded 85C which means value is not available. In the end I went for a complete different approach using the tasks if LMIC.

What I did was to create two additional tasks within my code. First task is what drives the LoRa code, send window etc, actually the original code. I then added two more tasks:

  1. Kicks the DS18B20’s to read the temperature. Depending on the resolution, it needs up to 750ms to read the temperature.
  2. To do the actual read of the temperature from the devices. This task is trigger by task about for about 2 seconds after task 1 ends. In the end this tasks schedule the task 1 again after about 58 seconds.

So simply:

  1. The LoRa loop runs on a 5 minute loop and just sends the temperatures as it is stored in the buffer.
  2. The temperate loop runs on a 60 second loop, first the trigger read of temperatures and then reading of the sensors.

I then reduced the payload to two bytes per temperature, with the limit of +/-300C.

This code has been running on my test node for a weeks without any issue at all.

If you want to have a look at the code, I have it on github (https://github.com/joshartman/heltec-lora-32-node-abp) if you want to look at it. I know there are keys in there but it is only for testing and the application and devices will disappear soon.

Jos

1 Like

@joshartman Thanks for that, I will have a look at it.

It turns out everything is working as long as the debug mode ist set higher than 0. That bringts me to the conclusion hat calling os_getTime() more often (debug does that all the time) is the solution here. Bur for the upcoming frost season I will just leave it on and will have a look at the problem later.

Thank you for the awesome support, I will be back with my code after optimization! :blush:

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.