What version of Universal Notifier are you using?
0.8.3
What version of Home Assistant are you using?
Core 2026.7.2 - OS 18.1
The problem
Title: clean_text_for_tts() strips valid SSML <voice> tags, breaking custom Alexa voice selection
Version: v0.8.3 (also present in v0.8.0-v0.8.2 based on changelog)
Description:
Since the v0.8.0 fix for "Voice channels no longer read HTML tags", the clean_text_for_tts() function appears to strip all angle-bracket tags indiscriminately, including valid SSML tags like <voice name="...">. This breaks the ability to select a custom voice for Alexa TTS notifications.
Steps to reproduce:
- Configure a voice channel targeting an Alexa Media Player device (e.g.
notify.alexa_media_echo_cucina).
- Call
universal_notifier.send with a message containing an SSML voice tag:
action: universal_notifier.send
data:
message: "<voice name='Giorgio'>Il sistema è operativo!</voice>"
targets:
- alexa_cucina
- Enable debug logging for
custom_components.universal_notifier.
Expected behavior:
The SSML <voice> tag should be preserved so Alexa reads the message using the specified custom voice.
Actual behavior:
The tag is completely removed before being sent to the TTS service. Debug log excerpt:
Sezione A, Specific Data {'message': "<voice name='Giorgio'>Il sistema è operativo!</voice>"}
...
Sezione D, Final message 'Il sistema è operativo!'
The message reaches notify.alexa_media_echo_cucina as plain text with no voice tag, so Alexa falls back to its default (female) voice instead of the configured custom voice.
Suggested fix:
clean_text_for_tts() should distinguish between HTML formatting tags (<b>, <i>, <a>, etc., which should be stripped) and valid SSML tags (<voice>, <prosody>, <break>, <say-as>, etc., which should be preserved when the target TTS engine supports SSML). Perhaps an allowlist of SSML tags, or a flag to opt a channel into "SSML-aware" cleaning, would resolve this without regressing the original HTML-stripping fix.
Happy to provide more logs or test a patch if useful.
What is your channels configuration for Universal Notifier?
Voice channel targeting Alexa via Alexa Media Player:
- alias: alexa_cucina
- service: notify.alexa_media_echo_cucina
- default_media_player: media_player.echo_cucina
- is_voice: true
- alt_services: {}
(Config reconstructed from debug log — set up via the UI config flow, not YAML)
What actions did you take in the developer tools?
Called universal_notifier.send from Developer Tools > Actions with:
action: universal_notifier.send
data:
message: "Il sistema è operativo!"
targets:
- alexa_cucina
Also enabled debug logging beforehand via configuration.yaml:
logger:
default: info
logs:
custom_components.universal_notifier: debug
Anything in the logs? Paste it here!
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: START, Channel Configuration {'alt_services': {'photo': {'service': 'telegram_bot.send_photo'}, 'video': {'service': 'telegram_bot.send_video'}}, 'default_media_player': '', 'is_voice': False, 'service': 'telegram_bot.send_message', 'target': '284788071'}
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione A, Specific Data {}
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione A, Dynamic Entities ['284788071']
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Service type None
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Service alt {'photo': {'service': 'telegram_bot.send_photo'}, 'video': {'service': 'telegram_bot.send_video'}}
2026-07-18 16:58:03.274 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Full Service Name telegram_bot.send_message
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione C, Is Command Message False
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione D, Final message '[<b>Alfred</b> - <b>16:58:03</b>] 📬 Alfred è operativo! 🕵
🟩 Avviato alle 16:57:31.48'
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione G, final_title 'None'
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione G, service_payload '{'parse_mode': 'html', 'message': '[<b>Alfred</b> - <b>16:58:03</b>] 📬 Alfred è operativo! 🕵 \n\n 🟩 Avviato alle 16:57:31.48'}'
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione H, service_payload '{'parse_mode': 'html', 'message': '[<b>Alfred</b> - <b>16:58:03</b>] 📬 Alfred è operativo! 🕵 \n\n 🟩 Avviato alle 16:57:31.48'}'
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione I, service_payload '{'parse_mode': 'html', 'message': '[<b>Alfred</b> - <b>16:58:03</b>] 📬 Alfred è operativo! 🕵 \n\n 🟩 Avviato alle 16:57:31.48'}'
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione J, Telegram to chat_id=284788071 payload {'parse_mode': 'html', 'message': '[<b>Alfred</b> - <b>16:58:03</b>] 📬 Alfred è operativo! 🕵 \n\n 🟩 Avviato alle 16:57:31.48', 'chat_id': 284788071}
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: START, Channel Configuration {'alt_services': {}, 'default_media_player': 'media_player.echo_cucina', 'is_voice': True, 'service': 'notify.alexa_media_echo_cucina', 'target': ''}
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione A, Specific Data {'message': "<voice name='Giorgio'>Il sistema è operativo!</voice>"}
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione A, Dynamic Entities []
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Service type None
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Service alt {}
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione B, Full Service Name notify.alexa_media_echo_cucina
2026-07-18 16:58:03.275 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione C, Is Command Message False
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione D, Final message 'Il sistema è operativo!'
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione G, final_title 'None'
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione G, service_payload '{'message': 'Il sistema è operativo!'}'
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione H, service_payload '{'message': 'Il sistema è operativo!', 'target': ['']}'
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione I, service_payload '{'message': 'Il sistema è operativo!', 'target': ['']}'
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione J, Media players coinvolti ['media_player.echo_cucina'].
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Sezione J, Messaggio per alexa_cucina accodato.
2026-07-18 16:58:03.277 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Snapshot originale salvato per media_player.echo_cucina: {'state': 'idle', 'volume': None, 'app_name': None, 'media_content_id': None, 'media_content_type': <MediaPlayerState.IDLE: 'idle'>, 'media_position': None, 'entity_id': 'media_player.echo_cucina'}
2026-07-18 16:58:03.278 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Elaborazione messaggio vocale: Il sistema è operativo!...
2026-07-18 16:58:03.278 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: ['media_player.echo_cucina'] 0.5 alexa_media_echo_cucina {'message': 'Il sistema è operativo!', 'target': ['media_player.echo_cucina']}
2026-07-18 16:58:03.279 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Attesa di 5.17s per fine messaggio.
2026-07-18 16:58:08.446 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Coda vuota, chiusura sessione e ripristino media.
2026-07-18 16:58:08.447 DEBUG (MainThread) [custom_components.universal_notifier] UniNotifier: Resume del volume di media_player.echo_cucina con 0.5
What version of Universal Notifier are you using?
0.8.3
What version of Home Assistant are you using?
Core 2026.7.2 - OS 18.1
The problem
Title:
clean_text_for_tts()strips valid SSML<voice>tags, breaking custom Alexa voice selectionVersion: v0.8.3 (also present in v0.8.0-v0.8.2 based on changelog)
Description:
Since the v0.8.0 fix for "Voice channels no longer read HTML tags", the
clean_text_for_tts()function appears to strip all angle-bracket tags indiscriminately, including valid SSML tags like<voice name="...">. This breaks the ability to select a custom voice for Alexa TTS notifications.Steps to reproduce:
notify.alexa_media_echo_cucina).universal_notifier.sendwith a message containing an SSML voice tag:custom_components.universal_notifier.Expected behavior:
The SSML
<voice>tag should be preserved so Alexa reads the message using the specified custom voice.Actual behavior:
The tag is completely removed before being sent to the TTS service. Debug log excerpt:
The message reaches
notify.alexa_media_echo_cucinaas plain text with no voice tag, so Alexa falls back to its default (female) voice instead of the configured custom voice.Suggested fix:
clean_text_for_tts()should distinguish between HTML formatting tags (<b>,<i>,<a>, etc., which should be stripped) and valid SSML tags (<voice>,<prosody>,<break>,<say-as>, etc., which should be preserved when the target TTS engine supports SSML). Perhaps an allowlist of SSML tags, or a flag to opt a channel into "SSML-aware" cleaning, would resolve this without regressing the original HTML-stripping fix.Happy to provide more logs or test a patch if useful.
What is your channels configuration for Universal Notifier?
Voice channel targeting Alexa via Alexa Media Player:
(Config reconstructed from debug log — set up via the UI config flow, not YAML)
What actions did you take in the developer tools?
Called universal_notifier.send from Developer Tools > Actions with:
action: universal_notifier.send
data:
message: "Il sistema è operativo!"
targets:
- alexa_cucina
Also enabled debug logging beforehand via configuration.yaml:
logger:
default: info
logs:
custom_components.universal_notifier: debug
Anything in the logs? Paste it here!