Coverage for custom_components/supernotify/const.py: 100%

255 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-11-08 17:42 +0000

1"""The Supernotify integration""" 

2 

3from typing import Final 

4 

5from homeassistant.const import ( 

6 ATTR_DEVICE_ID, 

7 ATTR_DOMAIN, 

8 ATTR_ENTITY_ID, 

9 ATTR_SERVICE, 

10 CONF_TARGET, 

11) 

12 

13# fired on the notification's context once it has been sent, so the logbook shows it against what caused it 

14EVENT_NOTIFICATION: Final[str] = "supernotify_notification" 

15 

16CONF_ACTIONS: Final[str] = "actions" # not fully implemented 

17CONF_TITLE: Final[str] = "title" 

18CONF_URI: Final[str] = "uri" 

19CONF_RECIPIENTS: Final[str] = "recipients" 

20CONF_RECIPIENTS_DISCOVERY: Final[str] = "recipients_discovery" 

21# config subentry type holding one recipient, in RECIPIENT_SCHEMA shape 

22SUBENTRY_TYPE_RECIPIENT: Final[str] = "recipient" 

23SUBENTRY_TYPE_TRANSPORT: Final[str] = "transport" 

24CONF_TEMPLATE_PATH: Final[str] = "template_path" 

25CONF_MEDIA_PATH: Final[str] = "media_path" 

26CONF_MEDIA_URL_PREFIX: Final[str] = "media_url_prefix" 

27CONF_HOUSEKEEPING: Final[str] = "housekeeping" 

28CONF_HOUSEKEEPING_TIME: Final[str] = "housekeeping_time" 

29# keep the deprecated recipient, delivery and transport binary_sensors an install already has 

30CONF_DEPRECATED_ENTITIES: Final[str] = "deprecated_entities" 

31CONF_ARCHIVE_PATH: Final[str] = "file_path" 

32CONF_ARCHIVE: Final[str] = "archive" 

33CONF_ARCHIVE_DAYS: Final[str] = "file_retention_days" 

34CONF_ARCHIVE_MQTT_TOPIC: Final[str] = "mqtt_topic" 

35CONF_ARCHIVE_MQTT_QOS: Final[str] = "mqtt_qos" 

36CONF_ARCHIVE_MQTT_RETAIN: Final[str] = "mqtt_retain" 

37CONF_TEMPLATE: Final[str] = "template" 

38CONF_DELIVERY_DEFAULTS: Final[str] = "delivery_defaults" 

39CONF_PERSON: Final[str] = "person" 

40CONF_USER_ID: Final[str] = "user_id" 

41CONF_TRANSPORT: Final[str] = "transport" 

42CONF_TRANSPORTS: Final[str] = "transports" 

43CONF_LOAD: Final[str] = "load" 

44CONF_DELIVERY: Final[str] = "delivery" 

45CONF_INCLUSION: Final[str] = "inclusion" 

46CONF_SELECTION: Final[str] = "selection" # deprecated, use CONF_INCLUSION 

47CONF_SELECTION_RANK: Final[str] = "selection_rank" 

48 

49 

50CONF_DATA: Final[str] = "data" 

51CONF_OPTIONS: Final[str] = "options" 

52CONF_MOBILE: Final[str] = "mobile" 

53CONF_NOTIFY: Final[str] = "notify" 

54 

55CONF_PRIORITY: Final[str] = "priority" 

56CONF_OCCUPANCY: Final[str] = "occupancy" 

57CONF_SCENARIOS: Final[str] = "scenarios" 

58CONF_SCENARIO_CONTROL: Final[str] = "scenario_control" 

59CONF_REFRESH_INTERVAL: Final[str] = "refresh_interval" 

60CONF_EXPOSE_STATE: Final[str] = "expose_state" 

61CONF_REFRESH: Final[str] = "refresh" 

62SCENARIO_STATE_REFRESH_DEFAULT: Final[int] = 60 

63CONF_MANUFACTURER: Final[str] = "manufacturer" 

64CONF_CLASS: Final[str] = "class" 

65 

66 

67CONF_MODEL: Final[str] = "model" 

68CONF_MESSAGE: Final[str] = "message" 

69CONF_TARGET_REQUIRED: Final[str] = "target_required" 

70CONF_MOBILE_DEVICES: Final[str] = "mobile_devices" 

71CONF_MOBILE_DISCOVERY: Final[str] = "mobile_discovery" 

72CONF_ACTION_TEMPLATE: Final[str] = "action_template" 

73CONF_ACTION_GROUPS: Final[str] = "action_groups" 

74CONF_TITLE_TEMPLATE: Final[str] = "title_template" 

75CONF_URI_TEMPLATE: Final[str] = "uri_template" 

76CONF_LEVEL: Final[str] = "level" 

77# a mobile action is a button by default, or at notification level is what tapping the notification itself opens 

78ACTION_LEVEL_ACTION: Final[str] = "action" 

79ACTION_LEVEL_NOTIFICATION: Final[str] = "notification" 

80CONF_MEDIA: Final[str] = "media" 

81CONF_CAMERA: Final[str] = "camera" 

82CONF_CLIP_URL: Final[str] = "clip_url" 

83CONF_PTZ_DELAY: Final[str] = "ptz_delay" 

84CONF_SNAP_WAIT: Final[str] = "snap_wait" 

85CONF_PTZ_METHOD: Final[str] = "ptz_method" 

86CONF_PTZ_CAMERA: Final[str] = "ptz_camera" 

87CONF_PTZ_PRESET_DEFAULT: Final[str] = "ptz_default_preset" 

88CONF_ALT_CAMERA: Final[str] = "alt_camera" 

89CONF_CAMERAS: Final[str] = "cameras" 

90CONF_ARCHIVE_PURGE_INTERVAL: Final[str] = "purge_interval" 

91CONF_ARCHIVE_EVENT_NAME: Final[str] = "event_name" 

92CONF_ARCHIVE_EVENT_SELECTION: Final[str] = "event_selection" 

93CONF_ARCHIVE_DIAGNOSTICS: Final[str] = "diagnostics" 

94CONF_MEDIA_STORAGE_DAYS: Final[str] = "media_storage_days" 

95 

96PLATFORM_FRIGATE = "frigate" 

97 

98OCCUPANCY_ANY_IN = "any_in" 

99OCCUPANCY_ANY_OUT = "any_out" 

100OCCUPANCY_ALL_IN = "all_in" 

101OCCUPANCY_ALL = "all" 

102OCCUPANCY_NONE = "none" 

103OCCUPANCY_ALL_OUT = "all_out" 

104OCCUPANCY_ONLY_IN = "only_in" 

105OCCUPANCY_ONLY_OUT = "only_out" 

106 

107ATTR_ENABLED = "enabled" 

108ATTR_OVERRIDDEN = "overridden" 

109# on a delivery switch: when the delivery last sent, and how the latest live notification went for it 

110ATTR_LAST_SENT_AT = "last_sent_at" 

111ATTR_LAST_OUTCOME = "last_outcome" 

112ATTR_LAST_SKIP_REASON = "last_skip_reason" 

113ATTR_TRANSPORT_ENABLED = "transport_enabled" 

114ATTR_PRIORITY = "priority" 

115ATTR_ACTION = "action" 

116ATTR_REPLY_TEXT = "reply_text" 

117ATTR_SCENARIOS_REQUIRE = "require_scenarios" 

118ATTR_SCENARIOS_APPLY = "apply_scenarios" 

119ATTR_FORCE_RESEND: Final[str] = "force_resend" 

120# a standard action-data field, same as force_resend/debug - Notification.call_transport() is what 

121# actually skips sending for SIMULATE, so nothing else needs to special-case it. An enum, not a 

122# boolean, so a future mode (e.g. SIMULATE_PLUS_MEDIA, also simulating the camera/media grab) can 

123# be added as a new value rather than forcing a second flag or a breaking type change later 

124ATTR_DRY_RUN: Final[str] = "dry_run" 

125DRY_RUN_LIVE = "live" 

126DRY_RUN_SIMULATE = "simulate" 

127DRY_RUN_VALUES = [DRY_RUN_LIVE, DRY_RUN_SIMULATE] 

128ATTR_SCENARIOS_CONSTRAIN = "constrain_scenarios" 

129ATTR_DELIVERY = "delivery" 

130ATTR_DEFAULT = "default" 

131ATTR_NOTIFICATION_ID = "notification_id" 

132ATTR_DELIVERY_SELECTION = "delivery_selection" 

133# supernotify.notify's free-form delivery field, merged into `delivery` with the delivery dropdown 

134ATTR_DELIVERY_CONTROL = "delivery_control" 

135ATTR_RECIPIENTS = "recipients" 

136ATTR_CUSTOM_TARGET = "custom_target" 

137ATTR_DATA = "data" 

138ATTR_EXTRA_DATA: Final[str] = "extra_data" 

139ATTR_MEDIA = "media" 

140ATTR_TITLE = "title" 

141ATTR_IMAGE = "image" 

142ATTR_VIDEO = "video" 

143ATTR_MEDIA_SNAPSHOT_URL = "snapshot_url" 

144ATTR_MEDIA_CAMERA_ENTITY_ID = "camera_entity_id" 

145ATTR_MEDIA_CAMERA_DELAY = "camera_delay" 

146ATTR_MEDIA_CAMERA_PTZ_PRESET = "camera_ptz_preset" 

147ATTR_MEDIA_CLIP_URL = "clip_url" 

148ATTR_MEDIA_SNAPSHOT_PATH = "snapshot_image_path" 

149ATTR_TOPIC = "topic" 

150ATTR_DISCORD_CHANNEL = "discord_channel" 

151ATTR_MATRIX_ROOM = "matrix_room" 

152ATTR_TELEGRAM_CHAT_ID = "telegram_chat_id" 

153ATTR_ACTION_GROUPS = "action_groups" 

154CONF_ACTION_GROUP_NAMES = "action_groups" 

155ATTR_ACTION_URL = "action_url" 

156ATTR_ACTION_URL_TITLE = "action_url_title" 

157ATTR_MESSAGE_HTML = "message_html" 

158ATTR_JPEG_OPTS = "jpeg_opts" 

159ATTR_PNG_OPTS = "png_opts" 

160ATTR_TIMESTAMP = "timestamp" 

161ATTR_SPOKEN_MESSAGE = "spoken_message" 

162ATTR_DEBUG = "debug" 

163ATTR_ACTIONS = "actions" 

164ATTR_USER_ID = "user_id" 

165ATTR_PERSON_ID = "person_id" 

166ATTR_MOBILE_APP_ID = "mobile_app_id" 

167ATTR_EMAIL = "email" 

168ATTR_PHONE = "phone" 

169ATTR_ALIAS = "alias" 

170 

171DELIVERY_SELECTION_IMPLICIT = "implicit" 

172DELIVERY_SELECTION_EXPLICIT = "explicit" 

173DELIVERY_SELECTION_FIXED = "fixed" 

174 

175DELIVERY_SELECTION_VALUES = [DELIVERY_SELECTION_EXPLICIT, DELIVERY_SELECTION_FIXED, DELIVERY_SELECTION_IMPLICIT] 

176PTZ_METHOD_ONVIF = "onvif" 

177PTZ_METHOD_FRIGATE = "frigate" 

178PTZ_METHOD_VALUES = [PTZ_METHOD_ONVIF, PTZ_METHOD_FRIGATE] 

179PTZ_DELAY_DEFAULT = 10 

180SNAP_WAIT_DEFAULT = 15 

181 

182INCLUSION_FALLBACK_ON_ERROR = "fallback_on_error" 

183INCLUSION_FALLBACK = "fallback" 

184# a delivery's own deliveries to try, in order, when it fails 

185CONF_FALLBACK = "fallback" 

186INCLUSION_BY_SCENARIO = "scenario" 

187INCLUSION_DEFAULT = "default" 

188INCLUSION_EXPLICIT = "explicit" 

189INCLUSION_VALUES = [ 

190 INCLUSION_FALLBACK_ON_ERROR, 

191 INCLUSION_EXPLICIT, 

192 INCLUSION_BY_SCENARIO, 

193 INCLUSION_DEFAULT, 

194 INCLUSION_FALLBACK, 

195] 

196 

197OCCUPANCY_VALUES = [ 

198 OCCUPANCY_ALL_IN, 

199 OCCUPANCY_ALL_OUT, 

200 OCCUPANCY_ANY_IN, 

201 OCCUPANCY_ANY_OUT, 

202 OCCUPANCY_ONLY_IN, 

203 OCCUPANCY_ONLY_OUT, 

204 OCCUPANCY_ALL, 

205 OCCUPANCY_NONE, 

206] 

207 

208PRIORITY_CRITICAL = "critical" 

209PRIORITY_HIGH = "high" 

210PRIORITY_MEDIUM = "medium" 

211PRIORITY_LOW = "low" 

212PRIORITY_MINIMUM = "minimum" 

213 

214# other names for priorities, such as those of Home Assistant's SMTP integration 

215PRIORITY_SYNONYMS: dict[str, str] = { 

216 "highest": PRIORITY_CRITICAL, 

217 "normal": PRIORITY_MEDIUM, 

218 "lowest": PRIORITY_MINIMUM, 

219} 

220 

221PRIORITY_VALUES: dict[str, int] = { 

222 PRIORITY_MINIMUM: 1, 

223 PRIORITY_LOW: 2, 

224 PRIORITY_MEDIUM: 3, 

225 PRIORITY_HIGH: 4, 

226 PRIORITY_CRITICAL: 5, 

227} 

228 

229CONF_TARGET_USAGE = "target_usage" 

230TARGET_USE_ON_NO_DELIVERY_TARGETS = "no_delivery" 

231TARGET_USE_ON_NO_ACTION_TARGETS = "no_action" 

232TARGET_USE_FIXED = "fixed" 

233TARGET_USE_MERGE_ALWAYS = "merge_always" 

234TARGET_USE_MERGE_ON_DELIVERY_TARGETS = "merge_delivery" 

235TARGET_USAGE_VALUES = [ 

236 TARGET_USE_ON_NO_ACTION_TARGETS, 

237 TARGET_USE_ON_NO_DELIVERY_TARGETS, 

238 TARGET_USE_MERGE_ON_DELIVERY_TARGETS, 

239 TARGET_USE_MERGE_ALWAYS, 

240 TARGET_USE_FIXED, 

241] 

242 

243# Options constants have been moved to `options.py` 

244 

245RE_DEVICE_ID = r"^[0-9a-f]{32}$" 

246RE_MEDIA_PLAYER_ENTITY_ID = r"^media_player\.[A-Za-z0-9_]+$" 

247RE_NOTIFY_ENTITY_ID = r"^notify\.[A-Za-z0-9_]+$" 

248 

249RESERVED_DELIVERY_NAMES: list[str] = ["ALL"] 

250RESERVED_SCENARIO_NAMES: list[str] = ["NO_SCENARIO", "NULL"] 

251RESERVED_DATA_KEYS: list[str] = [ATTR_DOMAIN, ATTR_SERVICE, "action"] 

252 

253CONF_DUPE_CHECK: Final[str] = "dupe_check" 

254CONF_DUPE_POLICY: Final[str] = "dupe_policy" 

255CONF_TTL: Final[str] = "ttl" 

256CONF_SIZE: Final[str] = "size" 

257ATTR_DUPE_POLICY_MTSLP: Final[str] = "dupe_policy_message_title_same_or_lower_priority" 

258ATTR_DUPE_POLICY_MT: Final[str] = "dupe_policy_message_title_same" 

259ATTR_DUPE_POLICY_NONE: Final[str] = "dupe_policy_none" 

260CONF_MOBILE_APP_ID: Final[str] = "mobile_app_id" 

261CONF_TRANSPORT_DATA: Final[str] = "transport_data" 

262 

263 

264CONF_DEVICE_TRACKER: Final[str] = "device_tracker" 

265 

266 

267CONF_DEVICE_NAME: Final[str] = "device_name" 

268CONF_DEVICE_LABELS: Final[str] = "device_labels" 

269 

270MANUFACTURER_APPLE = "Apple" 

271 

272TARGET_REQUIRE_ALWAYS = "always" 

273TARGET_REQUIRE_NEVER = "never" 

274TARGET_REQUIRE_OPTIONAL = "optional" 

275 

276## Transports 

277# Defined here rather than transports.py so that the strings can be imported 

278# without the transports, and avoid circular references or heavier imports 

279TRANSPORT_SMS = "sms" 

280TRANSPORT_TTS = "tts" 

281TRANSPORT_MQTT = "mqtt" 

282TRANSPORT_EMAIL = "email" 

283TRANSPORT_ALEXA = "alexa_devices" 

284TRANSPORT_ALEXA_MEDIA_PLAYER = "alexa_media_player" 

285TRANSPORT_MOBILE_PUSH = "mobile_push" 

286TRANSPORT_MEDIA = "media" 

287TRANSPORT_CHIME = "chime" 

288TRANSPORT_GENERIC = "generic" 

289TRANSPORT_NOTIFY_ENTITY = "notify_entity" 

290# a scenario or delivery exposed as its own notify.<value> entity, see notify.py 

291CONF_NOTIFY_ENTITY = "notify_entity" 

292TRANSPORT_PERSISTENT = "persistent" 

293TRANSPORT_NTFY = "ntfy" 

294TRANSPORT_GOTIFY = "gotify" 

295TRANSPORT_TELEGRAM = "telegram" 

296TRANSPORT_LAMETRIC = "lametric" 

297TRANSPORT_PUSHOVER = "pushover" 

298TRANSPORT_HTML5 = "html5" 

299TRANSPORT_MATRIX = "matrix" 

300TRANSPORT_KODI = "kodi" 

301TRANSPORT_DISCORD = "discord" 

302TRANSPORT_WEBOSTV = "webostv" 

303TRANSPORT_VALUES = [ 

304 TRANSPORT_SMS, 

305 TRANSPORT_MQTT, 

306 TRANSPORT_ALEXA, 

307 TRANSPORT_ALEXA_MEDIA_PLAYER, 

308 TRANSPORT_MOBILE_PUSH, 

309 TRANSPORT_CHIME, 

310 TRANSPORT_EMAIL, 

311 TRANSPORT_MEDIA, 

312 TRANSPORT_PERSISTENT, 

313 TRANSPORT_TTS, 

314 TRANSPORT_GENERIC, 

315 TRANSPORT_NOTIFY_ENTITY, 

316 TRANSPORT_NTFY, 

317 TRANSPORT_GOTIFY, 

318 TRANSPORT_TELEGRAM, 

319 TRANSPORT_LAMETRIC, 

320 TRANSPORT_PUSHOVER, 

321 TRANSPORT_HTML5, 

322 TRANSPORT_MATRIX, 

323 TRANSPORT_KODI, 

324 TRANSPORT_DISCORD, 

325 TRANSPORT_WEBOSTV, 

326] 

327 

328# The master list of target category names, independent of any one transport - both 

329# `Target` (for qualifying a target, e.g. `topic:my/topic` or `target: {topic: ...}`) 

330# and `Transport.target_categories` (for declaring which categories a transport accepts) 

331# reference this same list, rather than transports and targets each keeping their own. 

332TARGET_CATEGORY_VALUES = [ 

333 ATTR_ENTITY_ID, 

334 ATTR_DEVICE_ID, 

335 ATTR_EMAIL, 

336 ATTR_PHONE, 

337 ATTR_MOBILE_APP_ID, 

338 ATTR_TOPIC, 

339 ATTR_DISCORD_CHANNEL, 

340 ATTR_MATRIX_ROOM, 

341 ATTR_TELEGRAM_CHAT_ID, 

342] 

343 

344 

345CONF_CONNECTION: Final[str] = "connection" 

346CONF_ENCRYPTION: Final[str] = "encryption" 

347 

348CONF_DEVICE_DISCOVERY: Final[str] = "device_discovery" 

349CONF_DEVICE_DOMAIN: Final[str] = "device_domain" 

350CONF_DEVICE_MODEL_INCLUDE: Final[str] = "device_model_include" 

351CONF_DEVICE_MODEL_EXCLUDE: Final[str] = "device_model_exclude" 

352 

353# What a runtime override of a configured `enabled` flag can apply to - each also the unique_id 

354# prefix of the switch for it, e.g. switch unique_id "delivery_<name>" 

355OVERRIDE_KIND_SCENARIO: Final[str] = "scenario" 

356OVERRIDE_KIND_RECIPIENT: Final[str] = "recipient" 

357OVERRIDE_KIND_DELIVERY: Final[str] = "delivery" 

358OVERRIDE_KIND_TRANSPORT: Final[str] = "transport" 

359OVERRIDE_KINDS: Final[tuple[str, ...]] = ( 

360 OVERRIDE_KIND_SCENARIO, 

361 OVERRIDE_KIND_RECIPIENT, 

362 OVERRIDE_KIND_DELIVERY, 

363 OVERRIDE_KIND_TRANSPORT, 

364) 

365# Entity state attributes too large, or changing too often, to be worth keeping in history 

366DELIVERY_UNRECORDED_ATTRIBUTES: Final[frozenset[str]] = frozenset({ 

367 CONF_OPTIONS, 

368 CONF_DATA, 

369 CONF_TARGET, 

370 ATTR_LAST_SENT_AT, 

371 ATTR_LAST_OUTCOME, 

372 ATTR_LAST_SKIP_REASON, 

373}) 

374TRANSPORT_UNRECORDED_ATTRIBUTES: Final[frozenset[str]] = frozenset({ 

375 CONF_DELIVERY_DEFAULTS, 

376 "action_titles", 

377 "action_title_failures", 

378 "cached_templates", 

379}) 

380 

381CONF_SNOOZE = "snooze" 

382CONF_SNOOZE_TIME = "snooze_time" 

383 

384# Config entry options for the LLM tools offered to Assist and MCP, see llm.py 

385CONF_LLM_TOOLS: Final[str] = "llm_tools" 

386CONF_LLM_ACTION_TOOLS: Final[str] = "action_tools" 

387CONF_LLM_DIAGNOSTIC_TOOLS: Final[str] = "diagnostic_tools" 

388# sentences for Home Assistant's built-in conversation agent, which can't use LLM tools, see sentences.py 

389CONF_SENTENCE_COMMANDS: Final[str] = "sentence_commands" 

390 

391# Config entry options giving deliveries their defaults, where neither they nor their transport set one 

392CONF_DELIVERY_CONTROL: Final[str] = "delivery_control" 

393CONF_DEFAULT_INCLUSION: Final[str] = "default_inclusion" 

394CONF_VOICE_OCCUPANCY: Final[str] = "voice_occupancy" 

395DEFAULT_INCLUSION_VALUES: Final[list[str]] = [INCLUSION_DEFAULT, INCLUSION_EXPLICIT, INCLUSION_BY_SCENARIO] 

396 

397# Idea - differentiate enabled as recipient vs as occupant, for ALL_IN etc check 

398# May need condition, and also enabled if delivery disabled 

399# CONF_OCCUPANCY="occupancy" 

400# OPTION_OCCUPANCY_DEFAULT="default" 

401# OPTIONS_OCCUPANCY=[OPTION_OCCUPANCY_DEFAULT,OPTION_OCCUPANCY_EXCLUDE] 

402# OPTION_OCCUPANCY_EXCLUDE="exclude" 

403 

404CONF_PHONE_NUMBER: str = "phone_number" 

405 

406 

407CONF_TUNE: Final[str] = "tune" 

408CONF_VOLUME: Final[str] = "volume" 

409CONF_DURATION: Final[str] = "duration" 

410 

411OPTIONS_CHIME_DOMAINS = ["media_player", "switch", "script", "rest_command", "siren", "alexa_devices"] 

412 

413 

414# transport names that are acronyms, shown in capitals 

415_TRANSPORT_ACRONYMS: Final[dict[str, str]] = {"tts": "TTS", "sms": "SMS", "mqtt": "MQTT", "html5": "HTML5"} 

416 

417 

418def transport_display_name(name: str) -> str: 

419 """A transport's name to show, such as "Alexa Media Player" for alexa_media_player""" 

420 return " ".join(_TRANSPORT_ACRONYMS.get(word, word.capitalize()) for word in name.split("_")) 

421 

422 

423# subentry titles are prefixed by their type, to tell them apart in the integration's list of them 

424RECIPIENT_TITLE_PREFIX: Final[str] = "Recipient - " 

425TRANSPORT_TITLE_PREFIX: Final[str] = "Transport - " 

426 

427 

428def recipient_subentry_title(name: str) -> str: 

429 """A recipient subentry's title, such as "Recipient - Alice" for alice""" 

430 return name if name.startswith(RECIPIENT_TITLE_PREFIX) else f"{RECIPIENT_TITLE_PREFIX}{name}" 

431 

432 

433def transport_subentry_title(name: str) -> str: 

434 """A transport subentry's title, such as "Transport - Alexa Media Player" for alexa_media_player""" 

435 return f"{TRANSPORT_TITLE_PREFIX}{transport_display_name(name)}"