From d859e969d034fe66e753e2d32bbf938a530b3810 Mon Sep 17 00:00:00 2001 From: Guido Schmit Date: Wed, 29 Apr 2026 18:54:33 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20HA-Event-Update=20Fallback=20auf=20delet?= =?UTF-8?q?e+create=20calendar.update=5Fevent=20existiert=20erst=20ab=20HA?= =?UTF-8?q?=202024.6.=20Wenn=20der=20Service=20nicht=20verf=C3=BCgbar=20is?= =?UTF-8?q?t=20(400),=20wird=20stattdessen=20delete=5Fevent=20+=20create?= =?UTF-8?q?=5Fevent=20verwendet.=20Funktioniert=20mit=20HA=202022.5+.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/routers/homeassistant_router.py | 51 +++++++++++++++++++------ 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/backend/routers/homeassistant_router.py b/backend/routers/homeassistant_router.py index 76d4bb9..faadd7e 100644 --- a/backend/routers/homeassistant_router.py +++ b/backend/routers/homeassistant_router.py @@ -109,11 +109,9 @@ def _ha_get_events(url: str, token: str, entity_id: str, start_dt: datetime, end raise http_requests.exceptions.Timeout(f"HA Timeout für {entity_id}") -def _ha_update_event(url: str, token: str, entity_id: str, uid: str, data: dict): - """Update an event via HA service call API (calendar.update_event).""" - base = url.rstrip("/") - headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} - body = {"entity_id": entity_id, "uid": uid} +def _ha_build_event_body(entity_id: str, data: dict) -> dict: + """Build a service-call body for create_event / update_event.""" + body = {"entity_id": entity_id} if "title" in data: body["summary"] = data["title"] if "description" in data: @@ -129,18 +127,49 @@ def _ha_update_event(url: str, token: str, entity_id: str, uid: str, data: dict) e = data["end"].replace("Z", "+00:00") if data["end"].endswith("Z") else data["end"] body["start_date_time"] = s body["end_date_time"] = e - logger.info("HA update_event body: %s", body) + return body + + +def _ha_update_event(url: str, token: str, entity_id: str, uid: str, data: dict): + """Update via update_event service, fallback to delete+create.""" + base = url.rstrip("/") + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + + # Try update_event service (HA 2024.6+) + body = _ha_build_event_body(entity_id, data) + body["uid"] = uid resp = http_requests.post( f"{base}/api/services/calendar/update_event", headers=headers, json=body, timeout=15, verify=False, ) - if not resp.ok: + if resp.ok: + return resp + + logger.info("HA update_event not available (%s), falling back to delete+create", resp.status_code) + + # Fallback: delete old event, then create new one + del_resp = http_requests.post( + f"{base}/api/services/calendar/delete_event", + headers=headers, + json={"entity_id": entity_id, "uid": uid}, + timeout=15, verify=False, + ) + if not del_resp.ok: + logger.warning("HA delete_event failed (%s): %s", del_resp.status_code, del_resp.text[:200]) + # If delete also fails, try create anyway (might duplicate) + + create_body = _ha_build_event_body(entity_id, data) + create_resp = http_requests.post( + f"{base}/api/services/calendar/create_event", + headers=headers, json=create_body, timeout=15, verify=False, + ) + if not create_resp.ok: try: - detail = resp.json().get("message", resp.text[:500]) + detail = create_resp.json().get("message", create_resp.text[:500]) except Exception: - detail = resp.text[:500] if resp.text else f"HTTP {resp.status_code}" - raise Exception(f"HA update_event ({resp.status_code}): {detail}") - return resp + detail = create_resp.text[:500] if create_resp.text else str(create_resp.status_code) + raise Exception(f"HA create_event ({create_resp.status_code}): {detail}") + return create_resp def _ha_delete_event(url: str, token: str, entity_id: str, uid: str):