New V3 Node failed

photo_2021-10-11 22.38.33

Hello everyone. In the last few years I had some nodes in the V2 and also a gateway for everyone with an IC880A and a Raspberry pi running - everything worked. Unfortunately, there is now this new version V3. I first tried to update my gateway to V3 (without success) and have now set everything up again with balena. now i have tried to create a new application and a device to start again at 0 as before. Unfortunately I always get the following errors: see pictures in the attachment. I am also absolutely not clear how I should know which Lora Wan version my SX1276 has and how can I find out? I would be very grateful for any kind of help to get my sensors working again. A few information about my node: self-developed board with DHT22 sensor / LDR / arduino pro mini 3.3v and sma antenna connection. The board and the gateway (IC880A + RPI) ran perfectly for years. So I have to do something wrong with the switch to V3. Thanks in advance. greetings Marclora1

The chip doesn’t have a LoRaWAN version. The LoRaWAN version depends on the software you use to drive the sx1276. What software are you using on your node? Is it LMIC based? If so, which version of LMIC are you using? And does the documentation of that version mention which version of the LoRaWAN standard it implements?

The “unknown event: 20” message suggests you’re running some old example code with a newer stack, not necessarily a problem. I think you can look up the event ‘typedef enum’ statement in a header file of the stack to find out exactly what event this is.

You’re using OTAA, that makes things a lot easier, no need for hardcoding frequencies, RX delays, etc.

On the TTN side, I would register the device as a LoRaWAN version 1.0.3 device, defaults for the other parameters are generally OK.

When the device attempts to join, observe the gateway log and application log in the console. See if the application/join EUI + device EUI in the JOIN request is understood (no “mic mismatch” messages, etc) and a JOIN ACCEPT is sent back by the gateway. If that happens you know at least the ids/keys are OK.


thank you for the fast answer :wink: I check it and its this version on my Arduino.ide do you mean I must update ? regards from Germany

thank you for your help :wink: i have been doing the whole thing for a long time aly hobby so i haven’t learned anything in this direction. It really took me a long time to put the program together to read out my self-made sensor and send data via lora, so it wouldn’t be really nice if I had to delete everything again and have to deal with the bad description of the lora communication again :frowning: so if I understand correctly, can I not use my old code in this v3? Greetings from Germany

I only have a gateway API and an end device ID for my sensor, then an AppEUI and DevEUI and an AppKey. But it is not clear to me why there is still something in the application because of API keys (0) maybe something is wrong? Greetings Marc


In the console, both the application and the end node should have a panel ‘live data’. The gateway has a panel like that too. That is where you should see events coming in if the device is transmitting and the gateway is forwarding data.


this is the output of the data you say but I don’t understand that in v2 it was clear now I can not understand what this numbers mean

regards from Germany :slight_smile:

I cannot explain every detail about the v3 console that is different from the v2 console.
Just explore it a bit by yourself.

What I see in your gateway console live data view is that the gateway is actually talking to TheThingsNetwork and sending a status at a regular interval (that’s good!). However it appears that it is not receiving any LoRaWAN traffic at all, not from your node but also not from any other node.

Would be helpful to see some valid data indeed, but its not too unusual to receive nothing: i have two gateways, one receives nothing but my own devices, another just regularly picks up a device which sends in SF12.

But after @MarcKCity you created a new device: does your AppEUI have all zeros? (default if you create a device in V3)

I cannot receive anything from a device using an MCCI lib & has an all-zero AppEUI/JoinEUI set.
Just recently found this, because i created the first device in V3 (before i just migrated my old devices from V2, and so they all had something set / i copied the same values into V3.

If i set it to a random value everything is working, but according to the docs, this seems to be the right way to define one. Just try if this works in your code:


Some devices do not support using 0000000000000000 as a JoinEUI/AppEUI, because technically, this value is invalid. However, The Things Stack supports using this value to indicate the absence of an actual JoinEUI/AppEUI.

If your device gives an error when using 0000000000000000, try using the DevEUI value as a JoinEUI/AppEUI, both in The Things Stack and on your device.

Nick had previously posted this to the forum that may help for small number of devices (suggest dont use on a volume run - buy a block! :wink:

Derived from this:

Thank you all for helping me :slight_smile:

I have now used the Create random EUI generator but it don’t want to work with the custom EUI it shows again the same error in the Arduino IDE and no data in end device live data -.-

i don’t understand why the new v3 must be so complicated … it was already a struggle in v2 until everything was correct with all these keys to transmit 3 sensor values. in the end I only need a code with which I can query the dht22 and an ldr (. analog light sensor) and send this to ttn but that really seems to be a life’s work with the v3. through my search on the internet i noticed that not only i am very dissatisfied with the new system. I’m curious if some of the gateways might not go offline in the future because nobody wants to do it anymore when such trivial things no longer work without extreme effort. greetings marc :slight_smile:


TTN v3 isn’t really that difficult, not more difficult than v2 IMHO, actually a lot more powerful in terms of APIs to retrieve information from devices, gateways etc than I first assumed. I don’t think it’s going away.

I think the first steps are:

  • seeing that your node claims it’s transmitting something, like trying to do an OTAA join, perhaps you can see a radio signal on an SDR (node OK)
  • seeing that the OTAA join is received at the gateway and seeing it in the gateway console (gateway OK)
  • seeing that the join request triggers a join accept (settings in console and keys OK)

Then after that, you can start thinking about decoding the data and processing

It is a tough call with the migration - but the LoRaWAN standard moves on, as have the support libraries.

You need to be using the MCCI-LMIC library 3.3 or 4.0 for a compliant library.

If you can get that installed I can document the changes you need to make to the library to maximise available SRAM on the Pro Mini.

Thank you for the numerous answers and the help that is really very nice and not a matter of course in today’s world.

I updated the lmic to 4.1.0. and instead of the EUI with only zeros, I generated one via the generator.

Then I entered the APP EUI and the DEV EUI in lsb format. The APP key in msb format. and tested again with the same result :frowning: I don’t know what else I can do or what “could be wrong” in the appendix again some pictures and here the code including keys maybe someone sees an error. Or maybe someone has an Arduinio program that I can test (of course I add my keys beforehand) to test whether it is possibly due to the gateway and not to the arduino sketch? Many greetings Marc

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <DHT.h>
#include <DHT_U.h>
#include <Adafruit_Sensor.h>

// For normal use, we require that you edit the sketch to replace FILLMEIN
// with values assigned by the TTN console. However, for regression tests,
// we want to be able to compile these scripts. The regression tests define
// COMPILE_REGRESSION_TEST, and in that case we define FILLMEIN to a non-
// working but innocuous value.
# define FILLMEIN 0
# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"
# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)

// 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]= { 0x10, 0x0E, 0x7A, 0xB0, 0x04, 0x65, 0xA0, 0x0C };
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]= { 0x1F, 0x69, 0x04, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
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.
static const u1_t PROGMEM APPKEY[16]= { 0x2E, 0x66, 0x6D, 0xFB, 0x51, 0x9D, 0xF6, 0x79, 0x2F, 0x84, 0xB4, 0x1F, 0xC3, 0x13, 0xB0, 0x40 };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

static uint8_t btn_activated[1] = { 0x01};
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 5,
    .dio = {2, 3, LMIC_UNUSED_PIN},

//------ Added ----------------
#define LED_YELLOW 8
#define LED_GREEN  6

#define DHT_PIN 7
#define BTN_PIN 9

// DHT11 or DHT22
#define DHTTYPE DHT22

// Initialize dht

int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

int BattValue = 0;

int BattOut = A1; //Voltage Divider INPUT


void onEvent (ev_t ev) {
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
        case EV_BEACON_FOUND:
        case EV_BEACON_MISSED:
        case EV_BEACON_TRACKED:
        case EV_JOINING:
        case 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("artKey: ");
              for (int i=0; i<sizeof(artKey); ++i) {
                Serial.print(artKey[i], HEX);
              Serial.print("nwkKey: ");
              for (int i=0; i<sizeof(nwkKey); ++i) {
                Serial.print(nwkKey[i], HEX);
            // 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.
        || This event is defined but not used in the code. No
        || point in wasting codespace on it.
        || case EV_RFU1:
        ||     Serial.println(F("EV_RFU1"));
        ||     break;
        case EV_JOIN_FAILED:
        case EV_REJOIN_FAILED:
        case EV_TXCOMPLETE:
            Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if (LMIC.txrxFlags & TXRX_ACK)
              Serial.println(F("Received ack"));
            if (LMIC.dataLen) {
              Serial.print(F("Received "));
              Serial.println(F(" bytes of payload"));

              //------ Added ----------------
              if (LMIC.dataLen == 1) {
                uint8_t result = LMIC.frame[LMIC.dataBeg + 0];
                if (result == 0)  {
                  Serial.println("RESULT 0");
                  digitalWrite(LED_YELLOW, LOW);
                  digitalWrite(LED_GREEN, LOW);
                if (result == 1)  {
                  Serial.println("RESULT 1");
                  digitalWrite(LED_YELLOW, HIGH);
                  digitalWrite(LED_GREEN, LOW);                  
                if (result == 2)  {
                  Serial.println("RESULT 2");
                  digitalWrite(LED_YELLOW, LOW);
                  digitalWrite(LED_GREEN, HIGH);                     
                if (result == 3)  {
                  Serial.println("RESULT 3");
                  digitalWrite(LED_YELLOW, HIGH);
                  digitalWrite(LED_GREEN, HIGH);                       
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
        case EV_LOST_TSYNC:
        case EV_RESET:
        case EV_RXCOMPLETE:
            // data received in ping slot
        case EV_LINK_DEAD:
        case EV_LINK_ALIVE:
        || This event is defined but not used in the code. No
        || point in wasting codespace on it.
        || case EV_SCAN_FOUND:
        ||    Serial.println(F("EV_SCAN_FOUND"));
        ||    break;
        case EV_TXSTART:
            Serial.print(F("Unknown event: "));
            Serial.println((unsigned) ev);

void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        uint32_t humidity = dht.readHumidity(false) * 100;
        uint32_t temperature = dht.readTemperature(false) * 100;
        Serial.println("Humidity: " + String(humidity));
        Serial.println("Temperature: " + String(temperature));

        BattValue = averageAnalogRead(BattOut);
        int battVoltage = ( 3.36 / 1024 * BattValue * 2 * 100 ) - 250;

        byte payload[5];
        payload[0] = highByte(humidity);
        payload[1] = lowByte(humidity);
        payload[2] = highByte(temperature);
        payload[3] = lowByte(temperature); 
        payload[4] = battVoltage;
        //Prepare upstream data transmission at the next possible time.
        LMIC_setTxData2(1, payload, sizeof(payload), 0);
        Serial.println(F("Packet queued"));
    // Next TX is scheduled after TX_COMPLETE event.

//Takes an average of readings on a given pin
//Returns the average
int averageAnalogRead(int pinToRead)
  byte numberOfReadings = 8;
  unsigned int runningValue = 0; 

  for(int x = 0 ; x < numberOfReadings ; x++)
    runningValue += analogRead(pinToRead);
  runningValue /= numberOfReadings;


void setup() {

    //------ Added ----------------
    pinMode(LED_YELLOW, OUTPUT);
    pinMode(LED_GREEN, OUTPUT);
    pinMode(BTN_PIN, INPUT);

    digitalWrite(BTN_PIN, LOW); 

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);

    // LMIC init
    // Reset the MAC state. Session and pending data transfers will be discarded.

    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

    // Start job (sending automatically starts OTAA too)

void loop() {
    //------ Added ----------------
    // read the state of the button value:
    buttonState = digitalRead(BTN_PIN);

    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) {

        if (buttonState == HIGH) {
            // if the current state is HIGH then the button went from off to on:
            LMIC_setTxData2(1, btn_activated, sizeof(btn_activated), 0);
            Serial.println(F("Button On"));
        } else {
            // if the current state is LOW then the button went from on to off:
            Serial.println(F("Button Off"));
        // Delay a little bit to avoid bouncing

    // save the current state as the last state, for next time through the loop
    lastButtonState = buttonState;
type or paste code here


Thanks for all the detail, FYI, if it can be text, please use text (Arduino console log) and to save us (me) peering at small screen shots, can we switch to asking for information - a picture without expected information is a distraction - we promise to believe you if you say there is no Join-Accept!

However at present there doesn’t appear to be a Join-Request in your gateway console and the Arduino output doesn’t appear as expected - it’s not reporting EV_JOIN_TXCOMPLETE and is a classic issue where the whole stack has ground to a halt due to lack of memory, see this important tip:

So if you can hang on a few more hours, I can do the above.

sorry thought it would be good if I send pictures of all the details, ok then i know about the future

of course it doesn’t depend on a day, that would of course be very nice;)

Greetings from Germany

I haven’t seen any difference between v3.1.0 and v4.1.0 in terms of size, v3.1.0 is declared as being properly Class A compliant so I’ll leave you to figure out which version gives you the most SRAM but I have spun up an original TinyThing (Pro Mini + RFM95) to check it was good and it ran happily on OTAA for several hours. I used LMIC a lot when I first started with LoRaWAN so I’d say that it will just run & run (like the ones around the office & in the garden, 100k uplinks in some cases).

So the two main changes are to un-comment these lines:


If necessary (depends on what sensors you are using), you can also add a:


to match up with

and make sure the line 87 is:


I have transitioned the TinyThings to using ATmega4808 + RFM95 as one of the options - this triples the SRAM to 6K and increases flash from 32K to 48K. This means I can run LMIC with all the options with full logging (level 2) and line 93 uncommented - so I get ALL the detail. This is how I can then figure out what’s going on and then apply changes back to the original 328 version.

Please let me know how you get on,

1 Like


I get the same error in the Arduino IDE console unknown event: 20

But when I test the same code with a heltec board I get it in the gateway and see the payload so it must be something with the use of Arduino pro mini ?!

regards from Germany