Fix async probs (#9924)
* Update entity.py * Update entity_component.py * Update entity_component.py * Update __init__.py * Update entity_component.py * Update entity_component.py * Update entity.py * cleanup entity * Update entity_component.py * Update entity_component.py * Fix names & comments / fix tests * Revert deadlock protection * Add tests for entity * Add test fix name * Update other code * Fix lint * Remove restore state from template entities * Lint
This commit is contained in:
parent
6cce934f72
commit
c1b197419d
24 changed files with 356 additions and 362 deletions
|
@ -124,20 +124,13 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
method = "async_{}".format(SERVICE_TO_METHOD[service.service])
|
method = "async_{}".format(SERVICE_TO_METHOD[service.service])
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for alarm in target_alarms:
|
for alarm in target_alarms:
|
||||||
yield from getattr(alarm, method)(code)
|
yield from getattr(alarm, method)(code)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
for alarm in target_alarms:
|
|
||||||
if not alarm.should_poll:
|
if not alarm.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(alarm.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
alarm.async_update_ha_state(True))
|
|
||||||
if hasattr(alarm, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -15,13 +15,12 @@ from homeassistant.components.binary_sensor import (
|
||||||
DEVICE_CLASSES_SCHEMA)
|
DEVICE_CLASSES_SCHEMA)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_FRIENDLY_NAME, ATTR_ENTITY_ID, CONF_VALUE_TEMPLATE,
|
ATTR_FRIENDLY_NAME, ATTR_ENTITY_ID, CONF_VALUE_TEMPLATE,
|
||||||
CONF_SENSORS, CONF_DEVICE_CLASS, EVENT_HOMEASSISTANT_START, STATE_ON)
|
CONF_SENSORS, CONF_DEVICE_CLASS, EVENT_HOMEASSISTANT_START)
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_state_change, async_track_same_state)
|
async_track_state_change, async_track_same_state)
|
||||||
from homeassistant.helpers.restore_state import async_get_last_state
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -94,10 +93,6 @@ class BinarySensorTemplate(BinarySensorDevice):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
state = yield from async_get_last_state(self.hass, self.entity_id)
|
|
||||||
if state:
|
|
||||||
self._state = state.state == STATE_ON
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def template_bsensor_state_listener(entity, old_state, new_state):
|
def template_bsensor_state_listener(entity, old_state, new_state):
|
||||||
"""Handle the target device state changes."""
|
"""Handle the target device state changes."""
|
||||||
|
|
|
@ -126,23 +126,16 @@ def async_setup(hass, config):
|
||||||
"""Handle calls to the camera services."""
|
"""Handle calls to the camera services."""
|
||||||
target_cameras = component.async_extract_from_service(service)
|
target_cameras = component.async_extract_from_service(service)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for camera in target_cameras:
|
for camera in target_cameras:
|
||||||
if service.service == SERVICE_EN_MOTION:
|
if service.service == SERVICE_EN_MOTION:
|
||||||
yield from camera.async_enable_motion_detection()
|
yield from camera.async_enable_motion_detection()
|
||||||
elif service.service == SERVICE_DISEN_MOTION:
|
elif service.service == SERVICE_DISEN_MOTION:
|
||||||
yield from camera.async_disable_motion_detection()
|
yield from camera.async_disable_motion_detection()
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
for camera in target_cameras:
|
|
||||||
if not camera.should_poll:
|
if not camera.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(camera.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
camera.async_update_ha_state(True))
|
|
||||||
if hasattr(camera, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -236,24 +236,6 @@ def async_setup(hass, config):
|
||||||
load_yaml_config_file,
|
load_yaml_config_file,
|
||||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _async_update_climate(target_climate):
|
|
||||||
"""Update climate entity after service stuff."""
|
|
||||||
update_tasks = []
|
|
||||||
for climate in target_climate:
|
|
||||||
if not climate.should_poll:
|
|
||||||
continue
|
|
||||||
|
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
climate.async_update_ha_state(True))
|
|
||||||
if hasattr(climate, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_away_mode_set_service(service):
|
def async_away_mode_set_service(service):
|
||||||
"""Set away mode on target climate devices."""
|
"""Set away mode on target climate devices."""
|
||||||
|
@ -261,13 +243,19 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
away_mode = service.data.get(ATTR_AWAY_MODE)
|
away_mode = service.data.get(ATTR_AWAY_MODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
if away_mode:
|
if away_mode:
|
||||||
yield from climate.async_turn_away_mode_on()
|
yield from climate.async_turn_away_mode_on()
|
||||||
else:
|
else:
|
||||||
yield from climate.async_turn_away_mode_off()
|
yield from climate.async_turn_away_mode_off()
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_AWAY_MODE, async_away_mode_set_service,
|
DOMAIN, SERVICE_SET_AWAY_MODE, async_away_mode_set_service,
|
||||||
|
@ -281,10 +269,16 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
hold_mode = service.data.get(ATTR_HOLD_MODE)
|
hold_mode = service.data.get(ATTR_HOLD_MODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
yield from climate.async_set_hold_mode(hold_mode)
|
yield from climate.async_set_hold_mode(hold_mode)
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_HOLD_MODE, async_hold_mode_set_service,
|
DOMAIN, SERVICE_SET_HOLD_MODE, async_hold_mode_set_service,
|
||||||
|
@ -298,13 +292,19 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
aux_heat = service.data.get(ATTR_AUX_HEAT)
|
aux_heat = service.data.get(ATTR_AUX_HEAT)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
if aux_heat:
|
if aux_heat:
|
||||||
yield from climate.async_turn_aux_heat_on()
|
yield from climate.async_turn_aux_heat_on()
|
||||||
else:
|
else:
|
||||||
yield from climate.async_turn_aux_heat_off()
|
yield from climate.async_turn_aux_heat_off()
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_AUX_HEAT, async_aux_heat_set_service,
|
DOMAIN, SERVICE_SET_AUX_HEAT, async_aux_heat_set_service,
|
||||||
|
@ -316,6 +316,7 @@ def async_setup(hass, config):
|
||||||
"""Set temperature on the target climate devices."""
|
"""Set temperature on the target climate devices."""
|
||||||
target_climate = component.async_extract_from_service(service)
|
target_climate = component.async_extract_from_service(service)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for value, temp in service.data.items():
|
for value, temp in service.data.items():
|
||||||
|
@ -330,7 +331,12 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
yield from climate.async_set_temperature(**kwargs)
|
yield from climate.async_set_temperature(**kwargs)
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_TEMPERATURE, async_temperature_set_service,
|
DOMAIN, SERVICE_SET_TEMPERATURE, async_temperature_set_service,
|
||||||
|
@ -344,10 +350,15 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
humidity = service.data.get(ATTR_HUMIDITY)
|
humidity = service.data.get(ATTR_HUMIDITY)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
yield from climate.async_set_humidity(humidity)
|
yield from climate.async_set_humidity(humidity)
|
||||||
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_HUMIDITY, async_humidity_set_service,
|
DOMAIN, SERVICE_SET_HUMIDITY, async_humidity_set_service,
|
||||||
|
@ -361,10 +372,15 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
fan = service.data.get(ATTR_FAN_MODE)
|
fan = service.data.get(ATTR_FAN_MODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
yield from climate.async_set_fan_mode(fan)
|
yield from climate.async_set_fan_mode(fan)
|
||||||
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_FAN_MODE, async_fan_mode_set_service,
|
DOMAIN, SERVICE_SET_FAN_MODE, async_fan_mode_set_service,
|
||||||
|
@ -378,10 +394,15 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
operation_mode = service.data.get(ATTR_OPERATION_MODE)
|
operation_mode = service.data.get(ATTR_OPERATION_MODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
yield from climate.async_set_operation_mode(operation_mode)
|
yield from climate.async_set_operation_mode(operation_mode)
|
||||||
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_OPERATION_MODE, async_operation_set_service,
|
DOMAIN, SERVICE_SET_OPERATION_MODE, async_operation_set_service,
|
||||||
|
@ -395,10 +416,15 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
swing_mode = service.data.get(ATTR_SWING_MODE)
|
swing_mode = service.data.get(ATTR_SWING_MODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for climate in target_climate:
|
for climate in target_climate:
|
||||||
yield from climate.async_set_swing_mode(swing_mode)
|
yield from climate.async_set_swing_mode(swing_mode)
|
||||||
|
if not climate.should_poll:
|
||||||
|
continue
|
||||||
|
update_tasks.append(climate.async_update_ha_state(True))
|
||||||
|
|
||||||
yield from _async_update_climate(target_climate)
|
if update_tasks:
|
||||||
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SET_SWING_MODE, async_swing_set_service,
|
DOMAIN, SERVICE_SET_SWING_MODE, async_swing_set_service,
|
||||||
|
|
|
@ -169,21 +169,12 @@ def async_setup(hass, config):
|
||||||
params.pop(ATTR_ENTITY_ID, None)
|
params.pop(ATTR_ENTITY_ID, None)
|
||||||
|
|
||||||
# call method
|
# call method
|
||||||
|
update_tasks = []
|
||||||
for cover in covers:
|
for cover in covers:
|
||||||
yield from getattr(cover, method['method'])(**params)
|
yield from getattr(cover, method['method'])(**params)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
|
|
||||||
for cover in covers:
|
|
||||||
if not cover.should_poll:
|
if not cover.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(cover.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
cover.async_update_ha_state(True))
|
|
||||||
if hasattr(cover, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -24,7 +24,6 @@ from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.event import async_track_state_change
|
from homeassistant.helpers.event import async_track_state_change
|
||||||
from homeassistant.helpers.restore_state import async_get_last_state
|
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -134,7 +133,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
_LOGGER.error("No covers added")
|
_LOGGER.error("No covers added")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async_add_devices(covers, True)
|
async_add_devices(covers)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,10 +189,6 @@ class CoverTemplate(CoverDevice):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
state = yield from async_get_last_state(self.hass, self.entity_id)
|
|
||||||
if state:
|
|
||||||
self._position = 100 if state.state == STATE_OPEN else 0
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def template_cover_state_listener(entity, old_state, new_state):
|
def template_cover_state_listener(entity, old_state, new_state):
|
||||||
"""Handle target device state changes."""
|
"""Handle target device state changes."""
|
||||||
|
|
|
@ -215,20 +215,12 @@ def async_setup(hass, config: dict):
|
||||||
target_fans = component.async_extract_from_service(service)
|
target_fans = component.async_extract_from_service(service)
|
||||||
params.pop(ATTR_ENTITY_ID, None)
|
params.pop(ATTR_ENTITY_ID, None)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for fan in target_fans:
|
for fan in target_fans:
|
||||||
yield from getattr(fan, method['method'])(**params)
|
yield from getattr(fan, method['method'])(**params)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
|
|
||||||
for fan in target_fans:
|
|
||||||
if not fan.should_poll:
|
if not fan.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(fan.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(fan.async_update_ha_state(True))
|
|
||||||
if hasattr(fan, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -274,6 +274,7 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
preprocess_turn_on_alternatives(params)
|
preprocess_turn_on_alternatives(params)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for light in target_lights:
|
for light in target_lights:
|
||||||
if service.service == SERVICE_TURN_ON:
|
if service.service == SERVICE_TURN_ON:
|
||||||
yield from light.async_turn_on(**params)
|
yield from light.async_turn_on(**params)
|
||||||
|
@ -282,18 +283,9 @@ def async_setup(hass, config):
|
||||||
else:
|
else:
|
||||||
yield from light.async_toggle(**params)
|
yield from light.async_toggle(**params)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
|
|
||||||
for light in target_lights:
|
|
||||||
if not light.should_poll:
|
if not light.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(light.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
light.async_update_ha_state(True))
|
|
||||||
if hasattr(light, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -20,7 +20,6 @@ from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.event import async_track_state_change
|
from homeassistant.helpers.event import async_track_state_change
|
||||||
from homeassistant.helpers.restore_state import async_get_last_state
|
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -87,7 +86,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
_LOGGER.error("No lights added")
|
_LOGGER.error("No lights added")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async_add_devices(lights, True)
|
async_add_devices(lights)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,10 +149,6 @@ class LightTemplate(Light):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
state = yield from async_get_last_state(self.hass, self.entity_id)
|
|
||||||
if state:
|
|
||||||
self._state = state.state == STATE_ON
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def template_light_state_listener(entity, old_state, new_state):
|
def template_light_state_listener(entity, old_state, new_state):
|
||||||
"""Handle target device state changes."""
|
"""Handle target device state changes."""
|
||||||
|
@ -207,6 +202,7 @@ class LightTemplate(Light):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_update(self):
|
def async_update(self):
|
||||||
"""Update the state from the template."""
|
"""Update the state from the template."""
|
||||||
|
print("ASYNC UPDATE")
|
||||||
if self._template is not None:
|
if self._template is not None:
|
||||||
try:
|
try:
|
||||||
state = self._template.async_render().lower()
|
state = self._template.async_render().lower()
|
||||||
|
|
|
@ -90,24 +90,16 @@ def async_setup(hass, config):
|
||||||
|
|
||||||
code = service.data.get(ATTR_CODE)
|
code = service.data.get(ATTR_CODE)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for entity in target_locks:
|
for entity in target_locks:
|
||||||
if service.service == SERVICE_LOCK:
|
if service.service == SERVICE_LOCK:
|
||||||
yield from entity.async_lock(code=code)
|
yield from entity.async_lock(code=code)
|
||||||
else:
|
else:
|
||||||
yield from entity.async_unlock(code=code)
|
yield from entity.async_unlock(code=code)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
|
|
||||||
for entity in target_locks:
|
|
||||||
if not entity.should_poll:
|
if not entity.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(entity.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
entity.async_update_ha_state(True))
|
|
||||||
if hasattr(entity, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -406,16 +406,9 @@ def async_setup(hass, config):
|
||||||
update_tasks = []
|
update_tasks = []
|
||||||
for player in target_players:
|
for player in target_players:
|
||||||
yield from getattr(player, method['method'])(**params)
|
yield from getattr(player, method['method'])(**params)
|
||||||
|
|
||||||
for player in target_players:
|
|
||||||
if not player.should_poll:
|
if not player.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(player.async_update_ha_state(True))
|
||||||
update_coro = player.async_update_ha_state(True)
|
|
||||||
if hasattr(player, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -148,6 +148,7 @@ def async_setup(hass, config):
|
||||||
num_repeats = service.data.get(ATTR_NUM_REPEATS)
|
num_repeats = service.data.get(ATTR_NUM_REPEATS)
|
||||||
delay_secs = service.data.get(ATTR_DELAY_SECS)
|
delay_secs = service.data.get(ATTR_DELAY_SECS)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for remote in target_remotes:
|
for remote in target_remotes:
|
||||||
if service.service == SERVICE_TURN_ON:
|
if service.service == SERVICE_TURN_ON:
|
||||||
yield from remote.async_turn_on(activity=activity_id)
|
yield from remote.async_turn_on(activity=activity_id)
|
||||||
|
@ -160,17 +161,9 @@ def async_setup(hass, config):
|
||||||
else:
|
else:
|
||||||
yield from remote.async_turn_off(activity=activity_id)
|
yield from remote.async_turn_off(activity=activity_id)
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
for remote in target_remotes:
|
|
||||||
if not remote.should_poll:
|
if not remote.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(remote.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
remote.async_update_ha_state(True))
|
|
||||||
if hasattr(remote, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -19,7 +19,6 @@ from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||||
from homeassistant.helpers.event import async_track_state_change
|
from homeassistant.helpers.event import async_track_state_change
|
||||||
from homeassistant.helpers.restore_state import async_get_last_state
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -93,10 +92,6 @@ class SensorTemplate(Entity):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
state = yield from async_get_last_state(self.hass, self.entity_id)
|
|
||||||
if state:
|
|
||||||
self._state = state.state
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def template_sensor_state_listener(entity, old_state, new_state):
|
def template_sensor_state_listener(entity, old_state, new_state):
|
||||||
"""Handle device state changes."""
|
"""Handle device state changes."""
|
||||||
|
|
|
@ -107,6 +107,7 @@ def async_setup(hass, config):
|
||||||
"""Handle calls to the switch services."""
|
"""Handle calls to the switch services."""
|
||||||
target_switches = component.async_extract_from_service(service)
|
target_switches = component.async_extract_from_service(service)
|
||||||
|
|
||||||
|
update_tasks = []
|
||||||
for switch in target_switches:
|
for switch in target_switches:
|
||||||
if service.service == SERVICE_TURN_ON:
|
if service.service == SERVICE_TURN_ON:
|
||||||
yield from switch.async_turn_on()
|
yield from switch.async_turn_on()
|
||||||
|
@ -115,17 +116,9 @@ def async_setup(hass, config):
|
||||||
else:
|
else:
|
||||||
yield from switch.async_turn_off()
|
yield from switch.async_turn_off()
|
||||||
|
|
||||||
update_tasks = []
|
|
||||||
for switch in target_switches:
|
|
||||||
if not switch.should_poll:
|
if not switch.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(switch.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
switch.async_update_ha_state(True))
|
|
||||||
if hasattr(switch, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -19,7 +19,6 @@ from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.event import async_track_state_change
|
from homeassistant.helpers.event import async_track_state_change
|
||||||
from homeassistant.helpers.restore_state import async_get_last_state
|
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -71,7 +70,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
_LOGGER.error("No switches added")
|
_LOGGER.error("No switches added")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async_add_devices(switches, True)
|
async_add_devices(switches)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,10 +95,6 @@ class SwitchTemplate(SwitchDevice):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
state = yield from async_get_last_state(self.hass, self.entity_id)
|
|
||||||
if state:
|
|
||||||
self._state = state.state == STATE_ON
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def template_switch_state_listener(entity, old_state, new_state):
|
def template_switch_state_listener(entity, old_state, new_state):
|
||||||
"""Handle target device state changes."""
|
"""Handle target device state changes."""
|
||||||
|
|
|
@ -200,13 +200,7 @@ def async_setup(hass, config):
|
||||||
yield from getattr(vacuum, method['method'])(**params)
|
yield from getattr(vacuum, method['method'])(**params)
|
||||||
if not vacuum.should_poll:
|
if not vacuum.should_poll:
|
||||||
continue
|
continue
|
||||||
|
update_tasks.append(vacuum.async_update_ha_state(True))
|
||||||
update_coro = hass.async_add_job(
|
|
||||||
vacuum.async_update_ha_state(True))
|
|
||||||
if hasattr(vacuum, 'async_update'):
|
|
||||||
update_tasks.append(update_coro)
|
|
||||||
else:
|
|
||||||
yield from update_coro
|
|
||||||
|
|
||||||
if update_tasks:
|
if update_tasks:
|
||||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||||
|
|
|
@ -71,8 +71,11 @@ class Entity(object):
|
||||||
# If we reported if this entity was slow
|
# If we reported if this entity was slow
|
||||||
_slow_reported = False
|
_slow_reported = False
|
||||||
|
|
||||||
# protect for multiple updates
|
# Protect for multiple updates
|
||||||
_update_warn = None
|
_update_staged = False
|
||||||
|
|
||||||
|
# Process updates pararell
|
||||||
|
parallel_updates = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self) -> bool:
|
||||||
|
@ -197,11 +200,15 @@ class Entity(object):
|
||||||
|
|
||||||
# update entity data
|
# update entity data
|
||||||
if force_refresh:
|
if force_refresh:
|
||||||
if self._update_warn:
|
if self._update_staged:
|
||||||
# Update is already in progress.
|
|
||||||
return
|
return
|
||||||
|
self._update_staged = True
|
||||||
|
|
||||||
self._update_warn = self.hass.loop.call_later(
|
# Process update sequential
|
||||||
|
if self.parallel_updates:
|
||||||
|
yield from self.parallel_updates.acquire()
|
||||||
|
|
||||||
|
update_warn = self.hass.loop.call_later(
|
||||||
SLOW_UPDATE_WARNING, _LOGGER.warning,
|
SLOW_UPDATE_WARNING, _LOGGER.warning,
|
||||||
"Update of %s is taking over %s seconds", self.entity_id,
|
"Update of %s is taking over %s seconds", self.entity_id,
|
||||||
SLOW_UPDATE_WARNING
|
SLOW_UPDATE_WARNING
|
||||||
|
@ -217,8 +224,10 @@ class Entity(object):
|
||||||
_LOGGER.exception("Update for %s fails", self.entity_id)
|
_LOGGER.exception("Update for %s fails", self.entity_id)
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
self._update_warn.cancel()
|
self._update_staged = False
|
||||||
self._update_warn = None
|
update_warn.cancel()
|
||||||
|
if self.parallel_updates:
|
||||||
|
self.parallel_updates.release()
|
||||||
|
|
||||||
start = timer()
|
start = timer()
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class EntityComponent(object):
|
||||||
self.config = None
|
self.config = None
|
||||||
|
|
||||||
self._platforms = {
|
self._platforms = {
|
||||||
'core': EntityPlatform(self, domain, self.scan_interval, None),
|
'core': EntityPlatform(self, domain, self.scan_interval, 0, None),
|
||||||
}
|
}
|
||||||
self.async_add_entities = self._platforms['core'].async_add_entities
|
self.async_add_entities = self._platforms['core'].async_add_entities
|
||||||
self.add_entities = self._platforms['core'].add_entities
|
self.add_entities = self._platforms['core'].add_entities
|
||||||
|
@ -128,16 +128,22 @@ class EntityComponent(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Config > Platform > Component
|
# Config > Platform > Component
|
||||||
scan_interval = (platform_config.get(CONF_SCAN_INTERVAL) or
|
scan_interval = (
|
||||||
getattr(platform, 'SCAN_INTERVAL', None) or
|
platform_config.get(CONF_SCAN_INTERVAL) or
|
||||||
self.scan_interval)
|
getattr(platform, 'SCAN_INTERVAL', None) or self.scan_interval)
|
||||||
|
parallel_updates = getattr(
|
||||||
|
platform, 'PARALLEL_UPDATES',
|
||||||
|
int(not hasattr(platform, 'async_setup_platform')))
|
||||||
|
|
||||||
entity_namespace = platform_config.get(CONF_ENTITY_NAMESPACE)
|
entity_namespace = platform_config.get(CONF_ENTITY_NAMESPACE)
|
||||||
|
|
||||||
key = (platform_type, scan_interval, entity_namespace)
|
key = (platform_type, scan_interval, entity_namespace)
|
||||||
|
|
||||||
if key not in self._platforms:
|
if key not in self._platforms:
|
||||||
self._platforms[key] = EntityPlatform(
|
entity_platform = self._platforms[key] = EntityPlatform(
|
||||||
self, platform_type, scan_interval, entity_namespace)
|
self, platform_type, scan_interval, parallel_updates,
|
||||||
|
entity_namespace)
|
||||||
|
else:
|
||||||
entity_platform = self._platforms[key]
|
entity_platform = self._platforms[key]
|
||||||
|
|
||||||
self.logger.info("Setting up %s.%s", self.domain, platform_type)
|
self.logger.info("Setting up %s.%s", self.domain, platform_type)
|
||||||
|
@ -204,13 +210,6 @@ class EntityComponent(object):
|
||||||
|
|
||||||
entity.hass = self.hass
|
entity.hass = self.hass
|
||||||
|
|
||||||
# update/init entity data
|
|
||||||
if update_before_add:
|
|
||||||
if hasattr(entity, 'async_update'):
|
|
||||||
yield from entity.async_update()
|
|
||||||
else:
|
|
||||||
yield from self.hass.async_add_job(entity.update)
|
|
||||||
|
|
||||||
if getattr(entity, 'entity_id', None) is None:
|
if getattr(entity, 'entity_id', None) is None:
|
||||||
object_id = entity.name or DEVICE_DEFAULT_NAME
|
object_id = entity.name or DEVICE_DEFAULT_NAME
|
||||||
|
|
||||||
|
@ -235,7 +234,7 @@ class EntityComponent(object):
|
||||||
if hasattr(entity, 'async_added_to_hass'):
|
if hasattr(entity, 'async_added_to_hass'):
|
||||||
yield from entity.async_added_to_hass()
|
yield from entity.async_added_to_hass()
|
||||||
|
|
||||||
yield from entity.async_update_ha_state()
|
yield from entity.async_update_ha_state(update_before_add)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -316,17 +315,23 @@ class EntityComponent(object):
|
||||||
class EntityPlatform(object):
|
class EntityPlatform(object):
|
||||||
"""Keep track of entities for a single platform and stay in loop."""
|
"""Keep track of entities for a single platform and stay in loop."""
|
||||||
|
|
||||||
def __init__(self, component, platform, scan_interval, entity_namespace):
|
def __init__(self, component, platform, scan_interval, parallel_updates,
|
||||||
|
entity_namespace):
|
||||||
"""Initialize the entity platform."""
|
"""Initialize the entity platform."""
|
||||||
self.component = component
|
self.component = component
|
||||||
self.platform = platform
|
self.platform = platform
|
||||||
self.scan_interval = scan_interval
|
self.scan_interval = scan_interval
|
||||||
|
self.parallel_updates = None
|
||||||
self.entity_namespace = entity_namespace
|
self.entity_namespace = entity_namespace
|
||||||
self.platform_entities = []
|
self.platform_entities = []
|
||||||
self._tasks = []
|
self._tasks = []
|
||||||
self._async_unsub_polling = None
|
self._async_unsub_polling = None
|
||||||
self._process_updates = asyncio.Lock(loop=component.hass.loop)
|
self._process_updates = asyncio.Lock(loop=component.hass.loop)
|
||||||
|
|
||||||
|
if parallel_updates:
|
||||||
|
self.parallel_updates = asyncio.Semaphore(
|
||||||
|
parallel_updates, loop=component.hass.loop)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_block_entities_done(self):
|
def async_block_entities_done(self):
|
||||||
"""Wait until all entities add to hass."""
|
"""Wait until all entities add to hass."""
|
||||||
|
@ -377,6 +382,7 @@ class EntityPlatform(object):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_process_entity(new_entity):
|
def async_process_entity(new_entity):
|
||||||
"""Add entities to StateMachine."""
|
"""Add entities to StateMachine."""
|
||||||
|
new_entity.parallel_updates = self.parallel_updates
|
||||||
ret = yield from self.component.async_add_entity(
|
ret = yield from self.component.async_add_entity(
|
||||||
new_entity, self, update_before_add=update_before_add
|
new_entity, self, update_before_add=update_before_add
|
||||||
)
|
)
|
||||||
|
@ -432,26 +438,10 @@ class EntityPlatform(object):
|
||||||
|
|
||||||
with (yield from self._process_updates):
|
with (yield from self._process_updates):
|
||||||
tasks = []
|
tasks = []
|
||||||
to_update = []
|
|
||||||
|
|
||||||
for entity in self.platform_entities:
|
for entity in self.platform_entities:
|
||||||
if not entity.should_poll:
|
if not entity.should_poll:
|
||||||
continue
|
continue
|
||||||
|
tasks.append(entity.async_update_ha_state(True))
|
||||||
update_coro = entity.async_update_ha_state(True)
|
|
||||||
if hasattr(entity, 'async_update'):
|
|
||||||
tasks.append(
|
|
||||||
self.component.hass.async_add_job(update_coro))
|
|
||||||
else:
|
|
||||||
to_update.append(update_coro)
|
|
||||||
|
|
||||||
for update_coro in to_update:
|
|
||||||
try:
|
|
||||||
yield from update_coro
|
|
||||||
except Exception: # pylint: disable=broad-except
|
|
||||||
self.component.logger.exception(
|
|
||||||
"Error while update entity from %s in %s",
|
|
||||||
self.platform, self.component.domain)
|
|
||||||
|
|
||||||
if tasks:
|
if tasks:
|
||||||
yield from asyncio.wait(tasks, loop=self.component.hass.loop)
|
yield from asyncio.wait(tasks, loop=self.component.hass.loop)
|
||||||
|
|
|
@ -4,7 +4,6 @@ from datetime import timedelta
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from homeassistant.core import CoreState, State
|
|
||||||
from homeassistant.const import MATCH_ALL
|
from homeassistant.const import MATCH_ALL
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
from homeassistant.components.binary_sensor import template
|
from homeassistant.components.binary_sensor import template
|
||||||
|
@ -12,11 +11,9 @@ from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.helpers import template as template_hlpr
|
from homeassistant.helpers import template as template_hlpr
|
||||||
from homeassistant.util.async import run_callback_threadsafe
|
from homeassistant.util.async import run_callback_threadsafe
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
|
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
get_test_home_assistant, assert_setup_component, mock_component,
|
get_test_home_assistant, assert_setup_component, async_fire_time_changed)
|
||||||
async_fire_time_changed)
|
|
||||||
|
|
||||||
|
|
||||||
class TestBinarySensorTemplate(unittest.TestCase):
|
class TestBinarySensorTemplate(unittest.TestCase):
|
||||||
|
@ -169,41 +166,6 @@ class TestBinarySensorTemplate(unittest.TestCase):
|
||||||
run_callback_threadsafe(self.hass.loop, vs.async_check_state).result()
|
run_callback_threadsafe(self.hass.loop, vs.async_check_state).result()
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_restore_state(hass):
|
|
||||||
"""Ensure states are restored on startup."""
|
|
||||||
hass.data[DATA_RESTORE_CACHE] = {
|
|
||||||
'binary_sensor.test': State('binary_sensor.test', 'on'),
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.state = CoreState.starting
|
|
||||||
mock_component(hass, 'recorder')
|
|
||||||
|
|
||||||
config = {
|
|
||||||
'binary_sensor': {
|
|
||||||
'platform': 'template',
|
|
||||||
'sensors': {
|
|
||||||
'test': {
|
|
||||||
'friendly_name': 'virtual thingy',
|
|
||||||
'value_template':
|
|
||||||
"{{ states.sensor.test_state.state == 'on' }}",
|
|
||||||
'device_class': 'motion',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
yield from setup.async_setup_component(hass, 'binary_sensor', config)
|
|
||||||
|
|
||||||
state = hass.states.get('binary_sensor.test')
|
|
||||||
assert state.state == 'on'
|
|
||||||
|
|
||||||
yield from hass.async_start()
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get('binary_sensor.test')
|
|
||||||
assert state.state == 'off'
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_template_delay_on(hass):
|
def test_template_delay_on(hass):
|
||||||
"""Test binary sensor template delay on."""
|
"""Test binary sensor template delay on."""
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
"""The tests for the Template light platform."""
|
"""The tests for the Template light platform."""
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from homeassistant.core import callback, State, CoreState
|
from homeassistant.core import callback
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
import homeassistant.components as core
|
import homeassistant.components as core
|
||||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
from homeassistant.components.light import ATTR_BRIGHTNESS
|
||||||
from homeassistant.const import STATE_ON, STATE_OFF
|
from homeassistant.const import STATE_ON, STATE_OFF
|
||||||
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
|
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
get_test_home_assistant, assert_setup_component, mock_component)
|
get_test_home_assistant, assert_setup_component)
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -627,49 +625,3 @@ class TestTemplateLight:
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
|
||||||
assert state.attributes.get('friendly_name') == 'Template light'
|
assert state.attributes.get('friendly_name') == 'Template light'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_restore_state(hass):
|
|
||||||
"""Ensure states are restored on startup."""
|
|
||||||
hass.data[DATA_RESTORE_CACHE] = {
|
|
||||||
'light.test_template_light':
|
|
||||||
State('light.test_template_light', 'on'),
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.state = CoreState.starting
|
|
||||||
mock_component(hass, 'recorder')
|
|
||||||
yield from setup.async_setup_component(hass, 'light', {
|
|
||||||
'light': {
|
|
||||||
'platform': 'template',
|
|
||||||
'lights': {
|
|
||||||
'test_template_light': {
|
|
||||||
'value_template':
|
|
||||||
"{{states.light.test_state.state}}",
|
|
||||||
'turn_on': {
|
|
||||||
'service': 'test.automation',
|
|
||||||
},
|
|
||||||
'turn_off': {
|
|
||||||
'service': 'light.turn_off',
|
|
||||||
'entity_id': 'light.test_state'
|
|
||||||
},
|
|
||||||
'set_level': {
|
|
||||||
'service': 'test.automation',
|
|
||||||
'data_template': {
|
|
||||||
'entity_id': 'light.test_state',
|
|
||||||
'brightness': '{{brightness}}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
state = hass.states.get('light.test_template_light')
|
|
||||||
assert state.state == 'on'
|
|
||||||
|
|
||||||
yield from hass.async_start()
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get('light.test_template_light')
|
|
||||||
assert state.state == 'off'
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
"""The test for the Template sensor platform."""
|
"""The test for the Template sensor platform."""
|
||||||
import asyncio
|
from homeassistant.setup import setup_component
|
||||||
|
|
||||||
from homeassistant.core import CoreState, State
|
from tests.common import get_test_home_assistant, assert_setup_component
|
||||||
from homeassistant.setup import setup_component, async_setup_component
|
|
||||||
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
|
|
||||||
|
|
||||||
from tests.common import (
|
|
||||||
get_test_home_assistant, assert_setup_component, mock_component)
|
|
||||||
|
|
||||||
|
|
||||||
class TestTemplateSensor:
|
class TestTemplateSensor:
|
||||||
|
@ -188,36 +183,3 @@ class TestTemplateSensor:
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert self.hass.states.all() == []
|
assert self.hass.states.all() == []
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_restore_state(hass):
|
|
||||||
"""Ensure states are restored on startup."""
|
|
||||||
hass.data[DATA_RESTORE_CACHE] = {
|
|
||||||
'sensor.test_template_sensor':
|
|
||||||
State('sensor.test_template_sensor', 'It Test.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.state = CoreState.starting
|
|
||||||
mock_component(hass, 'recorder')
|
|
||||||
|
|
||||||
yield from async_setup_component(hass, 'sensor', {
|
|
||||||
'sensor': {
|
|
||||||
'platform': 'template',
|
|
||||||
'sensors': {
|
|
||||||
'test_template_sensor': {
|
|
||||||
'value_template':
|
|
||||||
"It {{ states.sensor.test_state.state }}."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
state = hass.states.get('sensor.test_template_sensor')
|
|
||||||
assert state.state == 'It Test.'
|
|
||||||
|
|
||||||
yield from hass.async_start()
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get('sensor.test_template_sensor')
|
|
||||||
assert state.state == 'It .'
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
"""The tests for the Template switch platform."""
|
"""The tests for the Template switch platform."""
|
||||||
import asyncio
|
from homeassistant.core import callback
|
||||||
|
|
||||||
from homeassistant.core import callback, State, CoreState
|
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
import homeassistant.components as core
|
import homeassistant.components as core
|
||||||
from homeassistant.const import STATE_ON, STATE_OFF
|
from homeassistant.const import STATE_ON, STATE_OFF
|
||||||
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
|
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
get_test_home_assistant, assert_setup_component, mock_component)
|
get_test_home_assistant, assert_setup_component)
|
||||||
|
|
||||||
|
|
||||||
class TestTemplateSwitch:
|
class TestTemplateSwitch:
|
||||||
|
@ -410,44 +407,3 @@ class TestTemplateSwitch:
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert len(self.calls) == 1
|
assert len(self.calls) == 1
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_restore_state(hass):
|
|
||||||
"""Ensure states are restored on startup."""
|
|
||||||
hass.data[DATA_RESTORE_CACHE] = {
|
|
||||||
'switch.test_template_switch':
|
|
||||||
State('switch.test_template_switch', 'on'),
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.state = CoreState.starting
|
|
||||||
mock_component(hass, 'recorder')
|
|
||||||
|
|
||||||
yield from setup.async_setup_component(hass, 'switch', {
|
|
||||||
'switch': {
|
|
||||||
'platform': 'template',
|
|
||||||
'switches': {
|
|
||||||
'test_template_switch': {
|
|
||||||
'value_template':
|
|
||||||
"{{ states.switch.test_state.state }}",
|
|
||||||
'turn_on': {
|
|
||||||
'service': 'switch.turn_on',
|
|
||||||
'entity_id': 'switch.test_state'
|
|
||||||
},
|
|
||||||
'turn_off': {
|
|
||||||
'service': 'switch.turn_off',
|
|
||||||
'entity_id': 'switch.test_state'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
state = hass.states.get('switch.test_template_switch')
|
|
||||||
assert state.state == 'on'
|
|
||||||
|
|
||||||
yield from hass.async_start()
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get('switch.test_template_switch')
|
|
||||||
assert state.state == 'unavailable'
|
|
||||||
|
|
|
@ -213,3 +213,162 @@ def test_async_schedule_update_ha_state(hass):
|
||||||
yield from hass.async_block_till_done()
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
assert update_call is True
|
assert update_call is True
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_async_pararell_updates_with_zero(hass):
|
||||||
|
"""Test pararell updates with 0 (disabled)."""
|
||||||
|
updates = []
|
||||||
|
test_lock = asyncio.Event(loop=hass.loop)
|
||||||
|
|
||||||
|
class AsyncEntity(entity.Entity):
|
||||||
|
|
||||||
|
def __init__(self, entity_id, count):
|
||||||
|
"""Initialize Async test entity."""
|
||||||
|
self.entity_id = entity_id
|
||||||
|
self.hass = hass
|
||||||
|
self._count = count
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_update(self):
|
||||||
|
"""Test update."""
|
||||||
|
updates.append(self._count)
|
||||||
|
yield from test_lock.wait()
|
||||||
|
|
||||||
|
ent_1 = AsyncEntity("sensor.test_1", 1)
|
||||||
|
ent_2 = AsyncEntity("sensor.test_2", 2)
|
||||||
|
|
||||||
|
ent_1.async_schedule_update_ha_state(True)
|
||||||
|
ent_2.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 2:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 2
|
||||||
|
assert updates == [1, 2]
|
||||||
|
|
||||||
|
test_lock.set()
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_async_pararell_updates_with_one(hass):
|
||||||
|
"""Test pararell updates with 1 (sequential)."""
|
||||||
|
updates = []
|
||||||
|
test_lock = asyncio.Lock(loop=hass.loop)
|
||||||
|
test_semephore = asyncio.Semaphore(1, loop=hass.loop)
|
||||||
|
|
||||||
|
yield from test_lock.acquire()
|
||||||
|
|
||||||
|
class AsyncEntity(entity.Entity):
|
||||||
|
|
||||||
|
def __init__(self, entity_id, count):
|
||||||
|
"""Initialize Async test entity."""
|
||||||
|
self.entity_id = entity_id
|
||||||
|
self.hass = hass
|
||||||
|
self._count = count
|
||||||
|
self.parallel_updates = test_semephore
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_update(self):
|
||||||
|
"""Test update."""
|
||||||
|
updates.append(self._count)
|
||||||
|
yield from test_lock.acquire()
|
||||||
|
|
||||||
|
ent_1 = AsyncEntity("sensor.test_1", 1)
|
||||||
|
ent_2 = AsyncEntity("sensor.test_2", 2)
|
||||||
|
ent_3 = AsyncEntity("sensor.test_3", 3)
|
||||||
|
|
||||||
|
ent_1.async_schedule_update_ha_state(True)
|
||||||
|
ent_2.async_schedule_update_ha_state(True)
|
||||||
|
ent_3.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 1:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 1
|
||||||
|
assert updates == [1]
|
||||||
|
|
||||||
|
test_lock.release()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 2:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 2
|
||||||
|
assert updates == [1, 2]
|
||||||
|
|
||||||
|
test_lock.release()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 3:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 3
|
||||||
|
assert updates == [1, 2, 3]
|
||||||
|
|
||||||
|
test_lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_async_pararell_updates_with_two(hass):
|
||||||
|
"""Test pararell updates with 2 (pararell)."""
|
||||||
|
updates = []
|
||||||
|
test_lock = asyncio.Lock(loop=hass.loop)
|
||||||
|
test_semephore = asyncio.Semaphore(2, loop=hass.loop)
|
||||||
|
|
||||||
|
yield from test_lock.acquire()
|
||||||
|
|
||||||
|
class AsyncEntity(entity.Entity):
|
||||||
|
|
||||||
|
def __init__(self, entity_id, count):
|
||||||
|
"""Initialize Async test entity."""
|
||||||
|
self.entity_id = entity_id
|
||||||
|
self.hass = hass
|
||||||
|
self._count = count
|
||||||
|
self.parallel_updates = test_semephore
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_update(self):
|
||||||
|
"""Test update."""
|
||||||
|
updates.append(self._count)
|
||||||
|
yield from test_lock.acquire()
|
||||||
|
|
||||||
|
ent_1 = AsyncEntity("sensor.test_1", 1)
|
||||||
|
ent_2 = AsyncEntity("sensor.test_2", 2)
|
||||||
|
ent_3 = AsyncEntity("sensor.test_3", 3)
|
||||||
|
ent_4 = AsyncEntity("sensor.test_4", 4)
|
||||||
|
|
||||||
|
ent_1.async_schedule_update_ha_state(True)
|
||||||
|
ent_2.async_schedule_update_ha_state(True)
|
||||||
|
ent_3.async_schedule_update_ha_state(True)
|
||||||
|
ent_4.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 2:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 2
|
||||||
|
assert updates == [1, 2]
|
||||||
|
|
||||||
|
test_lock.release()
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
test_lock.release()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(updates) == 4:
|
||||||
|
break
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
|
||||||
|
assert len(updates) == 4
|
||||||
|
assert updates == [1, 2, 3, 4]
|
||||||
|
|
||||||
|
test_lock.release()
|
||||||
|
yield from asyncio.sleep(0, loop=hass.loop)
|
||||||
|
test_lock.release()
|
||||||
|
|
|
@ -578,3 +578,79 @@ def test_platform_not_ready(hass):
|
||||||
yield from hass.async_block_till_done()
|
yield from hass.async_block_till_done()
|
||||||
assert len(platform1_setup.mock_calls) == 3
|
assert len(platform1_setup.mock_calls) == 3
|
||||||
assert 'test_domain.mod1' in hass.config.components
|
assert 'test_domain.mod1' in hass.config.components
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_pararell_updates_async_platform(hass):
|
||||||
|
"""Warn we log when platform setup takes a long time."""
|
||||||
|
platform = MockPlatform()
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def mock_update(*args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
platform.async_setup_platform = mock_update
|
||||||
|
|
||||||
|
loader.set_component('test_domain.platform', platform)
|
||||||
|
|
||||||
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
component._platforms = {}
|
||||||
|
|
||||||
|
yield from component.async_setup({
|
||||||
|
DOMAIN: {
|
||||||
|
'platform': 'platform',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
handle = list(component._platforms.values())[-1]
|
||||||
|
|
||||||
|
assert handle.parallel_updates is None
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_pararell_updates_async_platform_with_constant(hass):
|
||||||
|
"""Warn we log when platform setup takes a long time."""
|
||||||
|
platform = MockPlatform()
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def mock_update(*args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
platform.async_setup_platform = mock_update
|
||||||
|
platform.PARALLEL_UPDATES = 1
|
||||||
|
|
||||||
|
loader.set_component('test_domain.platform', platform)
|
||||||
|
|
||||||
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
component._platforms = {}
|
||||||
|
|
||||||
|
yield from component.async_setup({
|
||||||
|
DOMAIN: {
|
||||||
|
'platform': 'platform',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
handle = list(component._platforms.values())[-1]
|
||||||
|
|
||||||
|
assert handle.parallel_updates is not None
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_pararell_updates_sync_platform(hass):
|
||||||
|
"""Warn we log when platform setup takes a long time."""
|
||||||
|
platform = MockPlatform()
|
||||||
|
|
||||||
|
loader.set_component('test_domain.platform', platform)
|
||||||
|
|
||||||
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
component._platforms = {}
|
||||||
|
|
||||||
|
yield from component.async_setup({
|
||||||
|
DOMAIN: {
|
||||||
|
'platform': 'platform',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
handle = list(component._platforms.values())[-1]
|
||||||
|
|
||||||
|
assert handle.parallel_updates is not None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue