# MeshDD-Bot — Vollständige Beschreibung > Aktueller Stand: **v0.08.09** · 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.08.09" 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.01.00** | 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.02.00** | 2026-02-15 | **Konfiguration & Karte:** Zentrale `config.yaml` mit Live-Reload, Hop-Farbcodierung auf der Karte, Theme-Toggle (Hell/Dunkel), Kanalnamen in Nachrichten | | **0.02.05** | 2026-02-15 | **Nachrichten-Splitting:** Automatisches Aufteilen langer Nachrichten mit `[x/y]`-Nummerierung und Pause | | **0.03.01** | 2026-02-15 | **Scheduler:** Zeitgesteuerte Bot-Kommandos via Cron-Ausdrücke, `scheduler.yaml` mit File-Watcher, REST-CRUD-API, Live-Updates via WebSocket | | **0.03.02** | 2026-02-15 | **Nachrichten senden:** Direktes Senden aus dem Dashboard (`POST /api/send`); Scheduler-Typ „Nachricht" | | **0.03.05** | 2026-02-15 | **AdminLTE-Layout:** Einheitliches Sidebar-Layout für alle Seiten mit Active-State | | **0.03.06** | 2026-02-15 | **Node-Einstellungen:** `/settings`-Seite liest Gerät, LoRa, Kanäle, Position, Power, Bluetooth via Protobuf vom Node | | **0.04.00** | 2026-02-16 | **UX-Verbesserungen:** `?me`-Kommando, Ping mit Hop-Anzahl, PLZ-Support fürs Wetter, Luftdruck & Taupunkt, gesendete Nachrichten im Dashboard | | **0.05.00** | 2026-02-16 | **Benutzerverwaltung:** Session-Auth mit bcrypt, E-Mail-Verifikation, Rollen (public/user/admin), Admin-Panel, Passwort-Reset | | **0.05.03** | 2026-02-16 | **Secrets in .env:** AUTH_SECRET_KEY und SMTP-Einstellungen aus config.yaml in Umgebungsvariablen ausgelagert | | **0.05.04** | 2026-02-16 | **Admin erweitert:** Benutzer direkt anlegen mit Passwort, Bearbeiten-Modal, Passwort-Reset, Passwort-Generator | | **0.06.00** | 2026-02-17 | **Node-Detail-Modal:** Klick auf Node → Modal mit allen Feldern + Leaflet-Minikarte | | **0.06.01** | 2026-02-17 | **Docker-Support:** Dockerfile, docker-compose.yml, .dockerignore | | **0.06.02** | 2026-02-17 | **Geteiltes app.js:** ~360 Zeilen duplizierten Frontend-Code in gemeinsames Modul extrahiert | | **0.06.03** | 2026-02-17 | **WebSocket-Sicherheit:** `auth_clients` vs. `clients` — Nachrichten nur an authentifizierte WS-Clients | | **0.06.05** | 2026-02-17 | **Dark-Mode-Karte + Charts:** CartoDB Dark Matter, 3 Charts (Kanal, Hops, Hardware) | | **0.06.07** | 2026-02-17 | **Tabler 1.4.0:** Professionelleres CSS-Framework, überarbeitetes style.css | | **0.06.10** | 2026-02-18 | **Paket-Log:** Neue `/packets`-Seite, `packets`-Tabelle in DB, Typ-Filter, Echtzeit via WebSocket | | **0.06.13** | 2026-02-18 | **Karten-Alter-Transparenz:** Nodes >72h werden ausgeblendet; Legende mit Alter-Sektion | | **0.06.14** | 2026-02-18 | **Pakettypen-Chart:** Viertes Doughnut-Chart mit Pakettyp-Verteilung 24h | | **0.06.15** | 2026-02-18 | **Scheduler Template-Variablen:** `{time}`, `{date}`, `{weekday}`, `{nodes}` etc.; Footer auf allen Seiten | | **0.07.00** | 2026-02-18 | **Docker-Verbesserungen:** HEALTHCHECK, Logging-Config, korrigierter Port | | **0.08.00** | 2026-02-19 | **NINA-Integration:** BBK Warn-App angebunden; duales Polling (Dashboard + mapData); Konfigurationsseite; Monitor-Modus; Live-Tabelle via WebSocket | | **0.08.01** | 2026-02-19 | **NINA Resend-Loop:** Aktive Warnungen werden zyklisch wiederholt; AGS-Code-Tabelle statt Badges | | **0.08.02** | 2026-02-19 | **NINA geografische Filterung:** mapData nur noch ohne AGS-Codes aktiv (verhindert bundesweite Meldungen) | | **0.08.03** | 2026-02-19 | **NINA Gebietsanzeige:** Regionsname aus AGS-Labels in Meldung und Mesh-Text; Sachsen-Combobox | | **0.08.04** | 2026-02-19 | **NINA Sofortabfrage:** Nach Speichern der Config sofort pollen; `last_poll`-Zeitstempel anzeigen | | **0.08.05** | 2026-02-19 | **Kartenlegende Position:** von bottomright nach topleft verschoben | | **0.08.06** | 2026-02-19 | **Paket-Log informativer:** Erweiterte Payload-Zusammenfassung; eigene Telemetrie unterdrückt | | **0.08.07** | 2026-02-19 | **Race-Condition-Fix:** `threading.Event` verhindert falsche Startup-Warning „connection.established missed" | | **0.08.08** | 2026-02-19 | **Kartenlegende neu gestaltet:** Theme-aware CSS-Variablen, kompaktes Design | | **0.08.09** | 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*