From b623082c4aab6dde64c1f26d809713c19e17da69 Mon Sep 17 00:00:00 2001
From: lilly
Date: Thu, 14 May 2026 15:36:46 +0200
Subject: [PATCH] api: refactor ccujack state keeping
---
api/pyproject.toml | 1 -
api/src/dooris_api/app.py | 30 ++++++++++++++++--------------
api/src/dooris_api/ccujack.py | 8 ++++++--
api/src/dooris_api/deps.py | 8 --------
api/uv.lock | 11 -----------
5 files changed, 22 insertions(+), 36 deletions(-)
diff --git a/api/pyproject.toml b/api/pyproject.toml
index c382454..fe60426 100644
--- a/api/pyproject.toml
+++ b/api/pyproject.toml
@@ -5,7 +5,6 @@ description = "API for Dooris setup using HomeMatic."
requires-python = ">=3.13"
dependencies = [
"aiohttp>=3.13.5",
- "cachetools>=7.1.1",
"fastapi>=0.136.1",
"simple-openid-connect>=2.4.0",
"uvicorn>=0.46.0",
diff --git a/api/src/dooris_api/app.py b/api/src/dooris_api/app.py
index bb1ef02..8f4b68d 100644
--- a/api/src/dooris_api/app.py
+++ b/api/src/dooris_api/app.py
@@ -9,7 +9,6 @@ from fastapi.responses import RedirectResponse
from contextlib import asynccontextmanager
from simple_openid_connect.client import OpenidClient
from simple_openid_connect.data import TokenSuccessResponse, RpInitiatedLogoutRequest
-from cachetools import TTLCache
from aiohttp import BasicAuth
from dooris_api import deps, models, exceptions, app_config
@@ -37,12 +36,11 @@ async def lifespan(app: FastAPI):
scope=app_cfg.openid_scope,
)
- app.extra["cache"] = TTLCache(maxsize=64, ttl=30 * 60)
-
app.extra["ccujack"] = CCUJackClient(
"https://hmdooris-ccu.ccchh.net:2122",
auth=BasicAuth("dooris", os.environ["HMDOORIS_PW"]),
)
+ await app.extra["ccujack"].find_locks()
yield
@@ -178,7 +176,10 @@ async def logout(
):
deps.clear_auth_state(resp)
return oidc_client.initiate_logout(
- RpInitiatedLogoutRequest(id_token_hint=current_user.raw_id_token, post_logout_redirect_uri=f"{app_config.get().base_url}/")
+ RpInitiatedLogoutRequest(
+ id_token_hint=current_user.raw_id_token,
+ post_logout_redirect_uri=f"{app_config.get().base_url}/",
+ )
)
@@ -188,19 +189,11 @@ async def logout(
responses={status.HTTP_401_UNAUTHORIZED: {"model": models.HttpProblemDetail}},
)
async def list_locks(
- ccujack: deps.CCUJackClient, cache: deps.Cache
+ ccujack: deps.CCUJackClient
) -> List[models.Lock]:
- # discover locks from ccujack
- CACHE_KEY = "ccu-find-locks"
- if CACHE_KEY in cache:
- locks = cache[CACHE_KEY]
- else:
- locks = await ccujack.find_locks()
- cache[CACHE_KEY] = locks
-
# assemble result objects
result = []
- for i_lock, lock_channels in locks:
+ for i_lock, lock_channels in ccujack.locks:
status_data = dict()
for i_channel, channel_params in lock_channels:
for i_param in channel_params:
@@ -244,3 +237,12 @@ async def list_locks(
)
return result
+
+
+@app.patch(
+ "/api/locks/{name}",
+ tags=["locks"],
+ responses={status.HTTP_401_UNAUTHORIZED: {"model": models.HttpProblemDetail}},
+)
+async def operate_lock(name: str):
+ pass
diff --git a/api/src/dooris_api/ccujack.py b/api/src/dooris_api/ccujack.py
index e9820e3..7b6091c 100644
--- a/api/src/dooris_api/ccujack.py
+++ b/api/src/dooris_api/ccujack.py
@@ -55,13 +55,17 @@ class CCUValue(BaseModel):
v: Any
+LockData = List[Tuple[CCUDeviceInfo, List[Tuple[CCUChannelInfo, List[CCUParamInfo]]]]]
+
class CCUJackClient:
base_uri: str
+ locks: LockData
def __init__(self, base_uri: str, auth: BasicAuth):
self.http = ClientSession(base_url=base_uri, auth=auth, raise_for_status=True, connector=TCPConnector(ssl=False))
+ self.locks = None
- async def find_locks(self) -> List[Tuple[CCUDeviceInfo, List[Tuple[CCUChannelInfo, List[CCUParamInfo]]]]]:
+ async def find_locks(self):
logger.debug("Inspecting lock devices present in CCUJack")
async with self.http.get("/device") as resp:
devices = CCUDeviceList.model_validate(await resp.json())
@@ -72,7 +76,7 @@ class CCUJackClient:
if i.rel == "device"
])
- return [
+ self.locks = [
i
for i in device_infos
if i[0].type == DEVICE_TYPE_LOCK
diff --git a/api/src/dooris_api/deps.py b/api/src/dooris_api/deps.py
index 30292e0..ed7625c 100644
--- a/api/src/dooris_api/deps.py
+++ b/api/src/dooris_api/deps.py
@@ -4,7 +4,6 @@ from datetime import datetime, UTC, timedelta
from fastapi import Request, Depends, Response
from simple_openid_connect.data import TokenSuccessResponse
from simple_openid_connect.client import OpenidClient
-from cachetools import Cache
from dooris_api import models, exceptions
from dooris_api.ccujack import CCUJackClient
@@ -124,13 +123,6 @@ def clear_auth_state(resp: Response):
CurrentUser = Annotated[Optional[models.CurrentUser], Depends(get_current_user)]
-def get_cache(req: Request) -> Cache:
- return req.app.extra["cache"]
-
-
-Cache = Annotated[Cache, Depends(get_cache)]
-
-
def get_ccujack(req: Request) -> CCUJackClient:
return req.app.extra["ccujack"]
diff --git a/api/uv.lock b/api/uv.lock
index b2b2872..1c53fb5 100644
--- a/api/uv.lock
+++ b/api/uv.lock
@@ -139,15 +139,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
-[[package]]
-name = "cachetools"
-version = "7.1.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ff/e2/85f227594656000ff4d8adadae91a21f536d4a84c6c716a86bd6685874be/cachetools-7.1.1.tar.gz", hash = "sha256:27bdf856d68fd3c71c26c01b5edc312124ed427524d1ddb31aa2b7746fe20d4b", size = 40202, upload-time = "2026-05-03T20:00:29.391Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bf/0f/f897abe4ea0a8c408ae65c8c83bffab4936ad65d6032d4fb4cd35bbdc3ee/cachetools-7.1.1-py3-none-any.whl", hash = "sha256:0335cd7a0952d2b22327441fb0628139e234c565559eeb91a8a4ac7551c5353d", size = 16775, upload-time = "2026-05-03T20:00:27.857Z" },
-]
-
[[package]]
name = "certifi"
version = "2026.4.22"
@@ -361,7 +352,6 @@ version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
- { name = "cachetools" },
{ name = "fastapi" },
{ name = "simple-openid-connect" },
{ name = "uvicorn" },
@@ -375,7 +365,6 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "aiohttp", specifier = ">=3.13.5" },
- { name = "cachetools", specifier = ">=7.1.1" },
{ name = "fastapi", specifier = ">=0.136.1" },
{ name = "simple-openid-connect", specifier = ">=2.4.0" },
{ name = "uvicorn", specifier = ">=0.46.0" },