feat(homeassistant): an admin signs in to Home Assistant, with nothing added to it (#6355)
Replaces the read-only token and the webhook automation, which every install would have had to paste into its own Home Assistant. Connect now goes to Home Assistant's own sign-in page, and Steward keeps the refresh token that comes back, encrypted, and calls backup.create_automatic and update.install directly. The connection page warns that the stored credential has the same access as the user who signed in, and recommends a service account so Steward's actions are easy to tell apart in Home Assistant's logs. A user who isn't an administrator gets the status page and no Install. Those actions answer only when finished, so a request cut off once sent counts as sent and the outcome is read from the entities. Removing the connection, or signing in again, ends the old sign-in on Home Assistant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""The Home Assistant plugin's MCP tools and its get_overview findings.
|
||||
|
||||
get_home_assistant reads what the poll stored. update_home_assistant starts an
|
||||
update as the page's Install does. The token and webhook id are never returned.
|
||||
update as the page's Install does. The sign-in Steward holds is never returned.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -34,8 +34,8 @@ async def get_home_assistant() -> dict:
|
||||
|
||||
`installable` is what update_home_assistant takes (Core, OS, add-ons);
|
||||
`others_waiting` is firmware and custom integrations, which Steward leaves
|
||||
to Home Assistant. `automation` is the Steward maintenance automation's
|
||||
state: "on" is needed to install, null means it wasn't found.
|
||||
to Home Assistant. `can_install` is whether the Home Assistant user who signed
|
||||
Steward in is an administrator, which installing needs.
|
||||
"""
|
||||
now = now_utc()
|
||||
async with db_session() as db:
|
||||
@@ -43,12 +43,12 @@ async def get_home_assistant() -> dict:
|
||||
runs = list((await db.execute(select(HomeAssistantUpdate).order_by(
|
||||
HomeAssistantUpdate.started_at.desc()).limit(RECENT_UPDATES))).scalars())
|
||||
if c is None:
|
||||
return {"connected": False, "says": "No connection yet: an admin adds it on the Home Assistant page."}
|
||||
return {"connected": False, "says": "No connection yet: an admin signs in on the Home Assistant page."}
|
||||
reach, says = connection_says(c, now)
|
||||
backup = c.backup or {}
|
||||
age = backup_age_hours(backup, now)
|
||||
return {"connected": True, "url": redact_url(c.url), "reach": reach, "says": says,
|
||||
"polled_at": iso(c.last_polled_at), "ok_age_s": age_s(c.last_ok_at, now), "automation": c.automation,
|
||||
"polled_at": iso(c.last_polled_at), "ok_age_s": age_s(c.last_ok_at, now), "can_install": c.can_install,
|
||||
"installable": [{k: u[k] for k in ("entity_id", "title", "kind", "installed", "latest", "in_progress")}
|
||||
for u in installable(c)],
|
||||
"others_waiting": [u["title"] for u in c.updates or [] if u["waiting"] and not u["kind"]],
|
||||
|
||||
Reference in New Issue
Block a user