From 149f11a18ebe55c437b8c5b653f5f677c61d2959 Mon Sep 17 00:00:00 2001 From: Otto Date: Thu, 18 Jun 2026 12:57:01 +0200 Subject: [PATCH] Keep API responsive under HA events --- addon/Dockerfile | 2 +- addon/config.yaml | 2 +- app/main.py | 29 ++++++++++++++++++----------- pyproject.toml | 2 +- tests/test_addon_config.py | 2 +- tests/test_future_api.py | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/addon/Dockerfile b/addon/Dockerfile index 32c1e04..e22a924 100644 --- a/addon/Dockerfile +++ b/addon/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.13-slim WORKDIR /app -ARG SILLYHOME_FUTURE_REF=v2.0.0-alpha.5 +ARG SILLYHOME_FUTURE_REF=v2.0.0-alpha.6 RUN python -m pip install --no-cache-dir \ "http://192.168.6.31:3000/Otto/sillyhome-future/archive/${SILLYHOME_FUTURE_REF}.tar.gz" diff --git a/addon/config.yaml b/addon/config.yaml index 814a77e..14d139d 100644 --- a/addon/config.yaml +++ b/addon/config.yaml @@ -1,5 +1,5 @@ name: SillyHome Future -version: "2.0.0-alpha.5" +version: "2.0.0-alpha.6" slug: sillyhome_future description: Event-first SillyHome v2 test controller url: http://192.168.6.31:3000/Otto/sillyhome-future diff --git a/app/main.py b/app/main.py index beeea78..7a3867e 100644 --- a/app/main.py +++ b/app/main.py @@ -49,7 +49,7 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: app = FastAPI( title="SillyHome Future API", description="SillyHome v2 event-core side project.", - version="2.0.0-alpha.5", + version="2.0.0-alpha.6", lifespan=lifespan, ) @@ -189,24 +189,31 @@ def _load_initial_ha_states(client: FutureHaClient) -> None: async def _ha_listener_loop(client: FutureHaClient) -> None: while True: - runtime = stores.runtime() - runtime.websocket_status = "connecting" - stores.save_runtime(runtime) + await asyncio.to_thread(_set_websocket_status, "connecting") try: async for event in client.listen_state_events(): - runtime = stores.runtime() - runtime.websocket_status = "connected" - stores.save_runtime(runtime) - event_core.process_state_event(event, execute=_execute_ha_decision) + await asyncio.to_thread(_set_websocket_status, "connected") + await asyncio.to_thread( + event_core.process_state_event, + event, + execute=_execute_ha_decision, + ) + await asyncio.sleep(0) except asyncio.CancelledError: raise except Exception as exc: - runtime = stores.runtime() - runtime.websocket_status = f"reconnecting: {exc}" - stores.save_runtime(runtime) + await asyncio.to_thread(_set_websocket_status, f"reconnecting: {exc}") await asyncio.sleep(2) +def _set_websocket_status(status: str) -> None: + runtime = stores.runtime() + if runtime.websocket_status == status: + return + runtime.websocket_status = status + stores.save_runtime(runtime) + + def _execute_ha_decision(decision: object) -> bool: if ha_client is None or not hasattr(decision, "actuator_entity_id"): return False diff --git a/pyproject.toml b/pyproject.toml index 81086d3..10867f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "sillyhome-future" -version = "2.0.0-alpha.5" +version = "2.0.0-alpha.6" description = "SillyHome v2 event-core prototype" requires-python = ">=3.11" dependencies = [ diff --git a/tests/test_addon_config.py b/tests/test_addon_config.py index 7dc60cf..9f0a6b8 100644 --- a/tests/test_addon_config.py +++ b/tests/test_addon_config.py @@ -9,7 +9,7 @@ def test_addon_config_declares_future_addon() -> None: config = yaml.safe_load(Path("addon/config.yaml").read_text(encoding="utf-8")) assert config["slug"] == "sillyhome_future" - assert config["version"] == "2.0.0-alpha.5" + assert config["version"] == "2.0.0-alpha.6" assert config["ingress"] is True assert config["ingress_port"] == 8099 assert config["homeassistant_api"] is True diff --git a/tests/test_future_api.py b/tests/test_future_api.py index a8cba91..d8abcf8 100644 --- a/tests/test_future_api.py +++ b/tests/test_future_api.py @@ -15,7 +15,7 @@ def test_health_and_backup_roundtrip(tmp_path, monkeypatch) -> None: # type: ig assert stores is not None assert health.status_code == 200 - assert health.json()["version"] == "2.0.0-alpha.5" + assert health.json()["version"] == "2.0.0-alpha.6" assert backup.status_code == 200 assert restore.status_code == 200 assert restore.json() == {"status": "restored"}