Welche ESP32-Arduino-lib für TTN im Jahr 2023?

Ich bin etwas raus aus dem Thema and things have changed, Stichwort “The Things Stack V3”, daher meine Frage: Welche Bibliothek verwendet man denn heute für ein ESP32-basiertes board zusammen mit einem LoRa-Modul (RFMxx) wenn man die Arduino IDE nutzt und Daten an TTN schicken will?

Das habe ich für die ESP-IDF gefunden, also leider nicht für Arduino geeignet: GitHub - manuelbl/ttn-esp32: The Things Network device library for ESP32 (ESP-IDF) and SX127x based devices mit diesen netten features:

  • OTAA (over-the-air activation)
  • uplink and downlink messages
  • saving the EUIs and key in non-volatile memory
  • deep sleep and power off without the need for rejoining

Kennt ihr aktuelle Arduino-libs, die ähnliches unterstützen, besonders die deep sleep and power off-Geschichten?

Die Referenz im Arduino-Universum scheint immer noch das hier zu sein:

Als TTN-Overlay gibt es dazu GitHub - rgot-org/TheThingsNetwork_esp32

The TTN_esp32 class enables ESP32 devices with supported LoRaWAN modules to communicate via The Things Network. This library is a wrapper for MCCI-Catena/arduino-lmic library.

Es sei ein Versuch das hier für Arduino / Microchip RN2xx3 entwickelte nachzubauen, wobei die examples hier schon etwas reichhaltiger sind: arduino-device-lib/examples at master · TheThingsNetwork/arduino-device-lib · GitHub

2 Likes

Ja, scheint so. Hier beim originalen Repository steht folgendes dran:

Ja, das scheint die kanonische offizielle Bibliothek von/für TTN zu sein. Mit der geht es bestimmt noch nahtloser, allerdings steht dort dran:

Na, die sieht doch gut aus, und hat z.B. auch schon einen CayenneLPP Enkoder an Bord.

Aus gleichem Haus gibt es auch eine TTN-Ergänzung MCCI Arduino LoRaWAN Library: https://github.com/mcci-catena/arduino-lorawan

User-friendly library for using the Arduino LMIC library with The Things Network and LoRaWAN® networks.

Irgendwelche Vorteile / Nachteile? Im Vergleich zu

Diese Bibliothek beinhaltet eine CayenneLPP Implementierung, siehe TTN_CayenneLPP.h und TTN_CayenneLPP.cpp. Erstere scheinbar nicht, siehe find “cayenne” in arduino-lorawan.

1 Like

Am feinsten wäre es natürlich, die RadioLib Bibliothek verwenden zu können, da sie bereits für eine Vielzahl an Funkchips Unterstützung mitbringt.

Der Support für LoRaWAN ist in der Mache, hat es aber noch nicht geschafft, veröffentlicht zu werden.

Referenzen

/cc @einsiedlerkrebsISM-to-MQTT relay with radio chips and Arduino - #13 by Andreas

Bei ISM-to-MQTT relay with radio chips and Arduino - #15 by weef aufgegriffen, passt es glaube ich auch zu diesem Thema.

Das gleiche ist auch bei der LMIC Bibliothek der Fall:

Die RadioLib: Universal wireless communication library for Arduino unterstützt den Chip jedoch:

Rejoining LoRaWAN network after Deep Sleep

In diesem Kontext könnte auch folgende Geschichte nicht uninteressant sein. Mit der MCCI LMiC Bibliothek unter Arduino scheint das Thema… Naja, weiß nicht so recht…

Mit der ttn-esp32 Bibliothek (ESP IDF only, no Arduino HAL) sollte das gut klappen, siehe deep_sleep/main/main.cpp. Gelegentliche Schluckaufs, wie z.B. deep_sleep not saving data · Issue #68 · manuelbl/ttn-esp32 · GitHub, weisen nicht auf grundlegende Probleme hin.

Mir war nicht klar, dass dieses wichtige Detail ggf. so sensibel und teilweise noch unerschlossen ist/scheint. Aber gut, beim Embedded Programming mit Funkerei ist eigentlich jedes Detail sensibel.

Bei Terkin/MicroPython hatte @Thias damals das entsprechende Feature beigetragen, wenn mich nicht alles täuscht.

make use of LoRaWAN state restoration from NVRAM by thiasB · Pull Request #27 · hiveeyes/terkin-datalogger · GitHub
Only restore LoRa state from NVRAM on wake from deep sleep by thiasB · Pull Request #28 · hiveeyes/terkin-datalogger · GitHub
LoRaWAN: consider restored join status for both, OTAA and ABP activation · hiveeyes/terkin-datalogger@77a8f86 · GitHub

Soweit ich es mitbekommen habe, lief diese Geschichte seit Tag 0 immer gut? Oder hast Du dazu anderes zu berichten, @Thias?

P.S.: Auch hier ist die Softwareschnittstelle zum LoRa Chip als “ESP IDF only / no Arduino” ausgeführt, nur halt eben zusätzlich über ne MicroPython API zugänglich gemacht [1].


  1. Das gibts bisher exklusiv im Pycom MicroPython Derivat. Ich hoffe, dass vielleicht Adafruit mit CircuitPython einmal etwas Ähnliches rausbringt? ↩︎

1 Like

Deep sleep und TTN wollte ich mir auch nochmal genauer anschauen, Danke für den Impuls @Andreas, und ja, sehr komisch, dass bei TTN-Geräten – die ja sehr häufig ultra low power laufen sollen – dieses Thema anscheinend dann doch nicht so zentral ist, dass alle Anwendungsfälle und side cases schon durchdekliniert sind. Die Wichtigkeit das Thema wurde 2020 auch schon postuliert: Feature request: Keep session during deep sleep. · Issue #5 · manuelbl/ttn-esp32 · GitHub

Currently, the underlying MCCI LMIC library does not support it even though there are discussions about implementing it. The feature would be a huge win for many applications.

I will implement it in this library if the MCCI LMIC implements it or if I find another suitable library that could be used instead of MCCI LMIC.

Warum es bei manchen läuft, und bei anderen Probleme macht, könnte auch an folgenden beiden Parametern liegen: a) der verwendete join-Prozedur und b) der Umgang mit per sketch gesetzen Variablen-Inhalten nach sleep mode (sprich ESP vs. “Arduino”).

Join via OTAA vs ABP

Der Unterschied zwischen Over the air activation (OTAA) und Activation by personalization (ABP) wird ganz gut unter LoRa-Endgeräte-Aktivierung (ABP vs. OTAA) beschrieben.

Und mit dem OTAA-Detail hier kommen wir unserem Problem auch schon näher:

Das Endgerät startet den Join-Vorgang, indem es eine Join-Request-Nachricht sendet. Diese enthält DevEUI, AppEUI und DevNonce. DevEUI und AppEUI beziehen sich auf den Global End Device bzw. Application Identifier und folgen dem IEEE EUI-64 Adressraumformat.

Die DevNonce ist eine Zufallszahl, die mit jedem Join-Vorgang größer wird. Dazu muss die DevNonce in einem nichtflüchtigen Speicher gespeichert werden.

ESP32 vs. Arduino, z.B. Cortex M0

Bei einem “normalen” Arduino könnte man die DevNonce einfach in eine Variable schreiben, dort überleben die nach Programmstart veränderten Variableninhalte auch einen deep sleep. Dagegen vergisst der ESP alle Variableninhalte bzw. initialisiert sie ggf. neu mit den default-Werten, da setup() nach jedem deep sleep cycle ausgeführt wird.

Bei der ttn-esp32-lib wird das so bschreiben Deep Sleep and Power Off · manuelbl/ttn-esp32 Wiki · GitHub

So the challenge with deep sleep and power off is to retain the information associated with the current TTN session.

Weiter steht da, dass ein neuer OTAA join nach jedem deep sleep cycle auch keine gute Idee ist:

If the state were not retained, the device would need to rejoin every time it wakes up from deep sleep or power off. This does not only take a lot of time and power. It also undermines many mechanisms for the efficient use of the LoRa spectrum. This is why TTN v3 implements restrictive limits on the number of joins.

Daher gibt es in der ttn-esp32 eine Mechanismus für deep sleep, s. Understanding the need of re-join · Issue #30 · manuelbl/ttn-esp32 · GitHub und Deep Sleep and Power Off · manuelbl/ttn-esp32 Wiki · GitHub

Allerdings ist die ttn-esp32-lib für die ESP-IDF und nicht für Arduino.

Jack Gruber – ich kenne ihn nicht :-) – hat im Artikel https://jackgruber.github.io/2020-04-13-ESP32-DeepSleep-and-LoraWAN-OTAA-join/ (code unter https://github.com/JackGruber/ESP32-LMIC-DeepSleep-example/) beschreiben wie er die notwendigen Parameter im RTC memory des ESP deep sleep save speichert.

Diskussionen, allgemein zu deep sleep, ESP32 und TTN auch unter What LMIC state must be preserved during sleep mode? - #32 by bluejedi - LMIC - The Things Network

In eine issue der MCCI LMIC lib wird interessanterweise auf die Implementierung beim Pax-Counter verweisen: deep sleep ttn otaa · Issue #889 · mcci-catena/arduino-lmic · GitHub

Für “Arduino-Boards” brauchen wir diesen Zauber nicht, Stuart Robinson hat die gleiche Funktionalität so für ein Non-ESP-board implementiert: Easy Build TTN and LoRaWAN Nodes | StuartsProjects

Und wenn wir statt OTAA mit ABP joinen brauchen wir uns auch keine Gedanken darüber zu machen. Vermutlich läuft es auch schon bei @Thias seit Ewigkeiten stabil, da er mit ABP joined.

Sicherheitstechnisch hat OTAA Vorteile, und wir sollten das nutzen. Wenn ich richtig informiert bin, braucht ABP aber keine uplinks, und ist an Standorten stabiler an denen ein node noch ein gateway erreicht, aber der node Probleme beim Empfang hat.

2 Likes

Genau.

Ja genau. So habe ich @Thias damals auch verstanden.

Allerdings hat er u.U. Teile davon sogar für beide Verfahren erschlossen? Siehe LoRaWAN: consider restored join status for both, OTAA and ABP activation · hiveeyes/terkin-datalogger@77a8f86 · GitHub.

Ah, nein. Der referenzierte Code steckt im "not has_joined()" Zweig.

“Low power” ist vielleicht doch nicht so sehr bei den klassischen industriellen Anwendungsfällen relevant. Beispielsweise beim precision farming muss das Gerät, ob autonom oder nicht, genug Energie an Bord haben, um überhaupt fahren und mähen oder säen zu können. Dabei fällt die Versorgung eines Microcontrollers gar nicht so sehr ins Gewicht.

Aber für “remote monitoring”, und Energieversorgung per Solarzelle sieht es schon anders aus – klar.

Überblick

Anbei eine konkretere Auflistung der bisher bekannten Implementierungsvarianten bzw. -evolutionstufen.

  • Pycom MicroPython
  • ESP-IDF (kein Arduino) und ttn-esp32
  • ESP-IDF (Arduino) und LMiC (Jack Gruber)
  • Paxcounter (Arduino)

Pycom MicroPython

Ein wenig außer Konkurrenz, aber die Betrachtung der Implementierung kann trotzdem interessant sein.

ttn-esp32

Arduino ESP32-LMiC

Paxcounter

Die lowlevel Implementierung ttn_rtc_save im Paxcounter ist identisch mit der Implementierung in der ttn-esp32 Bibliothek.

Allerdings – auch Paxcounter basiert auf Arduino – ist hier noch zusätzlich die C++ SaveLMICToRTC Routine von Jack Gruber zu finden, die am Ende ttn_rtc_save() aufruft.

3 Likes

Der wesentliche Unterschied im low-level Bereich ist, dass das Beispiel von Jack Gruber pauschal alle Werte der LMiC Datenstruktur im RTC Speicher ablegt,

während sowohl ttn-esp32 als auch der Paxcounter per ttn_rtc_save eine vermutlich fortschrittlichere Implementierung haben, die nur bestimmte Teile der LMiC Datenstruktur speichert.

Copy LMIC struct except client, osjob, pendTxData and frame.

Interessant ist dabei der changelog auf https://jackgruber.github.io/2020-04-13-ESP32-DeepSleep-and-LoraWAN-OTAA-join/ ganz unten:

Updates

2020-09-18 Save and load complete LMIC structure and reset DutyCyle
2020-11-26 Correct DutyCyle calculation for LMIC EU like band planes
2022-01-03 Reload condition for LMIC corrected

Hört sich so an, also ob das bis zum ersten update anders war. Im GIT-repo ist der erste commit allerdings von 2020-09-18

1 Like

Interessant, ja. Das scheint also ein Thema zu sein, ob “alles”, oder “nur einen Teil davon”.

Hier auch die fertige Appliance von ihm.