Christian Mueller e706b22f31 Add design specification for LoRaWAN Web Portal
Based on Pflichtenheft v2.2, documents the full system design
including daemon, API, frontend, and infrastructure with agreed
deviations (Axum 0.8, SQLx 0.8, Vite 6, Tailwind 4).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:27:49 +01:00

9.6 KiB

HC-SR04 Ultraschallsensor mit LoRaWAN (LilyGO LoRa32 T3 V1.6.1)

Dieses Projekt liest Distanzmessungen vom HC-SR04 Ultraschallsensor aus und sendet die Daten über LoRaWAN. Die Messwerte werden zusätzlich auf einem OLED-Display angezeigt.

Hardware-Komponenten

  • LilyGO LoRa32 T3 V1.6.1 (ESP32 mit SX1276/SX1278 LoRa-Modul)
  • HC-SR04 Ultraschallsensor
  • OLED Display 128x64 (I2C, SSD1306)

Anschlussplan

HC-SR04 Ultraschallsensor

HC-SR04          LilyGO LoRa32 T3 V1.6.1
--------         -----------------------
VCC       <-->   5V (Pin mit 5V-Label)
TRIG      <-->   GPIO 12
ECHO      <-->   GPIO 13
GND       <-->   GND

Wichtig:

  • Der HC-SR04 sollte mit 5V betrieben werden für beste Ergebnisse
  • Das ECHO-Signal gibt 5V aus! Um den ESP32 zu schützen, verwende einen Spannungsteiler:
    • ECHO → 1kΩ Widerstand → GPIO 13 → 2kΩ Widerstand → GND
    • Alternativ: Viele HC-SR04 Module haben bereits einen integrierten Spannungsregler
  • GPIO 13 ist als INPUT sicher, solange das Signal nicht über 3.6V geht

OLED Display (SSD1306, 128x64, I2C)

OLED Display     LilyGO LoRa32 T3 V1.6.1
------------     -----------------------
VCC       <-->   3.3V
GND       <-->   GND
SDA       <-->   GPIO 21
SCL       <-->   GPIO 22

Hinweis: Beim LilyGO LoRa32 T3 V1.6.1 sind die I2C-Pins standardmäßig:

  • SDA: GPIO 21
  • SCL: GPIO 22

LoRa-Modul (bereits auf Board integriert)

Das LoRa-Modul SX1276/SX1278 ist bereits auf dem LilyGO Board integriert und nutzt folgende Pins:

LoRa SX1276      ESP32
-----------      -----
NSS (CS)  <-->   GPIO 18
RST       <-->   GPIO 23
DIO0      <-->   GPIO 26
DIO1      <-->   GPIO 33
DIO2      <-->   GPIO 32
MOSI      <-->   GPIO 27
MISO      <-->   GPIO 19
SCK       <-->   GPIO 5

Pinout-Übersicht LilyGO LoRa32 T3 V1.6.1

                    +------------------------+
                    | LilyGO LoRa32 T3 V1.6  |
                    |        (ESP32)          |
                    +------------------------+
                    |                        |
    HC-SR04 TRIG -> | GPIO 12         GPIO 21| <- OLED SDA
    HC-SR04 ECHO -> | GPIO 13         GPIO 22| <- OLED SCL
                    | GPIO 15         GPIO 23| <- LoRa RST
                    | GPIO 2           GPIO 5| <- LoRa SCK
                    | GPIO 4          GPIO 19| <- LoRa MISO
                    | GND             GPIO 27| <- LoRa MOSI
                    | 3.3V            GPIO 18| <- LoRa NSS
                    | 5V (VIN)        GPIO 26| <- LoRa DIO0
                    |                 GPIO 33| <- LoRa DIO1
                    |                 GPIO 32| <- LoRa DIO2
                    +------------------------+

Verfügbare freie GPIOs (falls du weitere Sensoren anschließen möchtest):

  • GPIO 2, 4, 15, 25, 34, 35, 36, 39 (36/39 nur Input)

LoRaWAN-Konfiguration

1. The Things Network (TTN) / ChirpStack einrichten

Application erstellen

  1. Melde dich bei TTN oder deinem ChirpStack-Server an
  2. Erstelle eine neue Application

Device registrieren

  1. Erstelle ein neues Device in deiner Application
  2. Wähle OTAA (Over-The-Air Activation)
  3. Notiere die folgenden Keys:
    • Device EUI (DevEUI) - 8 Bytes
    • Application EUI (AppEUI) - 8 Bytes
    • Application Key (AppKey) - 16 Bytes

2. Keys im Code eintragen

Öffne die Datei src/main.cpp und trage deine Keys ein:

// LoRaWAN Keys (hier deine echten Werte eintragen)
static const u1_t PROGMEM APPEUI[8]  = { 0x01, 0x00, 0x00, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
static const u1_t PROGMEM DEVEUI[8]  = { 0xB2, 0xA1, 0x05, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
static const u1_t PROGMEM APPKEY[16] = { 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x07, 0x18, 0x29, 0x38, 0x47, 0x56, 0xAB, 0xCD, 0xEF, 0x12 };

Wichtig: Die Keys müssen in LSB (Least Significant Byte) Format eingetragen werden!

Beispiel: TTN Keys konvertieren

Wenn TTN dir die Keys so anzeigt:

DevEUI:  70B3D57ED005A1B2
AppEUI:  0000000000000001
AppKey:  A1B2C3D4E5F6071829...

Dann musst du sie für LMIC umkehren (LSB):

// DevEUI: 70B3D57ED005A1B2 -> LSB
static const u1_t PROGMEM DEVEUI[8] = { 0xB2, 0xA1, 0x05, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };

// AppEUI: 0000000000000001 -> LSB
static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

// AppKey: bleibt in MSB Format (wird nicht umgedreht)
static const u1_t PROGMEM APPKEY[16] = { 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x07, 0x18, ... };

3. Sendeintervall anpassen

Das Sendeintervall kann in src/main.cpp:32 angepasst werden:

const unsigned TX_INTERVAL = 30;  // Sendeintervall in Sekunden

Payload-Format

Der Sensor sendet die Distanz als 2 Bytes (uint16_t):

Byte Beschreibung
0 High Byte (Distanz in mm)
1 Low Byte (Distanz in mm)

Beispiel:

  • Distanz: 123.4 cm = 1234 mm
  • Hex: 0x04D2
  • Payload: 04 D2

Messbereich: 0 - 65535 mm (0 - 65.5 m)

ChirpStack Decoder

Füge folgenden Decoder in ChirpStack unter Device Profile → Codec ein:

JavaScript Decoder (ChirpStack v3)

function Decode(fPort, bytes) {
  // Decoder für HC-SR04 Ultraschallsensor
  // Payload: 2 Bytes - Distanz in Millimeter (uint16_t)

  if (bytes.length !== 2) {
    return {
      error: "Invalid payload length"
    };
  }

  // Distanz aus 2 Bytes (Big Endian) auslesen
  var distanceMm = (bytes[0] << 8) | bytes[1];

  // Umrechnung in verschiedene Einheiten
  var distanceCm = distanceMm / 10.0;
  var distanceM = distanceMm / 1000.0;

  return {
    distance_mm: distanceMm,
    distance_cm: distanceCm,
    distance_m: distanceM
  };
}

JavaScript Decoder (ChirpStack v4)

function decodeUplink(input) {
  // Decoder für HC-SR04 Ultraschallsensor
  // Payload: 2 Bytes - Distanz in Millimeter (uint16_t)

  var bytes = input.bytes;

  if (bytes.length !== 2) {
    return {
      errors: ["Invalid payload length"]
    };
  }

  // Distanz aus 2 Bytes (Big Endian) auslesen
  var distanceMm = (bytes[0] << 8) | bytes[1];

  // Umrechnung in verschiedene Einheiten
  var distanceCm = distanceMm / 10.0;
  var distanceM = distanceMm / 1000.0;

  return {
    data: {
      distance_mm: distanceMm,
      distance_cm: distanceCm,
      distance_m: distanceM
    }
  };
}

Decoder testen

Test-Payload: 04 D2 (1234 mm)

Erwartetes Ergebnis:

{
  "distance_mm": 1234,
  "distance_cm": 123.4,
  "distance_m": 1.234
}

The Things Network (TTN) Payload Formatter

Für TTN unter Applications → Payload Formatters → Uplink:

function decodeUplink(input) {
  var bytes = input.bytes;

  if (bytes.length !== 2) {
    return {
      errors: ["Invalid payload length"]
    };
  }

  // Distanz aus 2 Bytes (Big Endian) auslesen
  var distanceMm = (bytes[0] << 8) | bytes[1];

  return {
    data: {
      distance_mm: distanceMm,
      distance_cm: distanceMm / 10.0,
      distance_m: distanceMm / 1000.0
    }
  };
}

Installation und Verwendung

Voraussetzungen

  • PlatformIO (VS Code Extension oder CLI)
  • USB-Treiber für CP2102 (falls nicht installiert)

Projekt kompilieren und hochladen

# Projekt bauen
pio run

# Auf Board hochladen
pio run --target upload

# Serial Monitor öffnen
pio device monitor

Serial Monitor Ausgabe

Nach dem Upload solltest du folgende Ausgabe sehen:

Starte HC-SR04 + OLED + LoRa
Beitritt läuft...
Netzwerkbeitritt erfolgreich
Distanz gesendet:
Distanz: 123.4 cm
Distanz: 1234.0 mm
Nachricht übertragen.

Bibliotheken

Die benötigten Bibliotheken werden automatisch über PlatformIO installiert (siehe platformio.ini):

  • gamegine/HCSR04 ultrasonic sensor - HC-SR04 Treiber
  • adafruit/Adafruit SSD1306 - OLED Display
  • adafruit/Adafruit GFX Library - Grafik-Bibliothek
  • mcci-catena/MCCI LoRaWAN LMIC library - LoRaWAN Stack (wird automatisch vom Framework geladen)

Fehlerbehebung

Device joint nicht

  • Überprüfe die Keys (DevEUI, AppEUI, AppKey)
  • Achte auf LSB-Format bei DevEUI und AppEUI
  • Prüfe die LoRaWAN-Frequenz (EU868, US915, etc.)
  • Stelle sicher, dass ein Gateway in Reichweite ist

HC-SR04 liefert -1 oder fehlerhafte Werte

  • Überprüfe die Verkabelung (TRIG → GPIO 15, ECHO → GPIO 13)
  • Prüfe die Stromversorgung (min. 5V für HC-SR04 empfohlen)
  • Halte Hindernisse im Messbereich (2 cm - 4 m)
  • Verwende ggf. einen Spannungsteiler für ECHO (5V → 3.3V)

OLED Display zeigt nichts an

  • Überprüfe die I2C-Verbindung (SDA → GPIO 21, SCL → GPIO 22)
  • Prüfe die I2C-Adresse (Standard: 0x3C)
  • Stelle sicher, dass die richtigen I2C-Pins verwendet werden (LilyGO T3 V1.6.1 nutzt GPIO 21/22)
  • Verwende einen I2C-Scanner zur Diagnose

Kompilierungsfehler

# Cache löschen und neu bauen
pio run --target clean
pio run

Energieverbrauch

  • Deep Sleep: Nicht implementiert (kontinuierlicher Betrieb)
  • Stromverbrauch: ~100-150 mA (ESP32 + LoRa TX)
  • Empfehlung: Für batteriebetriebenen Einsatz Deep Sleep zwischen Messungen implementieren

Lizenz

Dieses Projekt ist Open Source und steht unter der MIT-Lizenz.

Weitere Informationen