feat: v0.2.4 - Add /mesh command for mesh network overview

Shows total/online nodes, active 24h, positions, hop distribution,
and top 3 hardware models.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ppfeiffer 2026-02-15 14:32:03 +01:00
parent a1fe0a297d
commit b1e08ab720
3 changed files with 43 additions and 1 deletions

View file

@ -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`)

View file

@ -1,4 +1,4 @@
version: "0.2.3"
version: "0.2.4"
bot:
name: "MeshDD-Bot"

View file

@ -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