mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
commit
308d71c448
@ -115,7 +115,7 @@ def async_setup(hass, config):
|
|||||||
update_coro = hass.loop.create_task(
|
update_coro = hass.loop.create_task(
|
||||||
alarm.async_update_ha_state(True))
|
alarm.async_update_ha_state(True))
|
||||||
if hasattr(alarm, 'async_update'):
|
if hasattr(alarm, 'async_update'):
|
||||||
update_tasks.append(hass.loop.create_task(update_coro))
|
update_tasks.append(update_coro)
|
||||||
else:
|
else:
|
||||||
yield from update_coro
|
yield from update_coro
|
||||||
|
|
||||||
|
@ -13,8 +13,7 @@ from homeassistant.components.binary_sensor import (
|
|||||||
BinarySensorDevice, PLATFORM_SCHEMA)
|
BinarySensorDevice, PLATFORM_SCHEMA)
|
||||||
from homeassistant.components.sensor.nest import NestSensor
|
from homeassistant.components.sensor.nest import NestSensor
|
||||||
from homeassistant.const import (CONF_SCAN_INTERVAL, CONF_MONITORED_CONDITIONS)
|
from homeassistant.const import (CONF_SCAN_INTERVAL, CONF_MONITORED_CONDITIONS)
|
||||||
from homeassistant.components.nest import (
|
from homeassistant.components.nest import DATA_NEST
|
||||||
DATA_NEST, is_thermostat, is_camera)
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
DEPENDENCIES = ['nest']
|
DEPENDENCIES = ['nest']
|
||||||
@ -76,9 +75,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
_LOGGER.error(wstr)
|
_LOGGER.error(wstr)
|
||||||
|
|
||||||
sensors = []
|
sensors = []
|
||||||
device_chain = chain(nest.devices(),
|
device_chain = chain(nest.thermostats(),
|
||||||
nest.protect_devices(),
|
nest.smoke_co_alarms(),
|
||||||
nest.camera_devices())
|
nest.cameras())
|
||||||
for structure, device in device_chain:
|
for structure, device in device_chain:
|
||||||
sensors += [NestBinarySensor(structure, device, variable)
|
sensors += [NestBinarySensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
@ -86,9 +85,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
sensors += [NestBinarySensor(structure, device, variable)
|
sensors += [NestBinarySensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in CLIMATE_BINARY_TYPES
|
if variable in CLIMATE_BINARY_TYPES
|
||||||
and is_thermostat(device)]
|
and device.is_thermostat]
|
||||||
|
|
||||||
if is_camera(device):
|
if device.is_camera:
|
||||||
sensors += [NestBinarySensor(structure, device, variable)
|
sensors += [NestBinarySensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in CAMERA_BINARY_TYPES]
|
if variable in CAMERA_BINARY_TYPES]
|
||||||
@ -118,13 +117,14 @@ class NestActivityZoneSensor(NestBinarySensor):
|
|||||||
|
|
||||||
def __init__(self, structure, device, zone):
|
def __init__(self, structure, device, zone):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
super(NestActivityZoneSensor, self).__init__(structure, device, None)
|
super(NestActivityZoneSensor, self).__init__(structure, device, "")
|
||||||
self.zone = zone
|
self.zone = zone
|
||||||
|
self._name = "{} {} activity".format(self._name, self.zone.name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the nest, if any."""
|
"""Return the name of the nest, if any."""
|
||||||
return "{} {} activity".format(self._name, self.zone.name)
|
return self._name
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
|
@ -27,7 +27,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
if discovery_info is None:
|
if discovery_info is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
camera_devices = hass.data[nest.DATA_NEST].camera_devices()
|
camera_devices = hass.data[nest.DATA_NEST].cameras()
|
||||||
cameras = [NestCamera(structure, device)
|
cameras = [NestCamera(structure, device)
|
||||||
for structure, device in camera_devices]
|
for structure, device in camera_devices]
|
||||||
add_devices(cameras, True)
|
add_devices(cameras, True)
|
||||||
@ -43,7 +43,7 @@ class NestCamera(Camera):
|
|||||||
self.device = device
|
self.device = device
|
||||||
self._location = None
|
self._location = None
|
||||||
self._name = None
|
self._name = None
|
||||||
self._is_online = None
|
self._online = None
|
||||||
self._is_streaming = None
|
self._is_streaming = None
|
||||||
self._is_video_history_enabled = False
|
self._is_video_history_enabled = False
|
||||||
# Default to non-NestAware subscribed, but will be fixed during update
|
# Default to non-NestAware subscribed, but will be fixed during update
|
||||||
@ -76,7 +76,7 @@ class NestCamera(Camera):
|
|||||||
"""Cache value from Python-nest."""
|
"""Cache value from Python-nest."""
|
||||||
self._location = self.device.where
|
self._location = self.device.where
|
||||||
self._name = self.device.name
|
self._name = self.device.name
|
||||||
self._is_online = self.device.is_online
|
self._online = self.device.online
|
||||||
self._is_streaming = self.device.is_streaming
|
self._is_streaming = self.device.is_streaming
|
||||||
self._is_video_history_enabled = self.device.is_video_history_enabled
|
self._is_video_history_enabled = self.device.is_video_history_enabled
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
|
|
||||||
add_devices(
|
add_devices(
|
||||||
[NestThermostat(structure, device, temp_unit)
|
[NestThermostat(structure, device, temp_unit)
|
||||||
for structure, device in hass.data[DATA_NEST].devices()],
|
for structure, device in hass.data[DATA_NEST].thermostats()],
|
||||||
True
|
True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ def async_setup(hass, config):
|
|||||||
update_coro = hass.loop.create_task(
|
update_coro = hass.loop.create_task(
|
||||||
light.async_update_ha_state(True))
|
light.async_update_ha_state(True))
|
||||||
if hasattr(light, 'async_update'):
|
if hasattr(light, 'async_update'):
|
||||||
update_tasks.append(hass.loop.create_task(update_coro))
|
update_tasks.append(update_coro)
|
||||||
else:
|
else:
|
||||||
yield from update_coro
|
yield from update_coro
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
REQUIREMENTS = [
|
REQUIREMENTS = [
|
||||||
'http://github.com/technicalpickles/python-nest'
|
'http://github.com/technicalpickles/python-nest'
|
||||||
'/archive/b8391d2b3cb8682f8b0c2bdff477179983609f39.zip' # nest-cam branch
|
'/archive/e6c9d56a8df455d4d7746389811f2c1387e8cb33.zip' # nest-cam branch
|
||||||
'#python-nest==3.0.2']
|
'#python-nest==3.0.3']
|
||||||
|
|
||||||
DOMAIN = 'nest'
|
DOMAIN = 'nest'
|
||||||
|
|
||||||
@ -132,12 +132,12 @@ class NestDevice(object):
|
|||||||
self._structure = conf[CONF_STRUCTURE]
|
self._structure = conf[CONF_STRUCTURE]
|
||||||
_LOGGER.debug("Structures to include: %s", self._structure)
|
_LOGGER.debug("Structures to include: %s", self._structure)
|
||||||
|
|
||||||
def devices(self):
|
def thermostats(self):
|
||||||
"""Generator returning list of devices and their location."""
|
"""Generator returning list of thermostats and their location."""
|
||||||
try:
|
try:
|
||||||
for structure in self.nest.structures:
|
for structure in self.nest.structures:
|
||||||
if structure.name in self._structure:
|
if structure.name in self._structure:
|
||||||
for device in structure.devices:
|
for device in structure.thermostats:
|
||||||
yield (structure, device)
|
yield (structure, device)
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("Ignoring structure %s, not in %s",
|
_LOGGER.debug("Ignoring structure %s, not in %s",
|
||||||
@ -146,12 +146,12 @@ class NestDevice(object):
|
|||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Connection error logging into the nest web service.")
|
"Connection error logging into the nest web service.")
|
||||||
|
|
||||||
def protect_devices(self):
|
def smoke_co_alarms(self):
|
||||||
"""Generator returning list of protect devices."""
|
"""Generator returning list of smoke co alarams."""
|
||||||
try:
|
try:
|
||||||
for structure in self.nest.structures:
|
for structure in self.nest.structures:
|
||||||
if structure.name in self._structure:
|
if structure.name in self._structure:
|
||||||
for device in structure.protectdevices:
|
for device in structure.smoke_co_alarms:
|
||||||
yield(structure, device)
|
yield(structure, device)
|
||||||
else:
|
else:
|
||||||
_LOGGER.info("Ignoring structure %s, not in %s",
|
_LOGGER.info("Ignoring structure %s, not in %s",
|
||||||
@ -160,12 +160,12 @@ class NestDevice(object):
|
|||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Connection error logging into the nest web service.")
|
"Connection error logging into the nest web service.")
|
||||||
|
|
||||||
def camera_devices(self):
|
def cameras(self):
|
||||||
"""Generator returning list of camera devices."""
|
"""Generator returning list of cameras."""
|
||||||
try:
|
try:
|
||||||
for structure in self.nest.structures:
|
for structure in self.nest.structures:
|
||||||
if structure.name in self._structure:
|
if structure.name in self._structure:
|
||||||
for device in structure.cameradevices:
|
for device in structure.cameras:
|
||||||
yield(structure, device)
|
yield(structure, device)
|
||||||
else:
|
else:
|
||||||
_LOGGER.info("Ignoring structure %s, not in %s",
|
_LOGGER.info("Ignoring structure %s, not in %s",
|
||||||
@ -173,18 +173,3 @@ class NestDevice(object):
|
|||||||
except socket.error:
|
except socket.error:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Connection error logging into the nest web service.")
|
"Connection error logging into the nest web service.")
|
||||||
|
|
||||||
|
|
||||||
def is_thermostat(device):
|
|
||||||
"""Target devices that are Nest Thermostats."""
|
|
||||||
return bool(device.__class__.__name__ == 'Device')
|
|
||||||
|
|
||||||
|
|
||||||
def is_protect(device):
|
|
||||||
"""Target devices that are Nest Protect Smoke Alarms."""
|
|
||||||
return bool(device.__class__.__name__ == 'ProtectDevice')
|
|
||||||
|
|
||||||
|
|
||||||
def is_camera(device):
|
|
||||||
"""Target devices that are Nest Protect Smoke Alarms."""
|
|
||||||
return bool(device.__class__.__name__ == 'CameraDevice')
|
|
||||||
|
@ -115,7 +115,7 @@ def async_setup(hass, config):
|
|||||||
update_coro = hass.loop.create_task(
|
update_coro = hass.loop.create_task(
|
||||||
remote.async_update_ha_state(True))
|
remote.async_update_ha_state(True))
|
||||||
if hasattr(remote, 'async_update'):
|
if hasattr(remote, 'async_update'):
|
||||||
update_tasks.append(hass.loop.create_task(update_coro))
|
update_tasks.append(update_coro)
|
||||||
else:
|
else:
|
||||||
yield from update_coro
|
yield from update_coro
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@ import logging
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.nest import DATA_NEST, DOMAIN
|
from homeassistant.components.nest import (
|
||||||
|
DATA_NEST, DOMAIN)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_PLATFORM,
|
TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_PLATFORM,
|
||||||
@ -93,31 +94,21 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
_LOGGER.error(wstr)
|
_LOGGER.error(wstr)
|
||||||
|
|
||||||
all_sensors = []
|
all_sensors = []
|
||||||
for structure, device in chain(nest.devices(), nest.protect_devices()):
|
for structure, device in chain(nest.thermostats(), nest.smoke_co_alarms()):
|
||||||
sensors = [NestBasicSensor(structure, device, variable)
|
sensors = [NestBasicSensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in SENSOR_TYPES and is_thermostat(device)]
|
if variable in SENSOR_TYPES and device.is_thermostat]
|
||||||
sensors += [NestTempSensor(structure, device, variable)
|
sensors += [NestTempSensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in SENSOR_TEMP_TYPES and is_thermostat(device)]
|
if variable in SENSOR_TEMP_TYPES and device.is_thermostat]
|
||||||
sensors += [NestProtectSensor(structure, device, variable)
|
sensors += [NestProtectSensor(structure, device, variable)
|
||||||
for variable in conf
|
for variable in conf
|
||||||
if variable in PROTECT_VARS and is_protect(device)]
|
if variable in PROTECT_VARS and device.is_smoke_co_alarm]
|
||||||
all_sensors.extend(sensors)
|
all_sensors.extend(sensors)
|
||||||
|
|
||||||
add_devices(all_sensors, True)
|
add_devices(all_sensors, True)
|
||||||
|
|
||||||
|
|
||||||
def is_thermostat(device):
|
|
||||||
"""Target devices that are Nest Thermostats."""
|
|
||||||
return bool(device.__class__.__name__ == 'Device')
|
|
||||||
|
|
||||||
|
|
||||||
def is_protect(device):
|
|
||||||
"""Target devices that are Nest Protect Smoke Alarms."""
|
|
||||||
return bool(device.__class__.__name__ == 'ProtectDevice')
|
|
||||||
|
|
||||||
|
|
||||||
class NestSensor(Entity):
|
class NestSensor(Entity):
|
||||||
"""Representation of a Nest sensor."""
|
"""Representation of a Nest sensor."""
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ def async_setup(hass, config):
|
|||||||
update_coro = hass.loop.create_task(
|
update_coro = hass.loop.create_task(
|
||||||
switch.async_update_ha_state(True))
|
switch.async_update_ha_state(True))
|
||||||
if hasattr(switch, 'async_update'):
|
if hasattr(switch, 'async_update'):
|
||||||
update_tasks.append(hass.loop.create_task(update_coro))
|
update_tasks.append(update_coro)
|
||||||
else:
|
else:
|
||||||
yield from update_coro
|
yield from update_coro
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 35
|
MINOR_VERSION = 35
|
||||||
PATCH_VERSION = '2'
|
PATCH_VERSION = '3'
|
||||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||||
REQUIRED_PYTHON_VER = (3, 4, 2)
|
REQUIRED_PYTHON_VER = (3, 4, 2)
|
||||||
|
@ -55,7 +55,9 @@ class AsyncHandler(object):
|
|||||||
|
|
||||||
When blocking=True, will wait till closed.
|
When blocking=True, will wait till closed.
|
||||||
"""
|
"""
|
||||||
self.close()
|
if not self._thread.is_alive():
|
||||||
|
return
|
||||||
|
yield from self._queue.put(None)
|
||||||
|
|
||||||
if blocking:
|
if blocking:
|
||||||
# Python 3.4.4+
|
# Python 3.4.4+
|
||||||
|
@ -174,7 +174,7 @@ hikvision==0.4
|
|||||||
# http://github.com/adafruit/Adafruit_Python_DHT/archive/310c59b0293354d07d94375f1365f7b9b9110c7d.zip#Adafruit_DHT==1.3.0
|
# http://github.com/adafruit/Adafruit_Python_DHT/archive/310c59b0293354d07d94375f1365f7b9b9110c7d.zip#Adafruit_DHT==1.3.0
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
http://github.com/technicalpickles/python-nest/archive/b8391d2b3cb8682f8b0c2bdff477179983609f39.zip#python-nest==3.0.2
|
http://github.com/technicalpickles/python-nest/archive/e6c9d56a8df455d4d7746389811f2c1387e8cb33.zip#python-nest==3.0.3
|
||||||
|
|
||||||
# homeassistant.components.light.flux_led
|
# homeassistant.components.light.flux_led
|
||||||
https://github.com/Danielhiversen/flux_led/archive/0.10.zip#flux_led==0.10
|
https://github.com/Danielhiversen/flux_led/archive/0.10.zip#flux_led==0.10
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user