From cc392a125ab302769a83365221c20f3373303d8a Mon Sep 17 00:00:00 2001 From: ppfeiffer Date: Thu, 19 Feb 2026 17:20:35 +0100 Subject: [PATCH] =?UTF-8?q?fix(packets):=20informativer=20Payload=20+=20ei?= =?UTF-8?q?gene=20Telemetrie=20unterdr=C3=BCcken=20(fixes=20#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bot.py: vollständige Payload-Daten für Position, Telemetry (Device+Env), NodeInfo (hw_model), Routing (error), Traceroute (hops), Neighborinfo (count) - packets.js: fmtPayload() zeigt alle Felder; TELEMETRY_APP vom eigenen Node (my_node_id / short_name FTLW) wird unterdrückt und nicht gezählt Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 16 +++++++++++++ config.yaml | 2 +- meshbot/bot.py | 38 +++++++++++++++++++++++++++---- static/js/packets.js | 53 +++++++++++++++++++++++++++++++++++++++----- 4 files changed, 98 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a5c0a..544c6b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [0.8.6] - 2026-02-19 + +### Added +- **Paket-Log informativer Payload** (fixes #3): `bot.py` speichert nun vollständige + Paketdaten je Typ: + - `POSITION_APP`: lat/lon + Höhe, Geschwindigkeit, Satelliten + - `TELEMETRY_APP`: Akku, Spannung, Kanalauslastung, TX-Auslastung, Temperatur, + Luftfeuchtigkeit, Luftdruck (Environment Metrics) + - `NODEINFO_APP`: long_name, short_name + Hardware-Modell + - `ROUTING_APP`: Fehlercode (errorReason) + - `TRACEROUTE_APP`: Hop-Anzahl + - `NEIGHBORINFO_APP`: Anzahl Nachbarn +- **Telemetrie-Unterdrückung eigener Node** (fixes #3): Telemetriepakete vom eigenen + Node (per `my_node_id` oder short_name `FTLW`) werden im Paket-Log nicht angezeigt + und gehen nicht in die Zählung ein. + ## [0.8.5] - 2026-02-19 ### Fixed diff --git a/config.yaml b/config.yaml index f7eae65..0826f7f 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -version: "0.8.5" +version: "0.8.6" bot: name: "MeshDD-Bot" diff --git a/meshbot/bot.py b/meshbot/bot.py index ad303d8..c3785c2 100644 --- a/meshbot/bot.py +++ b/meshbot/bot.py @@ -256,13 +256,43 @@ class MeshBot: payload_summary = {"text": decoded.get("text", "")} elif portnum == "POSITION_APP": pos = decoded.get("position", {}) - payload_summary = {"lat": pos.get("latitude"), "lon": pos.get("longitude")} + payload_summary = { + "lat": pos.get("latitude"), + "lon": pos.get("longitude"), + "alt": pos.get("altitude"), + "speed": pos.get("groundSpeed"), + "sats": pos.get("satsInView"), + } elif portnum == "TELEMETRY_APP": - dm = decoded.get("telemetry", {}).get("deviceMetrics", {}) - payload_summary = {"battery": dm.get("batteryLevel"), "voltage": dm.get("voltage")} + telemetry = decoded.get("telemetry", {}) + dm = telemetry.get("deviceMetrics", {}) + em = telemetry.get("environmentMetrics", {}) + payload_summary = { + "battery": dm.get("batteryLevel"), + "voltage": dm.get("voltage"), + "ch_util": dm.get("channelUtilization"), + "air_util": dm.get("airUtilTx"), + "temp": em.get("temperature"), + "humidity": em.get("relativeHumidity"), + "pressure": em.get("barometricPressure"), + } elif portnum == "NODEINFO_APP": u = decoded.get("user", {}) - payload_summary = {"long_name": u.get("longName"), "short_name": u.get("shortName")} + payload_summary = { + "long_name": u.get("longName"), + "short_name": u.get("shortName"), + "hw_model": u.get("hwModel"), + } + elif portnum == "ROUTING_APP": + routing = decoded.get("routing", {}) + payload_summary = {"error": routing.get("errorReason")} + elif portnum == "TRACEROUTE_APP": + route = decoded.get("traceroute", {}) + snodes = route.get("route", []) + payload_summary = {"hops": len(snodes), "route": snodes} + elif portnum == "NEIGHBORINFO_APP": + ni = decoded.get("neighborinfo", {}) + payload_summary = {"count": len(ni.get("neighbors", []))} pkt_record = await self.db.insert_packet( str(from_id), str(to_id), portnum, channel, diff --git a/static/js/packets.js b/static/js/packets.js index 1e68dee..0d853de 100644 --- a/static/js/packets.js +++ b/static/js/packets.js @@ -6,6 +6,7 @@ const UNKNOWN_TYPE = '__unknown__'; let ws = null; let nodes = {}; // node_id -> {long_name, short_name, ...} let channels = {}; // ch_index -> channel name string +let myNodeId = null; let paused = false; let activeFilter = 'all'; let pendingRows = []; @@ -93,21 +94,56 @@ function portnumBadge(portnum) { return `${escapeHtml(cfg.label)}`; } +function isSuppressed(pkt) { + if (pkt.portnum !== 'TELEMETRY_APP') return false; + if (myNodeId && pkt.from_id === myNodeId) return true; + const n = nodes[pkt.from_id]; + return !!(n && n.short_name === 'FTLW'); +} + function fmtPayload(portnum, payloadStr) { let p = {}; try { p = JSON.parse(payloadStr || '{}'); } catch { return ''; } + if (portnum === 'TEXT_MESSAGE_APP' && p.text) return `${escapeHtml(p.text)}`; - if (portnum === 'POSITION_APP' && p.lat != null) - return `${p.lat?.toFixed(5)}, ${p.lon?.toFixed(5)}`; + + if (portnum === 'POSITION_APP' && p.lat != null) { + const parts = [`${p.lat.toFixed(5)}, ${p.lon.toFixed(5)}`]; + if (p.alt != null && p.alt !== 0) parts.push(`${p.alt} m`); + if (p.speed != null && p.speed !== 0) parts.push(`${p.speed} km/h`); + if (p.sats != null) parts.push(`${p.sats} Sat`); + return `${parts.join(' · ')}`; + } + if (portnum === 'TELEMETRY_APP') { const parts = []; - if (p.battery != null) parts.push(`🔋 ${p.battery}%`); - if (p.voltage != null) parts.push(`${p.voltage?.toFixed(2)} V`); + if (p.battery != null) parts.push(`🔋 ${p.battery}%`); + if (p.voltage != null) parts.push(`${p.voltage.toFixed(2)} V`); + if (p.ch_util != null) parts.push(`CH ${p.ch_util.toFixed(1)}%`); + if (p.air_util != null) parts.push(`TX ${p.air_util.toFixed(1)}%`); + if (p.temp != null) parts.push(`🌡 ${p.temp.toFixed(1)} °C`); + if (p.humidity != null) parts.push(`💧 ${p.humidity.toFixed(0)}%`); + if (p.pressure != null) parts.push(`${p.pressure.toFixed(0)} hPa`); return parts.length ? `${parts.join(' · ')}` : ''; } - if (portnum === 'NODEINFO_APP' && (p.long_name || p.short_name)) - return `${escapeHtml(p.long_name || '')}${p.short_name ? ` [${escapeHtml(p.short_name)}]` : ''}`; + + if (portnum === 'NODEINFO_APP' && (p.long_name || p.short_name)) { + let s = escapeHtml(p.long_name || ''); + if (p.short_name) s += ` [${escapeHtml(p.short_name)}]`; + if (p.hw_model) s += ` ${escapeHtml(p.hw_model)}`; + return `${s}`; + } + + if (portnum === 'ROUTING_APP' && p.error && p.error !== 'NONE') + return `${escapeHtml(p.error)}`; + + if (portnum === 'TRACEROUTE_APP' && p.hops != null) + return `${p.hops} Hop${p.hops !== 1 ? 's' : ''}`; + + if (portnum === 'NEIGHBORINFO_APP' && p.count != null) + return `${p.count} Nachbar${p.count !== 1 ? 'n' : ''}`; + return ''; } @@ -187,6 +223,7 @@ function buildRow(pkt) { } function addRow(pkt, prepend = true) { + if (isSuppressed(pkt)) return; knownTypes.add(typeKey(pkt.portnum)); const row = buildRow(pkt); if (prepend) { @@ -249,9 +286,13 @@ function handleMsg(msg) { case 'channels': channels = msg.data || {}; break; + case 'my_node_id': + myNodeId = msg.data; + break; case 'initial_packets': pktBody.innerHTML = ''; (msg.data || []).forEach(p => { + if (isSuppressed(p)) return; knownTypes.add(typeKey(p.portnum)); pktBody.appendChild(buildRow(p)); });