added more diagnostics

This commit is contained in:
Oliver Walter
2026-07-01 01:27:24 +02:00
parent ddbbd27dbe
commit 30948ebb0a
3 changed files with 102 additions and 1 deletions
+87 -1
View File
@@ -14,6 +14,7 @@ import os
import re
import sys
import time
from datetime import datetime, timezone
import paho.mqtt.client as mqtt
import requests
@@ -62,6 +63,36 @@ CHANNEL_KEY = expand_psk(CHANNEL_PSK)
# Matches "T1:20.8", "H2:54.4", "P:1013" etc. (unit suffix is ignored here).
PAIR_RE = re.compile(r"([A-Za-z][A-Za-z0-9_]*)\s*:\s*(-?\d+(?:\.\d+)?)")
# Built-in per-node diagnostic sensors derived from packet metadata.
DIAGNOSTICS = [
{
"key": "last_seen",
"name": "Last Seen",
"device_class": "timestamp",
"icon": "mdi:clock-outline",
},
{
"key": "rssi",
"name": "RSSI",
"device_class": "signal_strength",
"unit": "dBm",
"state_class": "measurement",
},
{
"key": "snr",
"name": "SNR",
"unit": "dB",
"state_class": "measurement",
"icon": "mdi:signal",
},
{
"key": "hops_away",
"name": "Hops Away",
"state_class": "measurement",
"icon": "mdi:transit-connection-variant",
},
]
# Set once the HA broker client is connected.
ha_client = None
@@ -158,10 +189,62 @@ def publish_discovery():
json.dumps(cfg),
retain=True,
)
log(f"[ha] published discovery for last_message + {len(SENSORS)} sensors")
for d in DIAGNOSTICS:
key = d["key"]
cfg = {
"name": d["name"],
"unique_id": f"{DEVICE_UID}_{key}",
"state_topic": f"{BASE_TOPIC}/{key}",
"availability_topic": AVAIL_TOPIC,
"entity_category": "diagnostic",
"device": device_block(),
}
if d.get("unit"):
cfg["unit_of_measurement"] = d["unit"]
if d.get("device_class"):
cfg["device_class"] = d["device_class"]
if d.get("state_class"):
cfg["state_class"] = d["state_class"]
if d.get("icon"):
cfg["icon"] = d["icon"]
ha_client.publish(
f"{DISCOVERY_PREFIX}/sensor/{DEVICE_UID}/{key}/config",
json.dumps(cfg),
retain=True,
)
log(
f"[ha] published discovery for last_message + {len(SENSORS)} sensors "
f"+ {len(DIAGNOSTICS)} diagnostics"
)
# --- Message handling --------------------------------------------------------
def publish_metadata(mp):
"""Publish link-quality diagnostics from a received MeshPacket."""
# Last seen: prefer the gateway's rx_time, fall back to now.
ts = (
datetime.fromtimestamp(mp.rx_time, tz=timezone.utc)
if mp.rx_time
else datetime.now(timezone.utc)
)
ha_client.publish(f"{BASE_TOPIC}/last_seen", ts.isoformat(), retain=True)
# RSSI/SNR are 0 for packets the gateway originated itself — only publish
# genuine over-the-air measurements.
if mp.rx_rssi != 0:
ha_client.publish(f"{BASE_TOPIC}/rssi", mp.rx_rssi, retain=True)
ha_client.publish(f"{BASE_TOPIC}/snr", round(mp.rx_snr, 2), retain=True)
# hop_start is the original TTL; hops taken = hop_start - hop_limit.
# hop_start == 0 means older firmware that didn't report it.
if mp.hop_start:
ha_client.publish(
f"{BASE_TOPIC}/hops_away", mp.hop_start - mp.hop_limit, retain=True
)
def handle_text(text, from_id, to_id):
# HA sensor states are limited to 255 chars.
ha_client.publish(f"{BASE_TOPIC}/last_message", text[:255], retain=True)
@@ -212,6 +295,9 @@ def on_src_message(client, userdata, msg):
mp = env.packet
from_id = getattr(mp, "from")
# Link diagnostics + last-seen update for every packet on the channel.
publish_metadata(mp)
if mp.HasField("decoded"):
data = mp.decoded
elif mp.HasField("encrypted"):