Node to close to gateway

Hi
I have the problem that when I’m in the testing stage that my node is to close to the gateway.
This is a follow up to this thread. But as it is already closed, I have to create a new one.
As I live in a small flat, the node and gateway have only about 3m distance. Due to that something goes wrong. I see on the gateway side and on the application side messages like:

Receive join-accept message
Forward join-accept message
Forward join-accept to Application server.

But no key exchange and payload transmit are working.
Eventually anyone knows why this is and if I can somehow reduce the power from the gateway so that a successfull communication can take place?
It would also be good to know why the lack of distance leads to this problem. I’ve read something about overloading the receivers. But a bit more detail would be nice.

p.s.
The reason why I want to have it so close is only for the time as long as I write code and testing and troubleshooting the code for my node. When everything is fine then I place the node to a destination with sufficient distance.

There are a number of tricks you can play to emulate operation at an increased distance however the 1st thing to say is DONT be tempted to run node or GW without Ant connected :wink: - Likely will work but high risk ant-less device will destroy itself or impare reliability such that there is then early failure in the field when finally deployed!

I often have multiple GW’s and nodes in very close proximity in office and bench areas here for test, development, soak tests, migration work etc.

  1. Within limited space place GW as far from test bench as possible…can you get say intervening storage racks or (best metal) filing cabinets? Ensure vertical displacement relative to each other - GW near ceiling, node on bench…a meter or two offset when at a distance makes little difference but when close you are benefiting from the deminised sensitivity of the donut polar plot. I find that gives typically 7-10db signal reduction…

  2. Change node ant orientation - if GW has vertical (as it typically should be), have the node Ant horizontal, again with top or bottom of ant oriented towards the GW direction - again that can give 5-12db assistance.

  3. Swap standard ant for a 50ohm dummy load - with sma connector enabled nodes or GW’s I find a small (1/8W) MO 50ohm (47?) leaded resistor with cropped leads, or a SMT version, soldered directly into a matching SMA connector/gender changer works well - will still radiate and presents a workable load to RF output without risk of damage but can gain anything from 15-35db reduction assistance

  4. Put node in metal box tin (ensure not shorting to the circuit bd if open frame) with say serial debug leads or USB/TTL/FTDI interface leads, and if needed external power if not on battery, comming out for debug (internal reflections, and ant detuning can be a problem in theory but should be ok), with tin lid loosely closed (I favour shortbread biscuit tins - not least as I have excuse to eat them 1st before use! :slight_smile: )

  5. a friend (yes I still have a few!) and fellow developer/collaborator Andy_T is like you in a small flat…he pursuaded a neighour to host his indoor GW, with it placed near their adjoining wall and connected to his wifi! so he can monitor directly. He always has about a 25-30db reduction in signal!. I know he also sometimes steps outside his flat front door into communal area to trigger join req’s if he suspects a problem with signal strength and proximity, before returning to bench for debug/operation checks.

I’m sure others will chip in with alternate suggestions…

Shhhh, don’t tell anyone, but whilst I say 5m & a brick wall, this is what I actually do with development devices:

50ohm

That’s an Adafruit Feather M0 with RFM95 on top of an STM32 B-L072Z - the bottom one has the resistor doubled up lead stuffed in the middle of the connector and the other end wrapped around the ring.

The office gateway is on the same desk, about 50cm away.

Still a bit loud, RSSI ~75, but works reliably.

One of the HAB communities guru’s runs workshops on building the trackers without antennas on the grounds he’s not yet damaged the RFM95’s being used - so for a while I didn’t either. But for other vendors where I can’t swap the radio, I do put a resistor on.

Hi

Have many thanks for your help and suggestions.
I’ve tried it with the resistor approach.
I played around with different resistors from 33Ω - 82Ω.
From 0 - ~2m I have connection and >2m there is no connection.
Unfortunately I didn’t have success.

Therefore I’ve reverted back to the normal setup and tried it again with bigger distance, up to 300 meters away and still without success. I see the traffic on the gateway and the traffic on the node in the application but no key exchange happend. Therefore I have always this messages like:

3289996: EV_JOINING
3290036: EV_TXSTART
3731338: LoRa: No Join Accept

This is a recording of one join request.
One time on the gateway side and one time on the node side.

Gateway
Applications

Maybe someone can help me, with what could be wrong. Or what I could check it would be very nice.

This is my complete coding (Keys have been changed to 0xXX for posting)
// CHAPTER: Includes
// #include <Timezone.h>
#include <SPI.h>
#include <lmic.h>
#include <Wire.h>
#include <Arduino.h>
#include <hal/hal.h>
#include <SdFat.h>
#include <TimeLib.h>
#include "Adafruit_HTU31D.h"

// CHAPTER Debug Flags
#define DEBUG 0
#define DEBUG_GPS 0
#define DEBUG_HTU 0

// CHAPTER: Global
long TimerJoin = 0;
long TimeoutJoin = 45000;

long Timer = 0;
long Timeout = 5000;
long Timer2 = 0;
long Timeout2 = 500;

// CHAPTER LED
bool led_stat = false;

int LED_Blau = 23;
int LED_Gruen = 22;
int LED_Rot = 21;

// CHAPTER: Adafruit OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
Adafruit_SH1107 display = Adafruit_SH1107(64, 128, &Wire);

#include <Bounce2.h>
#define BUTTON_A 15
Bounce2::Button button_a = Bounce2::Button();
#define BUTTON_B 16
Bounce2::Button button_b = Bounce2::Button();
#define BUTTON_C 17
Bounce2::Button button_c = Bounce2::Button();

// CHAPTER: GPS
String strGPS = ""; // Für Logfile
#include <Adafruit_I2CDevice.h>
#include <Adafruit_GPS.h>
#define GPSSerial Serial1
Adafruit_GPS GPS(&GPSSerial);
#define GPSECHO false
uint32_t timer = millis();

// CHAPTER: HTU31D Humidity and temperature sensor
Adafruit_HTU31D htu = Adafruit_HTU31D();
uint32_t timestamp;
bool heaterEnabled = false;
float Temperature_global;
float Humidity_global;

// CHAPTER: SD Card
#include <SD.h>
File myFile;
const int chipSelect = 9;

// CHAPTER: LoRa
// clang-format off
bool join_state = false;

// Format: little-endian
static const u1_t PROGMEM APPEUI[8] = {0xXX, 0xXX, 0xXX, 0xX, 0xXX, 0xXX, 0xXX, 0xXX};
void os_getArtEui(u1_t *buf) { memcpy_P(buf, APPEUI, 8); }

// Format: little-endian
static const u1_t PROGMEM DEVEUI[8] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX 0xXX};
void os_getDevEui(u1_t *buf) { memcpy_P(buf, DEVEUI, 8); }

// Format big-endian
static const u1_t PROGMEM APPKEY[16] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};
void os_getDevKey(u1_t *buf) { memcpy_P(buf, APPKEY, 16); }

// clang-format on
// PAYLOAD sendjob
static osjob_t sendjob;
const unsigned TX_INTERVAL = 60;

const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,
    .dio = {4, 5, 6},
    .rxtx_rx_active = 0,
    .rssi_cal = 0,
    .spi_freq = 0,
};
void TX_Power() {
    // FIXME TX Power
    // LMIC.dn2Dr = DR_SF12;        // Standard
    // LMIC_setDrTxpow(DR_SF11, 5); // Standard
    LMIC.dn2Dr = DR_SF12;
    LMIC_setDrTxpow(DR_SF11, 14);
}

// CHAPTER: LED Farben
void LED_GruenEin() {
    analogWrite(LED_Rot, 0);
    analogWrite(LED_Gruen, 8);
    analogWrite(LED_Blau, 0);
}

void LED_RotEin() {
    analogWrite(LED_Rot, 8);
    analogWrite(LED_Gruen, 0);
    analogWrite(LED_Blau, 0);
}

void LED_BlauEin() {
    analogWrite(LED_Rot, 0);
    analogWrite(LED_Gruen, 0);
    analogWrite(LED_Blau, 8);
}

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

// CHAPTER: LoRa do_send
void do_send(osjob_t *j) {
    sensors_event_t humidity, temp;
    htu.getEvent(&humidity, &temp);
    int Temperature;
    int Humidity;
    // Get Temperature
    Temperature = int(temp.temperature * 10);
    // Get humidity
    Humidity = int(humidity.relative_humidity * 100);

    // Check if there is not a current TX/RX job running
    if(LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        // PAYLOAD senden
        Serial.println("PayLoad wird gesendet");
        // prepare and schedule data for transmission
        LMIC.frame[0] = Temperature >> 8;
        LMIC.frame[1] = Temperature;
        LMIC.frame[2] = Humidity >> 8;
        LMIC.frame[3] = Humidity;

        // (port 1, 4 bytes, unconfirmed)
        LMIC_setTxData2(1, LMIC.frame, 4, 0);

        Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.
}

// CHAPTER: CreateLogEntry
void CreateLogEntry(String join_state) {

#if(DEBUG == 1)
    Serial.println("Create log entry");
#endif

    // make a string for assembling the data to log:
    String dataString = "";
    // read three sensors and append to the string:
    for(int analogPin = 0; analogPin < 3; analogPin++) {
        int sensor = analogRead(analogPin);
        dataString += String(sensor);
        if(analogPin < 2) { dataString += ","; }
    }
    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
    // if the file is available, write to it:
    if(dataFile) {

// TODO
#if(DEBUG_GPS == 1)
        timer = millis(); // reset the timer
        Serial.print("20");
        Serial.print(GPS.year, DEC);
        Serial.print(".");
        Serial.print(GPS.month, DEC);
        Serial.print(".");
        Serial.print(GPS.day, DEC);
        Serial.print(" ");
        if(GPS.hour < 10) { Serial.print('0'); }
        Serial.print(GPS.hour, DEC);
        Serial.print(':');
        if(GPS.minute < 10) { Serial.print('0'); }
        Serial.print(GPS.minute, DEC);
        Serial.print(':');
        if(GPS.seconds < 10) { Serial.print('0'); }
        Serial.print(GPS.seconds, DEC);
#endif
        // TODO
        // Datum
        timer = millis(); // reset the timer
        dataFile.print("20");
        dataFile.print(GPS.year, DEC);
        dataFile.print(".");
        dataFile.print(GPS.month, DEC);
        dataFile.print(".");
        dataFile.print(GPS.day, DEC);
        dataFile.print(",");
        // Zeit
        if(GPS.hour < 10) { dataFile.print('0'); }
        dataFile.print(GPS.hour, DEC);
        dataFile.print(':');
        if(GPS.minute < 10) { dataFile.print('0'); }
        dataFile.print(GPS.minute, DEC);
        dataFile.print(':');
        if(GPS.seconds < 10) { dataFile.print('0'); }
        dataFile.print(GPS.seconds, DEC);
        dataFile.print(",");
        // Position
        dataFile.print(GPS.latitudeDegrees, 8);
        dataFile.print(",");
        dataFile.print(GPS.longitudeDegrees, 8);
        dataFile.print(",");
        // Lora join
        dataFile.print(join_state);
        dataFile.println();
        dataFile.close();
    } else {
        Serial.println("error opening the file!");
    }
}

// CHAPTER: LoRa onEvent
void onEvent(ev_t ev) {
    Serial.print(os_getTime());
    Serial.print(": ");
    switch(ev) {
    case EV_SCAN_TIMEOUT:
        Serial.println(F("EV_SCAN_TIMEOUT"));
        break;
    case EV_BEACON_FOUND:
        Serial.println(F("EV_BEACON_FOUND"));
        break;
    case EV_BEACON_MISSED:
        Serial.println(F("EV_BEACON_MISSED"));
        break;
    case EV_BEACON_TRACKED:
        Serial.println(F("EV_BEACON_TRACKED"));
        break;
    case EV_JOINING:
        // FIXME TX Power
        TX_Power();
        // LMIC.dn2Dr = DR_SF12;        // So geht es mit einem fremden
        // Gateway LMIC_setDrTxpow(DR_SF11, 2); // So geht es mit einem
        // fremden Gateway
        Serial.println(F("EV_JOINING"));
        break;
    // GPS-ABRUF: Join -> Ja
    case EV_JOINED:
        Serial.println(F("EV_JOINED"));
        LED_GruenEin();
        join_state = true;
        LMIC_enableTracking(0);
        CreateLogEntry(join_state);
        {
            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);
        LMIC_setAdrMode(0);
        break;
    /*
    || 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:
        Serial.println(F("EV_JOIN_FAILED"));
        break;
    case EV_REJOIN_FAILED:
        Serial.println(F("EV_REJOIN_FAILED"));
        break;
    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.print(LMIC.dataLen);
            Serial.println(F(" bytes of payload"));
        }
        // Schedule next transmission
        os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL),
                            do_send);
        break;
    case EV_LOST_TSYNC:
        Serial.println(F("EV_LOST_TSYNC"));
        break;
    case EV_RESET:
        Serial.println(F("EV_RESET"));
        break;
    case EV_RXCOMPLETE:
        // data received in ping slot
        Serial.println(F("EV_RXCOMPLETE"));
        break;
    case EV_LINK_DEAD:
        Serial.println(F("EV_LINK_DEAD"));
        break;
    case EV_LINK_ALIVE:
        Serial.println(F("EV_LINK_ALIVE"));
        break;
    /*
    || 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.println(F("EV_TXSTART"));
        break;
    case EV_TXCANCELED:
        Serial.println(F("EV_TXCANCELED"));
        break;
    case EV_RXSTART:
        /* do not print anything -- it wrecks timing */
        break;
    // GPS-ABRUF: Join -> Nein
    case EV_JOIN_TXCOMPLETE:
        join_state = false;
        CreateLogEntry(join_state);
        LED_RotEin();

        display.fillRect(0, 0, 128, 8, SH110X_WHITE);
        display.setTextColor(SH110X_BLACK);
        display.setCursor(0, 0);
        display.print("LoRa: No Join Accept");
        Serial.print("LoRa: No Join Accept");
        display.display();
        break;
    default:
        Serial.print(F("Unknown event: "));
        Serial.println((unsigned)ev);
        break;
    }
}

// CHAPTER: JoinVersuch
void JoinVersuch() {
    LED_BlauEin();
    os_init();
    LMIC_reset();
    LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100);
    LMIC_setLinkCheckMode(0);
    LMIC_setAdrMode(1);
    Serial.println("Erneuter Verbindugsversuch");
    do_send(&sendjob);
}

void htu_Heater() {
    if((millis() - timestamp) > 5000) {
        // toggle the heater
        heaterEnabled = !heaterEnabled;
        if(!htu.enableHeater(heaterEnabled)) {
            Serial.println("Command failed");
        }
        timestamp = millis();
    }
}

void TempLuftfeuchtigkeit() {
    sensors_event_t humidity, temp;
    htu.getEvent(&humidity, &temp);
    Temperature_global = float(temp.temperature);
    Humidity_global = float(humidity.relative_humidity);

#if(DEBUG_HTU == 1)
    Serial.print("Temperature = ");
    Serial.println(Temperature_x);
    Serial.print("Humidity = ");
    Serial.println(Humidity_x);
#endif
    display.fillRect(0, 10, 80, 18, SH110X_BLACK);
    display.setTextColor(SH110X_WHITE);

    display.setCursor(0, 10);
    display.print("Temp:");
    display.setCursor(35, 10);
    display.print(Temperature_global);
    display.print("'C");
    display.setCursor(0, 20);
    display.print("Hum:");
    display.setCursor(35, 20);
    display.print(Humidity_global);
    display.print("%");
    display.display();
}

void PrintLogFile() {
    myFile = SD.open("dataLog.csv", FILE_WRITE);
    // open the file for reading:
    myFile = SD.open("dataLog.csv");
    if(myFile) {
        Serial.println("dataLog.csv:");
        // read from the file until there's nothing else in it:
        while(myFile.available()) { Serial.write(myFile.read()); }
        // close the file:
        myFile.close();
    } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
    }
}

void GPS_Adafruit() {
    char c = GPS.read();
    if(GPS.newNMEAreceived()) {
        // a tricky thing here is if we print the NMEA sentence, or data
        // we end up not listening and catching other sentences!
        // so be very wary if using OUTPUT_ALLDATA and trying to print out data
        // Serial.print(GPS.lastNMEA());  // this also sets the
        // newNMEAreceived() flag to false
        if(!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived()
                                       // flag to false
            return; // we can fail to parse a sentence in which case we should
                    // just wait for another
    }

    if(millis() - timer > 2000) {
        timer = millis(); // reset the timer

        if(GPS.fix) {
            display.fillRect(0, 30, 128, 27, SH110X_BLACK);
            display.setTextColor(SH110X_WHITE);

            display.setCursor(0, 30);
            display.print("GPS/lat: ");
            display.print(GPS.latitude, 4);
            display.setCursor(0, 40);
            display.print("GPS/lon: ");
            display.print(GPS.longitude, 4);
            display.setCursor(0, 50);
            display.print("GPS/sats: ");
            display.print((int)GPS.satellites);
            display.setCursor(80, 50);
            display.print("fix: ");
            display.print((int)GPS.fix);
            display.display();

#if(DEBUG_GPS == 1)
            Serial.println("");

            Serial.print("Location (Degress): ");
            Serial.print(GPS.latitudeDegrees, 8);
            Serial.print(",");
            Serial.println(GPS.longitudeDegrees, 8);

            Serial.print("Speed (km/h): ");
            Serial.println(GPS.speed * 0.539957);
            Serial.print("Angle: ");
            Serial.println(GPS.angle);
            Serial.print("Altitude: ");
            Serial.println(GPS.altitude);
            Serial.print("Satellites: ");
            Serial.println((int)GPS.satellites);
#endif
        }
    }
}

void Tastatur_abfragen() {
    int incomingByte = 0;
    // LOOP: Serial Input
    if(Serial.available()) { // if there is data comming
        // String command = Serial.readStringUntil('\n'); // read string
        // until meet newline character
        incomingByte = Serial.read();
        // say what you got:
        // Serial.print("I received: ");
        // Serial.println(incomingByte, DEC);

        switch(incomingByte) {
        case 48: // Taste "0" = RampMode 0
            break;
        case 49: // Taste "1" = RampMode 1
            break;
        case 50: // Taste "2" = RampMode 2
            break;
        case 51: // Taste "3" = RampMode 3
            break;
        case 101: // Taste "E" = Einschalten
            break;
        case 97: // Taste "A" = Ausschalten
            break;
        case 107: // Taste "K" = Kill
            break;
        case 105: // Taste "I" = Init
            break;
        case 114: // Taste "r" = re-join
            JoinVersuch();
            break;
        case 82: // Taste "R" = re-join
            JoinVersuch();
            break;
        case 112: // Taste "p" = print
            Serial.println("Aufruf von: do_send(&sendjob)");
            do_send(&sendjob);
            break;
        case 43: // Taste + = Schneller
            break;
        case 45: // Taste - = Langsamer
            break;
        default:
            // Tue etwas, im Defaultfall
            // Dieser Fall ist optional
            break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind
        }
    }
}

void setup() {
    // SETUP RGB LED
    pinMode(LED_Rot, OUTPUT);
    pinMode(LED_Gruen, OUTPUT);
    pinMode(LED_Blau, OUTPUT);
    analogWrite(LED_Rot, 0);
    analogWrite(LED_Gruen, 0);
    analogWrite(LED_Blau, 8);

    // SETUP Serial
    // while(!Serial && millis() < 4000) { ; }
    Serial.begin(115200);

    // SETUP: HTU31D (Temperatur und Luftfeuchtigkeit Sensor)
    Serial.println("Adafruit HTU31D test");
    if(!htu.begin(0x40)) {
        Serial.println("Couldn't find sensor!");
        while(1)
            ;
    }

    sensors_event_t humidity, temp;
    htu.getEvent(&humidity, &temp);
    Temperature_global = float(temp.temperature);
    Humidity_global = float(humidity.relative_humidity);

    timestamp = millis();

    // SETUP: Adafruit OLED Display
    display.begin(0x3C, true); // Address 0x3C default
    display.display();
    delay(10);
    display.clearDisplay();
    display.display();
    display.setRotation(1);

    button_a.attach(BUTTON_A, INPUT_PULLUP);
    button_a.interval(5);
    button_a.setPressedState(LOW);

    button_b.attach(BUTTON_B, INPUT_PULLUP);
    button_b.interval(5);
    button_b.setPressedState(LOW);

    button_c.attach(BUTTON_C, INPUT_PULLUP);
    button_c.interval(5);
    button_c.setPressedState(LOW);

    display.setTextSize(1);
    display.setTextColor(SH110X_WHITE);

    display.setCursor(0, 0);
    display.print("LoRa: Not connected");
    display.setCursor(0, 10);
    display.print("Temp:");
    display.setCursor(35, 10);
    display.print(Temperature_global);
    display.setCursor(0, 20);
    display.print("Hum:");
    display.setCursor(35, 20);
    display.print(Humidity_global);
    display.setCursor(0, 30);
    display.print("GPS:  Not connected");
    display.setCursor(0, 40);

    display.display();

    // SETUP SD-Card
    Serial.print("Initializing SD card...");
    if(!SD.begin(chipSelect)) {
        Serial.println("Initialization of SD card failed.");
        while(true)
            ;
    }
    Serial.println("initialization done.");

    // SETUP: LoRa
    Serial.println(F("Start LoRa OTAA"));
    os_init();
    LMIC_reset();
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
    LMIC_setLinkCheckMode(0);
    LMIC_setAdrMode(1);
    // FIXME TX Power
    TX_Power();
    // LMIC.dn2Dr = DR_SF12;        // So geht es mit einem fremden Gateway
    // LMIC_setDrTxpow(DR_SF11, 4); // So geht es mit einem fremden Gateway

    do_send(&sendjob);

    // SETUP: GPS
    GPS.begin(9600);
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
    GPS.sendCommand(PGCMD_ANTENNA);
    GPSSerial.println(PMTK_Q_RELEASE);
}

void LED_Blink_Gelb() {
    if(millis() > Timeout2 + Timer2) {
        Timer2 = millis();
        if(led_stat == false) {
            led_stat = true;
            analogWrite(LED_Rot, 0);
            analogWrite(LED_Gruen, 0);
            analogWrite(LED_Blau, 0);
        } else {
            led_stat = false;
            analogWrite(LED_Rot, 2);
            analogWrite(LED_Gruen, 2);
            analogWrite(LED_Blau, 0);
        }
    }
}

// STUB: loop
void loop() {
    if(millis() > TimeoutJoin + TimerJoin) {
        TimerJoin = millis();
        Serial.print("Join_State: ");
        Serial.println(join_state);
        if(join_state == false) {
            LED_RotEin();
            JoinVersuch();
        }
    }

    if(millis() > Timeout + Timer) {
        Timer = millis();
        TempLuftfeuchtigkeit();
        CreateLogEntry(join_state);
    }

    htu_Heater();

    // GPS_Adafruit();
    GPS_Adafruit();

    // LOOP: Button
    button_a.update();
    button_b.update();
    button_c.update();

    if(button_a.pressed()) { JoinVersuch(); }
    if(button_b.pressed()) { Serial.write(12); }
    if(button_c.pressed()) { Serial.println("Knopf C wurde gedrückt"); }

    Tastatur_abfragen();

    yield();

    // LOOP Lora
    os_runloop_once();
}

“There can be only one” - as says my older relative.

So, you have a nicely complicated bit of code - to which we strongly recommend you revert to no sensors, no complications, the out of the box LMIC TTN OTAA example.

There is an art to the LMIC loop and yours is rather busy - when you want to to do LMIC, there should be a state machine that ONLY allows the os_runloop_once() when it has work to do, otherwise you can upset the very sensitive timings for such things as receiving the Join Accept.

For any further debugging, we will need to know EXACTLY what board you are using and if you aren’t using LMIC 4.1, why not.

Thank you for the advise @descartes
Sure it’s better for troubleshooting.

Therefore I’ve gone back to the ttn-otaa.ino program, taken from the example folder in the library.
I’m using the latest version of the LMIC library (mcci-catena/MCCI LoRaWAN LMIC library @ ^4.1.0).
The code is running on a Teensy 3.2 and I use this LoRa module from Adafruit.

Because I use Visual Studio Code together with platformio instead of the Arduino IDE, I had to add 2 more includes. Otherwise I’ve got some errors when compiling.

The program in this state is also available in GitLab with branch = Bare-minimum:

For testing I have removed every component except the LoRa module.
Unfortunately I have exact the same result as before. Communication is working but no key exchange.

I know that the module is working, because when I turn off my gateway then it connects to another gateway in my neighbor town and key exchange is done and the payload is successfully sent.

Added:

#include <Arduino.h>
#include <Wire.h>

Changes made in the program:

  • APPEUI
  • DEVEUI
  • APPKEY
  • baudrate
  • Pin mapping

Data from the gateway:

"rssi": -121,
"channel_rssi": -121,
"snr": 0.5,

Details:

platformio.ini

[env:BareMinimum]
platform = teensy
board = teensy31
framework = arduino
monitor_speed = 115200
upload_port = /dev/cu.usbmodem93048701
monitor_port = /dev/cu.usbmodem93048701

lib_deps =
mcci-catena/MCCI LoRaWAN LMIC library @ ^4.1.0 ; LoRa
; mikalhart/TinyGPSPlus @ ^1.0.2 ; GPS
; adafruit/Adafruit GPS Library @ ^1.5.4 ; GPS
; thomasfredericks/Bounce2 @ ^2.70 ; Bounce
; jchristensen/Timezone @ ^1.2.4 ; Timezone
; adafruit/Adafruit HTU31D Library @ ^1.1.0 ; HTU31D
; adafruit/Adafruit SH110X @ ^2.1.3 ; Für OLED Display
; adafruit/Adafruit GFX Library @ ^1.10.12 ; Für OLED Display
; paulstoffregen/Time @ ^1.6.1 ; Für OLED Display
; adafruit/Adafruit Unified Sensor @ ^1.1.4 ; Für OLED Display

; *** Für MCCI Library ***
build_flags =
-D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS
-D CFG_eu868=1
-D CFG_sx1276_radio=1

; extra_scripts = upload_with_tycmd.py
; upload_protocol = custom
; upload_flags = --board

full coding

// clang-format off
#include <Arduino.h>
#include <Wire.h>
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

static const u1_t PROGMEM APPEUI[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

static const u1_t PROGMEM DEVEUI[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

static const u1_t PROGMEM APPKEY[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}

static uint8_t mydata = “Hello, world!”;
static osjob_t sendjob;

const unsigned TX_INTERVAL = 30;

// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = 10,
.rxtx = LMIC_UNUSED_PIN,
.rst = 14,
.dio = {4, 5, 6},
};

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

void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F(“EV_SCAN_TIMEOUT”));
break;
case EV_BEACON_FOUND:
Serial.println(F(“EV_BEACON_FOUND”));
break;
case EV_BEACON_MISSED:
Serial.println(F(“EV_BEACON_MISSED”));
break;
case EV_BEACON_TRACKED:
Serial.println(F(“EV_BEACON_TRACKED”));
break;
case EV_JOINING:
Serial.println(F(“EV_JOINING”));
break;
case EV_JOINED:
Serial.println(F(“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;
/*
|| 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:
Serial.println(F(“EV_JOIN_FAILED”));
break;
case EV_REJOIN_FAILED:
Serial.println(F(“EV_REJOIN_FAILED”));
break;
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.print(LMIC.dataLen);
Serial.println(F(” bytes of payload”));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F(“EV_LOST_TSYNC”));
break;
case EV_RESET:
Serial.println(F(“EV_RESET”));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F(“EV_RXCOMPLETE”));
break;
case EV_LINK_DEAD:
Serial.println(F(“EV_LINK_DEAD”));
break;
case EV_LINK_ALIVE:
Serial.println(F(“EV_LINK_ALIVE”));
break;
/

|| 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.println(F(“EV_TXSTART”));
break;
case EV_TXCANCELED:
Serial.println(F(“EV_TXCANCELED”));
break;
case EV_RXSTART:
/
do not print anything – it wrecks timing */
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F(“EV_JOIN_TXCOMPLETE: no JoinAccept”));
break;

    default:
        Serial.print(F("Unknown event: "));
        Serial.println((unsigned) ev);
        break;
}

}

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 {
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
Serial.println(F(“Packet queued”));
}
// Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
while(!Serial && millis() < 4000) { ; }
Serial.begin(115200);
Serial.println(F(“Starting”));

#ifdef VCC_ENABLE
// For Pinoccio Scout boards
pinMode(VCC_ENABLE, OUTPUT);
digitalWrite(VCC_ENABLE, HIGH);
delay(1000);
#endif
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();

// Start job (sending automatically starts OTAA too)
do_send(&sendjob);

}

void loop() {
os_runloop_once();
}

Dummy Antenna
Gateway

Node
Top View


Schematic:
Unfortunately the schematic seems not to be loading. Alternate place is in the GitLab repository linked above.
![Schematic|1000x706](upload://o831qGyhQeoJPEXmjG48yDAywYx.png)

I have now also tested with another LoRa module. Same type but a fresh one, which I never have used before. With the new module, I can turn off my own gateway and reach a gateway which is 3km away from me.
Also with the same result.

If someone has any Idea what I can check further I would aprechiate that.

Sorry. A correction. It worked a few moments later. I had to wait until it tried to connect with SF9BW125.
I try it now once again with my own gateway and the dummy load antenna.

Hi

Finally everything works.
The culprit was the packet forwarder.
I have installed the software according to this “howto”.
I tought that this would be okay because I have exactly this module from PiSupply.

I have then installed the packet forwarder directly from LoRa®️ · GitHub and suddenly I have nice and stable connections. I don’t even have to use the dummy load antenna. It works right away with the normal antenna and with 3 meter distance.

Later I think I write to PiSupply that they should point directly to the Lora-net repository or that they should update thei’re fork.

Very happy that it works now.

3 Likes

Excellent detail on the device, just that small wrinkle in your notes that it actually works and it your gateway doesn’t!

It may seem not, but you are still shouting in to the gateay’s receiver stage and it will end up with Mosh Pit Tinnitus. So keep the dummy load in place.

As they still sell the RAK HAT and others (including me) have been inconvenienced by the non-update of their software, feel free to be emphatic!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.