diff --git a/README.md b/README.md index d520e31..f240fa3 100644 --- a/README.md +++ b/README.md @@ -128,10 +128,11 @@ 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: + 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 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" } diff --git a/custom_components/wapi/notify.py b/custom_components/wapi/notify.py index 1523092..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( @@ -36,48 +37,112 @@ def get_service(hass, config, discovery_info=None): 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") - response.raise_for_status() - except requests.exceptions.RequestException as ex: - _LOGGER.error("Error sending notification using wapi: %s", ex) + headers = {} - def send_message(self, message="", **kwargs): - title = kwargs.get(ATTR_TITLE) - 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) + 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: + 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 "" + chat_id = kwargs.get(ATTR_TARGET) + data = kwargs.get(ATTR_DATA) or {} + + 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): + 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." + ) + + if not media_urls: + self.__send( + { + "content": format_text(title, message), + "chatId": chat_id, + "contentType": "string", + } + ) + return + + if ascaption: + 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": chat_id, + "contentType": "string", + } + ) + for url in media_urls: + self.__send( + { + "chatId": chat_id, + "contentType": "MessageMediaFromURL", + "content": url, + } + )