1 """Signal Messenger for notify component."""
3 from __future__
import annotations
8 from pysignalclirestapi
import SignalCliRestApi, SignalCliRestApiError
10 import voluptuous
as vol
14 PLATFORM_SCHEMA
as NOTIFY_PLATFORM_SCHEMA,
15 BaseNotificationService,
21 _LOGGER = logging.getLogger(__name__)
23 CONF_SENDER_NR =
"number"
24 CONF_RECP_NR =
"recipients"
25 CONF_SIGNAL_CLI_REST_API =
"url"
26 CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES = 52428800
27 ATTR_FILENAMES =
"attachments"
29 ATTR_VERIFY_SSL =
"verify_ssl"
30 ATTR_TEXTMODE =
"text_mode"
32 TEXTMODE_OPTIONS = [
"normal",
"styled"]
34 DATA_FILENAMES_SCHEMA = vol.Schema(
36 vol.Required(ATTR_FILENAMES): [cv.string],
37 vol.Optional(ATTR_TEXTMODE, default=
"normal"): vol.In(TEXTMODE_OPTIONS),
41 DATA_URLS_SCHEMA = vol.Schema(
43 vol.Required(ATTR_URLS): [cv.url],
44 vol.Optional(ATTR_VERIFY_SSL, default=
True): cv.boolean,
45 vol.Optional(ATTR_TEXTMODE, default=
"normal"): vol.In(TEXTMODE_OPTIONS),
49 DATA_SCHEMA = vol.Any(
53 vol.Optional(ATTR_TEXTMODE, default=
"normal"): vol.In(TEXTMODE_OPTIONS),
56 DATA_FILENAMES_SCHEMA,
60 PLATFORM_SCHEMA = NOTIFY_PLATFORM_SCHEMA.extend(
62 vol.Required(CONF_SENDER_NR): cv.string,
63 vol.Required(CONF_SIGNAL_CLI_REST_API): cv.string,
64 vol.Required(CONF_RECP_NR): vol.All(cv.ensure_list, [cv.string]),
72 discovery_info: DiscoveryInfoType |
None =
None,
73 ) -> SignalNotificationService:
74 """Get the SignalMessenger notification service."""
76 sender_nr = config[CONF_SENDER_NR]
77 recp_nrs = config[CONF_RECP_NR]
78 signal_cli_rest_api_url = config[CONF_SIGNAL_CLI_REST_API]
80 signal_cli_rest_api = SignalCliRestApi(signal_cli_rest_api_url, sender_nr)
86 """Implement the notification service for SignalMessenger."""
92 signal_cli_rest_api: SignalCliRestApi,
94 """Initialize the service."""
101 """Send a message to a one or more recipients. Additionally a file can be attached."""
103 _LOGGER.debug(
"Sending signal message")
105 data = kwargs.get(ATTR_DATA)
109 except vol.Invalid
as ex:
110 _LOGGER.error(
"Invalid message data: %s", ex)
115 data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self.
_hass_hass
122 attachments_as_bytes,
123 text_mode=
"normal" if data
is None else data.get(ATTR_TEXTMODE),
125 except SignalCliRestApiError
as ex:
126 _LOGGER.error(
"%s", ex)
131 """Extract attachment filenames from data."""
136 return data[ATTR_FILENAMES]
141 attachment_size_limit: int,
143 ) -> list[bytearray] |
None:
144 """Retrieve attachments from URLs defined in data."""
149 urls = data[ATTR_URLS]
151 attachments_as_bytes: list[bytearray] = []
155 if not hass.config.is_allowed_external_url(url):
156 _LOGGER.error(
"URL '%s' not in allow list", url)
160 url, verify=data[ATTR_VERIFY_SSL], timeout=10, stream=
True
162 resp.raise_for_status()
165 resp.headers.get(
"Content-Length")
is not None
166 and int(
str(resp.headers.get(
"Content-Length")))
167 > attachment_size_limit
169 content_length =
int(
str(resp.headers.get(
"Content-Length")))
171 "Attachment too large (Content-Length reports "
172 f
"{content_length}). Max size: "
173 f
"{CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES} bytes"
178 for chunk
in resp.iter_content(1024):
180 if size > attachment_size_limit:
182 f
"Attachment too large (Stream reports {size}). "
183 f
"Max size: {CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES} bytes"
188 attachments_as_bytes.append(chunks)
189 except Exception
as ex:
190 _LOGGER.error(
"%s", ex)
193 if not attachments_as_bytes:
196 return attachments_as_bytes
None send_message(self, str message="", **Any kwargs)
list[str]|None get_filenames(Any data)
None __init__(self, HomeAssistant hass, list[str] recp_nrs, SignalCliRestApi signal_cli_rest_api)
list[bytearray]|None get_attachments_as_bytes(Any data, int attachment_size_limit, HomeAssistant hass)
SignalNotificationService get_service(HomeAssistant hass, ConfigType config, DiscoveryInfoType|None discovery_info=None)