jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.55k stars 387 forks source link

RFM95 / Chirpstack no join acks #1288

Closed tebrown closed 2 days ago

tebrown commented 2 days ago

End user devices cannot join network with sample code. I tried two different gateways: ChirpStack and RAK7268V2 connecting to TTN. I see the join acks coming back from the gateway, and it should be transmitting. The devices are about 1m apart.

Chirpstack Logs:

Thu Oct 24 17:23:55 2024 user.info chirpstack-concentratord-sx1302[5175]: Frame received, uplink_id: 951884156, count_us: 1665329509, freq: 903900000, bw: 125000, mod: LoRa, dr: SF10, ftime_received: false, ftime_ns: 0
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Received uplink frame, uplink_id: 951884156
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Sending uplink event, uplink_id: 951884156, topic: us915_1/gateway/0016c001f160f3c5/event/up
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Received message, topic: us915_1/gateway/0016c001f160f3c5/command/down, qos: AtMostOnce
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Received downlink command, downlink_id: 212132108, topic: us915_1/gateway/0016c001f160f3c5/command/down
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Sending downlink frame, downlink_id: 212132108
Thu Oct 24 17:23:55 2024 user.info chirpstack-concentratord-sx1302[5175]: Enqueueing timestamped packet, downlink_id: 212132108, counter_us: 1670329509, current_counter_us: 1665572177
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Received ack, items: ["OK", "IGNORED"], downlink_id: 212132108
Thu Oct 24 17:23:55 2024 user.info chirpstack-mqtt-forwarder[6613]: Sending ack event, downlink_id: 212132108, topic: us915_1/gateway/0016c001f160f3c5/event/ack
Thu Oct 24 17:24:00 2024 user.info chirpstack-concentratord-sx1302[5175]: Scheduled packet for TX, downlink_id: 212132108, count_us: 1670329509, freq: 923300000, bw: 500000, mod: LoRa, dr: SF10
Thu Oct 24 17:24:10 2024 user.info chirpstack-concentratord-sx1302[5175]: Publishing stats event, rx_received: 1, rx_received_ok: 1, tx_received: 1, tx_emitted: 2

Device Logs:

17:23:54.649 > 
17:23:54.649 > Setup
17:23:54.649 > Wake not caused by deep sleep: 0
17:23:54.649 > Boot count: 1
17:23:54.649 > Initalise the radio
17:23:54.650 > RLB_DBG: 
17:23:54.650 > RadioLib Info
17:23:54.650 > Version:  "7.0.2.0"
17:23:54.650 > Platform: "ESP32"
17:23:54.650 > Compiled: "Oct 24 2024" "09:35:29"
17:23:54.656 > RLB_DBG: M       SX127x
17:23:54.662 > Recalling LoRaWAN nonces & session
17:23:54.664 > RLB_DBG: -1101 at .pio/libdeps/adafruit_feather_esp32s3_reversetft/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp:473
17:23:54.664 > Join ('login') to the LoRaWAN Network
17:23:54.665 > RLB_PRO: Setting up fixed channels (subband 2)
17:23:54.665 > RLB_PRO: UL:   8 1 903.900 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.665 > RLB_PRO: UL:   9 1 904.100 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.665 > RLB_PRO: UL:  10 1 904.300 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.665 > RLB_PRO: UL:  11 1 904.500 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.666 > RLB_PRO: UL:  12 1 904.700 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  13 1 904.900 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  14 1 905.100 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  15 1 905.300 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:   8 1 903.900 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:   9 1 904.100 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  10 1 904.300 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  11 1 904.500 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  12 1 904.700 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  13 1 904.900 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  14 1 905.100 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.668 > RLB_PRO: UL:  15 1 905.300 (0 - 3) | DL:   0 0   0.000 (0 - 0)
17:23:54.711 > RLB_PRO: [MAC] 0x03
17:23:54.711 > RLB_PRO: 00000000: 00                                               .                 
17:23:54.711 > RLB_PRO: LinkAdrReq: dataRate = 0, txSteps = 0, nbTrans = 0
17:23:54.711 > RLB_PRO: LinkAdrAns: 07
17:23:54.711 > RLB_PRO: [MAC] 0x04
17:23:54.712 > RLB_PRO: 00000000: 00                                               .                 
17:23:54.712 > RLB_PRO: DutyCycleReq: max duty cycle = 1/2^0
17:23:54.712 > RLB_PRO: [MAC] 0x05
17:23:54.712 > RLB_PRO: 00000000: 08 68 e2 8c                                      .h..              
17:23:54.712 > RLB_PRO: RXParamSetupReq: Rx1DrOffset = 0, rx2DataRate = 8, freq = 923.300
17:23:54.714 > RLB_PRO: [MAC] 0x08
17:23:54.714 > RLB_PRO: 00000000: 01                                               .                 
17:23:54.714 > RLB_PRO: RXTimingSetupReq: delay = 1 sec
17:23:54.714 > RLB_PRO: [MAC] 0x09
17:23:54.714 > RLB_PRO: 00000000: 1d                                               .                 
17:23:54.714 > RLB_PRO: [MAC] 0x0c
17:23:54.714 > RLB_PRO: 00000000: 65                                               e                 
17:23:54.714 > RLB_PRO: ADRParamSetupReq: limitExp = 6, delayExp = 5
17:23:54.714 > RLB_PRO: [MAC] 0x0f
17:23:54.715 > RLB_PRO: 00000000: fa                                               .                 
17:23:54.715 > RLB_PRO: RejoinParamSetupReq: maxTime = 15, maxCount = 10
17:23:54.760 > RLB_PRO: 
17:23:54.760 > RLB_PRO: PHY:  Frequency UL = 903.900 MHz
17:23:54.764 > RLB_PRO: LoRa: SF = 10, TX = 17 dBm, BW = 125.0 kHz, CR = 4/5
17:23:54.765 > RLB_DBG: Timeout in 556 ms
17:23:55.139 > RLB_PRO: JoinRequest sent (DevNonce = 8) <-- Rx Delay start
17:23:55.139 > RLB_PRO: 00000000: 00 5d 93 bf fa 10 9b 58 89 7e 26 ea 8c 36 96 b7  .].....X.~&..6..
17:23:55.139 > RLB_PRO: 00000010: d9 08 00 9b 26 2c 61                             ....&,a           
17:23:55.140 > RLB_PRO: 
17:23:55.141 > RLB_PRO: PHY:  Frequency DL = 923.300 MHz
17:23:55.144 > RLB_PRO: LoRa: SF = 10, TX = 17 dBm, BW = 500.0 kHz, CR = 4/5
17:24:00.130 > RLB_PRO: Opening Rx1 window (77 ms timeout)... <-- Rx Delay end 
17:24:00.207 > RLB_PRO: Closing Rx1 window
17:24:00.252 > Saving nonces to flash
17:24:00.258 > Join failed: -1116
17:24:00.258 > Boots since unsuccessful join: 1

Sketch that is causing the module fail

```c++ /* This demonstrates how to save the join information in to permanent memory so that if the power fails, batteries run out or are changed, the rejoin is more efficient & happens sooner due to the way that LoRaWAN secures the join process - see the wiki for more details. This is typically useful for devices that need more power than a battery driven sensor - something like a air quality monitor or GPS based device that is likely to use up it's power source resulting in loss of the session. The relevant code is flagged with a ##### comment Saving the entire session is possible but not demonstrated here - it has implications for flash wearing and complications with which parts of the session may have changed after an uplink. So it is assumed that the device is going in to deep-sleep, as below, between normal uplinks. Once you understand what happens, feel free to delete the comments and Serial.prints - we promise the final result isn't that many lines. */ #if !defined(ESP32) #pragma error ("This is not the example your device is looking for - ESP32 only") #endif // ##### load the ESP32 preferences facilites #include Preferences store; // LoRaWAN config, credentials & pinmap #include "config.h" #include // utilities & vars to support ESP32 deep-sleep. The RTC_DATA_ATTR attribute // puts these in to the RTC memory which is preserved during deep-sleep RTC_DATA_ATTR uint16_t bootCount = 0; RTC_DATA_ATTR uint16_t bootCountSinceUnsuccessfulJoin = 0; RTC_DATA_ATTR uint8_t LWsession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE]; // abbreviated version from the Arduino-ESP32 package, see // https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/deepsleep.html // for the complete set of options void print_wakeup_reason() { esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) { Serial.println(F("Wake from sleep")); } else { Serial.print(F("Wake not caused by deep sleep: ")); Serial.println(wakeup_reason); } Serial.print(F("Boot count: ")); Serial.println(++bootCount); // increment before printing } // put device in to lowest power deep-sleep mode void gotoSleep(uint32_t seconds) { esp_sleep_enable_timer_wakeup(seconds * 1000UL * 1000UL); // function uses uS Serial.println(F("Sleeping\n")); Serial.flush(); esp_deep_sleep_start(); // if this appears in the serial debug, we didn't go to sleep! // so take defensive action so we don't continually uplink Serial.println(F("\n\n### Sleep failed, delay of 5 minutes & then restart ###\n")); delay(5UL * 60UL * 1000UL); ESP.restart(); } int16_t lwActivate() { int16_t state = RADIOLIB_ERR_UNKNOWN; // setup the OTAA session information node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); Serial.println(F("Recalling LoRaWAN nonces & session")); // ##### setup the flash storage store.begin("radiolib"); // ##### if we have previously saved nonces, restore them and try to restore session as well if (store.isKey("nonces")) { uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE]; // create somewhere to store nonces store.getBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // get them from the store state = node.setBufferNonces(buffer); // send them to LoRaWAN debug(state != RADIOLIB_ERR_NONE, F("Restoring nonces buffer failed"), state, false); // recall session from RTC deep-sleep preserved variable state = node.setBufferSession(LWsession); // send them to LoRaWAN stack // if we have booted more than once we should have a session to restore, so report any failure // otherwise no point saying there's been a failure when it was bound to fail with an empty LWsession var. debug((state != RADIOLIB_ERR_NONE) && (bootCount > 1), F("Restoring session buffer failed"), state, false); // if Nonces and Session restored successfully, activation is just a formality // moreover, Nonces didn't change so no need to re-save them if (state == RADIOLIB_ERR_NONE) { Serial.println(F("Succesfully restored session - now activating")); state = node.activateOTAA(); debug((state != RADIOLIB_LORAWAN_SESSION_RESTORED), F("Failed to activate restored session"), state, true); // ##### close the store before returning store.end(); return(state); } } else { // store has no key "nonces" Serial.println(F("No Nonces saved - starting fresh.")); } // if we got here, there was no session to restore, so start trying to join state = RADIOLIB_ERR_NETWORK_NOT_JOINED; while (state != RADIOLIB_LORAWAN_NEW_SESSION) { Serial.println(F("Join ('login') to the LoRaWAN Network")); state = node.activateOTAA(); // ##### save the join counters (nonces) to permanent store Serial.println(F("Saving nonces to flash")); uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE]; // create somewhere to store nonces uint8_t *persist = node.getBufferNonces(); // get pointer to nonces memcpy(buffer, persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // copy in to buffer store.putBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // send them to the store // we'll save the session after an uplink if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Join failed: ")); Serial.println(state); // how long to wait before join attempts. This is an interim solution pending // implementation of TS001 LoRaWAN Specification section #7 - this doc applies to v1.0.4 & v1.1 // it sleeps for longer & longer durations to give time for any gateway issues to resolve // or whatever is interfering with the device <-> gateway airwaves. uint32_t sleepForSeconds = min((bootCountSinceUnsuccessfulJoin++ + 1UL) * 60UL, 3UL * 60UL); Serial.print(F("Boots since unsuccessful join: ")); Serial.println(bootCountSinceUnsuccessfulJoin); Serial.print(F("Retrying join in ")); Serial.print(sleepForSeconds); Serial.println(F(" seconds")); gotoSleep(sleepForSeconds); } // if activateOTAA state } // while join Serial.println(F("Joined")); // reset the failed join count bootCountSinceUnsuccessfulJoin = 0; delay(1000); // hold off off hitting the airwaves again too soon - an issue in the US // ##### close the store store.end(); return(state); } // setup & execute all device functions ... void setup() { Serial.begin(115200); while (!Serial); // wait for serial to be initalised delay(2000); // give time to switch to the serial monitor Serial.println(F("\nSetup")); print_wakeup_reason(); int16_t state = 0; // return value for calls to RadioLib // setup the radio based on the pinmap (connections) in config.h Serial.println(F("Initalise the radio")); state = radio.begin(); debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); // Set a datarate to start off with // activate node by restoring session or otherwise joining the network state = lwActivate(); // state is one of RADIOLIB_LORAWAN_NEW_SESSION or RADIOLIB_LORAWAN_SESSION_RESTORED // ----- and now for the main event ----- Serial.println(F("Sending uplink")); // this is the place to gather the sensor inputs // instead of reading any real sensor, we just generate some random numbers as example uint8_t value1 = radio.random(100); uint16_t value2 = radio.random(2000); // build payload byte array uint8_t uplinkPayload[3]; uplinkPayload[0] = value1; uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions uplinkPayload[2] = lowByte(value2); // perform an uplink state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug(state != RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); Serial.print(F("FcntUp: ")); Serial.println(node.getFCntUp()); // now save session to RTC memory uint8_t *persist = node.getBufferSession(); memcpy(LWsession, persist, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); // wait until next uplink - observing legal & TTN FUP constraints gotoSleep(uplinkIntervalSeconds); } // The ESP32 wakes from deep-sleep and starts from the very beginning. // It then goes back to sleep, so loop() is never called and which is // why it is empty. void loop() {} ``` and corresponding `config.h` ``` #ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H #define _RADIOLIB_EX_LORAWAN_CONFIG_H #include //#define RADIOLIB_CLOCK_DRIFT_MS 50 #define RFM95_CS 10 // "B" #define RFM95_INT 11 // "A" #define RFM95_RST 9 // "C" // first you have to set your radio model and pin configuration // this is provided just as a default example RFM95 radio = new Module(RFM95_CS, RFM95_INT, RFM95_RST, -1); // if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) // and are using one of the supported boards, you can do the following: /* #define RADIO_BOARD_AUTO #include Radio radio = new RadioModule(); */ // how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 30; // joinEUI - previous versions of LoRaWAN called this AppEUI // for development purposes you can use all zeros - see wiki for details #define RADIOLIB_LORAWAN_JOIN_EUI // the Device EUI & two keys can be generated on the TTN console #ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI // panic-02 #define RADIOLIB_LORAWAN_DEV_EUI #endif #ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key #define RADIOLIB_LORAWAN_APP_KEY #endif #ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here #define RADIOLIB_LORAWAN_NWK_KEY #endif // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips // regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 const LoRaWANBand_t Region = US915; const uint8_t subBand = 2; // For US915, change this to 2, otherwise leave on 0 // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... // Auto select MCU <-> radio connections // If you get an error message when compiling, it may be that the // pinmap could not be determined - see the notes for more info // Adafruit #if defined(ARDUINO_SAMD_FEATHER_M0) #pragma message ("Adafruit Feather M0 with RFM95") #pragma message ("Link required on board") SX1276 radio = new Module(8, 3, 4, 6); // LilyGo #elif defined(ARDUINO_TTGO_LORA32_V1) #pragma message ("TTGO LoRa32 v1 - no Display") SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") SX1276 radio = new Module(18, 26, 23, 33); // Heltec #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") #elif defined(ARDUINO_heltec_wifi_kit_32_V2) #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") SX1276 radio = new Module(18, 26, 14, 35); #elif defined(ARDUINO_heltec_wifi_kit_32_V3) #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") SX1262 radio = new Module(8, 14, 12, 13); #elif defined(ARDUINO_CUBECELL_BOARD) #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); #elif defined(ARDUINO_CUBECELL_BOARD_V2) #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") #else #pragma message ("Unknown board - no automagic pinmap available") // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); // SX1262 radio = new Module(8, 14, 12, 13); // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); // SX1278 radio = new Module(10, 2, 9, 3); #endif // Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // Create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); // Helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); Serial.print("("); Serial.print(state); Serial.println(")"); while (Freeze); } } // Helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for (uint16_t c = 0; c < len; c++) { Serial.printf("%02X", buffer[c]); } Serial.println(); } #endif ```

Expected behavior It looks like ChirpStack is transmitting, and I have a good antenna on both devices. I am betting it's a problem with config or something, but I have been banging my head against this for the last 10 hours and any help would be appreciated.

Additional info (please complete):

StevenCellist commented 2 days ago

"Good antenna" and "1m apart" are things that should never appear in the same sentence. My devices with a terrible Heltec antenna cannot receive SF11+ messages from a gateway 1m away without any antenna, not even a dummy load. So first advice would be to get 10m & a brick wall between devices and gateway, and if possible a terrible antenna / dummy load (don't be like me without antenna). The rest of the log looks decent to me on first glance, so I'd start with some separation and obstruction.

I would also suggest moving to upstream RadioLib as I've very recently pushed a fix for fixed bands (such as US915) in combination with persistence which you are using - it'll save you some frustration once the join is working.

HeadBoffin commented 2 days ago

As this isn't a RadioLib issue (RFM95 with about 5 different MCUs talking to Chirpstack & TTS is well exercised for many years), converting to discussion.