Electronics Design AU
LoRa & LoRaWANSolved

LoRaWAN OTAA join failing on TTN AU915 — JoinRequest visible in gateway traffic but device live data is empty

5 min read3 replies
Original Question

Asked by stale_biscuit_03 ·

Got a LilyGO T3S3 (ESP32-S3 + SX1262 onboard) and I'm trying to get it joining TTN on AU915. Been at this for most of yesterday and this morning and I'm going in circles.

Setup:

  • MCCI LMIC 4.1.1 via Arduino IDE
  • lmic_project_config.h has CFG_au915 and CFG_sx1262_radio defined
  • Device registered on TTN Australia 1 cluster, OTAA, LoRaWAN 1.0.3, frequency plan set to "Australia 915–928 MHz, FSB 2"
  • LMIC_selectSubBand(1) called in setup() after LMIC_reset()

Here's the part I can't figure out: I can actually see the JoinRequest arriving in the TTN gateway live data panel. It's on 917.4 MHz, SF9, RSSI around –97 dBm. So the radio is definitely transmitting and the gateway is hearing it.

But the device live data tab is completely empty. No JoinRequest event, no JoinAccept, nothing. Serial on the T3S3 just shows EV_JOINING every few minutes as LMIC retries.

Key arrays (sanitised, but byte order is exactly as copied from TTN):

// All zeros — standard MCCI LMIC convention for TTN
static const u1_t PROGMEM APPEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

// Copied from the TTN end device overview page
static const u1_t PROGMEM DEVEUI[8] = { 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x04, 0x2A, 0x8C };

// AppKey generated by TTN
static const u1_t PROGMEM APPKEY[16] = { 0x4A, 0x23, 0x96, 0xF1, 0x0B, 0x87, 0xE5, 0xD3,
                                          0xC7, 0x5E, 0x9A, 0x12, 0x34, 0x56, 0x78, 0x9A };

Setup:

void setup() {
    Serial.begin(115200);
    os_init();
    LMIC_reset();
    LMIC_selectSubBand(1);
    do_send(&sendjob);
}

The sub-band selection seems to be working — the gateway is hearing the JoinRequest fine. But it's like TTN doesn't know the device exists. Is there something about how gateway live data vs device live data works that explains this?

From the knowledge baseConnecting a LoRaWAN Device to The Things Network in Australia

3 Replies

tangled_awning_8
Accepted Answer

Your DEVEUI array is in the wrong byte order — that's the entire problem.

MCCI LMIC expects DEVEUI (and APPEUI) in LSB order: least significant byte first, which is the byte-reversed version of how TTN displays them in the console. So if your registered DevEUI is 70:B3:D5:7E:D0:04:2A:8C, the array must be:

// LSB order — bytes reversed from the TTN console display
static const u1_t PROGMEM DEVEUI[8] = { 0x8C, 0x2A, 0x04, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };

What you have now puts the bytes in MSB order. LMIC transmits the DEVEUI starting from index 7 (last byte first), so the DevEUI the gateway decodes from your JoinRequest is 8C:2A:04:D0:7E:D5:B3:70 — the reversed value. TTN's network server looks that up, finds no matching registration, and silently discards the frame without sending a JoinAccept.

That's exactly why you see the JoinRequest in gateway live data (gateways forward every frame they receive regardless of whether the network server recognises the device) but nothing in device live data (which only shows frames that the network server successfully attributed to a registered device).

Fix: In the TTN end device overview, look at the copy buttons next to DevEUI and JoinEUI — there are two: MSB and LSB. Use the LSB button for both DEVEUI and APPEUI. APPKEY is different: LoRaWAN always uses MSB order for the AppKey, so the default copy gives you what LMIC expects. That one is fine as-is.

After reflashing, check the gateway traffic details panel for your next JoinRequest. Some TTN gateways surface the decoded DevEUI in the packet metadata — if it matches your registered DevEUI exactly (not reversed), the next attempt will produce a JoinAccept.

One AU915-specific timing note: the OTAA receive window is 5 seconds after each JoinRequest (JOIN_ACCEPT_DELAY1 per the LoRa Alliance Regional Parameters RP002-1.0.3). LMIC handles the window automatically, but don't power-cycle or reset the device in the first few seconds after a join attempt while debugging — you'd miss the window every time. The longer delay also applies to RX2 at 6 seconds; regular data uplink windows are a separate 1-second delay.

Full AU915 sub-band table and the MCCI LMIC byte order requirement are both in the TTN AU915 setup guide — the LSB/MSB distinction is easy to miss the first time through.

link_budget_lou

Byte order answer is correct. Worth adding a diagnostic framework for the next time this category of failure appears.

The gateway-vs-device live data split cleanly separates two different OTAA failure modes:

JoinRequest in gateway traffic but absent from device live data — the gateway received and forwarded the frame, but the network server couldn't match it to any registered device. The on-air DevEUI doesn't match the registered DevEUI. Cause is almost always a byte order error in DEVEUI or APPEUI. This is what you had.

JoinRequest appears in device live data, but no JoinAccept follows — TTN matched the device correctly and sent a JoinAccept, but the device either couldn't decrypt it (AppKey mismatch) or missed both the RX1 and RX2 receive windows entirely. The latter usually means a clock or timing problem on a custom board rather than a dev board.

Knowing which mode you're in before starting to change things saves a lot of time. When the gateway traffic shows a JoinRequest, always expand the packet details and check the decoded DevEUI — it's your ground truth for what LMIC is actually putting on air.

Your LMIC_selectSubBand(1) position looks correct: after LMIC_reset() and before do_send(). Calling it before LMIC_reset() would be undone by the reset. For the AU915 channel table and sub-band 2 frequencies, the LoRaWAN AU915 TTN setup guide is the reference.

stale_biscuit_03

That fixed it. Switched to the LSB copy button for DEVEUI, reflashed, and it joined on the first attempt.

Went back to look at the gateway traffic details panel more carefully and I could see 8C:2A:04:D0:7E:D5:B3:70 in the decoded DevEUI field — the reversed bytes were there the whole time. Should have known to look for that earlier.

Thanks for the gateway vs device live data explanation too — that's a useful mental model for debugging this stuff going forward.

Related Discussions