mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-05-21 23:24:44 +02:00
feat: Feeder-level gateway awareness from /api/packets_seen
Samples recent packets and calls /api/packets_seen to discover which physical MQTT gateways hear each node. Per-gateway RSSI and SNR. UnifiedNode: - feeder_gateways list with gateway_id, gateway_name, avg_rssi, avg_snr - feeder_count, feeder_best (strongest signal), feeder_worst MeshviewSource: - Added feeders to ENDPOINT_SCHEDULE (every 20 ticks / 10 min) - _fetch_feeders() samples 20 packets and queries packets_seen - Auto-disables if endpoint returns 404 MeshDataStore: - _enrich_feeder_data() aggregates gateway data across all sources - _normalize_node_id() helper for hex/decimal conversion - get_feeder_map() shows per-gateway coverage statistics - get_node_feeders() returns sorted gateway list for a node MeshReporter: - Node detail shows feeder gateways with signal strength - Tier 1 shows total unique gateways and avg per node Discovered gateways: AIDA, BKBS, STLR, N7MH, stor, JTS Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b3c79f12da
commit
1d9c90911b
4 changed files with 568 additions and 239 deletions
|
|
@ -457,6 +457,19 @@ class MeshReporter:
|
|||
if pb["critical"]: parts.append(f"{pb['critical']} battery critical")
|
||||
lines.append(f"POWER (infra): {', '.join(parts)}")
|
||||
|
||||
# Feeder gateway summary
|
||||
all_nodes = list(health.nodes.values())
|
||||
nodes_with_feeders = [n for n in all_nodes if getattr(n, 'feeder_count', 0) > 0]
|
||||
if nodes_with_feeders:
|
||||
total_unique_gw = set()
|
||||
for n in nodes_with_feeders:
|
||||
for gw in n.feeder_gateways:
|
||||
total_unique_gw.add(gw["gateway_id"])
|
||||
|
||||
avg_feeders = sum(n.feeder_count for n in nodes_with_feeders) / len(nodes_with_feeders)
|
||||
lines.append("")
|
||||
lines.append(f"FEEDERS: {len(total_unique_gw)} physical gateways, avg {avg_feeders:.1f} per node ({len(nodes_with_feeders)} nodes sampled)")
|
||||
|
||||
# Source health section
|
||||
lines.extend(self._build_source_health_section())
|
||||
|
||||
|
|
@ -935,6 +948,27 @@ class MeshReporter:
|
|||
if node.sources:
|
||||
lines.append(f" Seen by: {', '.join(node.sources)} ({len(node.sources)} sources)")
|
||||
|
||||
# Feeder gateways
|
||||
if node.feeder_gateways:
|
||||
lines.append(f" Feeders ({node.feeder_count} gateways):")
|
||||
# Sort by signal strength (best RSSI first, closest to 0)
|
||||
sorted_gw = sorted(
|
||||
node.feeder_gateways,
|
||||
key=lambda g: g.get("avg_rssi") or -999,
|
||||
reverse=True
|
||||
)
|
||||
for gw in sorted_gw[:8]: # Top 8
|
||||
name_str = gw.get("gateway_name") or gw["gateway_id"]
|
||||
parts = []
|
||||
if gw.get("avg_rssi") is not None:
|
||||
parts.append(f"RSSI {gw['avg_rssi']:.0f}")
|
||||
if gw.get("avg_snr") is not None:
|
||||
parts.append(f"SNR {gw['avg_snr']:.1f}")
|
||||
sig_str = f" [{', '.join(parts)}]" if parts else ""
|
||||
lines.append(f" {name_str}{sig_str}")
|
||||
if len(sorted_gw) > 8:
|
||||
lines.append(f" ...and {len(sorted_gw) - 8} more")
|
||||
|
||||
# Neighbors section
|
||||
if node.neighbors:
|
||||
lines.append("")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue