Nicht jeder Sensor steht in Reichweite eines Routers. Der Acker, der Schrebergarten, der Wetter-Mast auf dem Dach der Scheune. Ab Version 1.9.0 bringt die HydroNode Arduino-Library einen ESP32 deshalb nicht nur über WLAN ins Netz, sondern auch über Ethernet, LTE-M, NB-IoT und LTE Cat-1, auf Wunsch mit WLAN zuerst und Mobilfunk als Rückfall. Dazu kommt ein Puffer: Messungen gehen nicht mehr verloren, wenn das Netz weg ist, und ein Akku-Gerät kann eine Stunde sammeln und dann alles auf einmal schicken.
Die Idee: das Netz ist ein eigenes Teil
Die Signatur jeder Anfrage hängt nicht am WLAN. Sie rechnet über die Werte und die Uhrzeit, egal wie die Bytes reisen. In 1.9.0 ist das Netz deshalb ein eigenes Objekt, der Transport. Du wählst ihn passend zu deiner Hardware, der Rest des Sketches bleibt gleich: Werte, Befehle, Akku-Schwellen, Updates.
// Before: WiFi built in
HydroNode hydro(SENSOR_ID, SECRET_KEY);
// Since 1.9.0: the network is its own object, the rest stays the same
HydroNodeWiFi wifi; // HOW the board reaches the internet
HydroNodeClient hydro(wifi, SENSOR_ID, SECRET_KEY); // WHAT it sends| Netz | Hardware | Beispiel in der Library |
|---|---|---|
| WLAN | Jeder ESP32 und ESP8266 | QuickStart, Transport_WiFi |
| Ethernet | ESP32 mit Buchse (WT32-ETH01, Olimex ESP32-POE) | Ethernet_ESP32 |
| Ethernet | W5500-Modul an SPI, jedes Board | Ethernet_W5500 |
| LTE-M, NB-IoT | SIM7080G, SIM7000, BG95, SARA-R4 | Cellular_SendNow, Cellular_CollectHourly |
| LTE Cat-1 | A7670, SIM7600, TLS im Modem | Cellular_ModemTLS |
| WLAN, sonst LTE-M | ESP32 mit Modem | WiFi_Fallback_LTE |
| Jeder TLS-Client | UNO R4 WiFi, MKR, Nano 33 IoT, Pico W | Board_MKR_WiFi1010, Board_AnyClient_Template |
HydroNode hydro(id, secret) ist jetzt der Client mit eingebautem WLAN. Jeder Sketch für 1.x kompiliert und verhält sich wie vorher. Kompiliert wird nur, was du einbindest: ein reiner WLAN-Sketch wird etwa 2 KB größer, Modem-Code landet nur in Sketches mit HydroNodeCellular.h. LTE-M und NB-IoT
TinyGSM für das Modem, ESP_SSLClient für TLS auf dem ESP32. Beide im Library Manager.TinyGSM steuert das Modem, ESP_SSLClient verschlüsselt auf dem ESP32 und prüft das Zertifikat von HydroNode gegen die mitgelieferten Wurzelzertifikate. Die Uhrzeit holt sich der Transport aus dem Modem, das Signal meldet er in dBm. LTE-M ist schneller und funktioniert auch in Bewegung, NB-IoT kommt tiefer in Keller und Schächte.
#define TINY_GSM_MODEM_SIM7080
#include <TinyGsmClient.h>
#include <ESP_SSLClient.h>
#include <HydroNodeClient.h>
#include <HydroNodeCellular.h>
#include <HydroNodeCerts.h>
TinyGsm modem(Serial1);
TinyGsmClient tcp(modem);
ESP_SSLClient tls; // TLS on the ESP32, any modem
HydroNodeCellular<TinyGsm> lte(modem, tls, HydroNodeNet::LTE_M);
HydroNodeClient hydro(lte, SENSOR_ID, SECRET_KEY);
void setup() {
Serial1.begin(115200, SERIAL_8N1, 4, 5); // modem RX, TX
tls.setClient(&tcp);
tls.setCACert(HYDRONODE_CA_BUNDLE);
lte.onBeforeConnect([](uint32_t now) { tls.setX509Time(now); });
hydro.setHttpTimeout(30000); // radio round trips take longer
modem.init();
modem.setPreferredMode(1); // 1 LTE-M, 2 NB-IoT
modem.waitForNetwork(180000L);
modem.gprsConnect("iot.1nce.net"); // the APN of your SIM
}
void loop() {
HydroNodeValue reading[] = {{"TEMPERATURE", 14.2}, {"HUMIDITY", 81}};
hydro.sendValues(reading, 2);
delay(5UL * 60UL * 1000UL);
} Im Dashboard steht beim Gerät unter Signal dann zum Beispiel LTE-M, -97 dBm statt einer WLAN-Stärke.
Sammeln und einmal pro Stunde senden
Auf Akku ist das Modem der größte Verbraucher. Einwählen und TLS kosten für einen Wert dasselbe wie für zehn. Deshalb misst das Beispiel Cellular_CollectHourly alle sechs Minuten, legt die Runde in den RTC-Speicher und schläft wieder. Erst beim zehnten Mal geht das Modem an und schickt alle Runden in einer Anfrage.
- Alle 6 minMessen, record(), schlafen
- 10 RundenOder die älteste ist 1 h alt
- flush()Modem an, eine Anfrage
- 202Jede Messung mit ihrer Zeit
RTC_DATA_ATTR uint8_t mem[4096]; // survives deep sleep
HydroNodeBuffer buffer(mem, sizeof(mem));
void setup() {
// modem, TLS and hydro as above
buffer.begin(); // keeps the rounds of the last wake-ups
hydro.attachBuffer(buffer);
HydroNodeValue reading[] = {{"TEMPERATURE", readTemp()}, {"SOIL_MOISTURE", readSoil()}};
hydro.record(reading, 2); // store, radio stays off
if (hydro.flushDue(10, 3600) && modemUp()) { // 10 stored, or the oldest is 1 h old
hydro.flush(); // all of them, one request
modemDown();
}
esp_deep_sleep(6ULL * 60 * 1000000); // next reading in 6 minutes
}- Grob 80 % weniger Funkenergie und ein Bruchteil der Daten, etwa 1,5 KB statt 10 KB pro Stunde.
- HydroNode lernt den Rhythmus aus den Lieferungen. Ein Gerät, das stündlich sendet, gilt erst nach drei Stunden als verspätet, nicht nach 15 Minuten.
- Befehle aus der App kommen mit der stündlichen Antwort.
- Klappt das Senden nicht, bleiben die Runden im Puffer, bis zu sieben Tage. Wird er voll, gehen die ältesten zuerst.
Nie wieder eine Messung verlieren
Der Puffer hilft auch ganz normalen WLAN-Geräten. Hängt er am Client, legt sendValues() eine Runde, die nicht rausging, selbst ab und gibt -7 zurück. Mit der nächsten erfolgreichen Anfrage folgen die gespeicherten Runden. Der Router startet neu, das Internet ist eine Stunde weg: im Diagramm fehlt nichts.
static uint8_t mem[8192]; // RAM, or save it to LittleFS
HydroNodeBuffer buffer(mem, sizeof(mem));
void setup() {
buffer.begin();
hydro.attachBuffer(buffer); // that is all
}
void loop() {
int status = hydro.sendValues(reading, 2); // -7 = stored, sent later
delay(60000);
} Wo der Puffer liegt, entscheidest du: im RAM, im RTC-Speicher des ESP32 (übersteht Deep Sleep) oder im Flash (übersteht einen Stromausfall, siehe Buffer_OfflineSafe). Beim Start prüft buffer.begin(), ob der Inhalt heil ist, und behält ihn nur dann.
WLAN zuerst, LTE als Rückfall
Ein Gerät am Rand der WLAN-Reichweite, oder eines, das auch melden muss, wenn der Router ausfällt: HydroNodeFailover nimmt pro Anfrage das erste Netz, das gerade da ist. Ist das WLAN zurück, geht es wieder darüber, das Modem kann aus.
HydroNodeWiFi wifi;
HydroNodeCellular<TinyGsm> lte(modem, tls, HydroNodeNet::LTE_M);
HydroNodeFailover net(wifi, lte); // WiFi while it is up, else LTE-M
HydroNodeClient hydro(net, SENSOR_ID, SECRET_KEY);Wie es weitergeht
- Alle Transporte, Zeitquellen und Puffer-Funktionen stehen in der Arduino-Anleitung und in den 16 Beispielen auf GitHub.
- Kein Arduino? Vom Raspberry Pi oder Pico W: Sensordaten aus Python, MicroPython, Node.js und Go senden.
- Auf Akku zusätzlich die Schwellen setzen: Ein Akku, der durchhält.

