router-status: publish missing values to HA as 'unavailable'
HA renders JSON null as 'None'; map None to the string 'unavailable' for the WAN, AP, Starlink, failover, thermal and battery payloads. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,18 @@ DEVICE_INFO = {"identifiers": [device_id], "name": "Van Router", "manufacturer":
|
|||||||
WAN_NAMES = ("wifi", "starlink", "cellular")
|
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):
|
def sh(args, timeout=10):
|
||||||
try:
|
try:
|
||||||
return subprocess.run(args, capture_output=True, text=True, timeout=timeout)
|
return subprocess.run(args, capture_output=True, text=True, timeout=timeout)
|
||||||
@@ -510,23 +522,23 @@ def publish_state(mqc):
|
|||||||
client_dir = collect_client_dir()
|
client_dir = collect_client_dir()
|
||||||
wan_rows = collect_wan()
|
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):
|
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}/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}/deploywarn", json.dumps(collect_deploywarn()))
|
||||||
mqc.publish(f"{state_root}/wan_prefer", json.dumps({"prefer": read_prefer() or "auto"}))
|
mqc.publish(f"{state_root}/wan_prefer", json.dumps({"prefer": read_prefer() or "auto"}))
|
||||||
|
|
||||||
failover = read_json_file(FAILOVER_STATE)
|
failover = read_json_file(FAILOVER_STATE)
|
||||||
if failover is not None:
|
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)
|
thermal = read_json_file(THERMAL_STATE)
|
||||||
if thermal is not None:
|
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)
|
battery = read_json_file(BATTERY_STATE)
|
||||||
if battery is not None:
|
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
|
return wan_rows
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user