Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions custom_components/wapi/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
131 changes: 98 additions & 33 deletions custom_components/wapi/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
CONF_URL = "url"
CONFIG_SESSION = "session"
CONFIG_TOKEN = "token"

_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
Expand All @@ -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,
}
)