From 99f1ea9b59edf03a1155381677002698f6cede88 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 11 Dec 2016 23:39:20 +0100 Subject: [PATCH] Migrate alarm control panel to async (#4807) * Merge alarm control panel to async * fix lint --- .../alarm_control_panel/__init__.py | 106 ++++++++++++------ .../alarm_control_panel/alarmdotcom.py | 5 - .../alarm_control_panel/concord232.py | 9 -- .../alarm_control_panel/envisalink.py | 2 +- .../components/alarm_control_panel/manual.py | 8 +- .../components/alarm_control_panel/nx584.py | 9 -- .../alarm_control_panel/simplisafe.py | 8 -- .../alarm_control_panel/verisure.py | 3 - 8 files changed, 77 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 49decfc62fe..1b64431c7a1 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -4,6 +4,7 @@ Component to interface with an alarm control panel. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/alarm_control_panel/ """ +import asyncio import logging import os @@ -42,40 +43,6 @@ ALARM_SERVICE_SCHEMA = vol.Schema({ }) -def setup(hass, config): - """Track states and offer events for sensors.""" - component = EntityComponent( - logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) - - component.setup(config) - - def alarm_service_handler(service): - """Map services to methods on Alarm.""" - target_alarms = component.extract_from_service(service) - - code = service.data.get(ATTR_CODE) - - method = SERVICE_TO_METHOD[service.service] - - for alarm in target_alarms: - getattr(alarm, method)(code) - - for alarm in target_alarms: - if not alarm.should_poll: - continue - - alarm.update_ha_state(True) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - for service in SERVICE_TO_METHOD: - hass.services.register(DOMAIN, service, alarm_service_handler, - descriptions.get(service), - schema=ALARM_SERVICE_SCHEMA) - return True - - def alarm_disarm(hass, code=None, entity_id=None): """Send the alarm the command for disarm.""" data = {} @@ -120,6 +87,53 @@ def alarm_trigger(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) +@asyncio.coroutine +def async_setup(hass, config): + """Track states and offer events for sensors.""" + component = EntityComponent( + logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) + + yield from component.async_setup(config) + + @asyncio.coroutine + def async_alarm_service_handler(service): + """Map services to methods on Alarm.""" + target_alarms = component.async_extract_from_service(service) + + code = service.data.get(ATTR_CODE) + + method = "async_{}".format(SERVICE_TO_METHOD[service.service]) + + for alarm in target_alarms: + yield from getattr(alarm, method)(code) + + update_tasks = [] + for alarm in target_alarms: + if not alarm.should_poll: + continue + + update_coro = hass.loop.create_task( + alarm.async_update_ha_state(True)) + if hasattr(alarm, 'async_update'): + update_tasks.append(hass.loop.create_task(update_coro)) + else: + yield from update_coro + + if update_tasks: + yield from asyncio.wait(update_tasks, loop=hass.loop) + + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, os.path.join( + os.path.dirname(__file__), 'services.yaml')) + + for service in SERVICE_TO_METHOD: + hass.services.async_register( + DOMAIN, service, async_alarm_service_handler, + descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) + + return True + + # pylint: disable=no-self-use class AlarmControlPanel(Entity): """An abstract class for alarm control devices.""" @@ -138,18 +152,42 @@ class AlarmControlPanel(Entity): """Send disarm command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_disarm(self, code=None): + """Send disarm command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_disarm, code) + def alarm_arm_home(self, code=None): """Send arm home command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_arm_home(self, code=None): + """Send arm home command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_arm_home, code) + def alarm_arm_away(self, code=None): """Send arm away command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_arm_away(self, code=None): + """Send arm away command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_arm_away, code) + def alarm_trigger(self, code=None): """Send alarm trigger command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_trigger(self, code=None): + """Send alarm trigger command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_trigger, code) + @property def state_attributes(self): """Return the state attributes.""" diff --git a/homeassistant/components/alarm_control_panel/alarmdotcom.py b/homeassistant/components/alarm_control_panel/alarmdotcom.py index cd37fc6a828..07f90cf4476 100644 --- a/homeassistant/components/alarm_control_panel/alarmdotcom.py +++ b/homeassistant/components/alarm_control_panel/alarmdotcom.py @@ -56,11 +56,6 @@ class AlarmDotCom(alarm.AlarmControlPanel): self._password = password self._state = STATE_UNKNOWN - @property - def should_poll(self): - """No polling needed.""" - return True - def update(self): """Fetch the latest state.""" self._state = self._alarm.state diff --git a/homeassistant/components/alarm_control_panel/concord232.py b/homeassistant/components/alarm_control_panel/concord232.py index 0bdcf274c08..de153a9e0a5 100755 --- a/homeassistant/components/alarm_control_panel/concord232.py +++ b/homeassistant/components/alarm_control_panel/concord232.py @@ -71,11 +71,6 @@ class Concord232Alarm(alarm.AlarmControlPanel): self._alarm.last_partition_update = datetime.datetime.now() self.update() - @property - def should_poll(self): - """Polling needed.""" - return True - @property def name(self): """Return the name of the device.""" @@ -126,7 +121,3 @@ class Concord232Alarm(alarm.AlarmControlPanel): def alarm_arm_away(self, code=None): """Send arm away command.""" self._alarm.arm('auto') - - def alarm_trigger(self, code=None): - """Alarm trigger command.""" - raise NotImplementedError() diff --git a/homeassistant/components/alarm_control_panel/envisalink.py b/homeassistant/components/alarm_control_panel/envisalink.py index e84320738a2..96b0fc83ea7 100644 --- a/homeassistant/components/alarm_control_panel/envisalink.py +++ b/homeassistant/components/alarm_control_panel/envisalink.py @@ -97,7 +97,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel): def _update_callback(self, partition): """Update HA state, if needed.""" if partition is None or int(partition) == self._partition_number: - self.hass.async_add_job(self.update_ha_state) + self.hass.async_add_job(self.async_update_ha_state()) @property def code_format(self): diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 073d55508ed..cc67795d713 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -116,7 +116,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_DISARMED self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() def alarm_arm_home(self, code=None): """Send arm home command.""" @@ -125,7 +125,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_ARMED_HOME self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._pending_time: track_point_in_time( @@ -139,7 +139,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_ARMED_AWAY self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._pending_time: track_point_in_time( @@ -151,7 +151,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._pre_trigger_state = self._state self._state = STATE_ALARM_TRIGGERED self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._trigger_time: track_point_in_time( diff --git a/homeassistant/components/alarm_control_panel/nx584.py b/homeassistant/components/alarm_control_panel/nx584.py index cb32fc924e6..58ec8d915ab 100644 --- a/homeassistant/components/alarm_control_panel/nx584.py +++ b/homeassistant/components/alarm_control_panel/nx584.py @@ -62,11 +62,6 @@ class NX584Alarm(alarm.AlarmControlPanel): self._alarm.list_zones() self._state = STATE_UNKNOWN - @property - def should_poll(self): - """Polling needed.""" - return True - @property def name(self): """Return the name of the device.""" @@ -122,7 +117,3 @@ class NX584Alarm(alarm.AlarmControlPanel): def alarm_arm_away(self, code=None): """Send arm away command.""" self._alarm.arm('exit') - - def alarm_trigger(self, code=None): - """Alarm trigger command.""" - raise NotImplementedError() diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index 40ebfb2f39f..7a8f8409c59 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -61,11 +61,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): else: self._state = STATE_UNKNOWN - @property - def should_poll(self): - """Poll the SimpliSafe API.""" - return True - @property def name(self): """Return the name of the device.""" @@ -104,7 +99,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('off') _LOGGER.info('SimpliSafe alarm disarming') - self.update() def alarm_arm_home(self, code=None): """Send arm home command.""" @@ -112,7 +106,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('home') _LOGGER.info('SimpliSafe alarm arming home') - self.update() def alarm_arm_away(self, code=None): """Send arm away command.""" @@ -120,7 +113,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('away') _LOGGER.info('SimpliSafe alarm arming away') - self.update() def _validate_code(self, code, state): """Validate given code.""" diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 4ef07c68f59..c1a394fe462 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -84,18 +84,15 @@ class VerisureAlarm(alarm.AlarmControlPanel): hub.my_pages.alarm.set(code, 'DISARMED') _LOGGER.info('verisure alarm disarming') hub.my_pages.alarm.wait_while_pending() - self.update() def alarm_arm_home(self, code=None): """Send arm home command.""" hub.my_pages.alarm.set(code, 'ARMED_HOME') _LOGGER.info('verisure alarm arming home') hub.my_pages.alarm.wait_while_pending() - self.update() def alarm_arm_away(self, code=None): """Send arm away command.""" hub.my_pages.alarm.set(code, 'ARMED_AWAY') _LOGGER.info('verisure alarm arming away') hub.my_pages.alarm.wait_while_pending() - self.update()