Coverage for custom_components/supernotify/transports/sms.py: 50%
38 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-01-07 15:35 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2026-01-07 15:35 +0000
1import logging
2from typing import Any
4from homeassistant.components.notify.const import ATTR_DATA, ATTR_TARGET
6from custom_components.supernotify import (
7 ATTR_PHONE,
8 OPTION_MESSAGE_USAGE,
9 OPTION_SIMPLIFY_TEXT,
10 OPTION_STRIP_URLS,
11 OPTION_TARGET_CATEGORIES,
12 TRANSPORT_SMS,
13)
14from custom_components.supernotify.envelope import Envelope
15from custom_components.supernotify.model import DebugTrace, MessageOnlyPolicy, TransportConfig, TransportFeature
16from custom_components.supernotify.transport import (
17 Transport,
18)
20RE_VALID_PHONE = r"^(\+\d{1,3})?\s?\(?\d{1,4}\)?[\s.-]?\d{3}[\s.-]?\d{4}$"
22_LOGGER = logging.getLogger(__name__)
25class SMSTransport(Transport):
26 name = TRANSPORT_SMS
27 MAX_MESSAGE_LENGTH = 158
29 def __init__(self, *args: Any, **kwargs: Any) -> None:
30 super().__init__(*args, **kwargs)
32 @property
33 def supported_features(self) -> TransportFeature:
34 return TransportFeature.MESSAGE | TransportFeature.TITLE
36 @property
37 def default_config(self) -> TransportConfig:
38 config = TransportConfig()
39 config.delivery_defaults.options = {
40 OPTION_SIMPLIFY_TEXT: True,
41 OPTION_STRIP_URLS: False,
42 OPTION_MESSAGE_USAGE: MessageOnlyPolicy.COMBINE_TITLE,
43 OPTION_TARGET_CATEGORIES: [ATTR_PHONE],
44 }
45 return config
47 def validate_action(self, action: str | None) -> bool:
48 """Override in subclass if transport has fixed action or doesn't require one"""
49 return action is not None
51 async def deliver(self, envelope: Envelope, debug_trace: DebugTrace | None = None) -> bool: # noqa: ARG002
52 _LOGGER.debug("SUPERNOTIFY notify_sms: %s", envelope.delivery_name)
54 data: dict[str, Any] = envelope.data or {}
55 mobile_numbers = envelope.target.phone or []
57 if not envelope.message:
58 _LOGGER.warning("SUPERNOTIFY notify_sms: No message to send")
59 return False
61 message: str = envelope.message or ""
62 if len(message) > self.MAX_MESSAGE_LENGTH:
63 _LOGGER.debug(
64 "SUPERNOTIFY notify_sms: Message too long (%d characters), truncating to %d characters",
65 len(message),
66 self.MAX_MESSAGE_LENGTH,
67 )
69 action_data = {"message": message[: self.MAX_MESSAGE_LENGTH], ATTR_TARGET: mobile_numbers}
70 if data and data.get("data"):
71 action_data[ATTR_DATA] = data.get("data", {})
73 return await self.call_action(envelope, action_data=action_data)