feat(homeassistant): waiting updates, backup age, and updates installed after a confirmed backup (#6355)
CI / lint (push) Failing after 2s
CI / unit (push) Failing after 1m42s
CI / integration (push) Successful in 1m51s
CI / publish (push) Skipped

A new plugin reads Home Assistant with a read-only token every 5 minutes and
shows which Core, OS and add-on updates are waiting and how old the last backup
is. Install takes a backup through a local-only webhook, confirms Home
Assistant's last-backup time moved, installs, and follows the update to its end,
through Home Assistant's and Steward's own restarts. One runs at a time. Each
ends as one timeline entry.

Steward holds nothing that can act on the house: the webhook's automation can
only take a backup or install an allowed update (System 231's ruling). A refused
token stops polling, as Home Assistant bans an address after a few refusals.

Milestone 576 steps 1 to 5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-30 23:09:27 -04:00
co-authored by Claude Opus 5.5
parent 8b9b7fc11d
commit b2a6e92ed3
27 changed files with 1802 additions and 4 deletions
+3
View File
@@ -298,6 +298,8 @@ def metric_value(name: str, value: Any) -> str:
# its underscores spaced (SNMP's OID labels are the operator's own words).
METRICS: dict[str, tuple[str, str]] = {
"is_up": ("Up or down", "whether the check passed"),
"backup_age_hours": ("Age of last backup (hours)", "hours since Home Assistant's last successful automatic backup"),
"updates_waiting": ("Updates waiting", "Core, OS and add-on updates Home Assistant has waiting"),
"is_healthy": ("Health check", "the container's own HEALTHCHECK result"),
"response_ms": ("Response time", "how long the check took"),
"ingest_posts": ("Agent posts per minute", "host-agent reports Steward took in the last minute"),
@@ -421,6 +423,7 @@ SOURCES: dict[str, str] = {
"http": "HTTP monitors", "steward": "Steward itself", "host_agent": "Host agent",
"docker": "Docker containers", "traefik": "Traefik routers", "unifi": "UniFi",
"snmp": "SNMP devices", "prometheus": "Prometheus targets", "syslog": "Syslog patterns",
"homeassistant": "Home Assistant",
}
+1
View File
@@ -181,6 +181,7 @@ DEFAULTS: dict[str, Any] = {
"plugin.snmp": {"enabled": True},
"plugin.prometheus": {"enabled": True},
"plugin.syslog": {"enabled": True},
"plugin.homeassistant": {"enabled": True},
# OIDC single-sign-on
"oidc.enabled": False,
"oidc.discovery_url": "",