diff --git a/homeassistant/components/cloud/tts.py b/homeassistant/components/cloud/tts.py index a9c607d27cd..021bf5a31c7 100644 --- a/homeassistant/components/cloud/tts.py +++ b/homeassistant/components/cloud/tts.py @@ -9,6 +9,7 @@ from homeassistant.components.tts import ( CONF_LANG, PLATFORM_SCHEMA, Provider, + Voice, ) from homeassistant.core import callback @@ -97,9 +98,11 @@ class CloudProvider(Provider): return [ATTR_GENDER, ATTR_VOICE, ATTR_AUDIO_OUTPUT] @callback - def async_get_supported_voices(self, language: str) -> list[str] | None: + def async_get_supported_voices(self, language: str) -> list[Voice] | None: """Return a list of supported voices for a language.""" - return TTS_VOICES.get(language) + if not (voices := TTS_VOICES.get(language)): + return None + return [Voice(voice, voice) for voice in voices] @property def default_options(self): diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index 0cafb440d65..faddb713750 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -66,6 +66,7 @@ from .const import ( from .helper import get_engine_instance from .legacy import PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, Provider, async_setup_legacy from .media_source import generate_media_source_id, media_source_id_to_kwargs +from .models import Voice __all__ = [ "async_get_media_source_audio", @@ -80,6 +81,7 @@ __all__ = [ "PLATFORM_SCHEMA", "Provider", "TtsAudioType", + "Voice", ] _LOGGER = logging.getLogger(__name__) @@ -302,7 +304,7 @@ class TextToSpeechEntity(RestoreEntity): return None @callback - def async_get_supported_voices(self, language: str) -> list[str] | None: + def async_get_supported_voices(self, language: str) -> list[Voice] | None: """Return a list of supported voices for a language.""" return None diff --git a/homeassistant/components/tts/legacy.py b/homeassistant/components/tts/legacy.py index 9ca80871655..138c0bf84c9 100644 --- a/homeassistant/components/tts/legacy.py +++ b/homeassistant/components/tts/legacy.py @@ -52,6 +52,7 @@ from .const import ( TtsAudioType, ) from .media_source import generate_media_source_id +from .models import Voice if TYPE_CHECKING: from . import SpeechManager @@ -229,7 +230,7 @@ class Provider: return None @callback - def async_get_supported_voices(self, language: str) -> list[str] | None: + def async_get_supported_voices(self, language: str) -> list[Voice] | None: """Return a list of supported voices for a language.""" return None diff --git a/homeassistant/components/tts/models.py b/homeassistant/components/tts/models.py new file mode 100644 index 00000000000..1ea49b1e9ed --- /dev/null +++ b/homeassistant/components/tts/models.py @@ -0,0 +1,10 @@ +"""Text-to-speech data models.""" +from dataclasses import dataclass + + +@dataclass(frozen=True) +class Voice: + """A TTS voice.""" + + voice_id: str + name: str diff --git a/tests/components/cloud/test_tts.py b/tests/components/cloud/test_tts.py index be023cd0d57..6f31d78ac28 100644 --- a/tests/components/cloud/test_tts.py +++ b/tests/components/cloud/test_tts.py @@ -78,7 +78,9 @@ async def test_provider_properties(cloud_with_prefs) -> None: ) assert provider.supported_options == ["gender", "voice", "audio_output"] assert "nl-NL" in provider.supported_languages - assert "ColetteNeural" in provider.async_get_supported_voices("nl-NL") + assert tts.Voice( + "ColetteNeural", "ColetteNeural" + ) in provider.async_get_supported_voices("nl-NL") async def test_get_tts_audio(cloud_with_prefs) -> None: diff --git a/tests/components/tts/common.py b/tests/components/tts/common.py index d1892a49b75..73cf8c5f246 100644 --- a/tests/components/tts/common.py +++ b/tests/components/tts/common.py @@ -13,6 +13,7 @@ from homeassistant.components.tts import ( Provider, TextToSpeechEntity, TtsAudioType, + Voice, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -61,10 +62,13 @@ class BaseProvider: return SUPPORT_LANGUAGES @callback - def async_get_supported_voices(self, language: str) -> list[str] | None: + def async_get_supported_voices(self, language: str) -> list[Voice] | None: """Return list of supported languages.""" if language == "en-US": - return ["James Earl Jones", "Fran Drescher"] + return [ + Voice("james_earl_jones", "James Earl Jones"), + Voice("fran_drescher", "Fran Drescher"), + ] return None @property diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index b5862482fac..5bd1f94ae41 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -1743,4 +1743,9 @@ async def test_ws_list_voices( msg = await client.receive_json() assert msg["success"] - assert msg["result"] == {"voices": ["James Earl Jones", "Fran Drescher"]} + assert msg["result"] == { + "voices": [ + {"voice_id": "james_earl_jones", "name": "James Earl Jones"}, + {"voice_id": "fran_drescher", "name": "Fran Drescher"}, + ] + }