Coverage for custom_components/supernotify/const.py: 100%
225 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
1"""The Supernotify integration"""
3from typing import Final
5from homeassistant.const import (
6 ATTR_DEVICE_ID,
7 ATTR_DOMAIN,
8 ATTR_ENTITY_ID,
9 ATTR_SERVICE,
10 CONF_TARGET,
11)
13CONF_ACTIONS: Final[str] = "actions" # not fully implemented
14CONF_TITLE: Final[str] = "title"
15CONF_URI: Final[str] = "uri"
16CONF_RECIPIENTS: Final[str] = "recipients"
17CONF_RECIPIENTS_DISCOVERY: Final[str] = "recipients_discovery"
18CONF_TEMPLATE_PATH: Final[str] = "template_path"
19CONF_MEDIA_PATH: Final[str] = "media_path"
20CONF_MEDIA_URL_PREFIX: Final[str] = "media_url_prefix"
21CONF_HOUSEKEEPING: Final[str] = "housekeeping"
22CONF_HOUSEKEEPING_TIME: Final[str] = "housekeeping_time"
23CONF_ARCHIVE_PATH: Final[str] = "file_path"
24CONF_ARCHIVE: Final[str] = "archive"
25CONF_ARCHIVE_DAYS: Final[str] = "file_retention_days"
26CONF_ARCHIVE_MQTT_TOPIC: Final[str] = "mqtt_topic"
27CONF_ARCHIVE_MQTT_QOS: Final[str] = "mqtt_qos"
28CONF_ARCHIVE_MQTT_RETAIN: Final[str] = "mqtt_retain"
29CONF_TEMPLATE: Final[str] = "template"
30CONF_DELIVERY_DEFAULTS: Final[str] = "delivery_defaults"
31CONF_LINKS: Final[str] = "links"
32CONF_PERSON: Final[str] = "person"
33CONF_USER_ID: Final[str] = "user_id"
34CONF_TRANSPORT: Final[str] = "transport"
35CONF_TRANSPORTS: Final[str] = "transports"
36CONF_LOAD: Final[str] = "load"
37CONF_DELIVERY: Final[str] = "delivery"
38CONF_INCLUSION: Final[str] = "inclusion"
39CONF_SELECTION: Final[str] = "selection" # deprecated, use CONF_INCLUSION
40CONF_SELECTION_RANK: Final[str] = "selection_rank"
43CONF_DATA: Final[str] = "data"
44CONF_OPTIONS: Final[str] = "options"
45CONF_MOBILE: Final[str] = "mobile"
46CONF_NOTIFY: Final[str] = "notify"
48CONF_PRIORITY: Final[str] = "priority"
49CONF_OCCUPANCY: Final[str] = "occupancy"
50CONF_SCENARIOS: Final[str] = "scenarios"
51CONF_SCENARIO_CONTROL: Final[str] = "scenario_control"
52CONF_REFRESH_INTERVAL: Final[str] = "refresh_interval"
53CONF_EXPOSE_STATE: Final[str] = "expose_state"
54CONF_REFRESH: Final[str] = "refresh"
55SCENARIO_STATE_REFRESH_DEFAULT: Final[int] = 60
56CONF_MANUFACTURER: Final[str] = "manufacturer"
57CONF_CLASS: Final[str] = "class"
60CONF_MODEL: Final[str] = "model"
61CONF_MESSAGE: Final[str] = "message"
62CONF_TARGET_REQUIRED: Final[str] = "target_required"
63CONF_MOBILE_DEVICES: Final[str] = "mobile_devices"
64CONF_MOBILE_DISCOVERY: Final[str] = "mobile_discovery"
65CONF_ACTION_TEMPLATE: Final[str] = "action_template"
66CONF_ACTION_GROUPS: Final[str] = "action_groups"
67CONF_TITLE_TEMPLATE: Final[str] = "title_template"
68CONF_MEDIA: Final[str] = "media"
69CONF_CAMERA: Final[str] = "camera"
70CONF_CLIP_URL: Final[str] = "clip_url"
71CONF_PTZ_DELAY: Final[str] = "ptz_delay"
72CONF_SNAP_WAIT: Final[str] = "snap_wait"
73CONF_PTZ_METHOD: Final[str] = "ptz_method"
74CONF_PTZ_CAMERA: Final[str] = "ptz_camera"
75CONF_PTZ_PRESET_DEFAULT: Final[str] = "ptz_default_preset"
76CONF_ALT_CAMERA: Final[str] = "alt_camera"
77CONF_CAMERAS: Final[str] = "cameras"
78CONF_ARCHIVE_PURGE_INTERVAL: Final[str] = "purge_interval"
79CONF_ARCHIVE_EVENT_NAME: Final[str] = "event_name"
80CONF_ARCHIVE_EVENT_SELECTION: Final[str] = "event_selection"
81CONF_ARCHIVE_DIAGNOSTICS: Final[str] = "diagnostics"
82CONF_MEDIA_STORAGE_DAYS: Final[str] = "media_storage_days"
84PLATFORM_FRIGATE = "frigate"
86OCCUPANCY_ANY_IN = "any_in"
87OCCUPANCY_ANY_OUT = "any_out"
88OCCUPANCY_ALL_IN = "all_in"
89OCCUPANCY_ALL = "all"
90OCCUPANCY_NONE = "none"
91OCCUPANCY_ALL_OUT = "all_out"
92OCCUPANCY_ONLY_IN = "only_in"
93OCCUPANCY_ONLY_OUT = "only_out"
95ATTR_ENABLED = "enabled"
96ATTR_TRANSPORT_ENABLED = "transport_enabled"
97ATTR_PRIORITY = "priority"
98ATTR_ACTION = "action"
99ATTR_REPLY_TEXT = "reply_text"
100ATTR_SCENARIOS_REQUIRE = "require_scenarios"
101ATTR_SCENARIOS_APPLY = "apply_scenarios"
102ATTR_FORCE_RESEND: Final[str] = "force_resend"
103ATTR_SCENARIOS_CONSTRAIN = "constrain_scenarios"
104ATTR_DELIVERY = "delivery"
105ATTR_DEFAULT = "default"
106ATTR_NOTIFICATION_ID = "notification_id"
107ATTR_DELIVERY_SELECTION = "delivery_selection"
108# supernotify.notify's free-form delivery field, merged into `delivery` with the delivery dropdown
109ATTR_DELIVERY_CONTROL = "delivery_control"
110ATTR_RECIPIENTS = "recipients"
111ATTR_CUSTOM_TARGET = "custom_target"
112ATTR_DATA = "data"
113ATTR_EXTRA_DATA: Final[str] = "extra_data"
114ATTR_MEDIA = "media"
115ATTR_TITLE = "title"
116ATTR_IMAGE = "image"
117ATTR_VIDEO = "video"
118ATTR_MEDIA_SNAPSHOT_URL = "snapshot_url"
119ATTR_MEDIA_CAMERA_ENTITY_ID = "camera_entity_id"
120ATTR_MEDIA_CAMERA_DELAY = "camera_delay"
121ATTR_MEDIA_CAMERA_PTZ_PRESET = "camera_ptz_preset"
122ATTR_MEDIA_CLIP_URL = "clip_url"
123ATTR_MEDIA_SNAPSHOT_PATH = "snapshot_image_path"
124ATTR_TOPIC = "topic"
125ATTR_DISCORD_CHANNEL = "discord_channel"
126ATTR_MATRIX_ROOM = "matrix_room"
127ATTR_ACTION_GROUPS = "action_groups"
128CONF_ACTION_GROUP_NAMES = "action_groups"
129ATTR_ACTION_URL = "action_url"
130ATTR_ACTION_URL_TITLE = "action_url_title"
131ATTR_MESSAGE_HTML = "message_html"
132ATTR_JPEG_OPTS = "jpeg_opts"
133ATTR_PNG_OPTS = "png_opts"
134ATTR_TIMESTAMP = "timestamp"
135ATTR_SPOKEN_MESSAGE = "spoken_message"
136ATTR_DEBUG = "debug"
137ATTR_ACTIONS = "actions"
138ATTR_USER_ID = "user_id"
139ATTR_PERSON_ID = "person_id"
140ATTR_MOBILE_APP_ID = "mobile_app_id"
141ATTR_EMAIL = "email"
142ATTR_PHONE = "phone"
143ATTR_ALIAS = "alias"
145DELIVERY_SELECTION_IMPLICIT = "implicit"
146DELIVERY_SELECTION_EXPLICIT = "explicit"
147DELIVERY_SELECTION_FIXED = "fixed"
149DELIVERY_SELECTION_VALUES = [DELIVERY_SELECTION_EXPLICIT, DELIVERY_SELECTION_FIXED, DELIVERY_SELECTION_IMPLICIT]
150PTZ_METHOD_ONVIF = "onvif"
151PTZ_METHOD_FRIGATE = "frigate"
152PTZ_METHOD_VALUES = [PTZ_METHOD_ONVIF, PTZ_METHOD_FRIGATE]
153PTZ_DELAY_DEFAULT = 10
154SNAP_WAIT_DEFAULT = 15
156INCLUSION_FALLBACK_ON_ERROR = "fallback_on_error"
157INCLUSION_FALLBACK = "fallback"
158INCLUSION_BY_SCENARIO = "scenario"
159INCLUSION_DEFAULT = "default"
160INCLUSION_EXPLICIT = "explicit"
161INCLUSION_VALUES = [
162 INCLUSION_FALLBACK_ON_ERROR,
163 INCLUSION_EXPLICIT,
164 INCLUSION_BY_SCENARIO,
165 INCLUSION_DEFAULT,
166 INCLUSION_FALLBACK,
167]
169OCCUPANCY_VALUES = [
170 OCCUPANCY_ALL_IN,
171 OCCUPANCY_ALL_OUT,
172 OCCUPANCY_ANY_IN,
173 OCCUPANCY_ANY_OUT,
174 OCCUPANCY_ONLY_IN,
175 OCCUPANCY_ONLY_OUT,
176 OCCUPANCY_ALL,
177 OCCUPANCY_NONE,
178]
180PRIORITY_CRITICAL = "critical"
181PRIORITY_HIGH = "high"
182PRIORITY_MEDIUM = "medium"
183PRIORITY_LOW = "low"
184PRIORITY_MINIMUM = "minimum"
186PRIORITY_VALUES: dict[str, int] = {
187 PRIORITY_MINIMUM: 1,
188 PRIORITY_LOW: 2,
189 PRIORITY_MEDIUM: 3,
190 PRIORITY_HIGH: 4,
191 PRIORITY_CRITICAL: 5,
192}
194CONF_TARGET_USAGE = "target_usage"
195TARGET_USE_ON_NO_DELIVERY_TARGETS = "no_delivery"
196TARGET_USE_ON_NO_ACTION_TARGETS = "no_action"
197TARGET_USE_FIXED = "fixed"
198TARGET_USE_MERGE_ALWAYS = "merge_always"
199TARGET_USE_MERGE_ON_DELIVERY_TARGETS = "merge_delivery"
201# Options constants have been moved to `options.py`
203RE_DEVICE_ID = r"^[0-9a-f]{32}$"
204RE_MEDIA_PLAYER_ENTITY_ID = r"^media_player\.[A-Za-z0-9_]+$"
205RE_NOTIFY_ENTITY_ID = r"^notify\.[A-Za-z0-9_]+$"
207RESERVED_DELIVERY_NAMES: list[str] = ["ALL"]
208RESERVED_SCENARIO_NAMES: list[str] = ["NO_SCENARIO", "NULL"]
209RESERVED_DATA_KEYS: list[str] = [ATTR_DOMAIN, ATTR_SERVICE, "action"]
211CONF_DUPE_CHECK: Final[str] = "dupe_check"
212CONF_DUPE_POLICY: Final[str] = "dupe_policy"
213CONF_TTL: Final[str] = "ttl"
214CONF_SIZE: Final[str] = "size"
215ATTR_DUPE_POLICY_MTSLP: Final[str] = "dupe_policy_message_title_same_or_lower_priority"
216ATTR_DUPE_POLICY_MT: Final[str] = "dupe_policy_message_title_same"
217ATTR_DUPE_POLICY_NONE: Final[str] = "dupe_policy_none"
218CONF_MOBILE_APP_ID: Final[str] = "mobile_app_id"
219CONF_TRANSPORT_DATA: Final[str] = "transport_data"
222CONF_DEVICE_TRACKER: Final[str] = "device_tracker"
225CONF_DEVICE_NAME: Final[str] = "device_name"
226CONF_DEVICE_LABELS: Final[str] = "device_labels"
228MANUFACTURER_APPLE = "Apple"
230TARGET_REQUIRE_ALWAYS = "always"
231TARGET_REQUIRE_NEVER = "never"
232TARGET_REQUIRE_OPTIONAL = "optional"
234## Transports
235# Defined here rather than transports.py so that the strings can be imported
236# without the transports, and avoid circular references or heavier imports
237TRANSPORT_SMS = "sms"
238TRANSPORT_TTS = "tts"
239TRANSPORT_MQTT = "mqtt"
240TRANSPORT_EMAIL = "email"
241TRANSPORT_ALEXA = "alexa_devices"
242TRANSPORT_ALEXA_MEDIA_PLAYER = "alexa_media_player"
243TRANSPORT_MOBILE_PUSH = "mobile_push"
244TRANSPORT_MEDIA = "media"
245TRANSPORT_CHIME = "chime"
246TRANSPORT_GENERIC = "generic"
247TRANSPORT_NOTIFY_ENTITY = "notify_entity"
248TRANSPORT_PERSISTENT = "persistent"
249TRANSPORT_NTFY = "ntfy"
250TRANSPORT_GOTIFY = "gotify"
251TRANSPORT_TELEGRAM = "telegram"
252TRANSPORT_LAMETRIC = "lametric"
253TRANSPORT_PUSHOVER = "pushover"
254TRANSPORT_HTML5 = "html5"
255TRANSPORT_MATRIX = "matrix"
256TRANSPORT_KODI = "kodi"
257TRANSPORT_DISCORD = "discord"
258TRANSPORT_VALUES = [
259 TRANSPORT_SMS,
260 TRANSPORT_MQTT,
261 TRANSPORT_ALEXA,
262 TRANSPORT_ALEXA_MEDIA_PLAYER,
263 TRANSPORT_MOBILE_PUSH,
264 TRANSPORT_CHIME,
265 TRANSPORT_EMAIL,
266 TRANSPORT_MEDIA,
267 TRANSPORT_PERSISTENT,
268 TRANSPORT_TTS,
269 TRANSPORT_GENERIC,
270 TRANSPORT_NOTIFY_ENTITY,
271 TRANSPORT_NTFY,
272 TRANSPORT_GOTIFY,
273 TRANSPORT_TELEGRAM,
274 TRANSPORT_LAMETRIC,
275 TRANSPORT_PUSHOVER,
276 TRANSPORT_HTML5,
277 TRANSPORT_MATRIX,
278 TRANSPORT_KODI,
279 TRANSPORT_DISCORD,
280]
282# The master list of target category names, independent of any one transport - both
283# `Target` (for qualifying a target, e.g. `topic:my/topic` or `target: {topic: ...}`)
284# and `Transport.target_categories` (for declaring which categories a transport accepts)
285# reference this same list, rather than transports and targets each keeping their own.
286TARGET_CATEGORY_VALUES = [
287 ATTR_ENTITY_ID,
288 ATTR_DEVICE_ID,
289 ATTR_EMAIL,
290 ATTR_PHONE,
291 ATTR_MOBILE_APP_ID,
292 ATTR_TOPIC,
293 ATTR_DISCORD_CHANNEL,
294 ATTR_MATRIX_ROOM,
295]
298CONF_CONNECTION: Final[str] = "connection"
299CONF_ENCRYPTION: Final[str] = "encryption"
301CONF_DEVICE_DISCOVERY: Final[str] = "device_discovery"
302CONF_DEVICE_DOMAIN: Final[str] = "device_domain"
303CONF_DEVICE_MODEL_INCLUDE: Final[str] = "device_model_include"
304CONF_DEVICE_MODEL_EXCLUDE: Final[str] = "device_model_exclude"
306# What a runtime override of a configured `enabled` flag can apply to - each also the unique_id
307# prefix of the switch for it, e.g. switch unique_id "delivery_<name>"
308OVERRIDE_KIND_SCENARIO: Final[str] = "scenario"
309OVERRIDE_KIND_RECIPIENT: Final[str] = "recipient"
310OVERRIDE_KIND_DELIVERY: Final[str] = "delivery"
311OVERRIDE_KIND_TRANSPORT: Final[str] = "transport"
312OVERRIDE_KINDS: Final[tuple[str, ...]] = (
313 OVERRIDE_KIND_SCENARIO,
314 OVERRIDE_KIND_RECIPIENT,
315 OVERRIDE_KIND_DELIVERY,
316 OVERRIDE_KIND_TRANSPORT,
317)
318# Entity state attributes too large, or changing too often, to be worth keeping in history
319DELIVERY_UNRECORDED_ATTRIBUTES: Final[frozenset[str]] = frozenset({CONF_OPTIONS, CONF_DATA, CONF_TARGET})
320TRANSPORT_UNRECORDED_ATTRIBUTES: Final[frozenset[str]] = frozenset({
321 CONF_DELIVERY_DEFAULTS,
322 "action_titles",
323 "action_title_failures",
324 "cached_templates",
325})
327CONF_SNOOZE = "snooze"
328CONF_SNOOZE_TIME = "snooze_time"
330# Config entry options for the LLM tools offered to Assist and MCP, see llm.py
331CONF_LLM_TOOLS: Final[str] = "llm_tools"
332CONF_LLM_ACTION_TOOLS: Final[str] = "action_tools"
333CONF_LLM_DIAGNOSTIC_TOOLS: Final[str] = "diagnostic_tools"
334# sentences for Home Assistant's built-in conversation agent, which can't use LLM tools, see sentences.py
335CONF_SENTENCE_COMMANDS: Final[str] = "sentence_commands"
337# Config entry options giving deliveries their defaults, where neither they nor their transport set one
338CONF_DELIVERY_CONTROL: Final[str] = "delivery_control"
339CONF_DEFAULT_INCLUSION: Final[str] = "default_inclusion"
340CONF_VOICE_OCCUPANCY: Final[str] = "voice_occupancy"
341DEFAULT_INCLUSION_VALUES: Final[list[str]] = [INCLUSION_DEFAULT, INCLUSION_EXPLICIT, INCLUSION_BY_SCENARIO]
343# Idea - differentiate enabled as recipient vs as occupant, for ALL_IN etc check
344# May need condition, and also enabled if delivery disabled
345# CONF_OCCUPANCY="occupancy"
346# OPTION_OCCUPANCY_DEFAULT="default"
347# OPTIONS_OCCUPANCY=[OPTION_OCCUPANCY_DEFAULT,OPTION_OCCUPANCY_EXCLUDE]
348# OPTION_OCCUPANCY_EXCLUDE="exclude"
350CONF_PHONE_NUMBER: str = "phone_number"
353CONF_TUNE: Final[str] = "tune"
354CONF_VOLUME: Final[str] = "volume"
355CONF_DURATION: Final[str] = "duration"
357OPTIONS_CHIME_DOMAINS = ["media_player", "switch", "script", "rest_command", "siren", "alexa_devices"]