lets_plaiy:lorawan:start
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| lets_plaiy:lorawan:start [2026/04/27 17:14] – jan.sonntag | lets_plaiy:lorawan:start [2026/04/28 12:20] (current) – jan.sonntag | ||
|---|---|---|---|
| Line 5: | Line 5: | ||
| ===== Was ist LoRaWAN? ===== | ===== Was ist LoRaWAN? ===== | ||
| + | {{pdfjs 75%, | ||
| ===== The Things Network ===== | ===== The Things Network ===== | ||
| Line 26: | Line 27: | ||
| Um die serielle Schnittstelle auf dem Raspberry Pi zu aktivieren, nutzt man den Befehl '' | Um die serielle Schnittstelle auf dem Raspberry Pi zu aktivieren, nutzt man den Befehl '' | ||
| - | ===== Erste manuelle Tests ===== | + | Das Terminal werden wir auch im weiteren Teil des Workshops verwenden. |
| + | |||
| + | ===== Was sind AT-Befehle und wie funktionieren sie? ===== | ||
| + | |||
| + | AT-Befehle (abgeleitet von **AT**tention) sind ein standardisierter Befehlssatz zur Steuerung von Modems und Funkmodulen über eine serielle Schnittstelle (UART). In diesem Workshop dienen sie als Brücke zwischen dem Raspberry Pi und dem LoRa-E5 Modul, um komplexe LoRaWAN-Prozesse durch einfache Textbefehle zu steuern. | ||
| + | |||
| + | ==== Funktionsweise im Projekt ==== | ||
| + | Die Kommunikation erfolgt nach einem einfachen Frage-Antwort-Prinzip: | ||
| + | |||
| + | * **Syntax:** Jeder Befehl beginnt mit dem Präfix '' | ||
| + | * **Testen:** Ein einfaches '' | ||
| + | * **Konfiguration: | ||
| + | * **Aktion:** Mit Befehlen wie '' | ||
| + | |||
| + | {{pdfjs 75%, | ||
| ===== Tests mit Python (Beispiel Skript) ===== | ===== Tests mit Python (Beispiel Skript) ===== | ||
| + | Für eine komfortable Steuerung des LoRa-Moduls steht das Skript '' | ||
| + | |||
| + | ==== Vorbereitung ==== | ||
| + | Bevor das Skript gestartet werden kann, muss die benötigte Python-Bibliothek installiert werden: | ||
| + | < | ||
| + | pip install pyserial | ||
| + | </ | ||
| + | |||
| + | Hier ist außerdem das Skript. Referenziere es gerne um bestimmte Funktionen zu verstehen: | ||
| + | <file python LoRaWorkshop.py> | ||
| + | import serial | ||
| + | import time | ||
| + | |||
| + | PORT = "/ | ||
| + | BAUD = 9600 | ||
| + | |||
| + | def send_command(ser, | ||
| + | """ | ||
| + | ser.write(f" | ||
| + | start_time = time.time() | ||
| + | response = "" | ||
| + | |||
| + | while (time.time() - start_time) < timeout: | ||
| + | if ser.in_waiting > 0: | ||
| + | line = ser.readline().decode(errors=' | ||
| + | if line: | ||
| + | print(f" | ||
| + | response += line | ||
| + | if wait_for in line: | ||
| + | return True | ||
| + | return False | ||
| + | |||
| + | def main_menu(): | ||
| + | try: | ||
| + | ser = serial.Serial(PORT, | ||
| + | print(" | ||
| + | |||
| + | while True: | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | print(" | ||
| + | # print(" | ||
| + | |||
| + | choice = input(" | ||
| + | |||
| + | if choice == ' | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | print(" | ||
| + | keywords = [" | ||
| + | ser.write(b" | ||
| + | start_time = time.time() | ||
| + | joined = False | ||
| + | |||
| + | while (time.time() - start_time) < 30: | ||
| + | if ser.in_waiting > 0: | ||
| + | line = ser.readline().decode(errors=' | ||
| + | if line: | ||
| + | print(f" | ||
| + | line_lower = line.lower() | ||
| + | if any(key in line_lower for key in keywords): | ||
| + | joined = True | ||
| + | break | ||
| + | if " | ||
| + | break | ||
| + | |||
| + | if joined: | ||
| + | print(" | ||
| + | else: | ||
| + | print(" | ||
| + | |||
| + | elif choice == ' | ||
| + | msg = input(" | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | hex_payload = input(" | ||
| + | hex_payload = hex_payload.replace(" | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | send_command(ser, | ||
| + | | ||
| + | elif choice == ' | ||
| + | msg = input(" | ||
| + | print(" | ||
| + | try: | ||
| + | while True: | ||
| + | print(f" | ||
| + | send_command(ser, | ||
| + | print(" | ||
| + | time.sleep(45) | ||
| + | # Es gibt Gesetzliche Vorgaben (5min) für den Abstand von Signalen | ||
| + | # Wollen ja nicht die Bundesnetzagentur im nacken haben | ||
| + | except KeyboardInterrupt: | ||
| + | print(" | ||
| + | |||
| + | elif choice == ' | ||
| + | msg = input(" | ||
| + | send_command(ser, | ||
| + | |||
| + | elif choice == ' | ||
| + | print(" | ||
| + | ser.close() | ||
| + | break | ||
| + | else: | ||
| + | print(" | ||
| + | | ||
| + | time.sleep(1) | ||
| + | |||
| + | except serial.SerialException as e: | ||
| + | print(f" | ||
| + | |||
| + | if __name__ == " | ||
| + | main_menu() | ||
| + | </ | ||
| + | |||
| + | ==== Skript starten ==== | ||
| + | Navigiere im Terminal in den Ordner, in dem die Datei liegt, und führe sie aus: | ||
| + | < | ||
| + | python LoRaWorkshop.py | ||
| + | </ | ||
| + | |||
| + | ==== Funktionsübersicht ==== | ||
| + | Nach dem Start erscheint ein Auswahlmenü mit folgenden Optionen: | ||
| + | |||
| + | ^ Auswahl ^ Funktion ^ Beschreibung ^ | ||
| + | | **1** | Test (AT) | Prüft, ob die RX/ | ||
| + | | **2** | IDs auslesen | Zeigt DevEui, DevAddr und AppEui für die TTN-Registrierung an. | | ||
| + | | **3** | Mit TTN verbinden | Startet den Join-Prozess (AT+JOIN). Ein Gateway muss erreichbar sein. | | ||
| + | | **4** | Nachricht senden (Text) | Übermittelt eine Nachricht im Klartext. | | ||
| + | | **5** | Nachricht senden (Hex) | Übermittelt Daten als Hexadezimal-Zeichen (ASCII-Code). | | ||
| + | | **6** | Reset | Startet das LoRa-Modul neu, falls es nicht reagiert. | | ||
| + | | **7** | Loop-Modus | Sendet automatisch alle 45 Sekunden eine Nachricht. | | ||
| + | | **f** | Verbindung erzwingen | Verlässt bestehende Sitzungen und erzwingt einen neuen Join (Force). | | ||
| + | | **q** | Beenden | Schließt das Skript (auch per STRG+C möglich). | | ||
| + | |||
| + | > **Hinweis: | ||
| + | |||
| + | ==== Payload Decoder ==== | ||
| + | Um die Daten, welche in TTN über LoRaWAN ankommen, zu decodieren kann ein sogenannter Payload Decoder hinterlegt werden. Da die Daten in diesem Fall über die ASCII Tabelle (Gerne mal googeln) codiert wurden in Hexadezimal, | ||
| + | <file javascript decoder.js> | ||
| + | function decodeUplink(input) { | ||
| + | var bytes = input.bytes; | ||
| + | | ||
| + | // Konvertierung der Bytes in einen String (ASCII) | ||
| + | var text = ""; | ||
| + | for (var i = 0; i < bytes.length; | ||
| + | text += String.fromCharCode(bytes[i]); | ||
| + | } | ||
| + | |||
| + | return { | ||
| + | data: { | ||
| + | type: " | ||
| + | message: text, | ||
| + | length: bytes.length | ||
| + | } | ||
| + | }; | ||
| + | } | ||
| + | </ | ||
| ===== Credits ===== | ===== Credits ===== | ||
lets_plaiy/lorawan/start.1777302866.txt.gz · Last modified: 2026/04/27 17:14 by jan.sonntag