From 0a79b01684ec31083ad495f192b573bc1638ebd6 Mon Sep 17 00:00:00 2001 From: rosenrot00 <121129193+rosenrot00@users.noreply.github.com> Date: Sun, 18 May 2025 23:48:45 +0200 Subject: [PATCH 1/5] Update notify.py --- custom_components/wapi/notify.py | 68 +++++++++++++++++++------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/custom_components/wapi/notify.py b/custom_components/wapi/notify.py index 1523092..b6e643a 100644 --- a/custom_components/wapi/notify.py +++ b/custom_components/wapi/notify.py @@ -25,7 +25,6 @@ extra=vol.ALLOW_EXTRA, ) - def get_service(hass, config, discovery_info=None): """Get the custom notifier service.""" url = config.get(CONF_URL) @@ -33,7 +32,6 @@ def get_service(hass, config, discovery_info=None): token = config.get(CONFIG_TOKEN) return MatterNotificationService(url, session, token) - class MatterNotificationService(BaseNotificationService): def __init__(self, url, session, token=None): self._url = url @@ -55,29 +53,45 @@ def __send(self, data): _LOGGER.error("Error sending notification using wapi: %s", ex) def send_message(self, message="", **kwargs): - title = kwargs.get(ATTR_TITLE) + title = kwargs.get(ATTR_TITLE) or "" chatId = kwargs.get(ATTR_TARGET) - data = kwargs.get(ATTR_DATA) - - msg_data = { - "content": "*" + title + "* \n" + message, - "chatId": chatId, - "contentType": "string", - } - self.__send(msg_data) - - if data is not None and data["media_url"] is not None: - media_urls = data["media_url"].splitlines() - for url in media_urls: - media_data = { - "content": url, - "chatId": chatId, - "contentType": "MessageMediaFromURL" - } - self.__send(media_data) - - - - - - + data = kwargs.get(ATTR_DATA) or {} + media_urls = data.get("media_url", "").splitlines() if data.get("media_url") else [] + message = "" if message == " " else message + ascaption = data.get("ascaption", False) + + def format_text(title, message): + return ("*" + title + "*" + ("\n" if message else "") if title else "") + (message or "") + + if ascaption and len(media_urls) > 1: + _LOGGER.warning("Multiple media URLs provided, but 'ascaption' is true. Only the first URL will have a caption.") + + if not media_urls: + self.__send({ + "content": format_text(title, message), + "chatId": chatId, + "contentType": "string", + }) + return + + if ascaption: + self.__send({ + "chatId": chatId, + "contentType": "MessageMediaFromURL", + "content": media_urls[0], + "options": {"caption": format_caption(title, message)} + }) + media_urls = media_urls[1:] + elif title or message: + self.__send({ + "content": format_text(title, message), + "chatId": chatId, + "contentType": "string", + }) + + for url in media_urls: + self.__send({ + "chatId": chatId, + "contentType": "MessageMediaFromURL", + "content": url, + }) From f6d053976e67c0fc68f3a20a18b9d97604d0e502 Mon Sep 17 00:00:00 2001 From: rosenrot00 <121129193+rosenrot00@users.noreply.github.com> Date: Sun, 18 May 2025 23:49:40 +0200 Subject: [PATCH 2/5] Update manifest.json --- custom_components/wapi/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/wapi/manifest.json b/custom_components/wapi/manifest.json index 58b51cd..1e8c119 100644 --- a/custom_components/wapi/manifest.json +++ b/custom_components/wapi/manifest.json @@ -1,10 +1,10 @@ { "domain": "wapi", - "name": "wapi notifier based on https://github.com/chrishubert/whatsapp-api and can send notifications to whatsapp groups and contacts", + "name": "wapi notifier based on https://github.com/chrishubert/whatsapp-api", "codeowners": ["@t0mer"], "documentation": "https://github.com/t0mer/wapi-custom-notifier", "iot_class": "local_polling", "issue_tracker": "https://github.com/t0mer/wapi-custom-notifier", "requirements": ["requests"], - "version": "0.2.0" + "version": "0.2.5" } From d6a59fe399b9fb9b6bda75c4a5574e8503bc8c4b Mon Sep 17 00:00:00 2001 From: rosenrot00 <121129193+rosenrot00@users.noreply.github.com> Date: Sun, 18 May 2025 23:52:31 +0200 Subject: [PATCH 3/5] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d520e31..f996e3e 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ data: title: Your Garage Door Friend target: xxxxxxxxxx@c.us #Can be contact or group chat id data: + ascaption: true #optional, attaches the title and message as caption to the first image othwise text is independent media_url: | https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Example https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Example From 81f414dccddce28393c400c7af504e357690c03d Mon Sep 17 00:00:00 2001 From: rosenrot00 <121129193+rosenrot00@users.noreply.github.com> Date: Sun, 18 May 2025 23:54:27 +0200 Subject: [PATCH 4/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f996e3e..f240fa3 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Multiple media files are now supported. Use the multiline feature as shown below ```yaml service: notify.wapi_whatsapp_notifire data: - message: The garage door has been open for 10 minutes. + message: The garage door has been open for 10 minutes. #messages can't be empty but if you want to send images only just put a space " " as message title: Your Garage Door Friend target: xxxxxxxxxx@c.us #Can be contact or group chat id data: From 8a12f365d68943db3f3e8fced291f1415c1809f2 Mon Sep 17 00:00:00 2001 From: rosenrot00 <121129193+rosenrot00@users.noreply.github.com> Date: Mon, 4 May 2026 15:52:52 +0200 Subject: [PATCH 5/5] Refactor MatterNotificationService for improved logging --- custom_components/wapi/notify.py | 121 ++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 35 deletions(-) diff --git a/custom_components/wapi/notify.py b/custom_components/wapi/notify.py index b6e643a..1a3d68d 100644 --- a/custom_components/wapi/notify.py +++ b/custom_components/wapi/notify.py @@ -14,6 +14,7 @@ CONF_URL = "url" CONFIG_SESSION = "session" CONFIG_TOKEN = "token" + _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -25,6 +26,7 @@ extra=vol.ALLOW_EXTRA, ) + def get_service(hass, config, discovery_info=None): """Get the custom notifier service.""" url = config.get(CONF_URL) @@ -32,66 +34,115 @@ def get_service(hass, config, discovery_info=None): token = config.get(CONFIG_TOKEN) return MatterNotificationService(url, session, token) + class MatterNotificationService(BaseNotificationService): def __init__(self, url, session, token=None): - self._url = url + self._url = url.rstrip("/") self.session = session self.token = token def __send(self, data): try: - if self.token is None: - response = requests.post(self._url + "/" + self.session, json=data) - else: - headers = {"x-api-key": self.token} - response = requests.post( - self._url + "/" + self.session, json=data, headers=headers - ) - _LOGGER.info("Message sent") + headers = {} + + if self.token is not None: + headers["x-api-key"] = self.token + + _LOGGER.debug("Sending WAPI payload: %s", data) + + response = requests.post( + f"{self._url}/{self.session}", + json=data, + headers=headers, + timeout=30, + ) + response.raise_for_status() + _LOGGER.info("WAPI message sent successfully") + except requests.exceptions.RequestException as ex: - _LOGGER.error("Error sending notification using wapi: %s", ex) + response_text = "" + + if getattr(ex, "response", None) is not None: + response_text = ex.response.text + + _LOGGER.error( + "Error sending notification using wapi: %s | response: %s", + ex, + response_text, + ) def send_message(self, message="", **kwargs): title = kwargs.get(ATTR_TITLE) or "" - chatId = kwargs.get(ATTR_TARGET) + chat_id = kwargs.get(ATTR_TARGET) data = kwargs.get(ATTR_DATA) or {} - media_urls = data.get("media_url", "").splitlines() if data.get("media_url") else [] + + if isinstance(chat_id, list): + chat_id = chat_id[0] if chat_id else None + + if not chat_id: + _LOGGER.error("No target/chatId provided for WAPI notification") + return + + chat_id = str(chat_id).strip().replace(" ", "") + + media_urls = ( + data.get("media_url", "").splitlines() + if data.get("media_url") + else [] + ) + message = "" if message == " " else message ascaption = data.get("ascaption", False) def format_text(title, message): - return ("*" + title + "*" + ("\n" if message else "") if title else "") + (message or "") + if title and message: + return f"*{title}*\n{message}" + if title: + return f"*{title}*" + return message or "" if ascaption and len(media_urls) > 1: - _LOGGER.warning("Multiple media URLs provided, but 'ascaption' is true. Only the first URL will have a caption.") + _LOGGER.warning( + "Multiple media URLs provided, but 'ascaption' is true. " + "Only the first URL will have a caption." + ) if not media_urls: - self.__send({ - "content": format_text(title, message), - "chatId": chatId, - "contentType": "string", - }) + self.__send( + { + "content": format_text(title, message), + "chatId": chat_id, + "contentType": "string", + } + ) return if ascaption: - self.__send({ - "chatId": chatId, - "contentType": "MessageMediaFromURL", - "content": media_urls[0], - "options": {"caption": format_caption(title, message)} - }) + self.__send( + { + "chatId": chat_id, + "contentType": "MessageMediaFromURL", + "content": media_urls[0], + "options": {"caption": format_text(title, message)}, + } + ) media_urls = media_urls[1:] + elif title or message: - self.__send({ - "content": format_text(title, message), - "chatId": chatId, - "contentType": "string", - }) + self.__send( + { + "content": format_text(title, message), + "chatId": chat_id, + "contentType": "string", + } + ) for url in media_urls: - self.__send({ - "chatId": chatId, - "contentType": "MessageMediaFromURL", - "content": url, - }) + self.__send( + { + "chatId": chat_id, + "contentType": "MessageMediaFromURL", + "content": url, + } + )