From 08a65a3b31eba44ad094a8473bc13df3662eb4d3 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 29 Oct 2016 21:19:27 +0200 Subject: [PATCH] Async input_*/zone migration (#4095) * Async input_* * Async zone component * rename service callback --- homeassistant/components/input_boolean.py | 29 ++++++++------- homeassistant/components/input_select.py | 45 +++++++++++++---------- homeassistant/components/input_slider.py | 21 ++++++----- homeassistant/components/zone.py | 15 +++++--- homeassistant/helpers/__init__.py | 6 ++- 5 files changed, 68 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/input_boolean.py b/homeassistant/components/input_boolean.py index 0477bb1dbfb..fdc514f957f 100644 --- a/homeassistant/components/input_boolean.py +++ b/homeassistant/components/input_boolean.py @@ -4,10 +4,12 @@ Component to keep track of user controlled booleans for within automation. For more details about this component, please refer to the documentation at https://home-assistant.io/components/input_boolean/ """ +import asyncio import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.const import ( ATTR_ENTITY_ID, CONF_ICON, CONF_NAME, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_TOGGLE, STATE_ON) @@ -55,7 +57,8 @@ def toggle(hass, entity_id): hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Set up input boolean.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -74,9 +77,10 @@ def setup(hass, config): if not entities: return False - def handler_service(service): + @callback + def async_handler_service(service): """Handle a calls to the input boolean services.""" - target_inputs = component.extract_from_service(service) + target_inputs = component.async_extract_from_service(service) for input_b in target_inputs: if service.service == SERVICE_TURN_ON: @@ -86,15 +90,14 @@ def setup(hass, config): else: input_b.toggle() - hass.services.register(DOMAIN, SERVICE_TURN_OFF, handler_service, - schema=SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_TURN_ON, handler_service, - schema=SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_TOGGLE, handler_service, - schema=SERVICE_SCHEMA) - - component.add_entities(entities) + hass.services.async_register( + DOMAIN, SERVICE_TURN_OFF, async_handler_service, schema=SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_TURN_ON, async_handler_service, schema=SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_TOGGLE, async_handler_service, schema=SERVICE_SCHEMA) + yield from component.async_add_entities(entities) return True @@ -131,9 +134,9 @@ class InputBoolean(ToggleEntity): def turn_on(self, **kwargs): """Turn the entity on.""" self._state = True - self.update_ha_state() + self.hass.loop.create_task(self.async_update_ha_state()) def turn_off(self, **kwargs): """Turn the entity off.""" self._state = False - self.update_ha_state() + self.hass.loop.create_task(self.async_update_ha_state()) diff --git a/homeassistant/components/input_select.py b/homeassistant/components/input_select.py index f94d8200d00..d309bf5c709 100644 --- a/homeassistant/components/input_select.py +++ b/homeassistant/components/input_select.py @@ -4,10 +4,12 @@ Component to offer a way to select an option from a list. For more details about this component, please refer to the documentation at https://home-assistant.io/components/input_select/ """ +import asyncio import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity @@ -86,7 +88,8 @@ def select_previous(hass, entity_id): }) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Setup input select.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -102,41 +105,43 @@ def setup(hass, config): if not entities: return False - def select_option_service(call): + @callback + def async_select_option_service(call): """Handle a calls to the input select option service.""" - target_inputs = component.extract_from_service(call) + target_inputs = component.async_extract_from_service(call) for input_select in target_inputs: input_select.select_option(call.data[ATTR_OPTION]) - hass.services.register(DOMAIN, SERVICE_SELECT_OPTION, - select_option_service, - schema=SERVICE_SELECT_OPTION_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_SELECT_OPTION, async_select_option_service, + schema=SERVICE_SELECT_OPTION_SCHEMA) - def select_next_service(call): + @callback + def async_select_next_service(call): """Handle a calls to the input select next service.""" - target_inputs = component.extract_from_service(call) + target_inputs = component.async_extract_from_service(call) for input_select in target_inputs: input_select.offset_index(1) - hass.services.register(DOMAIN, SERVICE_SELECT_NEXT, - select_next_service, - schema=SERVICE_SELECT_NEXT_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_SELECT_NEXT, async_select_next_service, + schema=SERVICE_SELECT_NEXT_SCHEMA) - def select_previous_service(call): + @callback + def async_select_previous_service(call): """Handle a calls to the input select previous service.""" - target_inputs = component.extract_from_service(call) + target_inputs = component.async_extract_from_service(call) for input_select in target_inputs: input_select.offset_index(-1) - hass.services.register(DOMAIN, SERVICE_SELECT_PREVIOUS, - select_previous_service, - schema=SERVICE_SELECT_PREVIOUS_SCHEMA) - - component.add_entities(entities) + hass.services.async_register( + DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service, + schema=SERVICE_SELECT_PREVIOUS_SCHEMA) + yield from component.async_add_entities(entities) return True @@ -186,11 +191,11 @@ class InputSelect(Entity): option, ', '.join(self._options)) return self._current_option = option - self.update_ha_state() + self.hass.loop.create_task(self.async_update_ha_state()) def offset_index(self, offset): """Offset current index.""" current_index = self._options.index(self._current_option) new_index = (current_index + offset) % len(self._options) self._current_option = self._options[new_index] - self.update_ha_state() + self.hass.loop.create_task(self.async_update_ha_state()) diff --git a/homeassistant/components/input_slider.py b/homeassistant/components/input_slider.py index 91ebbd844fc..f83d643cb5d 100644 --- a/homeassistant/components/input_slider.py +++ b/homeassistant/components/input_slider.py @@ -4,10 +4,12 @@ Component to offer a way to select a value from a slider. For more details about this component, please refer to the documentation at https://home-assistant.io/components/input_slider/ """ +import asyncio import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_NAME) import homeassistant.helpers.config_validation as cv @@ -71,7 +73,8 @@ def select_value(hass, entity_id, value): }) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Set up input slider.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -92,19 +95,19 @@ def setup(hass, config): if not entities: return False - def select_value_service(call): + @callback + def async_select_value_service(call): """Handle a calls to the input slider services.""" - target_inputs = component.extract_from_service(call) + target_inputs = component.async_extract_from_service(call) for input_slider in target_inputs: input_slider.select_value(call.data[ATTR_VALUE]) - hass.services.register(DOMAIN, SERVICE_SELECT_VALUE, - select_value_service, - schema=SERVICE_SELECT_VALUE_SCHEMA) - - component.add_entities(entities) + hass.services.async_register( + DOMAIN, SERVICE_SELECT_VALUE, async_select_value_service, + schema=SERVICE_SELECT_VALUE_SCHEMA) + yield from component.async_add_entities(entities) return True @@ -166,4 +169,4 @@ class InputSlider(Entity): num_value, self._minimum, self._maximum) return self._current_value = num_value - self.update_ha_state() + self.hass.loop.create_task(self.async_update_ha_state()) diff --git a/homeassistant/components/zone.py b/homeassistant/components/zone.py index ba5e1d6c9fc..a7c98dcd91c 100644 --- a/homeassistant/components/zone.py +++ b/homeassistant/components/zone.py @@ -4,6 +4,7 @@ Support for the definition of zones. For more details about this component, please refer to the documentation at https://home-assistant.io/components/zone/ """ +import asyncio import logging import voluptuous as vol @@ -12,7 +13,7 @@ from homeassistant.const import ( ATTR_HIDDEN, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_ICON) from homeassistant.helpers import config_per_platform -from homeassistant.helpers.entity import Entity, generate_entity_id +from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.util.location import distance import homeassistant.helpers.config_validation as cv @@ -87,16 +88,19 @@ def in_zone(zone, latitude, longitude, radius=0): return zone_dist - radius < zone.attributes[ATTR_RADIUS] -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Setup zone.""" entities = set() + tasks = [] for _, entry in config_per_platform(config, DOMAIN): name = entry.get(CONF_NAME) zone = Zone(hass, name, entry[CONF_LATITUDE], entry[CONF_LONGITUDE], entry.get(CONF_RADIUS), entry.get(CONF_ICON), entry.get(CONF_PASSIVE)) - zone.entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, entities) - zone.update_ha_state() + zone.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, name, + entities) + tasks.append(zone.async_update_ha_state()) entities.add(zone.entity_id) if ENTITY_ID_HOME not in entities: @@ -104,8 +108,9 @@ def setup(hass, config): hass.config.latitude, hass.config.longitude, DEFAULT_RADIUS, ICON_HOME, False) zone.entity_id = ENTITY_ID_HOME - zone.update_ha_state() + tasks.append(zone.async_update_ha_state()) + yield from asyncio.gather(*tasks, loop=hass.loop) return True diff --git a/homeassistant/helpers/__init__.py b/homeassistant/helpers/__init__.py index 3e45d3ecb83..0fc75a476f6 100644 --- a/homeassistant/helpers/__init__.py +++ b/homeassistant/helpers/__init__.py @@ -19,6 +19,7 @@ def config_per_platform(config: ConfigType, """Generator to break a component config into different platforms. For example, will find 'switch', 'switch 2', 'switch 3', .. etc + Async friendly. """ for config_key in extract_domain_configs(config, domain): platform_config = config[config_key] @@ -38,6 +39,9 @@ def config_per_platform(config: ConfigType, def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]: - """Extract keys from config for given domain name.""" + """Extract keys from config for given domain name. + + Async friendly. + """ pattern = re.compile(r'^{}(| .+)$'.format(domain)) return [key for key in config.keys() if pattern.match(key)]