diff --git a/router-status/van-router-mqtt b/router-status/van-router-mqtt index e00c165..a264c13 100644 --- a/router-status/van-router-mqtt +++ b/router-status/van-router-mqtt @@ -99,6 +99,18 @@ DEVICE_INFO = {"identifiers": [device_id], "name": "Van Router", "manufacturer": WAN_NAMES = ("wifi", "starlink", "cellular") +def mark_unavailable(obj): + """Copy of obj with every None replaced by 'unavailable' -- HA treats that string + as a missing value, whereas null renders as 'None'.""" + if obj is None: + return "unavailable" + if isinstance(obj, dict): + return {k: mark_unavailable(v) for k, v in obj.items()} + if isinstance(obj, list): + return [mark_unavailable(v) for v in obj] + return obj + + def sh(args, timeout=10): try: return subprocess.run(args, capture_output=True, text=True, timeout=timeout) @@ -510,23 +522,23 @@ def publish_state(mqc): client_dir = collect_client_dir() wan_rows = collect_wan() - mqc.publish(f"{state_root}/wan", json.dumps({"rows": wan_rows})) + mqc.publish(f"{state_root}/wan", json.dumps(mark_unavailable({"rows": wan_rows}))) for ap, meta in zip(aps, APS): - mqc.publish(f"{state_root}/ap/{meta['id']}", json.dumps(ap)) + mqc.publish(f"{state_root}/ap/{meta['id']}", json.dumps(mark_unavailable(ap))) mqc.publish(f"{state_root}/clients", json.dumps({"rows": collect_clients(aps, client_dir)})) - mqc.publish(f"{state_root}/starlink", json.dumps(collect_starlink())) + mqc.publish(f"{state_root}/starlink", json.dumps(mark_unavailable(collect_starlink()))) mqc.publish(f"{state_root}/deploywarn", json.dumps(collect_deploywarn())) mqc.publish(f"{state_root}/wan_prefer", json.dumps({"prefer": read_prefer() or "auto"})) failover = read_json_file(FAILOVER_STATE) if failover is not None: - mqc.publish(f"{state_root}/failover", json.dumps(failover)) + mqc.publish(f"{state_root}/failover", json.dumps(mark_unavailable(failover))) thermal = read_json_file(THERMAL_STATE) if thermal is not None: - mqc.publish(f"{state_root}/thermal", json.dumps(thermal)) + mqc.publish(f"{state_root}/thermal", json.dumps(mark_unavailable(thermal))) battery = read_json_file(BATTERY_STATE) if battery is not None: - mqc.publish(f"{state_root}/battery", json.dumps(battery)) + mqc.publish(f"{state_root}/battery", json.dumps(mark_unavailable(battery))) return wan_rows