Skip to Content

LoRaWAN mit Thinknode G1 Gateway

LoRaWAN mit Thinknode G1 Gateway

In diesem Beitrag zeige ich dir, wie du Daten mit LoRaWAN mit dem Thinknode G1 Gateway sendest. LoRa (Long Range) ist eine drahtlose Methode, um kleine Datenmengen über viel größere Entfernungen (mehrere Kilometer) zu übertragen, als es beispielsweise mit WiFi oder Bluetooth möglich ist.

LoRaWAN ist ein Übertragungsprotokoll, das LoRa verwendet. Es ermöglicht den Aufbau komplexer IoT-Systeme mit sicherer Kommunikation zwischen Geräten und Cloud-Anwendungen. Wenn du Sensoren über das Internet überwachen möchtest, ist LoRaWAN genau das Richtige.

Die Endgeräte (Sensoren) senden ihre Daten an ein Gateway, das diese an einen Netzwerkserver weiterleitet. Ein Anwendungsserver kann dann auf den Netzwerkserver zugreifen, um die Daten zu verarbeiten, z. B. um einen Graphen mit Temperaturdaten anzuzeigen.

LoRaWAN Architecture
LoRaWAN-Architektur (source)

Beachte, dass die Sensoren ihre Daten über LoRa an das Gateway senden, während das Gateway über eine Wi-Fi-, Ethernet- oder Mobilfunkverbindung mit dem Netzwerkserver kommuniziert. Das Gateway ist im Wesentlichen eine Brücke zwischen LoRa und dem Internet.

In den folgenden Abschnitten verwenden wir einen ESP32 mit einem SX1276 LoRa-Modul, um Umweltdaten wie Temperatur und Luftfeuchtigkeit, gemessen mit einem BME280, über LoRaWAN über ein Thinknode G1 Gateway zu übertragen.

Wir verbinden dieses Gateway mit einem Netzwerkserver auf dem The Things Network, wo du die Umweltdaten überwachen oder von einer Internetanwendung zur weiteren Verarbeitung abrufen kannst.

Lass uns loslegen!

Benötigte Teile

Ich habe einen ESP32 Lite als Mikroprozessor für den LoRa-Knoten verwendet, aber jeder andere ESP32 funktioniert ebenfalls gut. Wenn du einen Arduino oder einen anderen Mikroprozessor verwenden möchtest, benötigst du ein Board, das mit 3,3 V läuft.

Achte beim SX1276 LoRa-Transceiver-Modul darauf, welche Version du kaufst! Depending on the country die erlaubten Frequenzen sind unterschiedlich. In Europa sind es 868 MHz, in Nordamerika 915 MHz und in Asien 433 MHz.

Die Modulbeschreibung listet entweder die Frequenz auf oder enthält eine Zahl wie 868 oder 915 im Namen. Ich habe ein Modul mit 868 MHz verwendet, da ich in Europa bin. Du kannst dieses Modul aber auch für das 915-MHz-Band bekommen.

Stelle ebenso sicher, dass das von dir verwendete LoRaWAN-Gateway im erforderlichen Frequenzband arbeiten kann. Das unten aufgeführte ThinkNode G1 Gateway unterstützt die Frequenzen 868 MHz und 915 MHz.

Für den Umweltsensor habe ich den BME280 gewählt, der Temperatur, Luftfeuchtigkeit, Luftdruck und Höhe messen kann. Achte darauf, die 3,3-V-Version zu kaufen, da wir ihn an den ESP32 anschließen werden.

ThinkNode G1 LoRaWAN Gateway

LoRa 868/915M Modul SX1276

ESP32 lite Lolin32

ESP32 Lite

USB data cable

USB-Datenkabel

BME280

BME280 Sensor

Dupont wire set

Dupont-Kabelsatz

Half_breadboard56a

Breadboard

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Was ist LoRaWAN?

LoRaWAN steht für Long Range Wide Area Network. Es ist ein drahtloses Protokoll, das speziell für das Internet der Dinge (IoT) entwickelt wurde und es Geräten ermöglicht, über lange Distanzen – wir sprechen von mehreren Kilometern, auch in städtischen Gebieten – mit sehr geringem Energieverbrauch zu kommunizieren.

Im Gegensatz zu WiFi oder Bluetooth, die sich gut für Kurzstrecken- und hochbandbreiten Kommunikation eignen, geht es bei LoRaWAN um Reichweite und Effizienz. Ein Sensor sendet typischerweise nur kleine Datenpakete alle paar Minuten oder Stunden, kann aber jahrelang mit einer kleinen Batterie betrieben werden.

Es ist ideal für batteriebetriebene Geräte, die wenig Informationen senden, wie Temperatursensoren, GPS-Tracker oder Bodenfeuchtemesser, über Entfernungen, die Wi-Fi oder Bluetooth nicht erreichen können. Andererseits kannst du keine Bilder oder Videos über LoRa senden.

Angenommen, du hast einen Temperatursensor an einem abgelegenen Ort. Es gibt kein WiFi, aber du möchtest trotzdem alle 15 Minuten die Temperatur überwachen. Was machst du?

Du verbindest einen Temperatursensor mit einem ESP32, der an ein LoRa-Modul (wie das SX1276) angeschlossen ist. Es sendet die Daten drahtlos via LoRa an ein LoRaWAN-Gateway, in unserem Fall ein Thinknode G1. Dieses Gateway kann Signale von mehreren Sensoren in Kilometern Entfernung empfangen und leitet deren Daten an den Netzwerkserver weiter. Das Gateway ist im Grunde eine Brücke zum Web.

Du kannst deinen eigenen Netzwerkserver betreiben oder einen öffentlichen nutzen. Hier verwenden wir das The Things Network (TTN), eine kostenlose und Open-Source LoRaWAN-Infrastruktur. Von TTN aus können die Daten in einem Dashboard visualisiert, an einen Cloud-Dienst weitergeleitet oder genutzt werden, um andere Aktionen auszulösen – wie das Senden von Benachrichtigungen oder das Einschalten eines Ventilators. Da der Netzwerkserver in der Cloud läuft, können deine Daten von überall auf der Welt verarbeitet, visualisiert oder genutzt werden.

In den nächsten Abschnitten richten wir das Gateway ein, verbinden es mit The Things Network und bauen den LoRa-Endknoten mit einem ESP32 als Mikrocontroller, dem SX1276 als LoRa-Transceiver und dem BME280 als Umweltsensor.

Das ThinkNode G1 Gateway

ThinkNode G1 von Elecrow ist ein LoRaWAN-Innengateway, das für die Verbindung mit verschiedenen Netzwerkservern ausgelegt ist. Dieses Gateway unterstützt mehrere Verbindungsmethoden zur Konfiguration wie WiFi, Bluetooth und Ethernet. Es unterstützt 8-Kanal-Übertragung und nutzt LoRa-Funktechnologie für die Langstrecken-Datenübertragung.

ThinkNode G1 LoRaWAN Gateway (source)

Das Gateway ist mit einem SX1302 LoRa-Konzentrator und zwei SX1250 Chips ausgestattet und bietet 10 programmierbare parallele Demodulationspfade. Es unterstützt globale ISM-Frequenzbänder mit einem Frequenzbereich von 815 MHz bis 960 MHz.

Technische Spezifikationen

Die folgende Tabelle von der Elecrow Produktseite listet die technischen Details des Thinknode G1 Gateways auf:

ProzessorCPU/SoCMT7628N (MIPS24KEc@580MHz CPU)
Systemspeicher128 MB DDR2
Speicher32MB Nor Flash
KonfigurationssoftwareWEB
Kommunikation
Wi-FiUnterstützt IEEE 802.11 b/g/n Wireless-Standards, integrierte Antenne
KabelgebundenUnterstützt IEEE 802.3, IEEE 802.3u kabelgebundene Standards, RJ45 (10M / 100M)
Bluetooth-kompatibelBluetooth-kompatibler Dual-Mode (BR/EDR+BLE) 5.0 BLE, integrierte Keramikantenne
LoRaWANBasisband-ChipSX1302, verwendet LR1302 Basisband-Modul
Kanal8 Kanäle
KnotenprotokollUnterstützt Klasse A/Klasse B/Klasse C
FrequenzbandEU868/US915
Empfindlichkeit-125dBm @125KHz/SF7 -139dBm @125KHz/SF12
SendeleistungMaximal 26 dBm
Antenne1. Gummistabantenne (angepasst), 3dBi Gewinn, Impedanz 50 Ohm; 2. Externe Antenne mit Basis (optional), 3dBi Gewinn, Impedanz 50 Ohm;
Reserve-SchnittstelleDC-BuchseStromversorgung, DC 12V – 2A
EthernetRJ45 (10M / 100 M)
LoRa-AntennenanschlussRP-SMA Buchse
GPS-AntennenanschlussRP-SMA Buchse
Type-C SchnittstelleWird für Hintergrundsteuerung, Verbindung zum Hintergrundpanel zur Konfigurationsinformation oder Firmware-Flashen, Debugging verwendet
Micro SD-KartensteckplatzJA
Nano SIM-KartensteckplatzJA
Reserve-AnzeigeleuchteGerätestatusleuchteJA
4GJA (muss angepasst werden)
WLANJA
LoRaJA
PWRJA
TasteReset-Taste
Größe140*140*38mm
GehäusematerialABS+PC (Gehäuse), PC mattiert (Lichtleiter)
Stromeingang12V-2A
Betriebstemperatur-20℃~55℃
Lagertemperatur-30℃~70℃

Für weitere Informationen siehe die ThinkNode G1 Datasheet.

Anzeigeleuchten

Der Thinknode G1 hat fünf Anzeigeleuchten. Die vier an der Vorderseite zeigen an, ob das Gateway Strom hat und mit LoRa, WLAN oder LTE verbunden ist. Das Foto unten zeigt die Oberseite des G1 mit den vier Anzeigeleuchten an der Vorderseite des Gehäuses:

Indicator lights of the Thinknode G1
Anzeigeleuchten des ThinkNode G1 (source)

Die große, y-förmige LED-Anzeige oben kann in verschiedenen Farben und Blinkfrequenzen leuchten. Die folgende Tabelle beschreibt die Bedeutung der verschiedenen Signale:

LED Indicator Description for Thinknode G1
LED-Anzeigenbeschreibung für ThinkNode G1 (source)

Anschlüsse

Auf der Rückseite des Thinknode G1 findest du die Anschlüsse für die Stromversorgung, Ethernet (ETH), USB-C, die LoRa-Antenne sowie Steckplätze für eine Micro SD- und eine Nano SIM-Karte:

Connectors of the Thinknode G1
Anschlüsse des ThinkNode G1 (source)

Ebenfalls auf der Rückseite befindet sich eine Taste zum Neustarten oder zum Wechseln in den Konfigurationsmodus. Die folgende Tabelle beschreibt, wie man zwischen den Modi wechselt:

Button Description for Thinknode G1
Tastenbeschreibung für ThinkNode G1 (source)

Hardware einrichten

Zuerst die Antenne anschließen und dann die Stromversorgung. Die Power-LED sollte grün leuchten und die obere Anzeige rot, bis das Gateway richtig konfiguriert ist.

Hardware-Setup für ThinkNode G1 (source)

Zur Konfiguration kannst du dich über ein Ethernet-Kabel (ETH) oder WLAN mit dem Gateway verbinden. Das User Manual des ThinkNode G1 beschreibt beide Methoden. Im nächsten Abschnitt zeige ich dir, wie ich die Software des ThinkNode G1 über die WLAN-Verbindung konfiguriert habe.

Software-Konfiguration

Um über Wi-Fi zu konfigurieren, halte die Taste auf der Rückseite des ThinkNode G1 gedrückt, bis die LED-Anzeige oben blau wird (das dauert etwa 5 Sekunden):

Login zur Benutzeroberfläche

Scanne dann dein WLAN-Netzwerk nach einem neuen Access Point namens ThinkNode-G1_XXXXXX und verbinde dich damit:

Öffne anschließend deinen Browser und gehe zur IP-Adresse 192.168.1.1. Du solltest einen Login-Bildschirm sehen, wo du „root“ als Benutzername und auch als Passwort eingibst:

Mit WLAN verbinden

Um das Gateway mit deinem WLAN zu verbinden, gehe zu Network -> Wireless

und klicke auf Scan, um nach deinem WLAN-Netzwerk zu suchen:

Wähle in der Liste dein WLAN-Netzwerk aus und gib im folgenden Dialog das Passwort ein, um darauf zuzugreifen.

LoRaWAN konfigurieren

Als Nächstes müssen wir die LoRa-Schnittstelle und Frequenz konfigurieren. Gehe zu LoRaWAN -> LoRa Gateway

Wähle im folgenden Dialog WIFI als LoRa-Schnittstelle und EU868 als Frequenzplan für Europa. In Nordamerika musst du US915 auswählen. Setze den LoRa-Modus auf Packet Forwarder:

(Alternativ, wenn du das Gateway als Basisstation konfigurieren möchtest, schau dir das Webtutorial an).

Lass die anderen Parameter unverändert, aber stelle sicher, dass die Serveradresse auf eu1.cloud.thethings.network gesetzt ist (wenn du in Europa lebst). Wir benötigen sie, um das Gateway mit The Things Network zu verbinden.

Drücke abschließend auf Speichern & Anwenden, was das Gateway neu startet, und wenn du Glück hast, war es das.

Ich hatte jedoch Probleme und musste auch den DNS-Server eingeben, sonst konnte sich mein G1 nicht mit The Things Network verbinden.

DNS-Server

Um den DNS-Server hinzuzufügen oder zu bearbeiten, gehe zu Network -> Interfaces und klicke auf Bearbeiten für das LAN:

Klicke im Dialog auf den Tab Erweiterte Einstellungen und bearbeite die Felder für benutzerdefinierte DNS-Server:

Ich habe 8.8.8.8 (Google) und 1.1.1.1 (Cloudflare) als DNS-Server hinzugefügt, und schließlich hat sich mein Gateway mit The Things Network verbunden.

Gateway mit The Things Network verbinden

The Things Network (TTN) bietet dir einen öffentlichen Netzwerkserver, der es erlaubt, Sensordaten von einem LoRa-Gerät, z. B. Temperatur, an eine Webseite zu senden, wo du die Daten ansehen oder mit einer Webanwendung verarbeiten kannst.

Der erste Schritt ist, unser ThinkNode G1 Gateway mit TTN zu verbinden. Gehe zur folgenden URL: https://eu1.cloud.thethings.network/console/, klicke auf den blauen Hinzufügen-Button und wähle Neues Gateway hinzufügen:

Gib deine Gateway EUI ein, die auf der Rückseite des ThinkNode G1 Gateways aufgedruckt ist oder auf der Statusseite der Konfigurations-UI des Gateways zu finden ist. Nach Eingabe der EUI drücke Bestätigen:

Das Dialogfeld erweitert sich, und du kannst eine eindeutige Gateway-ID eingeben, z. B. die EUI des Gateways mit dem Präfix ‚eui‘ und einen Gateway-Namen. Für diesen Test habe ich Maet-ThinkNode-G1 gewählt. Du musst auch einen Frequenzplan auswählen, der zur Frequenz deines Gateways passt (für Europa 863-870 MHz), zum Beispiel:

Lass alles andere unverändert und klicke auf Gateway registrieren. Wenn alles korrekt funktioniert, siehst du eine Statusseite mit grünem Gateway-Status, der anzeigt, dass das Gateway verbunden ist:

Wenn du so weit gekommen bist, Glückwunsch. Das Schlimmste sollte vorbei sein ; )

Eine Anwendung erstellen

The Things Network (TTN) organisiert Endgeräte (Sensoren, Aktoren) in sogenannten „Applications“. Ihre Aufgabe ist es, Daten zu dekodieren und optional über Webhooks oder MQTT an externe Server weiterzuleiten.

Applications, Gateways und Endgeräte interagieren wie folgt: Das Endgerät sendet Daten (Uplink) via LoRa. Das Gateway empfängt die Daten und leitet sie an TTN weiter. Schließlich leitet der TTN-Netzwerkserver die Daten anhand der DevEUI des Geräts an eine bestimmte Application weiter.

[End Device] ←→ [Gateway] ←→ [TTN Network Server] ←→ [Application]

Bevor wir also Sensordaten auf TTN empfangen und überwachen können, müssen wir eine Application erstellen. Gehe dazu zu https://eu1.cloud.thethings.network/console/applications/add, was den folgenden Dialog öffnet:

Gib dort eine Application ID ein, z. B. env-sensor-network und einen Application-Namen, z. B. Environmental Sensors wie oben gezeigt.

Endgerät registrieren

Als Nächstes fügen wir unser Endgerät hinzu und registrieren es. Auf der Seite deiner Application (https://eu1.cloud.thethings.network/console/applications/env-sensor-network) solltest du ein Feld mit einem blauen Button „+ Register end device“ sehen:

Drücke diesen Button, und du erhältst den folgenden Dialog:

Gib die Daten für dein Endgerät ein, vor allem den Frequenzplan, die LoRaWAN-Version und die JoinEUI. Die JoinEUI (früher AppEUI genannt) ist eine Nummer im folgenden Format: 70B3D57EDxxxxxxx. Ersetze ‚xxxxxxx‘ durch eine Hex-Zahl, um eine eindeutige JoinEUI für dein Endgerät zu erstellen, z. B. 70B3D57ED0000001.

Klicke danach auf den Bestätigen Button rechts, der den Dialog erweitert und dir erlaubt, eine DevEUI und einen AppKey zu generieren. Schließlich musst du deinem Endgerät eine eindeutige ID geben:

Drücke Register end device und du solltest die Informationen für das erstellte Gerät sehen:

Die wichtigsten Informationen sind AppEUI, DevEUI und AppKey. Diese Zugangsdaten benötigst du im Code für das Endgerät. Sie ermöglichen dem Endgerät, sich bei The Things Network zu authentifizieren.

LoRaWAN-Endgerät mit SX1276 und ESP32 bauen

Du kannst viele vorgefertigte LoRaWAN-Geräte mit verschiedenen Sensoren und Funktionen kaufen, aber sie sind teuer. Eine Übersicht findest du im Device Repository for LoRaWAN von The Things Network. In diesem Tutorial bauen wir unser eigenes Endgerät, was nicht schwer und viel günstiger ist ; )

Wir verwenden einen ESP32 als Mikrocontroller und ein SX1276 Transceiver-Modul, um Daten via LoRa zu übertragen. Wenn du mehr Hintergrundinformationen zum SX1276 brauchst, siehe das Long range communication with LoRa SX1276 and ESP32 Tutorial. Im Folgenden halte ich es kurz und zeige dir nur, wie du den SX1276 mit dem ESP32 verbindest. Hier die Verbindungstabelle:

SX1276ESP32
MOSI23
MISO19
SCK18
RST17
NSS5
DIO04
DIO116
GNDGND
VCC3.3V

Achte darauf, dass du VCC an den 3,3V-Ausgangspin deines ESP32 anschließt. Neben der SPI-Schnittstelle (MOSI, MISO, SCK, RST, NSS) sind auch die digitalen IO-Verbindungen an den Pins DIO0 und DIO1 wichtig. Das Bild unten zeigt das vollständige Schaltbild:

Connecting SX1276 to ESP32
Anschluss SX1276 an ESP32

Wie bereits erwähnt, musst du ein SX1276 Transceiver-Modul verwenden, das auf dem LoRa frequency that is permitted in your country arbeitet. Im obigen Schaltbild ist der SX1276 mit 868M gekennzeichnet, was bedeutet, dass er das 868-MHz-Band für Europa nutzt. Für Nordamerika benötigst du ein 915-MHz-Modul.

Die Frequenz des SX1276, des Gateways und die Einstellungen bei The Things Network müssen alle übereinstimmen! In meinem Fall sind sie alle auf 868 MHz eingestellt.

Testdaten via LoRaWAN senden

Jetzt schreiben wir den Code, um Testdaten von unserem Endgerät (ESP32 + SX1276) via LoRaWAN an TTN zu senden.

Zuerst musst du jedoch eine Bibliothek für LoRaWAN installieren, und wir verwenden die MCCI LoRaWAN LMIC library. Öffne einfach den LIBRARY MANAGER, suche nach „mcci lorawan lmic library“ und klicke auf INSTALLIEREN. Das Bild unten zeigt eine erfolgreiche Installation:


Installing MCCI LoRaWAN LMIC library
Installation der MCCI LoRaWAN LMIC Bibliothek

LoRaWAN definiert drei Gerätekategorien: Klasse A, Klasse B und Klasse C, die jeweils unterschiedliche Kompromisse zwischen Stromverbrauch und Downlink-Verfügbarkeit bieten. Klasse A ist der Standard und der energieeffizienteste Modus, bei dem ein Gerät nur in zwei kurzen Fenstern nach dem Senden eines Uplinks Downlink-Nachrichten empfangen kann. Diese Klasse ist ideal für batteriebetriebene Sensoren und wird von der LMIC-Bibliothek vollständig unterstützt.

Klasse B fügt geplante Empfangsfenster mit periodischen Beacons hinzu, die vom Gateway gesendet werden, was einen vorhersehbareren Downlink-Zugang auf Kosten eines höheren Stromverbrauchs ermöglicht. Klasse C Geräte halten ihre Empfangsfenster fast ständig offen, was eine latenzarme Downlink-Kommunikation erlaubt, aber eine konstante Stromversorgung erfordert (z. B. netzbetriebene Geräte). Die LMIC-Bibliothek unterstützt jedoch nur Klasse A.

Bibliothekskonfiguration

Als Nächstes müssen wir die LMIC-Bibliothek für die LoRa-Frequenz, Version und den Chip konfigurieren, den wir verwenden. Die LMIC-Bibliothek enthält eine Datei lmic_project_config.h, die du typischerweise unter folgendem Windows-Pfad findest:

...\OneDrive\Documents\Arduino\libraries\MCCI_LoRaWAN_LMIC_library\project_config

Öffne diese Datei und bearbeite ihren Inhalt wie unten gezeigt:

#define CFG_eu868 1
//#define CFG_us915 1
//#define CFG_au915 1
//#define CFG_as923 1
//#define CFG_kr920 1
//#define CFG_in866 1

#define CFG_sx1276_radio 1
//#define CFG_sx1261_radio 1
//#define CFG_sx1262_radio 1

//#define ARDUINO_heltec_wifi_lora_32_V3
//#define LMIC_USE_INTERRUPTS

#define LMIC_LORAWAN_SPEC_VERSION    LMIC_LORAWAN_SPEC_VERSION_1_0_3

Wenn du nicht in Europa lebst, musst du die LoRa-Frequenz für dein Land auswählen (Europa -> CFG_eu868, Nordamerika -> CFG_us915, …). Achte darauf, alle anderen Frequenzen auszukommentieren.

Wir verwenden den SX1276 Chip, daher definieren wir auch CFG_sx1276_radio 1. Wenn du einen anderen LoRa-Chip verwendest, musst du das hier ebenfalls ändern.

Code zum Senden von Daten mit LoRaWAN

Der folgende Code sendet jede Minute einen Zählerwert als String, z. B. „Counter = 5“ von unserem Endgerät (ESP32 + SX1276) über das ThinkNode Gateway an TTN, wo wir ihn später ansehen können. Schau dir den Code kurz an, bevor wir die Details besprechen:

#include <lmic.h>
#include <hal/hal.h>


static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui(u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
                                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static osjob_t sendjob;

const unsigned TX_INTERVAL = 60;  // Send every minute

const lmic_pinmap lmic_pins = {
  .nss = 5,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 17,
  .dio = { 4, 16, LMIC_UNUSED_PIN }
};


void onEvent(ev_t ev) {
  Serial.printf("%d: ", os_getTime());
  switch (ev) {
    case EV_JOINING:
      Serial.println("EV_JOINING");
      break;
    case EV_JOINED:
      Serial.println("EV_JOINED");
      LMIC_setLinkCheckMode(0);
      break;
    case EV_JOIN_FAILED:
      Serial.println("EV_JOIN_FAILED");
      break;
    case EV_TXCOMPLETE:
      Serial.println("EV_TXCOMPLETE");
      if (LMIC.dataLen) {
        Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
        Serial.print("> Data: ");
        for (int i = 0; i < LMIC.dataLen; i++) {
          Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
        }
        Serial.println();
      }
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    case EV_TXCANCELED:
      Serial.println("EV_TXCANCELED");
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println("EV_JOIN_TXCOMPLETE: no JoinAccept");
      break;
    default:
      Serial.print("Unknown event: ");
      Serial.println((unsigned)ev);
      break;
  }
}

void do_send(osjob_t* j) {
  static uint16_t counter = 0;
  static char mydata[25];

  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    snprintf(mydata, sizeof(mydata), "Counter = %u", counter);
    LMIC_setTxData2(1, (uint8_t*)mydata, strlen(mydata), 0);
    Serial.printf("> Data: %s\n", mydata);
    counter++;
  }
}

void setup() {
  Serial.begin(115200);
  os_init_ex(&lmic_pins);
  LMIC_reset();
  do_send(&sendjob);
}

void loop() {
  os_runloop_once();
}

Bibliotheken

Der Code beginnt mit dem Einbinden der benötigten LMIC-Bibliotheken:

#include <lmic.h>
#include <hal/hal.h>

Diese Bibliotheken liefern alles, was wir brauchen, um mit dem SX1276 Chip zu kommunizieren und die LoRaWAN-Funktionalität zu verwalten. Die lmic.h Header-Datei kümmert sich um die Protokolllogik, während hal/hal.h LMIC mit der Hardware verbindet (in diesem Fall unseren ESP32 und SX1276).

Authentifizierung

Die LoRaWAN-Authentifizierung beginnt mit drei wichtigen Schlüsseln: APPEUI, DEVEUI und APPKEY. Diese sind Geräte-Zugangsdaten, die für den Beitritt zu einem LoRaWAN-Netzwerk mittels OTAA (Over-The-Air Activation) verwendet werden. Du hast diese Schlüssel eingegeben/erzeugt, als du das Endgerät in TTN erstellt hast, und kannst sie in den Geräteinformationen sehen:

Die LMIC-Bibliothek erwartet jedoch die Bytes für APPEUI und DEVEUI in LSB-Erster (Least Significant Byte zuerst) Reihenfolge, was bedeutet, dass du die Bytes für APPEUI und DEVEUI im Code umkehren musst. Wenn z. B. die AppEUI in den Geräteinformationen auf TTN 70 B3 D5 7E D0 00 00 01 ist, wird sie im Code so geschrieben:

APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };

Das Gleiche gilt für DEVUI, aber nicht für APPKEY – dieser bleibt in der gleichen Byte-Reihenfolge!

Schlüssel-Konstanten

Der Code erstellt konstante Arrays für diese Authentifizierungsschlüssel in der korrekten Byte-Reihenfolge und ruft dann eine Funktion auf, die den Schlüssel in einen Puffer kopiert, den LMIC während des Join-Prozesses verwendet. Diese Funktionen sorgen dafür, dass dein ESP32 sich sicher bei deinem LoRaWAN-Netzwerkserver, wie The Things Network, authentifizieren kann.

Unten siehst du die Konstante für die APPEUI mit der „copy“-Funktion os_getArtEui():

static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui(u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

Die PROGMEM Direktive speichert die Daten im Flash-Speicher, um RAM zu sparen. Ähnliche Logik gilt für die Geräte-EUI und den Anwendungsschlüssel. Denk daran, dass APPEUI und DEVEUI in umgekehrter Byte-Reihenfolge sind, aber nicht APPKEY:

static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
                                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

Natürlich musst du die APPEUI-, DEVEUI- und APPKEY-Werte für deine TTN-Anwendung und das Endgerät verwenden!

Konstanten

Als Nächstes definiert der Code ein globales Job-Objekt und ein Übertragungsintervall.

static osjob_t sendjob;
const unsigned TX_INTERVAL = 60;  // Send every minute

Das sendjob Objekt hält die Aufgabe, die später ausgeführt wird, während TX_INTERVAL festlegt, wie oft Daten gesendet werden sollen – in diesem Fall alle 60 Sekunden.

Pin-Belegung

Jetzt definieren wir die Pin-Belegung zwischen ESP32 und SX1276 LoRa-Modul:

const lmic_pinmap lmic_pins = {
  .nss = 5,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 17,
  .dio = { 4, 16, LMIC_UNUSED_PIN }
};

Diese Struktur teilt LMIC mit, welche GPIO-Pins mit den Steuerleitungen des SX1276 verbunden sind. Zum Beispiel ist nss der SPI-Chip-Select-Pin, rst ist Reset und dio sind die Interrupt-Pins, die vom Funkmodul verwendet werden.

onEvent

Die onEvent() Funktion behandelt verschiedene LoRaWAN-Ereignisse – von Join-Anfragen bis zu Übertragungsabschlüssen.

void onEvent(ev_t ev) {
  Serial.printf("%d: ", os_getTime());
  switch (ev) {
    case EV_JOINING:
      Serial.println("EV_JOINING");
      break;
    case EV_JOINED:
      Serial.println("EV_JOINED");
      LMIC_setLinkCheckMode(0);
      break;
    ...
  }
}

Diese Funktion hilft dir, zu überwachen, was dein Gerät gerade macht. Zum Beispiel bedeutet EV_JOINED, dass das Gerät erfolgreich mit dem Netzwerk verbunden ist, und wir schalten den Link-Check-Modus mit LMIC_setLinkCheckMode(0) aus, um Airtime zu sparen. Wenn EV_TXCOMPLETE ausgelöst wird, hat das Gerät das Senden abgeschlossen, und wir planen die nächste Übertragung ein:

    case EV_TXCOMPLETE:
      Serial.println("EV_TXCOMPLETE");
      if (LMIC.dataLen) {
        Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
        Serial.print("> Data: ");
        for (int i = 0; i < LMIC.dataLen; i++) {
          Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
        }
        Serial.println();
      }
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;

Der EV_TXCOMPLETE Fall prüft auch, ob das LoRa-Modul Daten empfangen hat (Downlink). Wenn ein Downlink (LMIC.dataLen > 0) vorliegt, gibt der Code die Bytes der Daten als hexadezimale Zahlen aus.

Du kannst Daten von TTN senden, indem du auf den Messaging-Tab deines Endgeräts klickst:

do_send

Die Kernlogik der Übertragung findet in der do_send() Funktion statt.

void do_send(osjob_t* j) {
  static uint16_t counter = 0;
  static char mydata[25];

  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    snprintf(mydata, sizeof(mydata), "Counter = %u", counter);
    LMIC_setTxData2(1, (uint8_t*)mydata, strlen(mydata), 0);
    Serial.printf("> Data: %s\n", mydata);
    counter++;
  }
}

Diese Funktion baut einen String wie "Counter = 23" und stellt ihn zur Übertragung bereit. Sie prüft zuerst, ob noch eine andere Übertragung aussteht – LoRaWAN ist zeitlich streng. Wenn frei, sendet sie das Paket auf Port 1 ohne Bestätigung (das letzte Argument 0 bedeutet unbestätigter Uplink).

setup

Die setup() Funktion startet alles:

void setup() {
  Serial.begin(115200);
  os_init_ex(&lmic_pins);
  LMIC_reset();
  do_send(&sendjob);
}

Sie initialisiert die serielle Schnittstelle für Debugging, richtet den LMIC-Stack mit der korrekten Pin-Belegung ein, setzt den internen Zustand von LMIC zurück und plant die erste Übertragung.

loop

Schließlich hält die loop() Funktion die LMIC-Laufzeit am Laufen.

void loop() {
  os_runloop_once();
}

Im Gegensatz zu traditionellen Arduino-Loops erfordert LMIC diesen Aufruf innerhalb von loop(), um den Job-Scheduler und das Ereignissystem korrekt zu betreiben.

Serieller Monitor

Wenn du den Code hochlädst und den Seriellen Monitor öffnest, solltest du folgende Meldungen sehen:

Uplink-Nachrichten

Mit dieser Einrichtung senden dein ESP32 und SX1276 jede Minute einen Zählerstring über LoRaWAN. Wenn du zu TTN gehst, kannst du die Uplink-Daten ansehen, die von unserem Endgerät gesendet werden. Wähle Applications und klicke auf Live data:

Auf der rechten Seite siehst du dann die zeitgestempelte Nachricht, die von unserem ESP32 gesendet wurde:

Payload Formatter

Allerdings zeigt TTN nicht die tatsächlichen Daten der Nachricht, unseren Zählerwert, an. Das liegt daran, dass TTN nicht weiß, wie die Daten im Payload dekodiert werden. Du musst einen Payload Formatter angeben oder implementieren, um die Daten sehen zu können.

Öffne die Sidebar, wähle Application, klicke auf Payload formatters und wähle Uplink:

Du kannst dann einen bestehenden Payload Formatter auswählen oder einen eigenen implementieren. Wir implementieren unseren eigenen und wählen daher „Custom Javascript formatter“ als Formatter-Typ:

Für Formatter-Code gib folgenden Code ein, der einfach die gesendeten Bytes zurück in Zeichen umwandelt:

function decodeUplink(input) {
  let str = "";
  for (let i = 0; i < input.bytes.length; i++) {
    str += String.fromCharCode(input.bytes[i]);
  }
  return { data: { message: str } };
}

Wenn du jetzt die Uplink-Nachrichten erneut ansiehst, findest du am Ende ein Feld Payload, das den String mit dem Zählerwert zeigt, den das Endgerät sendet:

Im nächsten Abschnitt fügen wir dem ESP32 einen Umweltsensor hinzu und ändern den Code, um Temperatur-, Feuchtigkeits- und Luftdruckdaten via LoRaWAN an TTN zu senden.

Umweltdaten via LoRaWAN senden

Eine klassische Anwendung für LoRaWAN ist das Senden von Umweltdaten wie Temperatur, Luftfeuchtigkeit und Luftdruck von einem LoRa-Endgerät an TTN. In diesem Abschnitt fügen wir den BME280 Sensor zu unserem Schaltkreis hinzu und erweitern den Code, um die vom Sensor gemessenen Daten zu senden.

Wenn du mehr Informationen zum BME280 möchtest, siehe das How To Use BME280 Pressure Sensor oder die Temperature Plotter on e-Paper Display Tutorials.

BME280 an ESP32 anschließen

Der BME280 Sensor hat eine I2C-Schnittstelle und lässt sich leicht in den Schaltkreis integrieren. Die folgende Tabelle zeigt alle Verbindungen, die du herstellen musst, einschließlich der bestehenden für den SX1276:

SX1276BME280ESP32
MOSI23
MISO19
SCK18
RST17
NSS5
DIO04
DIO116
SCL25
SDA33
GNDGNDGND
VCCVCC3.3V

Und hier die komplette Verkabelung zwischen BME280, SX1276 und ESP32:

Wiring of BME280, SX1276 and ESP32
Verkabelung von BME280, SX1276 und ESP32

Code zum Senden von Umweltdaten via LoRaWAN

Als Nächstes installieren wir zwei Bibliotheken: Die Adafruit_BME280 zum Auslesen der Daten vom BME280:

Adafruit_BME280 library in Library Manager
Adafruit_BME280 Bibliothek im Library Manager

und die CayenneLPP library, die Sensordaten für LoRaWAN-Übertragungen formatiert:

CayenneLPP library in Library Manager
CayenneLPP Bibliothek im Library Manager

Der folgende Code ist eine einfache Änderung und Erweiterung des vorherigen Codes. Statt eines Zählers senden wir Temperatur-, Feuchtigkeits- und Luftdruckmesswerte vom BME280 Sensor. Schau ihn dir kurz an, dann besprechen wir die Unterschiede zum vorherigen Code:

#include <lmic.h>
#include <hal/hal.h>
#include <CayenneLPP.h>
#include <Adafruit_BME280.h>


static const u1_t PROGMEM APPEUI[8] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getArtEui(u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

static const u1_t PROGMEM DEVEUI[8] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
void os_getDevEui(u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

static const u1_t PROGMEM APPKEY[16] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
                                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
void os_getDevKey(u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static osjob_t sendjob;

const unsigned TX_INTERVAL = 60;  // Send every minute

const lmic_pinmap lmic_pins = {
  .nss = 5,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 17,
  .dio = { 4, 16, LMIC_UNUSED_PIN }
};

CayenneLPP lpp(16);
Adafruit_BME280 bme;

void initBMESensor() {
  Wire.begin(33, 25);  // Software I2C for BME280
  bme.begin(0x76, &Wire);
  bme.setSampling(Adafruit_BME280::MODE_FORCED,
                  Adafruit_BME280::SAMPLING_X1,  // temperature
                  Adafruit_BME280::SAMPLING_X1,  // pressure
                  Adafruit_BME280::SAMPLING_X1,  // humidity
                  Adafruit_BME280::FILTER_OFF);
}

void onEvent(ev_t ev) {
  Serial.printf("%d: ", os_getTime());
  switch (ev) {
    case EV_JOINING:
      Serial.println("EV_JOINING");
      break;
    case EV_JOINED:
      Serial.println("EV_JOINED");
      LMIC_setLinkCheckMode(0);
      break;
    case EV_JOIN_FAILED:
      Serial.println("EV_JOIN_FAILED");
      break;
    case EV_TXCOMPLETE:
      Serial.println("EV_TXCOMPLETE");
      if (LMIC.dataLen) {
        Serial.printf("> Downlink %d bytes\n", LMIC.dataLen);
        Serial.print("> Data: ");
        for (int i = 0; i < LMIC.dataLen; i++) {
          Serial.printf("%02X ", LMIC.frame[LMIC.dataBeg + i]);
        }
        Serial.println();
      }
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    case EV_TXCANCELED:
      Serial.println("EV_TXCANCELED");
      break;
    case EV_JOIN_TXCOMPLETE:
      Serial.println("EV_JOIN_TXCOMPLETE: no JoinAccept");
      break;
    default:
      Serial.print("Unknown event: ");
      Serial.println((unsigned)ev);
      break;
  }
}

void do_send(osjob_t* j) {
  bme.takeForcedMeasurement();
  float temp = bme.readTemperature();
  float hum = bme.readHumidity();
  float pres = bme.readPressure() / 100.0;

  lpp.reset();
  lpp.addTemperature(1, temp);  // channel 1
  lpp.addRelativeHumidity(2, hum);   // channel 2
  lpp.addBarometricPressure(3, pres);   // channel 3

  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0);
    Serial.printf("> Temperature: %.2f\n", temp);
    Serial.printf("> Humidity: %.2f\n", hum);
    Serial.printf("> Pressure: %.2f\n", pres);
  }
}

void setup() {
  Serial.begin(115200);
  initBMESensor();
  os_init_ex(&lmic_pins);
  LMIC_reset();
  do_send(&sendjob);
}

void loop() {
  os_runloop_once();
}

Der Code verwendet die gleichen Schlüssel für APPEUI, DEVEUI und APPKEY wie zuvor. Die Hauptänderung ist eine Funktion, die den BME280 Sensor initialisiert, und eine Änderung der Funktion, die die Daten sendet.

initBMESensor

Die initBMESensor() Funktion initialisiert den BME280 über Software-I2C. Statt der Standard-I2C-Pins des ESP32 werden GPIO 33 für SDA und GPIO 25 für SCL verwendet:

void initBMESensor() {
  Wire.begin(33, 25);  // Software I2C for BME280
  bme.begin(0x76, &Wire);
  bme.setSampling(Adafruit_BME280::MODE_FORCED,
                  Adafruit_BME280::SAMPLING_X1,  // temperature
                  Adafruit_BME280::SAMPLING_X1,  // pressure
                  Adafruit_BME280::SAMPLING_X1,  // humidity
                  Adafruit_BME280::FILTER_OFF);
}

Beachte, dass ich die I2C-Adresse 0x76 verwende, wenn ich den Sensor über bme.begin(0x76, &Wire) konfiguriere. Dein Sensor kann eine andere I2C-Adresse haben. Zum Beispiel ist 0x77 auch häufig für den BME280.

Der Sensor wird im „forced mode“ betrieben, was bedeutet, dass er nur misst, wenn er explizit dazu aufgefordert wird. Diese Methode spart Energie. Die Abtastung ist auf das Minimum (1x) für Temperatur, Druck und Feuchtigkeit eingestellt, und der interne Filter ist deaktiviert.

do_send

Die do_send() Funktion liest zuerst Temperatur-, Feuchtigkeits- und Luftdruckwerte vom BME280 Sensor aus.

void do_send(osjob_t* j) {
  bme.takeForcedMeasurement();
  float temp = bme.readTemperature();
  float hum = bme.readHumidity();
  float pres = bme.readPressure() / 100.0;

Dann formatiert sie die Daten für die LoRaWAN-Übertragung, indem Temperatur, Feuchtigkeit und Luftdruck als verschiedene Kanäle zum Datenpaket hinzugefügt werden:

  lpp.reset();
  lpp.addTemperature(1, temp);  // channel 1
  lpp.addRelativeHumidity(2, hum);   // channel 2
  lpp.addBarometricPressure(3, pres);   // channel 3

Schließlich werden die Daten als übliches Byte-Paket gesendet. Zusätzlich gibt der Code die Daten im Seriellen Monitor aus:

  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0);
    Serial.printf("> Temperature: %.2f\n", temp);
    Serial.printf("> Humidity: %.2f\n", hum);
    Serial.printf("> Pressure: %.2f\n", pres);
  }
}

Für mehr Informationen siehe das Send Environmental Data with LoRa Tutorial, das Ähnliches macht, aber rohes LoRa statt LoRaWAN verwendet.

Serieller Monitor

Wenn du den Code hochlädst und ausführst, solltest du folgende Ausgabe im Seriellen Monitor sehen:

Payload Formatter

Wenn du die Daten auf TTN ansehen möchtest, musst du wie zuvor einen Payload Formatter angeben. In diesem Fall ist es jedoch einfacher. Wir müssen keinen eigenen Custom Javascript Formatter schreiben, sondern können den CayenneLPP Formatter verwenden:

In der Geräteübersicht siehst du dann die schön formatierten Umweltdaten, die in den drei Kanälen gesendet werden:

Und das war’s. Jetzt weißt du, wie du dein eigenes LoRaWAN-Endgerät baust, um Umweltdaten über das ThinkNode G1 Gateway an TTN zu senden.

Fazit

Dieser Artikel hat das Thinknode G1 Gateway vorgestellt. Ein LoRaWAN-Gateway ermöglicht es dir, Daten von LoRa-Sensoren ins Internet zu senden. Wir haben unseren eigenen LoRa-Sensor mit ESP32, SX1276 und BME280 gebaut und damit Temperatur, Luftfeuchtigkeit und Luftdruck an The Things Network gesendet.

Wir haben nur an der Oberfläche von LoRaWAN gekratzt, und ich empfehle dir, die Informationen auf www.thethingsnetwork.org/docs/lorawan zu durchstöbern, um mehr zu lernen. Für weitere Anleitungen zur Konfiguration des ThinkNode G1 siehe das Manual und das Webtutorial.

Wenn du nur Daten zwischen zwei LoRa-Geräten übertragen möchtest, ist LoRaWAN wahrscheinlich überdimensioniert, und du bist mit rohem LoRa besser bedient. Schau dir das Long range communication with LoRa SX1276 and ESP32 und das Send Environmental Data with LoRa an.

Schließlich, wenn du lieber einen Arduino als den ESP32 verwendest, musst du entweder einen Pegelwandler einsetzen oder einen Arduino verwenden, der mit 3,3 Volt arbeitet, da das SX1276 Modul nicht mit 5V funktioniert! Siehe das Interface Arduino Uno with ST7735 TFT using Level Shifter Tutorial für mehr Informationen.

Wenn du Fragen hast, kannst du sie gerne im Kommentarbereich stellen.

Viel Spaß beim Tüfteln ; )

Links

Einige Links, die ich beim Schreiben dieses Artikels nützlich fand: