diff --git a/CHANGELOG.md b/CHANGELOG.md index 54fe8d5..f236455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.2.3] - 2026-02-15 +### Added +- Kommando-Tracking in der Datenbank (neue Tabelle `commands`) +- Stats Card "Aktiv (24h)" zeigt Nodes der letzten 24 Stunden +- Stats Card "Anfragen" zeigt beantwortete Bot-Kommandos +- Kommando-Aufschlüsselung als Badges in voller Breite (z.B. /help 5, /ping 3) + +### Changed +- Stats Cards von 4er auf 3er Grid umgestellt plus Breakdown-Zeile +- Bot /stats Kommando zeigt aktualisierte Statistiken + ## [0.2.2] - 2026-02-15 ### Changed - SNR-Spalte rechtsbündig, Batterie-Spalte linksbündig diff --git a/config.yaml b/config.yaml index fd9fc6f..144da77 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -version: "0.2.2" +version: "0.2.3" bot: name: "MeshDD-Bot" diff --git a/meshbot/bot.py b/meshbot/bot.py index cc7dd74..046cbf9 100644 --- a/meshbot/bot.py +++ b/meshbot/bot.py @@ -196,9 +196,8 @@ class MeshBot: response = ( f"📊 Statistiken:\n" f"Nodes: {stats['total_nodes']}\n" - f"Mit Position: {stats['nodes_with_position']}\n" - f"Nachrichten: {stats['total_messages']}\n" - f"Textnachrichten: {stats['text_messages']}" + f"Aktiv (24h): {stats['nodes_24h']}\n" + f"Anfragen: {stats['total_commands']}" ) elif cmd == f"{prefix}uptime": @@ -206,6 +205,10 @@ class MeshBot: if response: self._send_text(response, channel) + await self.db.insert_command(cmd) + if self.ws_manager: + stats = await self.db.get_stats() + await self.ws_manager.broadcast("stats_update", stats) def _send_text(self, text: str, channel: int): if self.interface: diff --git a/meshbot/database.py b/meshbot/database.py index c594173..18b70e2 100644 --- a/meshbot/database.py +++ b/meshbot/database.py @@ -51,6 +51,12 @@ class Database: portnum TEXT, payload TEXT ); + + CREATE TABLE IF NOT EXISTS commands ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp REAL, + command TEXT + ); """) await self.db.commit() @@ -121,18 +127,28 @@ class Database: ) as cursor: return [dict(row) async for row in cursor] + async def insert_command(self, command: str): + now = time.time() + await self.db.execute( + "INSERT INTO commands (timestamp, command) VALUES (?, ?)", + (now, command), + ) + await self.db.commit() + async def get_stats(self) -> dict: stats = {} async with self.db.execute("SELECT COUNT(*) FROM nodes") as c: stats["total_nodes"] = (await c.fetchone())[0] + now = time.time() + day_ago = now - 86400 async with self.db.execute( - "SELECT COUNT(*) FROM nodes WHERE lat IS NOT NULL" + "SELECT COUNT(*) FROM nodes WHERE last_seen >= ?", (day_ago,) ) as c: - stats["nodes_with_position"] = (await c.fetchone())[0] - async with self.db.execute("SELECT COUNT(*) FROM messages") as c: - stats["total_messages"] = (await c.fetchone())[0] + stats["nodes_24h"] = (await c.fetchone())[0] + async with self.db.execute("SELECT COUNT(*) FROM commands") as c: + stats["total_commands"] = (await c.fetchone())[0] async with self.db.execute( - "SELECT COUNT(*) FROM messages WHERE portnum = 'TEXT_MESSAGE_APP'" - ) as c: - stats["text_messages"] = (await c.fetchone())[0] + "SELECT command, COUNT(*) as cnt FROM commands GROUP BY command ORDER BY cnt DESC" + ) as cursor: + stats["command_breakdown"] = {row[0]: row[1] async for row in cursor} return stats diff --git a/meshbot/webserver.py b/meshbot/webserver.py index c134360..ea23c6e 100644 --- a/meshbot/webserver.py +++ b/meshbot/webserver.py @@ -86,6 +86,7 @@ class WebServer: async def _api_stats(self, request: web.Request) -> web.Response: stats = await self.db.get_stats() + stats["version"] = config.get("version", "0.0.0") return web.json_response(stats) async def _serve_index(self, request: web.Request) -> web.Response: diff --git a/static/index.html b/static/index.html index fb52091..87a68dd 100644 --- a/static/index.html +++ b/static/index.html @@ -32,36 +32,38 @@
-
-
+
+
0
-
Nodes
+
Nodes gesamt
-
+
-
0
-
Mit Position
+
0
+
Aktiv (24h)
-
+
-
0
-
Nachrichten
+
0
+
Anfragen
-
-
-
-
0
-
Textnachrichten
+
+
+
+
+
+ Anfragen: +
diff --git a/static/js/dashboard.js b/static/js/dashboard.js index 997abb8..1c04dcb 100644 --- a/static/js/dashboard.js +++ b/static/js/dashboard.js @@ -118,9 +118,18 @@ function updateStats(stats) { document.getElementById('versionLabel').textContent = `v${stats.version}`; } document.getElementById('statNodes').textContent = stats.total_nodes || 0; - document.getElementById('statPositions').textContent = stats.nodes_with_position || 0; - document.getElementById('statMessages').textContent = stats.total_messages || 0; - document.getElementById('statTextMessages').textContent = stats.text_messages || 0; + document.getElementById('statNodes24h').textContent = stats.nodes_24h || 0; + document.getElementById('statCommands').textContent = stats.total_commands || 0; + + const breakdown = document.getElementById('commandBreakdown'); + const cmds = stats.command_breakdown || {}; + if (Object.keys(cmds).length > 0) { + breakdown.innerHTML = Object.entries(cmds).map(([cmd, count]) => + `${escapeHtml(cmd)} ${count}` + ).join(''); + } else { + breakdown.innerHTML = 'Noch keine Anfragen'; + } } function isOnline(lastSeen) {