diff --git a/docs/bot-beschreibung.md b/docs/bot-beschreibung.md new file mode 100644 index 0000000..e647841 --- /dev/null +++ b/docs/bot-beschreibung.md @@ -0,0 +1,597 @@ +# MeshDD-Bot — Vollständige Beschreibung + +> Aktueller Stand: **v0.8.9** · Letztes Update: 2026-02-19 + +--- + +## Inhaltsverzeichnis + +1. [Überblick](#überblick) +2. [Architektur](#architektur) +3. [Komponenten im Detail](#komponenten-im-detail) +4. [Bot-Kommandos](#bot-kommandos) +5. [Weboberfläche & Seiten](#weboberfläche--seiten) +6. [REST-API-Referenz](#rest-api-referenz) +7. [Zugriffsrechte](#zugriffsrechte) +8. [Konfiguration](#konfiguration) +9. [Datenbank](#datenbank) +10. [Deployment](#deployment) +11. [Wichtige Erweiterungsschritte](#wichtige-erweiterungsschritte) + +--- + +## Überblick + +**MeshDD-Bot** ist ein Python-basierter Bot für **Meshtastic**-Funknetze mit integriertem Web-Dashboard. Er verbindet sich per TCP mit einem lokalen Meshtastic-Node, empfängt und speichert alle Pakete im Netz, beantwortet Bot-Kommandos und stellt eine browserbasierte Oberfläche für Echtzeit-Monitoring, Verwaltung und Notfall-Warnsystem-Integration bereit. + +**Hauptmerkmale:** + +- Meshtastic TCP-Verbindung mit automatischem Reconnect +- Bot-Kommandos (Ping, Wetter, Node-Info, Mesh-Statistiken u.a.) +- Echtzeit-Web-Dashboard via WebSocket +- Interaktive Leaflet-Karte aller Nodes +- Zeitgesteuerter Scheduler (Cron-Ausdrücke) +- NINA BBK Warnmeldungs-Integration (warnung.bund.de) +- Benutzerverwaltung mit Rollen (public / user / admin) +- Hot-Reload für alle Konfigurationsdateien +- Paket-Log mit Typ-Filterung +- Docker-ready mit docker-compose + +--- + +## Architektur + +``` +┌─────────────────────────────────────────────────────┐ +│ main.py │ +│ asyncio event loop + threading für Meshtastic │ +│ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ +│ │ MeshBot │ │Scheduler │ │ NinaBot │ │ +│ │ bot.py │ │scheduler │ │ nina.py │ │ +│ └────┬─────┘ │ .py │ └────────┬─────────┘ │ +│ │ └────┬─────┘ │ │ +│ ┌────▼─────────────▼─────────────────▼──────────┐ │ +│ │ WebSocketManager │ │ +│ │ webserver.py (aiohttp) │ │ +│ └───────────────────┬───────────────────────────┘ │ +│ │ │ +│ ┌───────────────────▼───────────────────────────┐ │ +│ │ Database (aiosqlite) │ │ +│ │ database.py │ │ +│ └───────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ + │ TCP │ HTTP + ▼ ▼ + Meshtastic-Node Browser-Client + (192.168.11.4:4403) (Bootstrap 5.3 / Tabler) +``` + +### Technologie-Stack + +| Schicht | Technologie | +|---|---| +| Sprache | Python 3.12 | +| Async-Framework | asyncio + aiohttp | +| Meshtastic | meshtastic-python (TCPInterface) | +| Event-Bus | PyPubSub | +| Datenbank | SQLite via aiosqlite | +| Web-Server | aiohttp + WebSocket | +| Auth | bcrypt, aiohttp-session, EncryptedCookieStorage | +| Frontend | Bootstrap 5.3, Tabler 1.4.0, Bootstrap Icons | +| Karte | Leaflet.js | +| Charts | Chart.js | +| NINA-API | aiohttp (async HTTP-Polling) | +| Konfiguration | YAML (config.yaml, scheduler.yaml, nina.yaml) | +| Deployment | systemd Service / Docker + docker-compose | + +--- + +## Komponenten im Detail + +### `main.py` — Einstiegspunkt + +Startet alle Subsysteme in der richtigen Reihenfolge: + +1. SQLite-Datenbank verbinden +2. `WebSocketManager` erzeugen +3. `MeshBot` (mit Loop-Referenz) +4. `Scheduler` (referenziert Bot + WS-Manager) +5. `NinaBot` (referenziert Bot's `send_message` + WS-Manager) +6. `WebServer` starten +7. Meshtastic-Verbindung in separatem Thread starten +8. Config-Watcher, Scheduler-Watcher, NINA-Watcher als asyncio-Tasks +9. Auf SIGINT/SIGTERM warten → sauberer Shutdown + +### `meshbot/bot.py` — MeshBot + +Kernklasse für die Meshtastic-Integration: + +- **Verbindung:** `TCPInterface` über Host/Port aus `config.yaml` +- **PubSub-Subscriptions** (registriert *vor* dem Konstruktor): + - `meshtastic.receive` → Paket empfangen + - `meshtastic.connection.established` → Verbindung hergestellt + - `meshtastic.connection.lost` → Verbindung verloren + - `meshtastic.node.updated` → Node-Update +- **Race-Condition-Fix:** `threading.Event` wartet nach dem Konstruktor bis zu 10 s auf `connection.established`; Fallback-Initialisierung nur bei echtem Ausbleiben +- **Paket-Handler:** Extrahiert portnum, from/to-IDs, SNR, RSSI, Hop-Infos; erstellt `payload_summary` je Pakettyp +- **Nachrichtenversand:** `_send_text()` teilt lange Nachrichten automatisch mit `[x/y]`-Nummerierung (max. 170 Byte); 3 Sekunden Pause zwischen Teilen +- **Node-Config:** `get_node_config()` liest LoRa, Device, Channels, Position, Power, Bluetooth, Network via Protobuf + +**Unterstützte Pakettypen mit Payload-Zusammenfassung:** + +| Portnum | Gespeicherte Felder | +|---|---| +| `TEXT_MESSAGE_APP` | Nachrichtentext | +| `POSITION_APP` | lat, lon, alt, Geschwindigkeit, Satelliten | +| `TELEMETRY_APP` | Akku, Spannung, CH-Util, TX-Util, Temp, Feuchte, Druck | +| `NODEINFO_APP` | long_name, short_name, hw_model | +| `ROUTING_APP` | Fehlercode | +| `TRACEROUTE_APP` | Hop-Anzahl, Route | +| `NEIGHBORINFO_APP` | Anzahl Nachbarn | + +### `meshbot/nina.py` — NinaBot + +Integration des **NINA Warn-App des BBK** (Bundesamt für Bevölkerungsschutz und Katastrophenhilfe): + +- **API-Basis:** `https://warnung.bund.de/api31` +- **Duales Polling** pro Zyklus: + 1. **Dashboard-Endpunkt** (`/dashboard/{AGS12}.json`) — regionale Filterung durch den BBK-Server; bevorzugt wenn AGS-Codes konfiguriert + 2. **mapData-Endpunkt** (`/{quelle}/mapData.json`) — bundesweit, nur aktiv wenn **keine** AGS-Codes konfiguriert +- **De-Duplikation:** ID-Normalisierung verhindert Doppelmeldungen (`dwdmap.` → `dwd.`, `mow.` → `mowas.` usw.) +- **Schweregrade:** Minor / Moderate / Severe (Standard) / Extreme +- **Quellen:** Katwarn, BIWAPP, MoWaS, DWD, LHP, Polizei (einzeln aktivierbar) +- **Monitor-Modus:** `send_to_mesh=false` → Weboberfläche empfängt Warnungen, kein Funk-Versand +- **Resend-Loop:** Aktive Warnungen werden in konfigurierbarem Abstand erneut gesendet +- **Hot-Reload:** Konfigurationsänderungen in `nina.yaml` werden live übernommen +- **AGS-Unterstützung:** Alle 13 sächsischen Landkreise / kreisfreie Städte mit lesbaren Namen + +**Mesh-Nachrichtenformat:** +``` +[NINA] Schwerwiegend: Sturmböen (Dresden, Stadt) +Beschreibung des Ereignisses (max. 120 Zeichen)... + +[NINA] Aufgehoben: Sturmböen (Dresden, Stadt) +``` + +### `meshbot/scheduler.py` — Scheduler + +Zeitgesteuerte Bot-Aktionen via Cron-Ausdrücke: + +- **Cron-Parser:** eigene Implementierung (keine externen Abhängigkeiten) + - Format: `Minute Stunde Tag Monat Wochentag` + - Unterstützt `*`, `*/N`, Einzelwerte und Kommalisten +- **Job-Typen:** `command` (Bot-Kommando) oder `message` (freier Text) +- **Template-Variablen** für Nachrichten-Jobs: + - `{time}`, `{date}`, `{datetime}`, `{weekday}` + - `{nodes}`, `{nodes_24h}` (live aus der DB) +- **Hot-Reload:** Änderungen in `scheduler.yaml` werden alle 2 Sekunden erkannt +- **CRUD-API:** Jobs können über die Weboberfläche angelegt, bearbeitet und gelöscht werden + +### `meshbot/webserver.py` — WebServer + +aiohttp-basierter HTTP- und WebSocket-Server: + +- **WebSocketManager:** trennt `clients` (alle) von `auth_clients` (authentifiziert) +- **Initial-Payload bei WS-Verbindung:** Nodes, Stats, Channels, my_node_id, Bot-Status, letzte 200 Pakete, letzte 50 Nachrichten (nur auth) +- **broadcast vs. broadcast_auth:** Nachrichten und Warnmeldungen nur an authentifizierte Clients + +### `meshbot/auth.py` — Authentifizierung + +Session-basierte Authentifizierung mit E-Mail-Verifikation: + +- **Passwort-Hashing:** bcrypt, 12 Runden, Mindestlänge 8 Zeichen +- **Session-Storage:** `EncryptedCookieStorage` (Fernet, AES-128-CBC) +- **Token-System:** UUID-Tokens für Verifikation und Passwort-Reset (24h gültig) +- **E-Mail-Versand:** aiosmtplib (TLS Port 465), Fallback: Link ins Server-Log +- **Rollen:** `public` (nicht eingeloggt), `user`, `admin` +- **Admin kann:** Benutzer anlegen/bearbeiten/löschen, Rollen ändern, manuell verifizieren, Passwörter zurücksetzen, Info-Mails versenden + +### `meshbot/database.py` — Datenbank + +SQLite via aiosqlite mit WAL-Modus für bessere Nebenläufigkeit: + +| Tabelle | Inhalt | +|---|---| +| `nodes` | Alle bekannten Meshtastic-Nodes (ID, Name, HW, Position, Batterie, SNR, Hops) | +| `messages` | Empfangene und gesendete Textnachrichten | +| `commands` | Bot-Kommando-Protokoll pro Kanal | +| `packets` | Alle empfangenen Pakete mit Typ und Payload | +| `users` | Registrierte Web-Benutzer | +| `tokens` | Verifikations- und Reset-Tokens | +| `email_logs` | E-Mail-Versandprotokoll | + +Automatische DB-Migration bei Schema-Änderungen (z.B. `channel`-Spalte in `commands`). + +### `meshbot/config.py` — Konfiguration + +Live-Reload-fähige Konfiguration aus `config.yaml`: + +- Datei-Watcher prüft alle 5 Sekunden auf Änderungen +- Umgebungsvariablen über `config.env()` (für Secrets wie AUTH_SECRET_KEY, SMTP) +- Verschachtelte Keys per Punkt-Notation: `config.get("meshtastic.host")` + +--- + +## Bot-Kommandos + +Alle Kommandos beginnen mit dem konfigurierten Präfix (Standard: `?`). + +| Kommando | Beschreibung | +|---|---| +| `?ping` | Antwortet mit „Pong" und Hop-Anzahl des Absenders | +| `?nodes` | Anzahl bekannter Nodes im Netz | +| `?info` | Bot-Name, Version und Uptime | +| `?help` | Liste aller Kommandos | +| `?stats` | Gesamt-Nodes, aktive Nodes (24h), Anfragen-Zähler | +| `?uptime` | Laufzeit des Bots | +| `?me` | Eigene Node-Infos (Name, HW, Hops, SNR, RSSI, Batterie, Position) | +| `?weather` | Aktuelles Wetter am eigenen Standort (open-meteo.com) | +| `?weather plz:XXXXX` | Wetter für deutsche Postleitzahl | +| `?mesh` | Mesh-Netzwerk-Übersicht (Online-Nodes, Hop-Verteilung, Top-Hardware) | + +Lange Antworten werden automatisch gesplittet (`[1/3] ... [2/3] ... [3/3]`). + +--- + +## Weboberfläche & Seiten + +Alle Seiten verwenden ein einheitliches Layout: Tabler 1.4.0 (Bootstrap 5.3), fixed Top-Navbar (46px), Sidebar (200px), Content-Wrapper. Theme-Toggle (Hell/Dunkel) auf allen Seiten. Sidebar-Einträge für Admin-Bereiche werden per JS ausgeblendet wenn nicht admin. + +### `/` — Dashboard (public: Nodes/Stats, user: Nachrichten/Senden) + +- **Info-Boxen:** Nodes gesamt, aktiv (24h), Anfragen (24h), Bot-Uptime +- **Nodes-Tabelle:** Name, ID, HW, Hops, SNR, RSSI, Batterie, Zuletzt gesehen; Suchfeld, Online-Filter, sortierbar +- **Node-Detail-Modal:** Klick auf Node-Zeile öffnet Modal mit allen Feldern + Leaflet-Minikarte +- **Kanalfilter** in der Nachrichtenliste +- **Sende-Card** (user): Kanal-Dropdown + Textfeld → `POST /api/send` +- **Charts** (3 + 1): + - Kanal-Anfragen (Doughnut) + - Hop-Verteilung (Bar) + - Hardware Top-5 (Bar) + - Pakettypen 24h (Doughnut) + +### `/map` — Karte (public) + +- Leaflet.js mit Node-Markierungen +- **Farb-Codierung nach Hop-Anzahl:** Direkt=Grün, 1 Hop=Blau, 2 Hops=Orange, ≥3 Hops=Rot, via MQTT=Lila +- **Transparenz nach Alter:** <24h=90%, 24–48h=45%, 48–72h=20%, >72h=ausgeblendet +- **Kartenlegende** (topleft): Theme-aware, kompaktes Design mit HOPS- und ALTER-Sektionen +- **Dark/Light Tiles:** CartoDB Dark Matter / OpenStreetMap, wechselt live mit Theme +- **Tooltip** mit Node-Name, HW, Hops, Batterie, SNR beim Hover + +### `/packets` — Paket-Log (public) + +- Echtzeit-Tabelle aller empfangenen Pakete (max. 300 Einträge im Browser) +- Spalten: Zeit, Von, An, Typ, Kanal, SNR, RSSI, Hops, Info +- **Typ-Filterleiste** (farbige Pills, aktiv/inaktiv) +- **Pause- und Löschen-Funktion** +- Eigene Telemetrie-Pakete werden unterdrückt (`my_node_id` oder FTLW-Fallback) +- Informativer Info-Payload je Pakettyp + +### `/scheduler` — Scheduler (admin) + +- Jobs-Tabelle: Name, Cron-Ausdruck, Typ, Kommando/Nachricht, Kanal, Aktiv +- CRUD-Modals für Anlegen/Bearbeiten/Löschen +- Variablen-Badges (`{time}`, `{date}`, ...) klickbar im Nachrichten-Modus + +### `/nina` — NINA-Warnmeldungen (admin) + +- **Konfigurationskarte** mit allen NINA-Einstellungen (aktiviert, Send-to-Mesh, Intervalle, Kanal, Schweregrad, AGS-Codes, Quellen) +- **AGS-Code-Tabelle** mit Ortsname und Lösch-Button; Combobox mit allen sächsischen AGS-Codes +- **Status-Badge** (Aktiv/Deaktiviert, Regions-Anzahl, Mesh+Web/Nur Web) +- **Warnmeldungs-Tabelle:** Schweregrad-Badge, Headline, Gebiet, Typ, Mesh-Icon, Zeitstempel +- Aktive Warnungen werden beim Seitenaufruf sofort geladen (`GET /api/nina/alerts`) +- Neue Warnungen erscheinen live via WebSocket + +### `/settings` — Node-Einstellungen (admin) + +- Liest aktuelle Konfiguration vom lokalen Meshtastic-Node +- Zeigt: Gerät (Name, Firmware, HW-Modell, Node-Num), LoRa (Region, Preset, Hops, TX-Power), Kanäle, Position, Power, Bluetooth, Netzwerk + +### `/admin` — Benutzerverwaltung (admin) + +- Benutzertabelle mit Rolle, Verifikationsstatus, Erstellt-Datum +- Aktionen: Anlegen, Bearbeiten, Rolle ändern, Passwort zurücksetzen, verifizieren, löschen, Info-Mail senden +- Passwort-Generator in der UI + +### `/login` + `/register` — Authentifizierung (public) + +- Login / Registrierung / Passwort vergessen auf einer Seite +- E-Mail-Verifikationsflow: Token → Passwort setzen → Login +- Passwort-Reset-Flow analog + +--- + +## REST-API-Referenz + +### Öffentliche Endpunkte + +| Methode | Pfad | Beschreibung | +|---|---|---| +| `GET` | `/api/nodes` | Alle Nodes | +| `GET` | `/api/stats` | Statistiken + Version + Uptime | +| `GET` | `/api/packets` | Letzte Pakete (limit-Parameter) | +| `GET` | `/ws` | WebSocket-Verbindung | + +### User-Endpunkte + +| Methode | Pfad | Beschreibung | +|---|---|---| +| `GET` | `/api/auth/me` | Eigene Benutzerdaten | +| `GET` | `/api/messages` | Letzte Nachrichten | +| `POST` | `/api/send` | Nachricht senden | + +### Admin-Endpunkte + +| Methode | Pfad | Beschreibung | +|---|---|---| +| `GET` | `/api/node/config` | Node-Konfiguration lesen | +| `GET/POST` | `/api/scheduler/jobs` | Jobs lesen / anlegen | +| `PUT/DELETE` | `/api/scheduler/jobs/{name}` | Job bearbeiten / löschen | +| `GET` | `/api/nina/config` | NINA-Konfiguration lesen | +| `PUT` | `/api/nina/config` | NINA-Konfiguration speichern + Poll auslösen | +| `GET` | `/api/nina/alerts` | Aktuell aktive Warnmeldungen | +| `GET/POST` | `/api/admin/users` | Alle Benutzer / Anlegen | +| `PUT` | `/api/admin/users/{id}` | Benutzer bearbeiten | +| `DELETE` | `/api/admin/users/{id}` | Benutzer löschen | +| `POST` | `/api/admin/users/{id}/role` | Rolle ändern | +| `POST` | `/api/admin/users/{id}/verify` | Manuell verifizieren | +| `POST` | `/api/admin/users/{id}/reset-password` | Passwort zurücksetzen | +| `POST` | `/api/admin/users/{id}/send-info` | Info-Mail senden | + +### Auth-Endpunkte + +| Methode | Pfad | Beschreibung | +|---|---|---| +| `POST` | `/auth/login` | Einloggen | +| `POST` | `/auth/register` | Registrieren | +| `GET` | `/auth/logout` | Ausloggen | +| `GET` | `/auth/verify` | Verifikations-Link | +| `POST` | `/auth/set-password` | Passwort nach Verifikation setzen | +| `POST` | `/auth/forgot-password` | Passwort-Reset anfordern | +| `GET/POST` | `/auth/reset-password` | Passwort zurücksetzen | + +### WebSocket-Events (Server → Client) + +| Event | Inhalt | Auth | +|---|---|---| +| `initial` | Alle Nodes | alle | +| `stats_update` | Statistiken | alle | +| `channels` | Kanäle | alle | +| `my_node_id` | Eigene Node-ID | alle | +| `bot_status` | connected + uptime | alle | +| `initial_packets` | Letzte 200 Pakete | alle | +| `node_update` | Node-Daten (ein Node) | alle | +| `packet` | Neues Paket | alle | +| `initial_messages` | Letzte 50 Nachrichten | auth | +| `new_message` | Neue Nachricht | auth | +| `scheduler_update` | Jobs-Liste | alle | +| `nina_alert` | Neue Warnmeldung | alle | + +--- + +## Zugriffsrechte + +| Bereich | Public | User | Admin | +|---|---|---|---| +| Dashboard (Nodes, Stats, Karte) | Ja | Ja | Ja | +| Paket-Log | Ja | Ja | Ja | +| Dashboard (Nachrichten, Senden) | Nein | Ja | Ja | +| Scheduler | Nein | Nein | Ja | +| NINA-Verwaltung | Nein | Nein | Ja | +| Node-Einstellungen | Nein | Nein | Ja | +| Benutzerverwaltung | Nein | Nein | Ja | + +--- + +## Konfiguration + +### `config.yaml` — Hauptkonfiguration + +```yaml +version: "0.8.9" + +bot: + name: "MeshDD-Bot" + command_prefix: "?" # Präfix für Bot-Kommandos + +meshtastic: + host: "192.168.11.4" # IP des Meshtastic-Nodes + port: 4403 # TCP-Port + +web: + host: "0.0.0.0" # Web-Server-Bindung + port: 8081 # Web-Server-Port + +database: + path: "meshdd.db" # Pfad zur SQLite-DB + +auth: + session_max_age: 86400 # Session-Gültigkeit in Sekunden +``` + +### `.env` — Secrets (Umgebungsvariablen) + +``` +AUTH_SECRET_KEY=change-this-secret-key-32bytes!! +SMTP_HOST=ssl0.example.com +SMTP_PORT=465 +SMTP_USER=bot@example.com +SMTP_PASSWORD=secret +SMTP_FROM=MeshDD-Bot +SMTP_APP_URL=http://192.168.11.x:8081 +``` + +Ohne `SMTP_HOST` werden Verifikationslinks ins Server-Log ausgegeben (kein E-Mail-Versand). + +### `scheduler.yaml` — Scheduler-Jobs + +```yaml +jobs: + - name: "tagesinfo" + enabled: true + cron: "0 8 * * *" # täglich 08:00 + type: "message" + command: "Guten Morgen! Heute {weekday}, {date}. Aktive Nodes: {nodes_24h}" + channel: 0 + - name: "morgen-ping" + enabled: false + cron: "0 7 * * 1-5" # Mo–Fr 07:00 + type: "command" + command: "?ping" + channel: 0 +``` + +**Cron-Felder:** `Minute(0-59) Stunde(0-23) Tag(1-31) Monat(1-12) Wochentag(0-6, 0=Sonntag)` + +**Template-Variablen:** `{time}` `{date}` `{datetime}` `{weekday}` `{nodes}` `{nodes_24h}` + +### `nina.yaml` — NINA-Konfiguration + +```yaml +enabled: false +send_to_mesh: true +poll_interval: 300 # Abfrageintervall in Sekunden (min. 60) +resend_interval: 3600 # Wiederholungsintervall aktiver Warnungen +channel: 0 # Meshtastic-Kanal 0–7 +min_severity: Severe # Minor | Moderate | Severe | Extreme +ags_codes: + - "146120000000" # Dresden, Stadt + - "146270000000" # Meißen + - "146280000000" # Sächsische Schweiz-Osterzgebirge + - "146250000000" # Bautzen + - "146260000000" # Görlitz +sources: + katwarn: true + biwapp: true + mowas: true + dwd: true + lhp: true + police: false +``` + +--- + +## Datenbank + +SQLite-Datei `meshdd.db` (konfigurierbar). WAL-Modus für bessere Nebenläufigkeit. + +### Tabelle `nodes` + +```sql +node_id TEXT PRIMARY KEY, -- z.B. "!1a2b3c4d" +node_num INTEGER, -- Dezimalzahl +long_name TEXT, -- Langer Name +short_name TEXT, -- Kurzname (4 Zeichen) +hw_model TEXT, -- Hardware-Modell +lat REAL, lon REAL, -- Position +alt REAL, -- Höhe in Metern +battery INTEGER, -- Akkustand 0–100% +voltage REAL, -- Spannung in Volt +snr REAL, -- Signal-Rausch-Abstand +rssi INTEGER, -- Empfangsstärke in dBm +last_seen REAL, -- Unix-Timestamp +first_seen REAL, -- Unix-Timestamp +hop_count INTEGER, -- Hops vom Bot +via_mqtt INTEGER -- 0 oder 1 +``` + +### Tabelle `packets` + +```sql +id INTEGER PRIMARY KEY AUTOINCREMENT, +timestamp REAL, +from_id TEXT, to_id TEXT, +portnum TEXT, -- z.B. "TEXT_MESSAGE_APP" +channel INTEGER, +snr REAL, rssi INTEGER, +hop_limit INTEGER, hop_start INTEGER, +packet_id INTEGER, +payload TEXT -- JSON-Zusammenfassung je Typ +``` + +--- + +## Deployment + +### Systemd-Service + +```bash +# Service-Datei installieren +sudo cp meshdd-bot.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable meshdd-bot +sudo systemctl start meshdd-bot + +# Logs live verfolgen +journalctl -u meshdd-bot -f +``` + +### Docker / docker-compose + +```bash +# Bauen und starten +docker compose up -d + +# Logs +docker compose logs -f + +# Stoppen +docker compose down +``` + +`docker-compose.yml` verwendet Host-Netzwerk (direkter TCP-Zugriff auf Meshtastic-Node), Named Volume für SQLite, JSON-File-Logging (10 MB / 3 Dateien) und Health-Check (`/api/stats` alle 30s). + +### Direkt (Entwicklung) + +```bash +cd /home/peter/MeshDD-Bot +source venv/bin/activate +python main.py +``` + +--- + +## Wichtige Erweiterungsschritte + +Die folgende Tabelle zeigt die wichtigsten Entwicklungsmeilensteine von der ersten Version bis heute: + +| Version | Datum | Erweiterungsschritt | +|---|---|---| +| **0.1.0** | 2026-02-15 | **Grundgerüst:** Meshtastic TCP-Bot, SQLite-DB, Web-Dashboard mit WebSocket, Leaflet-Karte, Bot-Kommandos (ping, nodes, info, help, weather, stats, uptime) | +| **0.2.0** | 2026-02-15 | **Konfiguration & Karte:** Zentrale `config.yaml` mit Live-Reload, Hop-Farbcodierung auf der Karte, Theme-Toggle (Hell/Dunkel), Kanalnamen in Nachrichten | +| **0.2.5** | 2026-02-15 | **Nachrichten-Splitting:** Automatisches Aufteilen langer Nachrichten mit `[x/y]`-Nummerierung und Pause | +| **0.3.1** | 2026-02-15 | **Scheduler:** Zeitgesteuerte Bot-Kommandos via Cron-Ausdrücke, `scheduler.yaml` mit File-Watcher, REST-CRUD-API, Live-Updates via WebSocket | +| **0.3.2** | 2026-02-15 | **Nachrichten senden:** Direktes Senden aus dem Dashboard (`POST /api/send`); Scheduler-Typ „Nachricht" | +| **0.3.5** | 2026-02-15 | **AdminLTE-Layout:** Einheitliches Sidebar-Layout für alle Seiten mit Active-State | +| **0.3.6** | 2026-02-15 | **Node-Einstellungen:** `/settings`-Seite liest Gerät, LoRa, Kanäle, Position, Power, Bluetooth via Protobuf vom Node | +| **0.4.0** | 2026-02-16 | **UX-Verbesserungen:** `?me`-Kommando, Ping mit Hop-Anzahl, PLZ-Support fürs Wetter, Luftdruck & Taupunkt, gesendete Nachrichten im Dashboard | +| **0.5.0** | 2026-02-16 | **Benutzerverwaltung:** Session-Auth mit bcrypt, E-Mail-Verifikation, Rollen (public/user/admin), Admin-Panel, Passwort-Reset | +| **0.5.3** | 2026-02-16 | **Secrets in .env:** AUTH_SECRET_KEY und SMTP-Einstellungen aus config.yaml in Umgebungsvariablen ausgelagert | +| **0.5.4** | 2026-02-16 | **Admin erweitert:** Benutzer direkt anlegen mit Passwort, Bearbeiten-Modal, Passwort-Reset, Passwort-Generator | +| **0.6.0** | 2026-02-17 | **Node-Detail-Modal:** Klick auf Node → Modal mit allen Feldern + Leaflet-Minikarte | +| **0.6.1** | 2026-02-17 | **Docker-Support:** Dockerfile, docker-compose.yml, .dockerignore | +| **0.6.2** | 2026-02-17 | **Geteiltes app.js:** ~360 Zeilen duplizierten Frontend-Code in gemeinsames Modul extrahiert | +| **0.6.3** | 2026-02-17 | **WebSocket-Sicherheit:** `auth_clients` vs. `clients` — Nachrichten nur an authentifizierte WS-Clients | +| **0.6.5** | 2026-02-17 | **Dark-Mode-Karte + Charts:** CartoDB Dark Matter, 3 Charts (Kanal, Hops, Hardware) | +| **0.6.7** | 2026-02-17 | **Tabler 1.4.0:** Professionelleres CSS-Framework, überarbeitetes style.css | +| **0.6.10** | 2026-02-18 | **Paket-Log:** Neue `/packets`-Seite, `packets`-Tabelle in DB, Typ-Filter, Echtzeit via WebSocket | +| **0.6.13** | 2026-02-18 | **Karten-Alter-Transparenz:** Nodes >72h werden ausgeblendet; Legende mit Alter-Sektion | +| **0.6.14** | 2026-02-18 | **Pakettypen-Chart:** Viertes Doughnut-Chart mit Pakettyp-Verteilung 24h | +| **0.6.15** | 2026-02-18 | **Scheduler Template-Variablen:** `{time}`, `{date}`, `{weekday}`, `{nodes}` etc.; Footer auf allen Seiten | +| **0.7.0** | 2026-02-18 | **Docker-Verbesserungen:** HEALTHCHECK, Logging-Config, korrigierter Port | +| **0.8.0** | 2026-02-19 | **NINA-Integration:** BBK Warn-App angebunden; duales Polling (Dashboard + mapData); Konfigurationsseite; Monitor-Modus; Live-Tabelle via WebSocket | +| **0.8.1** | 2026-02-19 | **NINA Resend-Loop:** Aktive Warnungen werden zyklisch wiederholt; AGS-Code-Tabelle statt Badges | +| **0.8.2** | 2026-02-19 | **NINA geografische Filterung:** mapData nur noch ohne AGS-Codes aktiv (verhindert bundesweite Meldungen) | +| **0.8.3** | 2026-02-19 | **NINA Gebietsanzeige:** Regionsname aus AGS-Labels in Meldung und Mesh-Text; Sachsen-Combobox | +| **0.8.4** | 2026-02-19 | **NINA Sofortabfrage:** Nach Speichern der Config sofort pollen; `last_poll`-Zeitstempel anzeigen | +| **0.8.5** | 2026-02-19 | **Kartenlegende Position:** von bottomright nach topleft verschoben | +| **0.8.6** | 2026-02-19 | **Paket-Log informativer:** Erweiterte Payload-Zusammenfassung; eigene Telemetrie unterdrückt | +| **0.8.7** | 2026-02-19 | **Race-Condition-Fix:** `threading.Event` verhindert falsche Startup-Warning „connection.established missed" | +| **0.8.8** | 2026-02-19 | **Kartenlegende neu gestaltet:** Theme-aware CSS-Variablen, kompaktes Design | +| **0.8.9** | 2026-02-19 | **NINA aktive Warnungen:** `GET /api/nina/alerts` gibt beim Seitenaufruf alle aktiven Warnungen zurück | + +--- + +*MeshDD-Bot — entwickelt für das Dresdner Meshtastic-Netz · © MeshDD / PPfeiffer* diff --git a/docs/whats-new-0.8.md b/docs/whats-new-0.8.md new file mode 100644 index 0000000..5eae43e --- /dev/null +++ b/docs/whats-new-0.8.md @@ -0,0 +1,205 @@ +# Was ist neu in MeshDD-Bot 0.8.x + +> Aktueller Stand: **v0.8.9** · Release-Datum: 2026-02-19 + +--- + +## Übersicht + +Release 0.8 bringt die vollständige Integration des **NINA BBK Warnsystems** in den +MeshDD-Bot, ergänzt um eine Reihe von Verbesserungen am Paket-Log, der Karte und der +Verbindungsinitialisierung. + +--- + +## Neue Funktionen + +### NINA Warnmeldungs-Integration (`/nina`) + +Der Bot ist jetzt an die **NINA Warn-App des BBK** (Bundesamt für Bevölkerungsschutz +und Katastrophenhilfe) angebunden. Warnmeldungen werden automatisch per HTTP-Polling +von `warnung.bund.de/api31` abgerufen und ins Meshtastic-Netz gesendet. + +#### Konfigurationsseite + +Unter `/nina` (Admin-only) steht eine vollständige Verwaltungsseite bereit: + +| Einstellung | Beschreibung | +|---|---| +| **Aktiviert** | NINA-Abfragen ein-/ausschalten | +| **Ins Mesh senden** | Aus = Monitor-Modus (nur Weboberfläche, kein Mesh-Versand) | +| **Abfrageintervall** | Wie oft neue Warnmeldungen abgerufen werden (Sek., min. 60) | +| **Wiederholungsintervall** | Aktive Warnungen werden in diesem Abstand erneut ins Mesh gesendet | +| **Kanal** | Meshtastic-Kanal (0–7) für den Versand | +| **Mindest-Schweregrad** | Gering / Mäßig / Schwerwiegend / Extrem | +| **AGS-Codes** | Amtliche Gemeindeschlüssel der zu überwachenden Regionen | +| **Quellen** | Katwarn, BIWAPP, MoWaS, DWD, LHP, Polizei | + +#### AGS-Code-Verwaltung + +- AGS-Codes werden in einer **Tabelle** mit Ortsname und Lösch-Button angezeigt +- Bei der Eingabe schlägt eine **Combobox** alle sächsischen Landkreise und kreisfreien + Städte vor (Name + 12-stelliger Code) +- Voreingestellt: 5 Codes für den **Raum Dresden** (Stadt Dresden, LK Meißen, + LK Sächsische Schweiz-Osterzgebirge, LK Bautzen, LK Görlitz) + +#### Polling-Strategie + +Zwei parallele Abfragestrategien pro Zyklus: + +1. **Dashboard-Endpunkt** (`/dashboard/{AGS12}.json`) — regionale Filterung durch den + BBK-Server; deckt alle Quellen für konfigurierte AGS-Codes ab. +2. **mapData-Endpunkt** (`/{quelle}/mapData.json`) — wird **nur verwendet, wenn keine + AGS-Codes konfiguriert sind** (bundesweite Abfrage ohne Geo-Filterung). + +Quellenübergreifende **De-Duplikation** via ID-Normalisierung verhindert doppelte +Meldungen (z. B. `dwdmap.` ↔ `dwd.`, `mow.` ↔ `mowas.`). + +#### Warnmeldungen im Mesh + +Nachrichten-Format im Meshtastic-Netz: + +``` +[NINA] Schwerwiegend: Sturmböen (Dresden, Stadt) +Beschreibung des Ereignisses (max. 120 Zeichen)... + +[NINA] Aufgehoben: Sturmböen (Dresden, Stadt) +``` + +Das **Herkunftsgebiet** (AGS-Regionsname) wird automatisch an Meldung und Aufhebung +angehängt. + +#### Live-Anzeige in der Weboberfläche + +Die Tabelle „Letzte Warnmeldungen" zeigt: + +| Spalte | Inhalt | +|---|---| +| **Schweregrad** | Farbiger Badge (Extrem / Schwerwiegend / Mäßig / Gering / Aufgehoben) | +| **Meldung** | Headline der Warnung | +| **Gebiet** | AGS-Regionsname (z. B. „Dresden, Stadt") | +| **Typ** | Quell-Präfix (z. B. `dwd`, `katwarn`) | +| **Mesh** | Broadcast-Icon (gesendet) oder Auge-Icon (Monitor-Only) | +| **Zeitstempel** | Sendezeitpunkt der Warnung | + +Beim Seitenaufruf werden alle **aktuell aktiven Warnungen** sofort geladen +(`GET /api/nina/alerts`). Neue Warnungen erscheinen live via WebSocket. + +#### Sofortabfrage nach dem Speichern + +Nach dem Klick auf „Speichern" wird unmittelbar eine NINA-Abfrage gestartet — kein +Warten auf den nächsten Intervall-Zyklus. Unterhalb des Abfrageintervall-Felds wird +Datum und Uhrzeit der **letzten erfolgreichen Abfrage** angezeigt. + +--- + +## Verbesserungen am Paket-Log (`/packets`) + +### Informativerer Payload + +Die Info-Spalte zeigt jetzt deutlich mehr Daten je Pakettyp: + +| Typ | Angezeigte Felder | +|---|---| +| `POSITION_APP` | Koordinaten + Höhe (m), Geschwindigkeit (km/h), Satelliten | +| `TELEMETRY_APP` | Akku (%), Spannung (V), Kanalauslastung (%), TX-Auslastung (%), Temperatur (°C), Luftfeuchtigkeit (%), Luftdruck (hPa) | +| `NODEINFO_APP` | long_name, short_name, Hardware-Modell | +| `ROUTING_APP` | Fehlercode (wenn vorhanden) | +| `TRACEROUTE_APP` | Anzahl Hops | +| `NEIGHBORINFO_APP` | Anzahl Nachbarn | + +### Unterdrückung eigener Telemetrie + +Telemetriepakete vom **eigenen Node** werden im Paket-Log weder angezeigt noch gezählt. +Die Erkennung erfolgt automatisch per `my_node_id` (WebSocket-Initial-Payload) sowie als +Fallback über den Short-Name `FTLW`. + +--- + +## Verbesserungen an der Karte (`/map`) + +### Neue Legendenposition + +Die Kartenlegende wurde von `bottomright` nach **`topleft`** verschoben — direkt +unterhalb der Zoom-Schaltfläche, wo sie auf allen Bildschirmgrößen sicher sichtbar ist. + +### Neues Legengendesign + +Die Legende wurde komplett neu gestaltet: + +- **Theme-aware**: passt sich automatisch Light- und Dark-Mode an (CSS-Variablen) +- **Kompaktes Layout**: kleine Uppercase-Abschnittsköpfe (`HOPS` / `ALTER`) +- **Weicherer Schatten** und dezentes Border + +--- + +## Bugfixes + +### Startup-Warning „connection.established missed" (fixes #2) + +Beim Start erschien regelmäßig eine Warnung im Log: + +``` +[WARNING] meshbot.bot: connection.established missed – applying fallback +``` + +**Ursache:** `bot.connect()` läuft in einem separaten Thread. Der `TCPInterface`-Konstruktor +kehrte zurück, bevor das `connection.established`-Event aus dem Meshtastic-Bibliotheks-Thread +gefeuert wurde. Der sofortige Check sah `_connected = False` und löste den Fallback aus. + +**Fix:** Ein `threading.Event` (`_conn_event`) wird in `_on_connection` gesetzt. +Nach dem Konstruktor wartet der Code bis zu 10 Sekunden auf dieses Event. Der +Fallback greift nur noch bei echtem Ausbleiben. + +--- + +## Konfigurationsdateien + +### `nina.yaml` + +Separate Hot-reload-fähige Konfigurationsdatei für NINA (analog zu `scheduler.yaml`). +Wird automatisch angelegt wenn nicht vorhanden. + +```yaml +enabled: false +send_to_mesh: true +poll_interval: 300 # Sekunden, min. 60 +resend_interval: 3600 # Sekunden, Wiederholung aktiver Warnungen +channel: 0 # Meshtastic-Kanal 0–7 +min_severity: Severe # Minor | Moderate | Severe | Extreme +ags_codes: [] +sources: + katwarn: true + biwapp: true + mowas: true + dwd: true + lhp: true + police: false +``` + +--- + +## Neue API-Endpunkte + +| Methode | Pfad | Beschreibung | Auth | +|---|---|---|---| +| `GET` | `/api/nina/config` | NINA-Konfiguration lesen | Admin | +| `PUT` | `/api/nina/config` | NINA-Konfiguration speichern + Poll auslösen | Admin | +| `GET` | `/api/nina/alerts` | Aktuell aktive Warnmeldungen | Admin | + +--- + +## Versionshistorie 0.8.x + +| Version | Datum | Schwerpunkt | +|---|---|---| +| 0.8.0 | 2026-02-19 | NINA-Integration (Grundfunktion) | +| 0.8.1 | 2026-02-19 | Wiederholungsintervall, AGS-Tabelle, Badge-Fixes | +| 0.8.2 | 2026-02-19 | mapData nur ohne AGS-Codes (geografische Filterung) | +| 0.8.3 | 2026-02-19 | Gebietsanzeige, AGS-Ortsname, Sachsen-Combobox | +| 0.8.4 | 2026-02-19 | Sofortabfrage nach Speichern, Zeitstempel letzte Abfrage | +| 0.8.5 | 2026-02-19 | Kartenlegende nach topleft verschoben (fixes #5) | +| 0.8.6 | 2026-02-19 | Informativer Paket-Payload, FTLW-Telemetrie unterdrückt (fixes #3) | +| 0.8.7 | 2026-02-19 | threading.Event-Fix für Startup-Warning (fixes #2) | +| 0.8.8 | 2026-02-19 | Kartenlegende neu gestaltet (theme-aware) | +| 0.8.9 | 2026-02-19 | Aktive NINA-Warnungen beim Seitenaufruf laden |