Coverage for custom_components/supernotify/transports/notify_entity.py: 100%
46 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-09-25 21:14 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-09-25 21:14 +0000
1from __future__ import annotations
3import logging
4from typing import TYPE_CHECKING, Any
6from homeassistant.const import ATTR_ENTITY_ID # ATTR_VARIABLES from script.const has import issues
7from homeassistant.helpers.typing import ConfigType
9from custom_components.supernotify.const import (
10 INCLUSION_DEFAULT,
11 RE_NOTIFY_ENTITY_ID,
12 TRANSPORT_NOTIFY_ENTITY,
13)
14from custom_components.supernotify.model import (
15 DebugTrace,
16 MessageOnlyPolicy,
17 TransportConfig,
18 TransportFeature,
19)
20from custom_components.supernotify.options import (
21 OPTION_MESSAGE_USAGE,
22 OPTION_SIMPLIFY_TEXT,
23 OPTION_STRIP_URLS,
24 OPTION_TARGET_SELECT,
25 OPTION_UNIQUE_TARGETS,
26)
27from custom_components.supernotify.schema import SelectionRank
28from custom_components.supernotify.target import TargetEntityCategory
29from custom_components.supernotify.transport import (
30 Transport,
31)
33if TYPE_CHECKING:
34 from custom_components.supernotify.envelope import Envelope
35 from custom_components.supernotify.hass_api import HomeAssistantAPI
37_LOGGER = logging.getLogger(__name__)
40FIXED_ACTION = "notify.send_message"
43class NotifyEntityTransport(Transport):
44 """Call any notify entity"""
46 name = TRANSPORT_NOTIFY_ENTITY
48 def __init__(self, *args: Any, **kwargs: Any) -> None:
49 super().__init__(*args, **kwargs)
51 @property
52 def supported_features(self) -> TransportFeature:
53 return TransportFeature.MESSAGE | TransportFeature.TITLE
55 @property
56 def default_config(self) -> TransportConfig:
57 config = TransportConfig()
58 config.delivery_defaults.action = FIXED_ACTION
59 config.delivery_defaults.selection_rank = SelectionRank.LAST
60 config.delivery_defaults.inclusion = self.inclusion_mode
61 config.delivery_defaults.options = {
62 OPTION_SIMPLIFY_TEXT: False,
63 OPTION_STRIP_URLS: False,
64 OPTION_MESSAGE_USAGE: MessageOnlyPolicy.STANDARD,
65 OPTION_UNIQUE_TARGETS: True,
66 OPTION_TARGET_SELECT: [RE_NOTIFY_ENTITY_ID],
67 }
68 return config
70 @property
71 def target_categories(self) -> list[str | TargetEntityCategory]:
72 # no platform restriction - the generic catch-all for any notify.* entity not
73 # claimed by a more specific transport (html5, alexa_devices); selection_rank=LAST
74 # ensures those get first refusal
75 return [TargetEntityCategory(domain="notify")]
77 @property
78 def inclusion_mode(self) -> list[str]:
79 # a notify.* entity maps cleanly to a recipient, so it's reasonable to fire on
80 # every notification by default
81 return [INCLUSION_DEFAULT]
83 def is_viable(self, hass_api: HomeAssistantAPI) -> bool:
84 return bool(hass_api.entity_ids_for_domain("notify"))
86 def build_standard_deliveries(self, hass_api: HomeAssistantAPI) -> dict[str, ConfigType]:
87 return {self.name: {}}
89 async def deliver(self, envelope: Envelope, debug_trace: DebugTrace | None = None) -> bool:
90 targets = envelope.target.entity_ids or []
91 if not targets:
92 _LOGGER.warning("SUPERNOTIFY notify_entity: no targets")
93 return False
94 target_data: dict[str, Any] = {ATTR_ENTITY_ID: targets}
95 # area_id
96 # device_id
97 # label_id
98 action_data = envelope.core_action_data()
100 return await self.call_action(envelope, FIXED_ACTION, action_data=action_data, target_data=target_data)