diff --git a/CHANGELOG.md b/CHANGELOG.md index f236455..6f42094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [0.2.4] - 2026-02-15 +### Added +- Neuer Befehl /mesh - zeigt Mesh-Netzwerk-Infos (Nodes online/gesamt, aktiv 24h, Positionen, Hop-Verteilung, Top-Hardware) + ## [0.2.3] - 2026-02-15 ### Added - Kommando-Tracking in der Datenbank (neue Tabelle `commands`) diff --git a/config.yaml b/config.yaml index 144da77..714370e 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -version: "0.2.3" +version: "0.2.4" bot: name: "MeshDD-Bot" diff --git a/meshbot/bot.py b/meshbot/bot.py index 046cbf9..b5bed2c 100644 --- a/meshbot/bot.py +++ b/meshbot/bot.py @@ -185,6 +185,7 @@ class MeshBot: f"{prefix}stats - Statistiken\n" f"{prefix}uptime - Laufzeit\n" f"{prefix}weather - Wetter\n" + f"{prefix}mesh - Mesh-Netzwerk\n" f"{prefix}help - Diese Hilfe" ) @@ -200,6 +201,9 @@ class MeshBot: f"Anfragen: {stats['total_commands']}" ) + elif cmd == f"{prefix}mesh": + response = await self._get_mesh_info() + elif cmd == f"{prefix}uptime": response = f"⏱️ Uptime: {self._format_uptime()}" @@ -232,6 +236,40 @@ class MeshBot: parts.append(f"{seconds}s") return " ".join(parts) + async def _get_mesh_info(self) -> str: + nodes = await self.db.get_all_nodes() + total = len(nodes) + now = time.time() + online = sum(1 for n in nodes if n.get("last_seen") and now - n["last_seen"] < 900) + active_24h = sum(1 for n in nodes if n.get("last_seen") and now - n["last_seen"] < 86400) + with_pos = sum(1 for n in nodes if n.get("lat") and n.get("lon")) + + # Hop distribution + hop_counts = {} + for n in nodes: + h = n.get("hop_count") + if h is not None: + hop_counts[h] = hop_counts.get(h, 0) + 1 + hop_str = ", ".join(f"{k}h:{v}" for k, v in sorted(hop_counts.items())) + + # Hardware distribution (top 3) + hw_counts = {} + for n in nodes: + hw = n.get("hw_model") + if hw: + hw_counts[hw] = hw_counts.get(hw, 0) + 1 + top_hw = sorted(hw_counts.items(), key=lambda x: -x[1])[:3] + hw_str = ", ".join(f"{hw}:{cnt}" for hw, cnt in top_hw) + + return ( + f"🕸️ Mesh-Netzwerk:\n" + f"Nodes: {total} ({online} online)\n" + f"Aktiv 24h: {active_24h}\n" + f"Mit Position: {with_pos}\n" + f"Hops: {hop_str or '-'}\n" + f"Hardware: {hw_str or '-'}" + ) + async def _get_weather(self, from_id: str) -> str: node = await self.db.get_node(from_id) fallback = False