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:
This is a recording of one join request.
One time on the gateway side and one time on the node side.
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();
}