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
+6 -1
View File
@@ -29,6 +29,7 @@ KEPT: frozenset[str] = frozenset({
# Syslog senders: which were added, under what name, and which ignored.
"syslog_sources",
"syslog_patterns",
"homeassistant_connection",
})
# Rows that are measurements, logs, history or in-flight work: left out.
@@ -67,6 +68,7 @@ EXCLUDED: frozenset[str] = frozenset({
"unifi_events", "unifi_fw_rules", "unifi_networks", "unifi_port_forwards",
"unifi_speedtest_results", "unifi_wan_stats", "unifi_wlan_stats",
"syslog_lines",
"homeassistant_updates",
})
# ── What a check compares (#5823) ────────────────────────────────────────────
@@ -91,6 +93,8 @@ ACTIVITY: dict[str, frozenset[str]] = {
"snmp_devices": frozenset({"last_polled_at", "last_ok_at", "last_error", "missing"}),
"prometheus_targets": frozenset({"last_scraped_at", "last_ok_at", "last_error", "last_kept",
"last_dropped", "last_capped"}),
"homeassistant_connection": frozenset({"refused", "last_polled_at", "last_ok_at", "last_error",
"updates", "backup", "automation"}),
# What the sender last sent; its address, name, state and host are setup.
"syslog_sources": frozenset({"hostname_seen", "first_seen_at", "last_seen_at", "lines_total",
"last_severity", "last_line"}),
@@ -121,5 +125,6 @@ AREAS: tuple[tuple[str, tuple[str, ...]], ...] = (
("Ansible", ("ansible_targets", "ansible_groups", "ansible_target_groups", "ansible_schedules")),
("Dashboards", ("dashboards", "dashboard_widgets", "dashboard_share_tokens")),
("Plugins", ("snmp_devices", "prometheus_targets", "prometheus_widget_templates",
"unifi_known_clients", "syslog_sources", "syslog_patterns")),
"unifi_known_clients", "syslog_sources", "syslog_patterns",
"homeassistant_connection")),
)