Seamlessly chirpstack server change for field nodes

Hello friends,

I have a need that i can’t to solve alone.

We have a Chirpstack server running in production environment and if i want i need to change the servers for any reasons, we need to reset the field nodes to make a new Join Session with new devaddress.

¿it’s there any function to reconnect to Lora and recieve a new devaddress when i change the server?
I need to solve that for failover reasons, to make my network more robust.

I’m using wisblock boxes with RAK4630 inside and using Arduino Framework with SX126x-Arduino library from Begee-Tokyo.

I tried with “lmh_join();” before to send any message but doesnt works. I too tried with “int8_t loraInitResult = initLoRaWan();” before to send all my messages but neither worked it.

When staying with OTAA as join method, I see only one solution.
Use a confirmed packet send every now and then to check whether the connection to the LNS is still working.
If there is no ACK received from the LNS for the confirmed packet, you can restart joining with lmh_join() or reset the device to perform a new join request.

If you can switch to ABP as join method, the device should be able to send to the new LNS if it is registered with the same keys there. (not tested).

Thanks for the help mr Beegee.

To add more information to any that have the same problem, i didn’t can’t to solve using just “lmh_join()” function but using all the “block of code” that make the connection for the first time, it’s worked flawlessly

This its the code that you need to run if you need to register your device in a new server without push the reset button:

// Initialize LoRaWan and start join request
  int8_t loraInitResult = initLoRaWan();

  #ifndef MAX_SAVE
  if (loraInitResult != 0) {
    switch (loraInitResult) {
      case -1:
        Serial.println("SX126x init failed");
        break;
      case -2:
        Serial.println("LoRaWan init failed");
        break;
      case -3:
        Serial.println("Subband init error");
        break;
      case -4:
        Serial.println("LoRa Task init error");
        break;
      default:
        Serial.println("LoRa init unknown error");
        break;
    }

    // Without working LoRa we just stop here
    while (1) {
      Serial.println("LoRA doesnt works, freezing.");
      delay(5000);
    }
  }
  Serial.println("LoRaWan init success");
  #endif

lmh_join() should work. The code is assuming you are not connected and starts a new Join Request.

What do you see on the LoRaWAN server when you call lmh_join()?

If i use lmh_join() instead the block of code that i posted 2 days ago, i receive the following logs in chirpstack (all deveui was change by XXXX):

gateway region_id="au915_1" topic="au915_1/gateway/XXXXXXXXXXXX/event/up" qos=0 json=false
2024-01-31T13:17:54.689599Z  INFO up{deduplication_id=722720a7-fbcc-4efc-8637-XXXXXXXX}: chirpstack::uplink: Uplink received m_type=ConfirmedDataUp
2024-01-31T13:17:54.690220Z  INFO up{deduplication_id=b81e1d67-6679-4980-a0bc-XXXXXXXX}: chirpstack::uplink: Uplink received m_type=ConfirmedDataUp
2024-01-31T13:17:54.694327Z  INFO up{deduplication_id=b81e1d67-6679-4980-a0bc-XXXXXXXXX}:data_up: chirpstack::uplink::data: No device-session exists for dev_addr dev_addr=01e4dbff
2024-01-31T13:17:54.695075Z  INFO up{deduplication_id=722720a7-fbcc-4efc-8637-XXXXXXXXX}:data_up: chirpstack::uplink::data: No device-session exists for dev_addr dev_addr=01e4dbff
2024-01-31T13:17:55.279596Z  INFO chirpstack::gateway::backend::mqtt: Message received from gateway region_id="au915_1" topic="au915_1/gateway/XXXXXX/event/up" qos=0 json=false
2024-01-31T13:17:55.280957Z  INFO chirpstack::gateway::backend::mqtt: Message received from gateway region_id="au915_1" topic="au915_1/gateway/XXXXXXX/event/up" qos=0 json=false
2024-01-31T13:17:55.482692Z  INFO up{deduplication_id=efce245d-2641-494c-be00-XXXXXXX}: chirpstack::uplink: Uplink received m_type=ConfirmedDataUp
2024-01-31T13:17:55.487849Z  INFO up{deduplication_id=efce245d-2641-494c-be00-XXXXXXX}:data_up: chirpstack::storage::device_session: Device-session saved dev_eui=XXXXXXXX dev_addr=01c27e99

The devaddress “01e4dbff” it’s from the old chirpstack server, the server that im simulating a “crash” so i need to create a new server that will recieve the data from field nodes. The logs from the new server says that “No device-session exists for dev_addr dev_addr=01e4dbff”

This it’s the block of code that send a confirmed message and make a lmh_join if recieves error -1

/**
   @brief Enviamos un keep alive por LoRAWAN. Si no se recibe respuesta del server, hacemos un Join

   @return result of send request
*/
bool sendLoraKeepAlive(uint8_t dataFlags, uint8_t batteryLevel) {


  m_lora_app_data.port = LORAWAN_APP_PORT;


  unsigned long age;


  //Prueba Gabriel
  int32_t ilat = 0;
  int32_t ilon = 0;
  memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
  // m_lora_app_data.port = gAppPort;
  m_lora_app_data.buffer[0] = 0x09;
  //lat data
  m_lora_app_data.buffer[1] = (ilat & 0xFF000000) >> 24;
  m_lora_app_data.buffer[2] = (ilat & 0x00FF0000) >> 16;
  m_lora_app_data.buffer[3] = (ilat & 0x0000FF00) >> 8;
  m_lora_app_data.buffer[4] = ilat & 0x000000FF;

  m_lora_app_data.buffer[6] = (ilon & 0xFF000000) >> 24;
  m_lora_app_data.buffer[7] = (ilon & 0x00FF0000) >> 16;
  m_lora_app_data.buffer[8] = (ilon & 0x0000FF00) >> 8;
  m_lora_app_data.buffer[9] = ilon & 0x000000FF;


  m_lora_app_data.buffer[10] = dataFlags;
  m_lora_app_data.buffer[11] = batteryLevel;
  // m_lora_app_data.buffer[12] = (val_y & 0x0000FF00) >> 8;
  // m_lora_app_data.buffer[13] = val_y & 0xFF;
  // m_lora_app_data.buffer[14] = (val_z & 0x0000FF00) >> 8;
  // m_lora_app_data.buffer[15] = val_z & 0xFF;
  m_lora_app_data.buffsize = 16;


  //Intentamos reconexión antes de mandar el paquete (por si cambió la ip o el servidor)
    // Initialize LoRaWan and start join request
  // lmh_join();

  //Era lmh_send pero a veces se perdía el paquete de las ventanas RX porque se duerme el uC
  // lmh_error_status error = lmh_send(&m_lora_app_data, LMH_UNCONFIRMED_MSG);  //Era unconfirmed, pero lo cambiamos por esto https://github.com/beegee-tokyo/SX126x-Arduino/issues/42#issuecomment-862039568
  lmh_error_status error = lmh_send_blocking(&m_lora_app_data, LMH_CONFIRMED_MSG, 20000);

  
  if (error == -1) {



    //VAMOS A PROBAR LA CONFIG DE BEEGEE TOKYO
  //   #ifndef MAX_SAVE
  //   Serial.println("lmh error = Error -1, reintentamos conexión con LNS");
  //   #endif

  // // Initialize LoRaWan and start join request
  // int8_t loraInitResult = initLoRaWan();

  // #ifndef MAX_SAVE
  // if (loraInitResult != 0) {
  //   switch (loraInitResult) {
  //     case -1:
  //       Serial.println("SX126x init failed");
  //       break;
  //     case -2:
  //       Serial.println("LoRaWan init failed");
  //       break;
  //     case -3:
  //       Serial.println("Subband init error");
  //       break;
  //     case -4:
  //       Serial.println("LoRa Task init error");
  //       break;
  //     default:
  //       Serial.println("LoRa init unknown error");
  //       break;
  //   }

  //   // Without working LoRa we just stop here
  //   while (1) {
  //     Serial.println("Reiniciamos Microcontrolador");
  //     delay(100);
  //     NVIC_SystemReset(); //Comando para reiniciar RAK4630
  //   }
  // }
  // Serial.println("LoRaWan init success");
  // #endif

  // #ifndef MAX_SAVE
  //     Serial.println("ya terminamos la inicialización lorawan, intentamos reenviar mensaje");
  // #endif


    //Intentamos reconexión antes de mandar el paquete (por si cambió la ip o el servidor)
    // Initialize LoRaWan and start join request
    lmh_join();



  
    lmh_error_status error = lmh_send_blocking(&m_lora_app_data, LMH_CONFIRMED_MSG, 20000);

    #ifndef MAX_SAVE
    if (error == -1) Serial.println("lmh error = Error -1 2da vez");
    if (error == 0) Serial.println("lmh error = envío exitoso 2da vez");
    if (error == 1) Serial.println("lmh error = Error 1 (busy) 2da vez");
    #endif
  }

  #ifndef MAX_SAVE
  if (error == 0) Serial.println("lmh error = envío exitoso");
  if (error == 1) Serial.println("lmh error = Error 1 (busy)");
  #endif

  return (error == 0);
}

If you have some doubt, please feel free to ask