No join accept

I use the following code to communicate with my TTN (Europe):

#include <SPI.h>
#include <WiFi.h>
#include <lmic.h>
#include <hal/hal.h>
#include <Arduino.h>

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8] = { 0x15, 0x44, , , , , 0x84, 0xEA };
void os_getArtEui(u1_t* buf){ memcpy_P(buf, APPEUI, 8); }

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8] = { 0x2C, 0x4F, , , , , 0x70, 0x00 };
void os_getDevEui(u1_t* buf){ memcpy_P(buf, DEVEUI, 8); }

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = { 0x14, 0x5B, , , , , , , , , , , , , 0x3A, 0xDD };
void os_getDevKey(u1_t* buf){ memcpy_P(buf, APPKEY, 16); }

static uint8_t Payload[] = "Hello, world!";
static osjob_t TransmitJob;

const lmic_pinmap lmic_pins = {
    .nss = 18,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,
    .dio = {26, 35, LMIC_UNUSED_PIN},
};

const uint8_t TX_INTERVAL       = 60;

void Transmit(osjob_t* Job);

void printHex2(unsigned v)
{
    v &= 0xff;
    if (v < 16)
        Serial.print('0');
    Serial.print(v, HEX);
}

void onEvent(ev_t Event)
{
    Serial.print(os_getTime());
    Serial.print(": ");
    switch(Event)
    {
        case EV_SCAN_TIMEOUT:
            Serial.println("EV_SCAN_TIMEOUT");
            break;
        case EV_BEACON_FOUND:
            Serial.println("EV_BEACON_FOUND");
            break;
        case EV_BEACON_MISSED:
            Serial.println("EV_BEACON_MISSED");
            break;
        case EV_BEACON_TRACKED:
            Serial.println("EV_BEACON_TRACKED");
            break;
        case EV_JOINING:
            Serial.println("EV_JOINING");
            break;
        case EV_JOINED:
            Serial.println("EV_JOINED");
            {
                u4_t netid = 0;
                devaddr_t devaddr = 0;
                u1_t nwkKey[16];
                u1_t artKey[16];
                LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
                Serial.print("netid: ");
                Serial.println(netid, DEC);
                Serial.print("devaddr: ");
                Serial.println(devaddr, HEX);
                Serial.print("AppSKey: ");
                for(size_t i = 0; i < sizeof(artKey); ++i)
                {
                    if(i != 0)
                    {
                        Serial.print("-");
                        printHex2(artKey[i]);
                    }
                }
                Serial.println("");
                Serial.print("NwkSKey: ");
                for(size_t i = 0; i < sizeof(nwkKey); ++i)
                {
                    if(i != 0)
                    {
                        Serial.print("-");
                    }
                    
                    printHex2(nwkKey[i]);
                }
                Serial.println();
            }
            // Disable link check validation (automatically enabled
            // during join, but because slow data rates change max TX
	    // size, we don't use it in this example.
            LMIC_setLinkCheckMode(0);
            break;
        case EV_JOIN_FAILED:
            Serial.println("EV_JOIN_FAILED");
            break;
        case EV_REJOIN_FAILED:
            Serial.println("EV_REJOIN_FAILED");
            break;
        case EV_TXCOMPLETE:
            Serial.println("EV_TXCOMPLETE (includes waiting for RX windows)");
            if(LMIC.txrxFlags & TXRX_ACK)
            {
                Serial.println("Received ack");
            }
            if(LMIC.dataLen)
            {
                Serial.print("Received ");
                Serial.print(LMIC.dataLen);
                Serial.println(" bytes of payload");
                for (int i = 0x00; i < LMIC.dataLen; i++)
                {
                    Serial.print(LMIC.frame[LMIC.dataBeg + i], 16);
                    Serial.print(" - ");
                }
            }
            os_setTimedCallback(&TransmitJob, os_getTime() + sec2osticks(TX_INTERVAL), Transmit);
            break;
        case EV_LOST_TSYNC:
            Serial.println("EV_LOST_TSYNC");
            break;
        case EV_RESET:
            Serial.println("EV_RESET");
            break;
        case EV_RXCOMPLETE:
            Serial.println("EV_RXCOMPLETE");
            break;
        case EV_LINK_DEAD:
            Serial.println("EV_LINK_DEAD");
            break;
        case EV_LINK_ALIVE:
            Serial.println("EV_LINK_ALIVE");
            break;
        case EV_TXSTART:
            Serial.println("EV_TXSTART");
            break;
        case EV_TXCANCELED:
            Serial.println("EV_TXCANCELED");
            break;
        case EV_RXSTART:
            break;
        case EV_JOIN_TXCOMPLETE:
            Serial.println("EV_JOIN_TXCOMPLETE: no JoinAccept");
            break;
        default:
            Serial.print("Unknown event: ");
            Serial.println((uint8_t)Event);
            break;
    }
}

void Transmit(osjob_t* Job)
{
    if(LMIC.opmode & OP_TXRXPEND)
    {
        Serial.println("OP_TXRXPEND, not sending");
    }
    else
    {
        LMIC_setTxData2(1, Payload, sizeof(Payload) - 1, 0);
        Serial.println("Packet queued");
    }
}

void setup(void)
{
    Serial.begin(115200);
    Serial.println("[INFO] Starting...");

    SPI.begin(5, 19, 27);

    os_init();

    LMIC_reset();
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

    #if defined(CFG_eu868)
        // Set up the channels used by the Things Network, which corresponds
        // to the defaults of most gateways. Without this, only three base
        // channels from the LoRaWAN specification are used, which certainly
        // works, so it is good for debugging, but can overload those
        // frequencies, so be sure to configure the full frequency range of
        // your network here (unless your network autoconfigures them).
        // Setting up channels should happen after LMIC_setSession, as that
        // configures the minimal channel set.
        // NA-US channels 0-71 are configured automatically
        LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
        LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
        // TTN defines an additional channel at 869.525Mhz using SF9 for class B
        // devices' ping slots. LMIC does not have an easy way to define set this
        // frequency and support for class B is spotty and untested, so this
        // frequency is not configured here.
    #elif defined(CFG_us915)
        // NA-US channels 0-71 are configured automatically
        // but only one group of 8 should (a subband) should be active
        // TTN recommends the second sub band, 1 in a zero based count.
        // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
        LMIC_selectSubBand(1);
    #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 (note: txpow seems to be ignored by the library)
    LMIC_setDrTxpow(DR_SF7, 14);

    Transmit(&TransmitJob);
}

void loop(void)
{
    os_runloop_once();
    delay(1000);
}

And the following device in TTN:

ID

TTN receives and displays the data in the device, but I don´t get a join accept.

51566429: EV_TXSTART
51566500: TXMODE, freq=868100000, len=23, SF=9, BW=125, CR=4/5, IH=0
start single rx: now-rxtime: 1429
51941461: RXMODE_SINGLE, freq=868100000, SF=9, BW=125, CR=4/5, IH=0
rxtimeout: entry: 52003904 rxtime: 51940027 entry-rxtime: 63877 now-entry: 62504 rxtime-txend: 311126
start single rx: now-rxtime: 126679
52128961: RXMODE_SINGLE, freq=869525000, SF=12, BW=125, CR=4/5, IH=0
rxtimeout: entry: 52191404 rxtime: 52002277 entry-rxtime: 189127 now-entry: 62504 rxtime-txend: 373376
52253926: EV_JOIN_TXCOMPLETE: no JoinAccept
52316403: engineUpdate, opmode=0xc

What´s the reason for this?

On the device data page, do you see the join data when the device transmits? (Only data transmitted when the page is open is displayed)
Does the device have a last seen date unequal to never? Has it been updated during your last attempt?

If no data is visible your EUIs and Key might not match or are in the wrong order or your transmission is not received by a gateway. Do you have your own gateway? If so is your node at least 3 meter (more is better and preferably a wall in between as well) for the gateway?

Please identify exactly what the rest of the code is that does the actual work of implementing LoRaWan.

It looks like a version of LMiC, but please be specific exactly which download or which repository at which checkout hash you used.

Also state the hardware it is running on, and exactly which Arduino support is being used to do that.

Hello,

I use the following library (PlattformIo):

mcci-catena/MCCI LoRaWAN LMIC library@^3.3.0

See this link for more information.
I run the code on a Heltec LoRa V2 (ESP32) in combination with the Arduino and the Espressif IDF…

You should spend some time reviewing the existing threads on the unique challenges of that combination

I see the transmission on the device and on the gateway page (see screenshot).

Data

The gateway is my own device (Dragino Outdoor Gateway) and I remove the gateway from my room and place it in another room at the end of my house.

It looks like the device does not receive the downlink OTAA reply packet. In 99% of the cases that is due to timing issues. The node should be listening for data precisely 5 seconds and 6 seconds after the transmission. As suggested read up on the ESP32 challenges with LMIC, there is probably a pointer on how to solve this in those topics.

The hint with a potential timing issue was helpful. The delay was the reason for the error.

Hi @Kampi can you figure out what exactly was your solution ? I think that this issue with join-request from v2 migration to v3 will hit many users here ! thanks in advance

Hello @jensileinchen,

it´s difficult. I just have removed the delay(1000) in the loop section, but I don´t use the “original” Arduino environment on the ESP. Instead, I use a mix with the espidf setup and start the Arduino task on my own. Maybe I have some issue there.

So it might be possible that this problem will happen when my loop needs some more time for a complete cycle. I add a work around by moving the os_runloop_once function into a separate task of FreeRTOS:

static void LoRaTask(void* p_Parameters)
{
    while(1)
    {
        os_runloop_once();
    }
}

It is not an ideal solution, but it seems that this solution works (even with the delay).

This would only by coincidence have anything to do with TTN V2 vs V3.

More importantly it sounds like the basis of your software is not yet sufficiently informed by an understanding of the fact that events in LoRaWan must happen precisely when scheduled with next to no allowance for jitter or latency.

Get the timing wrong, and downlinks fail.

When downlinks fail, not just you but all other network users suffer, because a gateway transmitting a downlink is one that cannot hear any other node uplink.