From 8057751c11adef52c478d3fb4e99370b688bdbbd Mon Sep 17 00:00:00 2001 From: Otto Date: Thu, 18 Jun 2026 17:30:48 +0200 Subject: [PATCH] Filter autopilot trigger candidates --- addon/Dockerfile | 2 +- addon/config.yaml | 2 +- app/main.py | 37 +++++++++++++++++++++++++++++++++++-- pyproject.toml | 2 +- tests/test_addon_config.py | 2 +- tests/test_future_api.py | 2 +- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/addon/Dockerfile b/addon/Dockerfile index 1374aa7..a06e05a 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.13 +ARG SILLYHOME_FUTURE_REF=v2.0.0-alpha.14 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 8df5289..0fe0b32 100644 --- a/addon/config.yaml +++ b/addon/config.yaml @@ -1,5 +1,5 @@ name: SillyHome Future -version: "2.0.0-alpha.13" +version: "2.0.0-alpha.14" 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 848ceda..3f06d32 100644 --- a/app/main.py +++ b/app/main.py @@ -155,7 +155,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.13", + version="2.0.0-alpha.14", lifespan=lifespan, ) @@ -951,6 +951,11 @@ def _run_autopilot_once() -> AutopilotRunResult: if not settings.enabled: return AutopilotRunResult(candidates=[], trained_models=[], evaluations=[]) learning = stores.learning() + learning.candidates = { + candidate_id: candidate + for candidate_id, candidate in learning.candidates.items() + if _is_good_trigger_id(candidate.trigger_entity_id) + } candidates = _generate_candidates(settings) for candidate in candidates: learning.candidates[candidate.candidate_id] = candidate @@ -974,7 +979,7 @@ def _generate_candidates(settings: AutopilotSettings) -> list[CandidateRecommend triggers = [ entity for entity in runtime.entities.values() - if entity.domain in {"binary_sensor", "sensor"} + if entity.domain == "binary_sensor" and _is_good_trigger_id(entity.entity_id) ][:500] result: list[CandidateRecommendation] = [] for actuator in actuators: @@ -1023,6 +1028,34 @@ def _candidate_score(actuator: EntityState, trigger: EntityState) -> tuple[float return 0.0, "" +def _is_good_trigger_id(entity_id: str) -> bool: + raw = entity_id.lower() + bad = { + "battery", + "batterie", + "low", + "update", + "problem", + "connectivity", + "linkquality", + "tamper", + } + good = { + "door", + "tuer", + "ture", + "window", + "fenster", + "motion", + "pir", + "occupancy", + "presence", + "kontakt", + "contact", + } + return not any(token in raw for token in bad) and any(token in raw for token in good) + + def _entity_tokens(entity: EntityState) -> set[str]: raw = f"{entity.entity_id} {entity.friendly_name or ''}".lower() return {part for part in raw.replace(".", "_").split("_") if len(part) >= 4} diff --git a/pyproject.toml b/pyproject.toml index 5016438..9b3d3f9 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.13" +version = "2.0.0-alpha.14" 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 9839152..6b72989 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.13" + assert config["version"] == "2.0.0-alpha.14" 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 f94d75e..4a27bfd 100644 --- a/tests/test_future_api.py +++ b/tests/test_future_api.py @@ -19,7 +19,7 @@ def test_health_and_backup_roundtrip(tmp_path, monkeypatch) -> None: # type: ig restore = client.post("/v2/backup/restore", json=backup.json()) assert health.status_code == 200 - assert health.json()["version"] == "2.0.0-alpha.13" + assert health.json()["version"] == "2.0.0-alpha.14" assert backup.status_code == 200 assert restore.status_code == 200 assert restore.json() == {"status": "restored"}