UX-09 review: short start-up timeout, latch rows pinned in shadow, plainer rows
checks / unit (pull_request) Successful in 8m50s
infra-pin / fresh (pull_request) Successful in 1s

The Supervisor questions for the Details link are asked together with a
3 s budget instead of one after the other at 10 s each, so a hung
Supervisor cannot hold control start for 20 s. In shadow mode the
circulating and site-direction latches are pinned to keep their own red
row that says how they clear. Plainer inverter and battery wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 04:45:06 +02:00
co-authored by Claude Opus 5.5
parent 00e3ee9de8
commit 63dee6db1e
4 changed files with 51 additions and 16 deletions
+14 -9
View File
@@ -5370,27 +5370,32 @@ def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event,
stop.set()
DOCS_LINK_TIMEOUT_S = 3
async def docs_link_facts(session, token: str) -> dict:
"""`{slug, ha_version}` from the Supervisor, each None when unreadable.
`GET /addons/self/info` and `GET /info` are on the Supervisor's bypass
list for an add-on's own token, so they need no role (see selfconfig.py).
Asked together with a 3 s budget: a link may never hold up control start.
"""
out = {"slug": None, "ha_version": None}
for key, url, field in (("slug", "http://supervisor/addons/self/info",
"slug"),
("ha_version", "http://supervisor/info",
"homeassistant")):
async def ask(url, field):
try:
async with session.get(url, timeout=10, headers={
async with session.get(url, timeout=DOCS_LINK_TIMEOUT_S, headers={
"Authorization": f"Bearer {token}"}) as r:
body = await r.json(content_type=None)
data = body.get("data", body) if isinstance(body, dict) else {}
out[key] = data.get(field) if isinstance(data, dict) else None
return data.get(field) if isinstance(data, dict) else None
except Exception as err: # noqa: BLE001 - a link, never a stop
_LOG.info("docs link: %s unreadable (%s)", url, err)
_LOG.info("docs link: slug %s, Home Assistant %s", out["slug"],
out["ha_version"])
return None
slug, ha = await asyncio.gather(
ask("http://supervisor/addons/self/info", "slug"),
ask("http://supervisor/info", "homeassistant"))
out = {"slug": slug, "ha_version": ha}
_LOG.info("docs link: slug %s, Home Assistant %s", slug, ha)
return out