Device address change on my Beehive project

Hi everybody,

I’m comming to you because I have an issue on my project:
https://www.thethingsnetwork.org/forum/t/connected-hive/33430

I’m using a Dragino Hat v1.0 on my raspberry pi, configured as a single channel “gateway”, and a PCB I made with an ESP32 and RFM95 lora module on it. Since 4 months I put it in test to check if all is working fine, For maybe a month the data I receive has not been arriving every time. I use my ESP in Deep sleep mode every 2 hours. By looking more closely and by changing my deep sleep to 1 min I saw in the traffic gateway that my device address change many time. The good address is normaly 26 01 10 A9
Capture

I don’t undersant what is going one…

My code may be help:

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "HX711.h"
#include "soc/rtc.h"
//#include <LowPower.h>

//Deep sleep
#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
//#define TIME_TO_SLEEP 7200      /* Time ESP32 will go to sleep (in seconds) */
#define TIME_TO_SLEEP 60      /* Time ESP32 will go to sleep (in seconds) */
RTC_DATA_ATTR int bootCount = 0;

//BME sensor
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

// supply control
const int transistorPin = 16;

//capteur de poids
#define DOUT  25 //pour ESP32 wemos
#define CLK  26
float weight = 0;
float weightcorrection = 3.390;
float calibration_factor = 21650;  //You must change this factor depends on your scale,sensors and etc.

// Vbat is connected to GPIO 32 
const int batPin = 32;

// variable for storing the Vbat value
int batValue = 0;
float volt=0.00;
float vbat=0.00;


// For normal use, we require that you edit the sketch to replace FILLMEIN
// with values assigned by the TTN console. However, for regression tests,
// we want to be able to compile these scripts. The regression tests define
// COMPILE_REGRESSION_TEST, and in that case we define FILLMEIN to a non-
// working but innocuous value.

#ifdef COMPILE_REGRESSION_TEST
# define FILLMEIN 0
#else
# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"
# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)
#endif


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

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

// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed.
#ifndef COMPILE_REGRESSION_TEST
static const u4_t DEVADDR = 0x260110A9;
#else
static const u4_t DEVADDR = 0;
#endif

// 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) { }

// payload to send to TTN gateway
static uint8_t payload[9];
static osjob_t sendjob;

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

// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
  .nss = 5,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 13,
           // LBT cal for the Adafruit Feather M0 LoRa, in dB
 //  .dio = {12, 14, 17}
     .dio = {27, 14, 17}
};


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.println(F("Received "));
              Serial.println(LMIC.dataLen);
              Serial.println(F(" bytes of payload"));
            }
            // Schedule next transmission
             delay(2000);
             digitalWrite (transistorPin, LOW);
             Deep_Sleep_Now();
           // 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;
        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 {
       
        // read the temperature from the BME280
        float temp = bme.readTemperature();
        Serial.print("Temperature: "); Serial.print(temp);
        Serial.println(" *C");
        float humidity = bme.readHumidity();
        Serial.print("humidité: ");Serial.print(humidity);
        Serial.println("% ");

        // read weight from the HX711
        HX711 scale(DOUT, CLK);
        scale.set_scale(calibration_factor); //Adjust to this calibration factor
        Serial.print("Reading: ");
        weight = scale.get_units();
        weight = weight + weightcorrection;
        Serial.print(weight, 2);
        Serial.println(" kg"); // You can change this to other type of weighing value and re-adjust the calibration factor.
        Serial.print(" calibration_factor: ");
        Serial.println(calibration_factor);

        Serial.println("Boot number: " + String(bootCount));

         // Reading potentiometer value
         batValue = analogRead(batPin);
         volt = batValue;
         vbat=volt/732;
         Serial.print("Voltage = ");  
         Serial.println(vbat);

       
int16_t celciusInt = temp * 100; // convert to signed 16 bits integer: 0x0929
int16_t humidityInt = humidity * 100;
int16_t weightInt = weight * 100;
//int16_t bootCountInt = bootCount * 100;
int16_t bootCountInt = bootCount;
int16_t vbatInt = vbat * 100;

uint8_t buffer[10]; // reserve 2 bytes in memory

// Handle high byte (MSB) first; 0x09 for 23.45
// 0x0929 >> 8 shifts the 0x29 out of memory, leaving 0x0009
// 0x0009 does not fit in a single byte, so only 0x09 is stored in buffer[0]:
buffer[0] = celciusInt >> 8;
buffer[1] = celciusInt;
buffer[2] = humidityInt >> 8;
buffer[3] = humidityInt;
buffer[4] = weightInt >> 8;
buffer[5] = weightInt;
buffer[6] = bootCountInt >> 8;
buffer[7] = bootCountInt;
buffer[8] = vbatInt >> 8;
buffer[9] = vbatInt;


// Send on port 1, without asking for confirmation:
LMIC_setTxData2(1, buffer, sizeof(buffer), 0); // 0x0929 for 23.45
        Serial.println(F("Packet queued"));
    }
  
    // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
    delay(4000);
    while (!Serial);
    Serial.begin(115200);
    pinMode (transistorPin, OUTPUT);
    digitalWrite (transistorPin, HIGH);
    delay(1000);
    Serial.println(F("Starting"));
    bme.begin(0x76);  
    ++bootCount;
       rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();

    // Set static session parameters. Instead of dynamically establishing a session
    // by joining the network, precomputed session parameters are be provided.
    // 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);
    
   #if defined(CFG_eu868) // EU channel setup
  int channel = 0;
   int dr = DR_SF7;
   for(int i=0; i<9; i++) { 
     if(i != channel) {
       LMIC_disableChannel(i);
     }
   }
   // Set data rate (SF) and transmit power for uplink
   LMIC_setDrTxpow(dr, 14);    // g-band
#elif defined(CFG_us915) // US channel setup
  // Instead of using selectSubBand, which will cycle through a sub-band of 8
  // channels. We'll configure the device to only use one frequency.
  // First disable all sub-bands
  for (int b = 0; b < 8; ++b) {
    LMIC_disableSubBand(b);
  }
  // Then enable the channel(s) you want to use
  //LMIC_enableChannel(8); // 903.9 MHz
  LMIC_enableChannel(17);
#endif
    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // 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();  
}

void Deep_Sleep_Now() // New function - moded code out of void loop so that the sleep function can be called if we fail to connect to Wi-Fi or Blynk
{
  esp_sleep_enable_timer_wakeup((uint64_t)(TIME_TO_SLEEP) * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");
  Serial.println("Going to sleep now");
  Serial.flush(); 
   esp_deep_sleep_start();
  
  delay(2000);
} 

Many thanks in adance for your help

christophe

Get yourself a LoRaWAN compliant GW :slight_smile:

Single channel packet forwarders such as yours are not LoRaWAN compliant, and given you see traffic from other nodes (the ones starting 00 or 01 are designated as ‘experimental’ nodes and likely being used by people running tests/trials though likely under ABP vs OTAA, and the one starting 10 will be from another network), likely you will be disrupting the device behaviour of other network users.

If your node is LoRaWAN compliant thne likely it will/should be using any one of 8 (randomly chosen) channels for any given transmission - your GW lookes fixed on 868.1MHz, potentially clogging that channel if you focus your devices efforts on that channel only if running single frequency, potentially only picking up 1 in 8 packets over time if running multi freq.

Search the Forum for single channel packet forwarders or singe channel GW’s and you will see these are deprecated on TTN and not supported, plus lots of comments and background as to why…

Finally it looks like your dev addr isnt changing but is correctly set and received as 26 xx xx xx (as set in you code - note I havent read/reviewed the code just noticed this point -
static const u4_t DEVADDR = 0x260110A9; ) - but I note the 2 samples in the log post show cnt = 0. Has device been reset recently or had power outage and restart? If so if you are using cnt check on back end the system wont pass data until cnt is > last seen highest number… experiment with turning off count check on device/application console and better yet use OTAA for device join (note then Dev addr WILL change after each new join!) as that takes care of cnt reset each time :slight_smile:

Many Thanks Jeff-UK for your answer.
My device Reset every awakening period, so it’s normal to have every time the cnt=0 .
In fact all the messages that are received, come from my device. As soon I remove the battery not more message are coming.

No, that may be expected behavior for that device but for LoRaWAN devices it is not normal behavior. TTN allows a way to work around this by providing options to reset the counter and to ignore it, but that is not LoRaWAN compliant and should only be used while developing new code.

Thanks Kersing for your answer :).
I know that my device is not LoRaWAN complaint but I did not find any solution on my code to fixe it. But regarding the decive address my gateway received? It was working fine before :). Do you think that there is any link with cnt? sorry but my knowledge is not high :). I try to learn every day :slight_smile:

They are somebody else’s devices that your gateway is receiving.

No, there no more devices around my gateway. As soon I supply my device I receive different device address so it’s comming from my device…

How can you be sure?

Somehow your device creates some device addresses with some count values?

I guess this is possible with some serious memory corruption in the LMIC library - dev 010010A9 appears to have sent twice, with a count of 11937 & then 52129 and the last two bytes of 10A9 looks similar to your dev address of 260110A9.

Do you have the original code before you made changes?

Which version of the LMIC library are you using?

Can you get a proper 8 channel gateway?

1 Like

+1 on that suggestion, try it on a proper Gateway.

I’m sure because as soon I supply my device I receive message on TTN traffic as it’s show on my screen shot.
the LMIC version I used is the 1.6.6. The code is used is the same from begining and it was working fine…
And no I don’t have a proper 8 channel gateway, I need to buy one :).

Which is it? You said you put a check in and now it’s not working properly.

On power up you get a good message. Then some garbage. Either the gateway is on the fritz or the device is borked. Maybe you need to reprogram them both.

It was an issue of my gateway :). Know it’s working better with an other one. I will invest on a 8 channels gateway like raspberry + RAK831 :slight_smile:
Many thanks for your support :slight_smile:

This has the latest Semtech chipset on it, available on promotion:

Many thanks :slight_smile:

Hi Cristophe, have you solved this? I would be glad to hear about your progress.

My view on the code:

1., I do not believe your DEVEUI changes over time. Your gateway may receive messages from other devices from your neighborhood. It does not matter if you have 1 or 8 channels. Those messages are coming from other devices. The less number of channels could cause more message conflicts (and loss), but not DEVEUI change.

2., I see you

  • modified your onEvent() processing loop,
  • commented out os_setTimedCallback() and
  • inserted the deep sleep call.

IMHO the problem is that by removing os_setTimedCallback() you do not define the scheduled do_send() callback therefore no message will go out after the first message successfully sent. The code you used as a template is a generic deep sleep example, hence does not care about the lora state machine.

Putting an ESP running lmic library into deep sleep is tricky (and I haven’t solved it yet TBH), because lmic has its own, scheduled state machine (onEvent()) so you must be very careful these timed functions are called regularly.

My 2 cents.

Hi Zoltansz,

Yes I solved my problem, since I bought a professionnal gateway all is working perfectly ;).

Christophe

So we don’t get any forum searches yielding interesting results:

A devices DevEUI will never change unless you change it.

It matters a lot - anything less than an 8 channel LoRaWAN gateway is not a gateway and should not be connected to TTN.

You do not have to use the timed call backs in LMIC. You can call do_send() or build it’s equivalent as you require. You do have to run os_runloop_once(); in the main loop - you can sleep for a reasonable period of time or go & perform a blocking call on something, but you must call the runloop at some point and once you put a send on the os request list, it won’t be processed until the runloop is called, which can have some blocking aspects to it.

I believe this is the big unsolved technical puzzle of LMIC & ESP32. I gather it’s about storing the join keys so that they can be restore when the ESP32 wakes as deep sleep mode doesn’t keep main RAM working.

One of the other issues with ESP32 is that if you invoke the FreeRTOS voodoo, you end up with LMIC running it’s own little task scheduler inside the FreeRTOS scheduler. Mostly it works OK but FreeRTOS doesn’t know not to interrupt LMIC when it’s on a mission - mostly the reasonably precise timing of the Rx1 & Rx2 windows. So if you have an intensive other task running you can upset the whole shebang.

Hi, thanks for your feedback.

It matters a lot - anything less than an 8 channel LoRaWAN gateway is not a gateway and should not be connected to TTN.

Absolutely agree, but, as I said, I think the problem is not the number of channels being used. I am aware a microcontroller could change its own DEVEUI, but this code definitely does not do such thing.

I gather it’s about storing the join keys so that they can be restore when the ESP32 wakes as deep sleep mode doesn’t keep main RAM working.

You’re right, the device gets a complete reset so the keys need to be restored too and it has to rejoin the network.

Off: Now I see the advantages of an RN2483 breakout board with its own microcontroller that runs LoRa stack so deep sleep, and everything else, on the ESP would be much simpler.

The changing “device addresses” in the log bear substantial resemblance to the actual device address offset by a byte and/or corrupted (since they appeared or disappeared with node power, they’re probably not from something else).

This makes it most likely that the issue is a processor - radio SPI communication bug in the design of the illicit fake gateway, or possibly in the design of the node. Byte misalignment would also explain why the frame count of the messages with wrong device addresses is also jumping all over the place.

Or possibly the node is too close to the gateway and overloading the receiver.

At any rate, as the issue was unique to a prohibited fake gateway that is not allowed to be connected to TTN, the topic should probably be closed.

What is general is that a LoRaWan device must not reset its frame counter, but rather continue it ever forward.