From 7e0f52ebb0f094de61501f48295aaddbdac5e0b3 Mon Sep 17 00:00:00 2001 From: mrtncode <145050460+mrtncode@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:10:43 +0100 Subject: [PATCH] Improve Home Assistant notifications (#750) Improve Home Assistant notifications (#750) --- backend/app/services/notification_service.py | 36 ++++++++++++++++--- .../src/components/AddNotificationModal.tsx | 4 ++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/backend/app/services/notification_service.py b/backend/app/services/notification_service.py index fd394d949..1f671b732 100644 --- a/backend/app/services/notification_service.py +++ b/backend/app/services/notification_service.py @@ -488,10 +488,11 @@ class NotificationService: async def _send_homeassistant( self, config: dict, title: str, message: str, db: AsyncSession | None = None ) -> tuple[bool, str]: - """Send notification via Home Assistant persistent notifications. + """Send notification via Home Assistant. - Uses the globally configured HA URL/token from settings, - and calls POST /api/services/persistent_notification/create. + Uses the globally configured HA URL/token from settings. + Defaults to persistent_notification/create, but supports + custom services via config["service"] (e.g. notify.mobile_app_myphone). """ # Get HA connection settings from global config ha_url = "" @@ -518,7 +519,34 @@ class NotificationService: "Home Assistant is not configured. Please set HA URL and token in Settings → Network → Home Assistant." ) - url = f"{ha_url.rstrip('/')}/api/services/persistent_notification/create" + # Determine which HA service to call - Default: persistent_notification.create + service = (config.get("service") or "").strip() + if service: + # Allow in different forms: + # - notify.mobile_app_ + # - notify/mobile_app_ + # - api/services/notify/mobile_app_ + service_str = service.lstrip("/") + if service_str.startswith("api/services/"): + endpoint = service_str + elif "/" in service_str: + endpoint = f"api/services/{service_str}" + elif "." in service_str: + domain, svc = service_str.split(".", 1) + endpoint = f"api/services/{domain}/{svc}" + else: + return False, ( + "Invalid Home Assistant service name. Use e.g. 'notify.mobile_app_yourdevice' or 'notify/your_service'." + ) + + if not re.match(r"^api/services/[a-zA-Z0-9_]+/[a-zA-Z0-9_]+$", endpoint): + return False, ( + "Invalid Home Assistant service name. Domain and service must only contain letters, numbers, and underscores." + ) + else: + endpoint = "api/services/persistent_notification/create" + + url = f"{ha_url.rstrip('/')}/{endpoint}" headers = { "Authorization": f"Bearer {ha_token}", "Content-Type": "application/json", diff --git a/frontend/src/components/AddNotificationModal.tsx b/frontend/src/components/AddNotificationModal.tsx index 5b8907c3b..6c8b3d118 100644 --- a/frontend/src/components/AddNotificationModal.tsx +++ b/frontend/src/components/AddNotificationModal.tsx @@ -213,7 +213,9 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal { key: 'field_message', label: 'Message Field Name', placeholder: 'message', type: 'text', required: false, showIf: (cfg: Record) => cfg.payload_format !== 'slack' }, ]; case 'homeassistant': - return []; + return [ + { key: 'service', label: 'Home Assistant Service', placeholder: 'notify.mobile_app_myphone', type: 'text', required: false }, + ]; default: return []; }