Radiolib Chirpstack V4 DevNonce problem

Is anybody using Radiolib library with Chirpstack V4. I can’t connect my node Heltec wireless stick lite V3 to CS V4. Node works just fine with CS V3 but not on V4. I see join request in LoraWAN frames and error log DevNonce has already been used in events.

In Application > Devices, you can try to Flush the OTAA Device Nonce.

Just curios What IDE did you use?

I’m new and learning, but I have Heltec Wireless Stick V3s and I’ve been using the Heltec ESP_32 library and the Heltec Dev Board in the Arduino IDE. I’ve been SOOO confused but I finally discovered at 2am last night that it’s Arduino IDE. After flashing new changes it was always a huge hassle trying to get them to connect to the gateway.

Last night I noticed weird inaccuracies with Arduino. Uninstalled everything, did a full wipe (temp files/logs/registry/…) Clean install and flashed the Node, came up instantly. Made 1 edit to test and it was just to Serial.print Rx/tx stats. Tried flashing it, wouldn’t conned to the gateway. Just to test; twice more I Uninstalled & wiped everything … Same results . So I’m trying to figure out PlatformIO at the moment

I didn’t see anything in the Docs other than a bugfix v4.4

  • Fix OTAA join-request MIC check and DevNonce validation order.

Thanks. i did flush device nonce. More then once. But that didn’t fix the issue.

I’m using latest Arduino IDE on Linux. I also use WSLV3 and I’ve been told that radiolib is better option for lorawan. And it works on CS3. Only need to figure how to make it work on CS4.

Thx!! I’ll try that out while until I learn PlatformIO.

Did you update your MQTT prior to your upgrade? I saw a specific not about that.

Gateway to ChirpStack MQTT

The ChirpStack Gateway Bridge v3.14.0+ version is compatible with both ChirpStack v3 and ChirpStack v4, as long as the protobuf marshaler is configured (default value). This to eases the migration, as the published MQTT data can be consumed by both ChirpStack v3 and ChirpStack v4.

I did fresh docker install of CS4. So mqtt should be good.

My problem is probably GW. I’m using old Heltec HT-M01 GW connected with usb to windows machine. Picogw_ui from semtech is packet forwarder. It is old GW with old software. Probably that is why it works with CS3 and not with CS4.

Double check your device profile is setup the same way in the gateway? Specifically the MAC version?

Have you tried to Disable Frame counters to check?

Hm, if I disable frame counter it works.

I checked again my node code it seams that I disabled counter code. I re added that code part and enabled frame counter again. Now it works even with frame counter. Yeeeee


If it’s not to much to ask, would you mind sharing your Wireless Stick config? I’ve been hitting so many road blocks getting my Sticks running properly

Sure. This is from radiolib end device lorawan example. I added deep sleep code at the end. Also there is comment out fixed DR if you need that.

  RadioLib LoRaWAN End Device Persistent Example

  This example assumes you have tried one of the OTAA or ABP
  examples and are familiar with the required keys and procedures.
  This example restores and saves a session such that you can use
  deepsleep or survive power cycles. Before you start, you will 
  have to register your device at
  and join the network using either OTAA or ABP.
  Please refer to one of the other LoRaWAN examples for more
  information regarding joining a network.

  NOTE: LoRaWAN requires storing some parameters persistently!
        RadioLib does this by using EEPROM, by default
        starting at address 0 and using 448 bytes.
        If you already use EEPROM in your application,
        you will have to either avoid this range, or change it
        by setting a different start address by changing the value of
        during build or in src/BuildOpt.h.

  For default module settings, see the wiki page

  For full API reference, see the GitHub Pages

// include the library
#include <RadioLib.h>
#include <SPI.h>
SPIClass spi(SPI);
SPISettings spiSettings(2000000, MSBFIRST, SPI_MODE0);
// SX1262 has the following pin order:
// Module(NSS/CS, DIO1, RESET, BUSY)
SX1262 radio = new Module(8, 14, 12, 13, spi, spiSettings);

#define SECONDS_TO_SLEEP 600
#define uS_TO_S_FACTOR 1000000

// SX1278 has the following pin order:
// Module(NSS/CS, DIO0, RESET, DIO1)
//SX1278 radio = new Module(10, 2, 9, 3);

// create the node instance on the EU-868 band
// using the radio module and the encryption key
// make sure you are using the correct band
// based on your geographical location!
LoRaWANNode node(&radio, &EU868);

// for fixed bands with subband selection
// such as US915 and AU915, you must specify
// the subband that matches the Frequency Plan
// that you selected on your LoRaWAN console
  LoRaWANNode node(&radio, &US915, 2);

void gotoSleep() {

  //log_d("Going to sleep");
  // Allow wake up if Button Switch is pressed
  //esp_sleep_enable_ext0_wakeup((gpio_num_t)BTN_PIN, LOW);  // could use: GPIO_NUM_26

  // Allow RTC to wake up this device after X seconds
  esp_sleep_enable_timer_wakeup(SECONDS_TO_SLEEP * uS_TO_S_FACTOR);

  // Sleep starts

void setup() {
	spi.begin(9, 11, 10, 8);
  // initialize SX1278 with default settings
  Serial.print(F("[SX1262] Initializing ... "));
  int state = radio.begin();
  if(state == RADIOLIB_ERR_NONE) {
  } else {
    Serial.print(F("failed, code "));

  // start the activation
  Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... "));
  uint64_t joinEUI = 0x0000000000000000;
  uint64_t devEUI  = 0xd--CHANGE-THIS--9b0;
  uint8_t nwkKey[] = { 0x5A, CHANGE, THIS, 0x65 };
  uint8_t appKey[] = { 0x61, CHANGE, THIS, 0x37 };
  state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
  // ADR False and set DR to 9
  //state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, 3);
  // disable the ADR algorithm
  // set a fixed datarate

// on EEPROM-enabled boards, after the device has been activated,
  // the session can be restored without rejoining after device power cycle
  // by calling the same `beginOTAA()` or `beginABP()` function with the same keys
  // or call `restore()` where it will restore any existing session
  // `restore()` returns the active mode if it succeeded (OTAA or ABP)
  Serial.print(F("[LoRaWAN] Resuming previous session ... "));
  //state = node.restore();
  if(state >= RADIOLIB_ERR_NONE) {
    Serial.print(F("Restored an "));
      Serial.println(F("OTAA session."));
    else {
      Serial.println(F("ABP session."));
  } else {
    Serial.print(F("failed, code "));


// counter to keep track of transmitted packets
int count = 0;

void loop() {
  // send uplink to port 10
  Serial.print(F("[LoRaWAN] Sending uplink packet ... "));
  String strUp = "111111" + String(count++);
  String strDown;
  int state = node.sendReceive(strUp, 10, strDown);
  if(state == RADIOLIB_ERR_NONE) {
    Serial.println(F("received a downlink!"));

    // print data of the packet (if there are any)
    Serial.print(F("[LoRaWAN] Data:\t\t"));
    if(strDown.length() > 0) {
    } else {
      Serial.println(F("<MAC commands only>"));

    // print RSSI (Received Signal Strength Indicator)
    Serial.print(F("[LoRaWAN] RSSI:\t\t"));
    Serial.println(F(" dBm"));

    // print SNR (Signal-to-Noise Ratio)
    Serial.print(F("[LoRaWAN] SNR:\t\t"));
    Serial.println(F(" dB"));

    // print frequency error
    Serial.print(F("[LoRaWAN] Frequency error:\t"));
    Serial.println(F(" Hz"));
  } else if(state == RADIOLIB_ERR_RX_TIMEOUT) {
    Serial.println(F("no downlink!"));
  } else {
    Serial.print(F("failed, code "));

  // on EEPROM enabled boards, you can save the current session
  // by calling "saveSession" which allows retrieving the session after reboot or deepsleep

  // wait before sending another packet
  // alternatively, call a deepsleep function here
  // make sure to send the radio to sleep as well using radio.sleep()
//  uint32_t minimumDelay = 900000;                  // try to send once every minute
//  uint32_t interval = node.timeUntilUplink();     // calculate minimum duty cycle delay (per law!)
//  uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows

//  delay(delayMs);
  Serial.println(F("Radio sleep!!!"));
  delay (1000);
  Serial.println(F("ESP Sleep!!!"));
  //go to sleep

1 Like

You need to install GitHub - espressif/arduino-esp32: Arduino core for the ESP32 into board manager and use esp32s3 as board and not Heltec wireless stick lite v3 board.

@vladosam , I owe you such a big thank you and probably a good bottle of American Whiskey!
After messing around with RadioLib for a few hours, I have a great starting template to work off of… Well at least I think I do, we’ll see :rofl:

Now on to learn the next step…

But you point me into right direction with disabling frame counter. So I own you a bottle of serbian plum brandy :smiley: . We can call it even. :smiley:


I have no idea why disabling Counter check is related to DevOnce.

Could any one please explain the relation for me?
Thanks millions.

What I’m thinking is:

Since Frame Counters /Nonce can only be used once and is stored Persistently on the Node. Disabling the validation on the Gateway allows the Gateway to sync back up with the Node’s Frame Counter. Then when you re-enable Frame-Counter Validation everyone is happy happy happy.

1 Like