Fix HA websocket state change handling
Some checks failed
quality / test (3.11) (push) Has been cancelled
quality / test (3.13) (push) Has been cancelled

This commit is contained in:
2026-06-15 18:15:14 +02:00
parent 5727053951
commit 3140f65527
6 changed files with 20 additions and 7 deletions

View File

@@ -1,5 +1,10 @@
# Changelog # Changelog
## 0.7.7 - 2026-06-15
- WebSocket-State-Changes lesen jetzt das echte Home-Assistant-Eventformat
(`event.data.entity_id`), damit Kontextwechsel wie Türsensoren sofort
Vorhersagen und Schaltungen auslösen statt erst beim nächsten Statusabruf
## 0.7.6 - 2026-06-14 ## 0.7.6 - 2026-06-14
- Kontextvorschläge blenden zusätzlich Batterie-, Status-, Node-, Last-Seen- - Kontextvorschläge blenden zusätzlich Batterie-, Status-, Node-, Last-Seen-
und Basic-Entities aus, sofern sie nicht bewusst manuell ausgewählt wurden und Basic-Entities aus, sofern sie nicht bewusst manuell ausgewählt wurden

View File

@@ -1,5 +1,5 @@
name: SillyHome Next name: SillyHome Next
version: "0.7.6" version: "0.7.7"
slug: sillyhome_next slug: sillyhome_next
description: Lernt automatisch aus deinem Verhalten und steuert freigegebene Aktoren description: Lernt automatisch aus deinem Verhalten und steuert freigegebene Aktoren
url: http://192.168.6.31:3000/pino/sillyhome-next url: http://192.168.6.31:3000/pino/sillyhome-next

View File

@@ -100,7 +100,7 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
app = FastAPI( app = FastAPI(
title="SillyHome Next API", title="SillyHome Next API",
description="Lokales Smart-Home-Intelligenzsystem für Home Assistant.", description="Lokales Smart-Home-Intelligenzsystem für Home Assistant.",
version="0.7.6", version="0.7.7",
lifespan=lifespan, lifespan=lifespan,
) )
app.state.settings = load_settings() app.state.settings = load_settings()
@@ -213,12 +213,20 @@ async def _ha_event_listener(app: FastAPI, client: HaClient) -> None:
event = data.get("event", {}) event = data.get("event", {})
if event.get("event_type") != "state_changed": if event.get("event_type") != "state_changed":
continue continue
entity_id = event.get("entity_id") event_data = event.get("data", {})
if not isinstance(event_data, dict):
logger.warning("State-Changed-Event ohne gültige Daten empfangen")
continue
entity_id = event_data.get("entity_id")
if not entity_id: if not entity_id:
continue continue
# Prüfe, ob Entity ein Aktor oder relevanter Kontext ist # Prüfe, ob Entity ein Aktor oder relevanter Kontext ist
# Sofortige Vorhersage für betroffene Aktoren auslösen # Sofortige Vorhersage für betroffene Aktoren auslösen
await asyncio.to_thread(engine.handle_state_change, entity_id, event.get("new_state")) await asyncio.to_thread(
engine.handle_state_change,
entity_id,
event_data.get("new_state"),
)
except json.JSONDecodeError: except json.JSONDecodeError:
logger.warning("Ungültige JSON-Nachricht von HA-WebSocket") logger.warning("Ungültige JSON-Nachricht von HA-WebSocket")
except Exception as exc: except Exception as exc:

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "sillyhome-next" name = "sillyhome-next"
version = "0.7.6" version = "0.7.7"
description = "Lokales Smart-Home-Intelligenzsystem für Home Assistant" description = "Lokales Smart-Home-Intelligenzsystem für Home Assistant"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [

View File

@@ -78,7 +78,7 @@ def _service(
model_store=str(tmp_path / "models"), model_store=str(tmp_path / "models"),
automation_store=str(tmp_path / "automations"), automation_store=str(tmp_path / "automations"),
actuator_store=str(tmp_path / "actuators"), actuator_store=str(tmp_path / "actuators"),
history_days=14, history_days=31,
min_training_points=5, min_training_points=5,
retrain_stale_hours=24, retrain_stale_hours=24,
reconcile_interval_seconds=900, reconcile_interval_seconds=900,

View File

@@ -55,7 +55,7 @@ def test_ha_event_listener_processes_state_change(tmp_path: Path) -> None:
'{"type":"auth_ok"}', '{"type":"auth_ok"}',
( (
'{"type":"event","event":{"event_type":"state_changed",' '{"type":"event","event":{"event_type":"state_changed",'
'"entity_id":"light.test","new_state":{"state":"on"}}}' '"data":{"entity_id":"light.test","new_state":{"state":"on"}}}}'
), ),
asyncio.CancelledError(), asyncio.CancelledError(),
] ]