From f36a126200082e362cb481eaeeb809454be9f2a2 Mon Sep 17 00:00:00 2001 From: ppfeiffer Date: Thu, 19 Feb 2026 17:37:49 +0100 Subject: [PATCH] feat(nina): aktive Warnmeldungen beim Seitenaufruf laden (GET /api/nina/alerts) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _active speichert jetzt msgType/area/monitor_only. get_active_alerts() gibt sortierte Liste zurück. nina.js lädt beim Init und dedupliziert per ID. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 9 +++++++++ config.yaml | 2 +- meshbot/nina.py | 6 ++++++ meshbot/webserver.py | 7 +++++++ static/js/nina.js | 20 ++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2e634b..1d0488c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.8.9] - 2026-02-19 + +### Added +- **NINA aktive Warnmeldungen beim Seitenaufruf laden**: Neuer Endpunkt + `GET /api/nina/alerts` gibt alle aktuell aktiven Warnungen aus `_active` zurück. + Die NINA-Seite lädt diese beim Init und zeigt sie in der Tabelle an — auch + Warnungen die bereits vor dem Seitenaufruf ins Mesh gesendet wurden. + Neu eintreffende WS-Events (`nina_alert`) werden per ID dedupliziert. + ## [0.8.8] - 2026-02-19 ### Changed diff --git a/config.yaml b/config.yaml index cc2fd86..3a8f4cf 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -version: "0.8.8" +version: "0.8.9" bot: name: "MeshDD-Bot" diff --git a/meshbot/nina.py b/meshbot/nina.py index 3e7ae16..5f9b937 100644 --- a/meshbot/nina.py +++ b/meshbot/nina.py @@ -156,6 +156,9 @@ class NinaBot: def get_config(self) -> dict: return {**self.config, "last_poll": self._last_poll} + def get_active_alerts(self) -> list[dict]: + return sorted(self._active.values(), key=lambda x: x.get("sent", ""), reverse=True) + def update_config(self, updates: dict) -> dict: if "sources" in updates: self.config["sources"] = { @@ -444,8 +447,11 @@ class NinaBot: "channel": channel, "headline": headline, "severity": severity, + "msgType": msg_type, "id": identifier, "sent": sent, + "area": area, + "monitor_only": not self.config.get("send_to_mesh", True), } if self.config.get("send_to_mesh", True): diff --git a/meshbot/webserver.py b/meshbot/webserver.py index 27bf3cd..69e819e 100644 --- a/meshbot/webserver.py +++ b/meshbot/webserver.py @@ -79,6 +79,7 @@ class WebServer: self.app.router.add_get("/api/node/config", self._api_node_config) self.app.router.add_get("/api/nina/config", self._api_nina_get) self.app.router.add_put("/api/nina/config", self._api_nina_update) + self.app.router.add_get("/api/nina/alerts", self._api_nina_alerts) self.app.router.add_get("/login", self._serve_login) self.app.router.add_get("/register", self._serve_login) self.app.router.add_get("/admin", self._serve_admin) @@ -222,6 +223,12 @@ class WebServer: asyncio.create_task(self.nina.trigger_poll()) return web.json_response(cfg) + async def _api_nina_alerts(self, request: web.Request) -> web.Response: + require_admin_api(request) + if not self.nina: + return web.json_response([]) + return web.json_response(self.nina.get_active_alerts()) + async def _api_scheduler_get(self, request: web.Request) -> web.Response: if not self.scheduler: return web.json_response([], status=200) diff --git a/static/js/nina.js b/static/js/nina.js index 5f997ab..80a7eae 100644 --- a/static/js/nina.js +++ b/static/js/nina.js @@ -241,11 +241,30 @@ function renderAlerts() { } function addAlert(alert) { + // Replace existing entry with same id (dedup) + const idx = alerts.findIndex(a => a.id === alert.id); + if (idx !== -1) alerts.splice(idx, 1); alerts.unshift(alert); if (alerts.length > MAX_ALERTS) alerts.pop(); renderAlerts(); } +async function loadAlerts() { + try { + const resp = await fetch('/api/nina/alerts'); + if (!resp.ok) return; + const data = await resp.json(); + if (!Array.isArray(data) || data.length === 0) return; + data.forEach(a => { + alerts.push(a); + }); + if (alerts.length > MAX_ALERTS) alerts.length = MAX_ALERTS; + renderAlerts(); + } catch (e) { + console.error('NINA alerts load failed:', e); + } +} + // ── WebSocket ───────────────────────────────────────────────────────────────── function connectWebSocket() { @@ -267,4 +286,5 @@ function connectWebSocket() { fillDatalist(); loadConfig(); +loadAlerts(); connectWebSocket();