Bugfix voicerss post api (#5021)

* Bugfix voicerss post api

* fix unittest

* Add cache to service description
This commit is contained in:
Pascal Vizeli 2016-12-21 10:22:12 +01:00 committed by GitHub
parent b170f4c399
commit 25469dd8ee
3 changed files with 68 additions and 12 deletions

View File

@ -3,12 +3,16 @@ say:
fields: fields:
entity_id: entity_id:
description: Name(s) of media player entities description: Name(s) of media player entities.
example: 'media_player.floor' example: 'media_player.floor'
message: message:
description: Text to speak on devices description: Text to speak on devices.
example: 'My name is hanna' example: 'My name is hanna'
cache:
description: Control file cache of this message.
example: 'true'
clear_cache: clear_cache:
description: Remove cache files and RAM cache. description: Remove cache files and RAM cache.

View File

@ -21,6 +21,18 @@ _LOGGER = logging.getLogger(__name__)
VOICERSS_API_URL = "https://api.voicerss.org/" VOICERSS_API_URL = "https://api.voicerss.org/"
ERROR_MSG = [
b'Error description',
b'The subscription is expired or requests count limitation is exceeded!',
b'The request content length is too large!',
b'The language does not support!',
b'The language is not specified!',
b'The text is not specified!',
b'The API key is not available!',
b'The API key is not specified!',
b'The subscription does not support SSML!',
]
SUPPORT_LANGUAGES = [ SUPPORT_LANGUAGES = [
'ca-es', 'zh-cn', 'zh-hk', 'zh-tw', 'da-dk', 'nl-nl', 'en-au', 'en-ca', 'ca-es', 'zh-cn', 'zh-hk', 'zh-tw', 'da-dk', 'nl-nl', 'en-au', 'en-ca',
'en-gb', 'en-in', 'en-us', 'fi-fi', 'fr-ca', 'fr-fr', 'de-de', 'it-it', 'en-gb', 'en-in', 'en-us', 'fi-fi', 'fr-ca', 'fr-fr', 'de-de', 'it-it',
@ -83,7 +95,7 @@ class VoiceRSSProvider(Provider):
self.hass = hass self.hass = hass
self.extension = conf.get(CONF_CODEC) self.extension = conf.get(CONF_CODEC)
self.params = { self.form_data = {
'key': conf.get(CONF_API_KEY), 'key': conf.get(CONF_API_KEY),
'hl': conf.get(CONF_LANG), 'hl': conf.get(CONF_LANG),
'c': (conf.get(CONF_CODEC)).upper(), 'c': (conf.get(CONF_CODEC)).upper(),
@ -94,21 +106,28 @@ class VoiceRSSProvider(Provider):
def async_get_tts_audio(self, message): def async_get_tts_audio(self, message):
"""Load TTS from voicerss.""" """Load TTS from voicerss."""
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
form_data = self.form_data.copy()
form_data['src'] = message
request = None request = None
try: try:
with async_timeout.timeout(10, loop=self.hass.loop): with async_timeout.timeout(10, loop=self.hass.loop):
request = yield from websession.post( request = yield from websession.post(
VOICERSS_API_URL, params=self.params, VOICERSS_API_URL, data=form_data
data=bytes(message, 'utf-8')
) )
if request.status != 200: if request.status != 200:
_LOGGER.error("Error %d on load url %s", _LOGGER.error("Error %d on load url %s.",
request.status, request.url) request.status, request.url)
return (None, None) return (None, None)
data = yield from request.read() data = yield from request.read()
if data in ERROR_MSG:
_LOGGER.error(
"Error receive %s from voicerss.", str(data, 'utf-8'))
return (None, None)
except (asyncio.TimeoutError, aiohttp.errors.ClientError): except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.error("Timeout for voicerss api.") _LOGGER.error("Timeout for voicerss api.")
return (None, None) return (None, None)

View File

@ -20,11 +20,12 @@ class TestTTSVoiceRSSPlatform(object):
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.url = "https://api.voicerss.org/" self.url = "https://api.voicerss.org/"
self.url_param = { self.form_data = {
'key': '1234567xx', 'key': '1234567xx',
'hl': 'en-us', 'hl': 'en-us',
'c': 'MP3', 'c': 'MP3',
'f': '8khz_8bit_mono', 'f': '8khz_8bit_mono',
'src': "I person is on front of your door.",
} }
def teardown_method(self): def teardown_method(self):
@ -63,7 +64,7 @@ class TestTTSVoiceRSSPlatform(object):
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
aioclient_mock.post( aioclient_mock.post(
self.url, params=self.url_param, status=200, content=b'test') self.url, data=self.form_data, status=200, content=b'test')
config = { config = {
tts.DOMAIN: { tts.DOMAIN: {
@ -82,15 +83,16 @@ class TestTTSVoiceRSSPlatform(object):
assert len(calls) == 1 assert len(calls) == 1
assert len(aioclient_mock.mock_calls) == 1 assert len(aioclient_mock.mock_calls) == 1
assert aioclient_mock.mock_calls[0][2] == self.form_data
assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find(".mp3") != -1 assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find(".mp3") != -1
def test_service_say_german(self, aioclient_mock): def test_service_say_german(self, aioclient_mock):
"""Test service call say with german code.""" """Test service call say with german code."""
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
self.url_param['hl'] = 'de-de' self.form_data['hl'] = 'de-de'
aioclient_mock.post( aioclient_mock.post(
self.url, params=self.url_param, status=200, content=b'test') self.url, data=self.form_data, status=200, content=b'test')
config = { config = {
tts.DOMAIN: { tts.DOMAIN: {
@ -110,13 +112,14 @@ class TestTTSVoiceRSSPlatform(object):
assert len(calls) == 1 assert len(calls) == 1
assert len(aioclient_mock.mock_calls) == 1 assert len(aioclient_mock.mock_calls) == 1
assert aioclient_mock.mock_calls[0][2] == self.form_data
def test_service_say_error(self, aioclient_mock): def test_service_say_error(self, aioclient_mock):
"""Test service call say with http response 400.""" """Test service call say with http response 400."""
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
aioclient_mock.post( aioclient_mock.post(
self.url, params=self.url_param, status=400, content=b'test') self.url, data=self.form_data, status=400, content=b'test')
config = { config = {
tts.DOMAIN: { tts.DOMAIN: {
@ -135,13 +138,14 @@ class TestTTSVoiceRSSPlatform(object):
assert len(calls) == 0 assert len(calls) == 0
assert len(aioclient_mock.mock_calls) == 1 assert len(aioclient_mock.mock_calls) == 1
assert aioclient_mock.mock_calls[0][2] == self.form_data
def test_service_say_timeout(self, aioclient_mock): def test_service_say_timeout(self, aioclient_mock):
"""Test service call say with http timeout.""" """Test service call say with http timeout."""
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
aioclient_mock.post( aioclient_mock.post(
self.url, params=self.url_param, exc=asyncio.TimeoutError()) self.url, data=self.form_data, exc=asyncio.TimeoutError())
config = { config = {
tts.DOMAIN: { tts.DOMAIN: {
@ -160,3 +164,32 @@ class TestTTSVoiceRSSPlatform(object):
assert len(calls) == 0 assert len(calls) == 0
assert len(aioclient_mock.mock_calls) == 1 assert len(aioclient_mock.mock_calls) == 1
assert aioclient_mock.mock_calls[0][2] == self.form_data
def test_service_say_error_msg(self, aioclient_mock):
"""Test service call say with http error api message."""
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
aioclient_mock.post(
self.url, data=self.form_data, status=200,
content=b'The subscription does not support SSML!'
)
config = {
tts.DOMAIN: {
'platform': 'voicerss',
'api_key': '1234567xx',
}
}
with assert_setup_component(1, tts.DOMAIN):
setup_component(self.hass, tts.DOMAIN, config)
self.hass.services.call(tts.DOMAIN, 'voicerss_say', {
tts.ATTR_MESSAGE: "I person is on front of your door.",
})
self.hass.block_till_done()
assert len(calls) == 0
assert len(aioclient_mock.mock_calls) == 1
assert aioclient_mock.mock_calls[0][2] == self.form_data