Custom TTS component for Home Assistant. Utilizes the OpenAI speech engine or any compatible endpoint to deliver high-quality speech. Optionally offers chime and audio normalization features.
Python
217
251 commits
updated Sep 21, 2026
Text-to-Speech component that connects Home Assistant to OpenAI's TTS API and any OpenAI-compatible backend.
OpenAI TTS turns text into speech inside Home Assistant. It works with the official OpenAI Audio Speech API and any compatible self-hosted backend (Chatterbox, pocket-tts, LocalAI, TTS Web UI, and others). Configure one or more TTS agents per OpenAI account, target announcements at any media player, optionally prepend a chime, normalise loudness for small speakers, and have the original volume and music restored after the announcement.
Version 3.9 is mostly about backends other than OpenAI, and about what a speaker does while an announcement is playing.
response_variable is supported on openai_tts.say.openai_tts.set_api_key is an admin action that replaces the key on an
entry, so an automation can rotate a short lived token without anyone opening
the settings. The key is checked against the endpoint before it is stored.WHATSNEW.md lists every change, including the fixes.
tts-1, tts-1-hd, gpt-4o-mini-tts (with custom speaking-style instructions).alloy, ash, coral, echo, fable, nova, onyx, sage, shimmer, plus the gpt-4o-mini-tts-only voices ballad, cedar, marin, verse.mp3, opus, aac, flac, wav, pcm per profile.mp3,
opus, aac and pcm; wav and flac state their length in a header before any
audio exists, so they are always assembled in full first.mp3
or pcm, since the other formats cannot be joined end to end.config/custom_components/openai_tts/chime).extra_payload for backend-specific JSON parameters.custom_components/openai_tts/ into <config>/custom_components/openai_tts/.Each integration entry stores the API credentials and endpoint. Each sub-entry (TTS agent) stores the per-profile settings:
voice field, such as audio.cpp serving Chatterbox or VoxCPM2.Enabling chime disables streaming for that profile, since a chime has to be attached to finished audio. Loudness normalisation does not: it runs on the stream for
mp3,opus,aacandpcm.
openai_tts.say serviceTargets media players directly, with per-call overrides for voice, speed,
instructions, chime, normalise, volume and announcement behaviour. Only
tts_entity and message are required, and anything left out falls back to the
profile.
pause_playback is still accepted as an older name for announce so existing
automations keep working, but new ones should use announce.
action: openai_tts.say
target:
entity_id: media_player.living_room_speaker
# area_id: living_room
# device_id: 12345abcde
data:
tts_entity: tts.openai_tts_living_room
message: "Dinner is ready"
volume: 0.6 # snapshot and restore the speaker volume
announce: true # let the speaker duck its own music where it can
chime: true # prepend the configured chime
chime_sound: threetone.mp3
normalize_audio: true # loudness-normalise for small speakers
voice: nova
speed: 1.0
language: en
instructions: "Say it warmly"
extra_payload: '{"temperature": 0.8}'
openai_tts.set_api_key actionReplaces the stored API key on an entry, so an automation can rotate a short
lived token without anyone opening the settings. It needs an administrator, and
it targets either config_entry_id or tts_entity, not both.
The key is checked against the endpoint before it is stored, so a token the
endpoint refuses leaves the working one in place. Add validate: false to store
it without checking, which is what a backend that rejects the probe request
needs. The entry reloads straight away, so no restart is required.
action: openai_tts.set_api_key
data:
config_entry_id: 01ABCDEF...
api_key: "{{ token.content.access_token }}"
# validate: false
With response_variable the call reports what it did: changed is false when the
key was already the one stored, and reloading says whether the running entity
picked it up or will do so at the next load.
The integration works with any OpenAI-compatible TTS endpoint. Mistral Voxtral,
Groq, Lemonfox, Kokoro-FastAPI and Chatterbox have presets that fill in the
endpoint and the catalogue for you, and anything else is configured as a custom
endpoint. When the URL is not api.openai.com:
pocket-tts returning PCM).voice key.Bug reports, backend reports and pull requests are all welcome. Pull
requests target the dev branch, and for anything larger than a small
fix it is worth opening an issue first so the shape can be agreed before
you write it. CONTRIBUTING.md has the details.
If you use a backend that behaves differently from the others, saying so in an issue is useful on its own, even without a patch.
For OpenAI, an API key with available balance is required. Pricing: https://platform.openai.com/docs/pricing
Python
100.0%
Custom TTS component for Home Assistant. Utilizes the OpenAI speech engine or any compatible endpoint to deliver high-quality speech. Optionally offers chime and audio normalization features.
Python
217
251 commits
updated Sep 21, 2026
Text-to-Speech component that connects Home Assistant to OpenAI's TTS API and any OpenAI-compatible backend.
OpenAI TTS turns text into speech inside Home Assistant. It works with the official OpenAI Audio Speech API and any compatible self-hosted backend (Chatterbox, pocket-tts, LocalAI, TTS Web UI, and others). Configure one or more TTS agents per OpenAI account, target announcements at any media player, optionally prepend a chime, normalise loudness for small speakers, and have the original volume and music restored after the announcement.
Version 3.9 is mostly about backends other than OpenAI, and about what a speaker does while an announcement is playing.
response_variable is supported on openai_tts.say.openai_tts.set_api_key is an admin action that replaces the key on an
entry, so an automation can rotate a short lived token without anyone opening
the settings. The key is checked against the endpoint before it is stored.WHATSNEW.md lists every change, including the fixes.
tts-1, tts-1-hd, gpt-4o-mini-tts (with custom speaking-style instructions).alloy, ash, coral, echo, fable, nova, onyx, sage, shimmer, plus the gpt-4o-mini-tts-only voices ballad, cedar, marin, verse.mp3, opus, aac, flac, wav, pcm per profile.mp3,
opus, aac and pcm; wav and flac state their length in a header before any
audio exists, so they are always assembled in full first.mp3
or pcm, since the other formats cannot be joined end to end.config/custom_components/openai_tts/chime).extra_payload for backend-specific JSON parameters.custom_components/openai_tts/ into <config>/custom_components/openai_tts/.Each integration entry stores the API credentials and endpoint. Each sub-entry (TTS agent) stores the per-profile settings:
voice field, such as audio.cpp serving Chatterbox or VoxCPM2.Enabling chime disables streaming for that profile, since a chime has to be attached to finished audio. Loudness normalisation does not: it runs on the stream for
mp3,opus,aacandpcm.
openai_tts.say serviceTargets media players directly, with per-call overrides for voice, speed,
instructions, chime, normalise, volume and announcement behaviour. Only
tts_entity and message are required, and anything left out falls back to the
profile.
pause_playback is still accepted as an older name for announce so existing
automations keep working, but new ones should use announce.
action: openai_tts.say
target:
entity_id: media_player.living_room_speaker
# area_id: living_room
# device_id: 12345abcde
data:
tts_entity: tts.openai_tts_living_room
message: "Dinner is ready"
volume: 0.6 # snapshot and restore the speaker volume
announce: true # let the speaker duck its own music where it can
chime: true # prepend the configured chime
chime_sound: threetone.mp3
normalize_audio: true # loudness-normalise for small speakers
voice: nova
speed: 1.0
language: en
instructions: "Say it warmly"
extra_payload: '{"temperature": 0.8}'
openai_tts.set_api_key actionReplaces the stored API key on an entry, so an automation can rotate a short
lived token without anyone opening the settings. It needs an administrator, and
it targets either config_entry_id or tts_entity, not both.
The key is checked against the endpoint before it is stored, so a token the
endpoint refuses leaves the working one in place. Add validate: false to store
it without checking, which is what a backend that rejects the probe request
needs. The entry reloads straight away, so no restart is required.
action: openai_tts.set_api_key
data:
config_entry_id: 01ABCDEF...
api_key: "{{ token.content.access_token }}"
# validate: false
With response_variable the call reports what it did: changed is false when the
key was already the one stored, and reloading says whether the running entity
picked it up or will do so at the next load.
The integration works with any OpenAI-compatible TTS endpoint. Mistral Voxtral,
Groq, Lemonfox, Kokoro-FastAPI and Chatterbox have presets that fill in the
endpoint and the catalogue for you, and anything else is configured as a custom
endpoint. When the URL is not api.openai.com:
pocket-tts returning PCM).voice key.Bug reports, backend reports and pull requests are all welcome. Pull
requests target the dev branch, and for anything larger than a small
fix it is worth opening an issue first so the shape can be agreed before
you write it. CONTRIBUTING.md has the details.
If you use a backend that behaves differently from the others, saying so in an issue is useful on its own, even without a patch.
For OpenAI, an API key with available balance is required. Pricing: https://platform.openai.com/docs/pricing
Python
100.0%