fix(packets): informativer Payload + eigene Telemetrie unterdrücken (fixes #3)
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
407addc919
commit
cc392a125a
16
CHANGELOG.md
16
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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version: "0.8.5"
|
||||
version: "0.8.6"
|
||||
|
||||
bot:
|
||||
name: "MeshDD-Bot"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 `<span class="badge bg-${cfg.color} pkt-type-badge ${txtCls}">${escapeHtml(cfg.label)}</span>`;
|
||||
}
|
||||
|
||||
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 `<span class="text-body">${escapeHtml(p.text)}</span>`;
|
||||
if (portnum === 'POSITION_APP' && p.lat != null)
|
||||
return `<span class="text-body-secondary">${p.lat?.toFixed(5)}, ${p.lon?.toFixed(5)}</span>`;
|
||||
|
||||
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 `<span class="text-body-secondary">${parts.join(' · ')}</span>`;
|
||||
}
|
||||
|
||||
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.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 ? `<span class="text-body-secondary">${parts.join(' · ')}</span>` : '';
|
||||
}
|
||||
if (portnum === 'NODEINFO_APP' && (p.long_name || p.short_name))
|
||||
return `<span class="text-body-secondary">${escapeHtml(p.long_name || '')}${p.short_name ? ` [${escapeHtml(p.short_name)}]` : ''}</span>`;
|
||||
|
||||
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 += ` <span class="opacity-50">${escapeHtml(p.hw_model)}</span>`;
|
||||
return `<span class="text-body-secondary">${s}</span>`;
|
||||
}
|
||||
|
||||
if (portnum === 'ROUTING_APP' && p.error && p.error !== 'NONE')
|
||||
return `<span class="text-danger">${escapeHtml(p.error)}</span>`;
|
||||
|
||||
if (portnum === 'TRACEROUTE_APP' && p.hops != null)
|
||||
return `<span class="text-body-secondary">${p.hops} Hop${p.hops !== 1 ? 's' : ''}</span>`;
|
||||
|
||||
if (portnum === 'NEIGHBORINFO_APP' && p.count != null)
|
||||
return `<span class="text-body-secondary">${p.count} Nachbar${p.count !== 1 ? 'n' : ''}</span>`;
|
||||
|
||||
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));
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue