Zusammenfassung #
LoRa - Verbindungsaufbau zum Gateaway #
Um eine Verbindung zu einem Gateway (vermutet ist das nächstgelegene, dies ist aber nicht immer der Fall) aufzubauen, wird eine Antenne genutzt, wobei die Verwendung verschiedener Antennen natürlich Unterschiede in der Reichweite zur Folge hat. Im einfachsten Fall, dass wie bei uns direkter Sichtkontakt zum Gateway besteht, sollte allerdings so ziemlich jede Antenne funktionieren, aber solch kurze Distanz ist wohl meistens nur bei Testzwecken der Fall.
Für Interessierte zu möglichen Reichweiten und einem Rekordversuch dahingehend gibt es hier ein Video verlinkt :)
Implementierung für das Senden von Daten #
Allgemeines #
Für eine einfache Testverbindung kann die Beispielimplementierung SendReceive.ino aus der Heltec Bibliothek mit Authentifikation über OTAA verwendet werden. Für unsere Zwecke muss das Programm ein wenig abgeändert werden, dazu im Folgenden mehr.
Gateway Heatmap mit TTN-Mapper #
Mit der App TTN-Mapper kann man auf einer Karte (einer sogenannten Heatmap) die Anzahl an Gateways in der Umgebung, sowie die Empfangsstärke darstellen. Somit können wir z.B. den Empfang von Gateways in Dresden anschauen und mit unseren eigens empfangenen Daten mit den allgemein zugänglichen der Heatmap vergleichen. Damit dies funktioniert, muss sich der Mikrocontroller zu einem Gateway verbinden und Daten mit diesem austauschen.
Da die Daten aus der TTN Cloud kommen, verwendet TTN-Mapper die MQTT Schnittstelle der TTN Cloud. In der TTN-Mapper App muss das verbundene Gerät mit den Daten der TTN Cloud eingerichtet werden. Dafür geht man auf Settings > Link a new device > The Things Stack (v3)
und gibt die Daten für MQTT und das Endgerät (zu finden auf der Seite vom TheThingsNetwork) ein.
Wenn der Datenaustausch erfolgreich war, werden sowohl die GPS-Daten des Handy-Standortes für die Heatmap, sowie Metadaten wie Empfangsstärke und Position des Gateways gemappt.
Im einfachsten Falle sind die Daten einfach Zahlen von einem Counter. Dies kann man mit dem Programm SendReceive.ino leicht implementieren. Dazu verwendet man eine Counter-Variable, welche bei jedem Sendevorgang ihren Wert erhöht und den aktuellen Wert an ein Gateway sendet.
static uint8_t counter = 0;
loop() {
// just some dummy data we send for the example
counter++;
if (LoRaWAN.send(1, &counter, 1, requestack)) {
Serial.println("Send OK");
} else {
Serial.println("Send FAILED");
}
}
Der komplette Prozess ausführlicher und mit Bildern ist in unserem Entwicklertagebuch unter diesem Eintrag zu finden.
Programmbeispiel #
Wir verwenden die Bibliothek Wire.h
für die Kommunikation mit I2C/TWI Geräten, dazu sind weitere Informationen unter
https://www.arduino.cc/reference/en/language/functions/communication/wire/
zu finden. Im Header des Examples SendReceive.ino muss die Bibliothek mittels
#include <Wire.h>
eingebunden werden.
Die OTAA Parameter für das TTN können in der TTN Cloud eingesehen werden
static uint8_t devEui[] = { 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x05, 0x75, 0xC7 };
static uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t appKey[] = { 0x8F, 0x20, 0xAA, 0x14, 0x80, 0x12, 0x6D, 0x02, 0x44, 0x7C, 0xEA, 0xBA, 0x9E, 0xB5, 0x20, 0x69 };
Diese werden dann im setup()
verwendet, um dem Netzwerk beizutreten.
LoRaWAN.joinOTAA(appEui, appKey, devEui);
Eine Prüfung über Erfolg oder Misserfolg kann folgendermaßen geschehen:
if (LoRaWAN.isJoined()) { ... }
War das joinen erfolgreich, können nun Daten gesendet werden.
LoRaWAN.send(sizeof(dataP), &dataP, 1, false)
Diese Beschreibung ist nur eine Übersicht über die generelle Funktionsweise und den allgemeinen Ablauf, mehr dazu im Abschnitt Sensordaten oder im Programm SendReceive.ino.
RGB #
Wenn LoraWan_RGB auf Active gesetzt ist können zusätzlich folgende Farbcodes der LED für den momentanen Status ausgelesen werden:
RGB | State |
---|---|
rot | sending |
lila | join done |
blau | RxWindow1 |
gelb | RxWindow2 |
grün | receive done |
Einstellungen in der Arduino IDE #
In der Arduino IDE muss neben dem korrekten Programm zum Senden auch die für die Region korrekte Sendefrequenz des Mikrocontrollers eingestellt werden. Dies kann man unter Tools -> LORAWAN_REGION
tun. Für Europa sollte die Region REGION_EU868
ausgewählt werden, damit sendet der Mikrocontroller auf der für Europa üblichen Frequenz von 868 MHz.
Die vom Controller gesendeten Daten kann man dann in der TTN Konsole sehen:
Bei Problemen mit dem Programm kann auch der Debugger unter Tools -> LoRaWan Debug Level
genutzt werden. Damit kann man z.B. herausfinden, auf welcher Frequenz der Controller ohne Voreinstellungen sendet.
Da man bei einem Versuchsaufbau aber nicht immer davon ausgehen kann, dass der Fehler in der Software liegt und man ggf. mit fehlerhafter Hardware rechnen muss: Hier ein Eintrag aus dem Entwicklertagebuch aus dem Laborbereich der HTW Dresden.
I2C Verbindungstest #
Zur Überprüfung der Verbindung zwischen Mikrocontroller und Sensor verwenden wir das Codebeispiel isConnected.ino.
Das setup()
für I2C Devices sieht dann im Groben folgendermaßen aus:
#include <I2C.h>
#include <Wire.h>
void setup() {
I2C_Start();
Wire.begin();
}
Der hier zusehende Vext Pin
wird mit folgendem Code angesteuert. Dabei wird nur in diesem Falle der Output geliefert. sendet die Daten und geht schlafen
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW); // oder HIGH
Im fertigen Programm später wird
- der Mikrocontroller mit dem TTN_Netzwerk verbunden
- der Vext-Pin wird eingeschalten
- der Controller liest die Sensordaten
- der Vext-Pin wird ausgeschalten
- der Controller geht schlafen
Zum Testen, welche Adressen erreichbar sind, beginnen wir eine Übertragung zu allen möglichen Adressen und testen, welche erreichbar sind. Die Funktion endTransmission()
beendet die Übertragung zu der Adresse, die mit beginTransmission()
angesteuert wurde und gibt einen Fehlercode != 0 zurück, wenn die Übertragung nicht erfolgreich war. An allen Adressen mit Fehlercode 0 wurde dementsprechend ein I2C Device gefunden.
#include <Wire.h>
for(byte address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address");
Serial.println(address, HEX);
}
}
Sensordaten #
Ist nun ein Sensor angeschlossen und es können Daten gelesen werden, brauchen wir für diese eine Struktur für das Datenpaket, sowie die Daten selber. Allerdings mussten wir bei der Implementierung feststellen, dass die Bibliothek Wire.h
beispielsweise beim SHT21-Sensor Probleme mit der Übertragung hatte, obwohl sie beim Sensor TSL2561 funktionierte. Daher verwenden wir einen HTU21-Sensor mit der SparkFunHTU21D Bibliothek.
#include "SparkFunHTU21D.h"
struct DataPackage {
float temperature;
float humidity;
};
DataPackage dataP;
HTU21D myHumidity;
Den loop()
von oben können wir nun ergänzen und die Luftfeuchtigkeit und die Temperatur einlesen.
myHumidity.begin();
dataP.humidity = myHumidity.readHumidity();
dataP.temperature = myHumidity.readTemperature();
Wire.end();
Wenn ein Fehler auftritt kann dieser folgendermaßen erkannt werden:
if (dataP.temperature == ERROR_I2C_TIMEOUT) {
Serial.print("i2c timeout");
} else if (dataP.temperature == ERROR_BAD_CRC) {
Serial.print("bad crc");
}
Wenn kein Fehler aufgetreten ist können die Daten gesendet werden.
if (LoRaWAN.send(sizeof(dataP), &dataP, 1, false)) {
Serial.println("Send OK");
} else {
Serial.println("Send FAILED");
}
Der Payload besteht aus 4 Bytes für die Feuchtigkeit und 4 Bytes für die Temperatur
Das komplette Programm findet man hier.