diff --git a/.coveragerc b/.coveragerc index 353aeaf5684..20bbc0474eb 100644 --- a/.coveragerc +++ b/.coveragerc @@ -651,6 +651,7 @@ omit = homeassistant/components/waqi/sensor.py homeassistant/components/waterfurnace/* homeassistant/components/watson_iot/* + homeassistant/components/watson_tts/tts.py homeassistant/components/waze_travel_time/sensor.py homeassistant/components/webostv/* homeassistant/components/wemo/* diff --git a/CODEOWNERS b/CODEOWNERS index ea0840a2519..cf71e61ead6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -254,6 +254,7 @@ homeassistant/components/velux/* @Julius2342 homeassistant/components/version/* @fabaff homeassistant/components/vizio/* @raman325 homeassistant/components/waqi/* @andrey-git +homeassistant/components/watson_tts/* @rutkai homeassistant/components/weather/* @fabaff homeassistant/components/weblink/* @home-assistant/core homeassistant/components/websocket_api/* @home-assistant/core diff --git a/homeassistant/components/watson_tts/__init__.py b/homeassistant/components/watson_tts/__init__.py new file mode 100644 index 00000000000..abdc9308ca3 --- /dev/null +++ b/homeassistant/components/watson_tts/__init__.py @@ -0,0 +1 @@ +"""Support for IBM Watson TTS integration.""" diff --git a/homeassistant/components/watson_tts/manifest.json b/homeassistant/components/watson_tts/manifest.json new file mode 100644 index 00000000000..d40baaca132 --- /dev/null +++ b/homeassistant/components/watson_tts/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "watson_tts", + "name": "IBM Watson TTS", + "documentation": "https://www.home-assistant.io/components/watson_tts", + "requirements": [ + "ibm-watson==3.0.3" + ], + "dependencies": [], + "codeowners": [ + "@rutkai" + ] +} diff --git a/homeassistant/components/watson_tts/tts.py b/homeassistant/components/watson_tts/tts.py new file mode 100644 index 00000000000..be60908d096 --- /dev/null +++ b/homeassistant/components/watson_tts/tts.py @@ -0,0 +1,137 @@ +"""Support for IBM Watson TTS integration.""" +import logging + +import voluptuous as vol + +from homeassistant.components.tts import PLATFORM_SCHEMA, Provider +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +CONF_URL = 'watson_url' +CONF_APIKEY = 'watson_apikey' +ATTR_CREDENTIALS = 'credentials' + +DEFAULT_URL = 'https://stream.watsonplatform.net/text-to-speech/api' + +CONF_VOICE = 'voice' +CONF_OUTPUT_FORMAT = 'output_format' +CONF_TEXT_TYPE = 'text' + +# List from https://tinyurl.com/watson-tts-docs +SUPPORTED_VOICES = [ + "de-DE_BirgitVoice", + "de-DE_BirgitV2Voice", + "de-DE_DieterVoice", + "de-DE_DieterV2Voice" + "en-GB_KateVoice", + "en-US_AllisonVoice", + "en-US_AllisonV2Voice", + "en-US_LisaVoice", + "en-US_LisaV2Voice", + "en-US_MichaelVoice", + "en-US_MichaelV2Voice", + "es-ES_EnriqueVoice", + "es-ES_LauraVoice", + "es-LA_SofiaVoice", + "es-US_SofiaVoice", + "fr-FR_ReneeVoice", + "it-IT_FrancescaVoice", + "it-IT_FrancescaV2Voice", + "ja-JP_EmiVoice", + "pt-BR_IsabelaVoice" +] + +SUPPORTED_OUTPUT_FORMATS = [ + 'audio/flac', + 'audio/mp3', + 'audio/mpeg', + 'audio/ogg', + 'audio/ogg;codecs=opus', + 'audio/ogg;codecs=vorbis', + 'audio/wav' +] + +CONTENT_TYPE_EXTENSIONS = { + 'audio/flac': 'flac', + 'audio/mp3': 'mp3', + 'audio/mpeg': 'mp3', + 'audio/ogg': 'ogg', + 'audio/ogg;codecs=opus': 'ogg', + 'audio/ogg;codecs=vorbis': 'ogg', + 'audio/wav': 'wav', +} + +DEFAULT_VOICE = 'en-US_AllisonVoice' +DEFAULT_OUTPUT_FORMAT = 'audio/mp3' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_URL, default=DEFAULT_URL): cv.string, + vol.Required(CONF_APIKEY): cv.string, + vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): vol.In(SUPPORTED_VOICES), + vol.Optional(CONF_OUTPUT_FORMAT, default=DEFAULT_OUTPUT_FORMAT): + vol.In(SUPPORTED_OUTPUT_FORMATS), +}) + + +def get_engine(hass, config): + """Set up IBM Watson TTS component.""" + from ibm_watson import TextToSpeechV1 + + service = TextToSpeechV1( + url=config[CONF_URL], + iam_apikey=config[CONF_APIKEY] + ) + + supported_languages = list({s[:5] for s in SUPPORTED_VOICES}) + default_voice = config[CONF_VOICE] + output_format = config[CONF_OUTPUT_FORMAT] + + return WatsonTTSProvider( + service, supported_languages, default_voice, output_format) + + +class WatsonTTSProvider(Provider): + """IBM Watson TTS api provider.""" + + def __init__(self, + service, + supported_languages, + default_voice, + output_format): + """Initialize Watson TTS provider.""" + self.service = service + self.supported_langs = supported_languages + self.default_lang = default_voice[:5] + self.default_voice = default_voice + self.output_format = output_format + self.name = 'Watson TTS' + + @property + def supported_languages(self): + """Return a list of supported languages.""" + return self.supported_langs + + @property + def default_language(self): + """Return the default language.""" + return self.default_lang + + @property + def default_options(self): + """Return dict include default options.""" + return {CONF_VOICE: self.default_voice} + + @property + def supported_options(self): + """Return a list of supported options.""" + return [CONF_VOICE] + + def get_tts_audio(self, message, language=None, options=None): + """Request TTS file from Watson TTS.""" + response = self.service.synthesize( + message, accept=self.output_format, + voice=self.default_voice).get_result() + + return (CONTENT_TYPE_EXTENSIONS[self.output_format], + response.content) diff --git a/requirements_all.txt b/requirements_all.txt index 4cb94a4aeb7..2730695cf96 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -595,6 +595,9 @@ hydrawiser==0.1.1 # homeassistant.components.htu21d # i2csense==0.0.4 +# homeassistant.components.watson_tts +ibm-watson==3.0.3 + # homeassistant.components.watson_iot ibmiotf==0.3.4