SmartestHome/hosts/thin-client/agent/thinclient_agent/digest_canvas.py

74 lines
2.7 KiB
Python

"""Handles "show my digest" requests on this thin client.
Division of responsibility (project-plan Phase 11.8): Home Assistant resolves *who* and
*where* — which person's wake word fired in which room, whether more than one person is
present, and the "whose digest?" disambiguation prompt — and sends this agent an
already-resolved request. Nothing in this file looks at presence, person, or area
entities, and it must stay that way: duplicating that resolution locally would create a
second, un-audited answer to "whose personal section may be shown", which is exactly the
question the plan says must never be guessed.
This module only shows what it is told to show.
"""
from __future__ import annotations
import json
import logging
from urllib.parse import urlencode
from .sway_control import WS_DIGEST
log = logging.getLogger(__name__)
DETAIL_LEVELS = ("compact", "full")
DEFAULT_DETAIL_LEVEL = "full"
class DigestCanvas:
def __init__(self, sway, digest_web_url: str):
self.sway = sway
self.digest_web_url = (digest_web_url or "").rstrip("/")
self.detail_level = DEFAULT_DETAIL_LEVEL
def set_detail_level(self, level: str) -> str:
level = level.strip().lower()
if level not in DETAIL_LEVELS:
log.warning("ignoring unknown detail level %r", level)
return self.detail_level
self.detail_level = level
log.info("detail level set to %s", level)
return self.detail_level
def _url(self, detail_level: str, person: str | None) -> str:
params = {"detail_level": detail_level}
if person:
params["person"] = person
return f"{self.digest_web_url}/full.html?{urlencode(params)}"
def show(self, payload: str) -> None:
if not self.digest_web_url:
log.error("DIGEST_WEB_URL is not configured; cannot show the digest canvas")
return
request = {}
payload = (payload or "").strip()
if payload.startswith("{"):
try:
request = json.loads(payload)
except ValueError:
log.warning("could not parse digest request payload %r", payload)
detail_level = str(request.get("detail_level") or self.detail_level).lower()
if detail_level not in DETAIL_LEVELS:
detail_level = self.detail_level
# Set by the HA automation that already resolved presence. Absent means "no
# personal section" — never a local fallback to a default person.
person = request.get("person") or None
url = self._url(detail_level, person)
log.info("showing digest canvas (detail_level=%s, person=%s)", detail_level, bool(person))
self.sway.switch_workspace(WS_DIGEST)
self.sway.open_url(url)