From c8f2810fac989d2a8275bfb92603a5877113beed Mon Sep 17 00:00:00 2001
From: Martin Hjelmare <marhje52@kth.se>
Date: Sun, 1 Apr 2018 17:36:26 +0200
Subject: [PATCH] Make mysensors updates and platform setup async (#13603)

* Use async updates but keep methods that interact with mysensors
  gateway thread, eg turn_on and turn_off, non async.
* Use Python 3.5 async syntax.
---
 .../components/binary_sensor/mysensors.py     |  7 +++--
 homeassistant/components/climate/mysensors.py | 12 ++++---
 homeassistant/components/cover/mysensors.py   |  8 +++--
 .../components/device_tracker/mysensors.py    | 20 ++++++------
 homeassistant/components/light/mysensors.py   | 31 ++++++++++---------
 homeassistant/components/mysensors.py         | 19 ++++++------
 homeassistant/components/notify/mysensors.py  |  4 +--
 homeassistant/components/sensor/mysensors.py  |  6 ++--
 homeassistant/components/switch/mysensors.py  | 15 ++++-----
 9 files changed, 65 insertions(+), 57 deletions(-)

diff --git a/homeassistant/components/binary_sensor/mysensors.py b/homeassistant/components/binary_sensor/mysensors.py
index 1e9359b6902..21443021193 100644
--- a/homeassistant/components/binary_sensor/mysensors.py
+++ b/homeassistant/components/binary_sensor/mysensors.py
@@ -21,11 +21,12 @@ SENSORS = {
 }
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
-    """Set up the MySensors platform for binary sensors."""
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
+    """Set up the mysensors platform for binary sensors."""
     mysensors.setup_mysensors_platform(
         hass, DOMAIN, discovery_info, MySensorsBinarySensor,
-        add_devices=add_devices)
+        async_add_devices=async_add_devices)
 
 
 class MySensorsBinarySensor(mysensors.MySensorsEntity, BinarySensorDevice):
diff --git a/homeassistant/components/climate/mysensors.py b/homeassistant/components/climate/mysensors.py
index b526d8b066c..2545094ceec 100644
--- a/homeassistant/components/climate/mysensors.py
+++ b/homeassistant/components/climate/mysensors.py
@@ -31,10 +31,12 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_HIGH |
                  SUPPORT_OPERATION_MODE)
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
-    """Set up the MySensors climate."""
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
+    """Set up the mysensors climate."""
     mysensors.setup_mysensors_platform(
-        hass, DOMAIN, discovery_info, MySensorsHVAC, add_devices=add_devices)
+        hass, DOMAIN, discovery_info, MySensorsHVAC,
+        async_add_devices=async_add_devices)
 
 
 class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
@@ -163,8 +165,8 @@ class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
             self._values[self.value_type] = operation_mode
             self.schedule_update_ha_state()
 
-    def update(self):
+    async def async_update(self):
         """Update the controller with the latest value from a sensor."""
-        super().update()
+        await super().async_update()
         self._values[self.value_type] = DICT_MYS_TO_HA[
             self._values[self.value_type]]
diff --git a/homeassistant/components/cover/mysensors.py b/homeassistant/components/cover/mysensors.py
index 391d2a22bda..669a7ce6723 100644
--- a/homeassistant/components/cover/mysensors.py
+++ b/homeassistant/components/cover/mysensors.py
@@ -9,10 +9,12 @@ from homeassistant.components.cover import ATTR_POSITION, DOMAIN, CoverDevice
 from homeassistant.const import STATE_OFF, STATE_ON
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
-    """Set up the MySensors platform for covers."""
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
+    """Set up the mysensors platform for covers."""
     mysensors.setup_mysensors_platform(
-        hass, DOMAIN, discovery_info, MySensorsCover, add_devices=add_devices)
+        hass, DOMAIN, discovery_info, MySensorsCover,
+        async_add_devices=async_add_devices)
 
 
 class MySensorsCover(mysensors.MySensorsEntity, CoverDevice):
diff --git a/homeassistant/components/device_tracker/mysensors.py b/homeassistant/components/device_tracker/mysensors.py
index f68eb361ca0..b0d29bf0566 100644
--- a/homeassistant/components/device_tracker/mysensors.py
+++ b/homeassistant/components/device_tracker/mysensors.py
@@ -6,15 +6,15 @@ https://home-assistant.io/components/device_tracker.mysensors/
 """
 from homeassistant.components import mysensors
 from homeassistant.components.device_tracker import DOMAIN
-from homeassistant.helpers.dispatcher import dispatcher_connect
+from homeassistant.helpers.dispatcher import async_dispatcher_connect
 from homeassistant.util import slugify
 
 
-def setup_scanner(hass, config, see, discovery_info=None):
+async def async_setup_scanner(hass, config, async_see, discovery_info=None):
     """Set up the MySensors device scanner."""
     new_devices = mysensors.setup_mysensors_platform(
         hass, DOMAIN, discovery_info, MySensorsDeviceScanner,
-        device_args=(see, ))
+        device_args=(async_see, ))
     if not new_devices:
         return False
 
@@ -22,9 +22,9 @@ def setup_scanner(hass, config, see, discovery_info=None):
         dev_id = (
             id(device.gateway), device.node_id, device.child_id,
             device.value_type)
-        dispatcher_connect(
+        async_dispatcher_connect(
             hass, mysensors.SIGNAL_CALLBACK.format(*dev_id),
-            device.update_callback)
+            device.async_update_callback)
 
     return True
 
@@ -32,20 +32,20 @@ def setup_scanner(hass, config, see, discovery_info=None):
 class MySensorsDeviceScanner(mysensors.MySensorsDevice):
     """Represent a MySensors scanner."""
 
-    def __init__(self, see, *args):
+    def __init__(self, async_see, *args):
         """Set up instance."""
         super().__init__(*args)
-        self.see = see
+        self.async_see = async_see
 
-    def update_callback(self):
+    async def async_update_callback(self):
         """Update the device."""
-        self.update()
+        await self.async_update()
         node = self.gateway.sensors[self.node_id]
         child = node.children[self.child_id]
         position = child.values[self.value_type]
         latitude, longitude, _ = position.split(',')
 
-        self.see(
+        await self.async_see(
             dev_id=slugify(self.name),
             host_name=self.name,
             gps=(latitude, longitude),
diff --git a/homeassistant/components/light/mysensors.py b/homeassistant/components/light/mysensors.py
index 7aa1e754c43..6e41e0f5693 100644
--- a/homeassistant/components/light/mysensors.py
+++ b/homeassistant/components/light/mysensors.py
@@ -15,8 +15,9 @@ import homeassistant.util.color as color_util
 SUPPORT_MYSENSORS_RGBW = SUPPORT_COLOR | SUPPORT_WHITE_VALUE
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
-    """Set up the MySensors platform for lights."""
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
+    """Set up the mysensors platform for lights."""
     device_class_map = {
         'S_DIMMER': MySensorsLightDimmer,
         'S_RGB_LIGHT': MySensorsLightRGB,
@@ -24,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
     }
     mysensors.setup_mysensors_platform(
         hass, DOMAIN, discovery_info, device_class_map,
-        add_devices=add_devices)
+        async_add_devices=async_add_devices)
 
 
 class MySensorsLight(mysensors.MySensorsEntity, Light):
@@ -140,12 +141,12 @@ class MySensorsLight(mysensors.MySensorsEntity, Light):
             self._values[value_type] = STATE_OFF
             self.schedule_update_ha_state()
 
-    def _update_light(self):
+    def _async_update_light(self):
         """Update the controller with values from light child."""
         value_type = self.gateway.const.SetReq.V_LIGHT
         self._state = self._values[value_type] == STATE_ON
 
-    def _update_dimmer(self):
+    def _async_update_dimmer(self):
         """Update the controller with values from dimmer child."""
         value_type = self.gateway.const.SetReq.V_DIMMER
         if value_type in self._values:
@@ -153,7 +154,7 @@ class MySensorsLight(mysensors.MySensorsEntity, Light):
             if self._brightness == 0:
                 self._state = False
 
-    def _update_rgb_or_w(self):
+    def _async_update_rgb_or_w(self):
         """Update the controller with values from RGB or RGBW child."""
         value = self._values[self.value_type]
         color_list = rgb_hex_to_rgb_list(value)
@@ -177,11 +178,11 @@ class MySensorsLightDimmer(MySensorsLight):
         if self.gateway.optimistic:
             self.schedule_update_ha_state()
 
-    def update(self):
+    async def async_update(self):
         """Update the controller with the latest value from a sensor."""
-        super().update()
-        self._update_light()
-        self._update_dimmer()
+        await super().async_update()
+        self._async_update_light()
+        self._async_update_dimmer()
 
 
 class MySensorsLightRGB(MySensorsLight):
@@ -203,12 +204,12 @@ class MySensorsLightRGB(MySensorsLight):
         if self.gateway.optimistic:
             self.schedule_update_ha_state()
 
-    def update(self):
+    async def async_update(self):
         """Update the controller with the latest value from a sensor."""
-        super().update()
-        self._update_light()
-        self._update_dimmer()
-        self._update_rgb_or_w()
+        await super().async_update()
+        self._async_update_light()
+        self._async_update_dimmer()
+        self._async_update_rgb_or_w()
 
 
 class MySensorsLightRGBW(MySensorsLightRGB):
diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py
index 74df860a0fc..17c9129a31d 100644
--- a/homeassistant/components/mysensors.py
+++ b/homeassistant/components/mysensors.py
@@ -4,7 +4,6 @@ Connect to a MySensors gateway via pymysensors API.
 For more details about this component, please refer to the documentation at
 https://home-assistant.io/components/mysensors/
 """
-import asyncio
 from collections import defaultdict
 import logging
 import os
@@ -519,11 +518,12 @@ def get_mysensors_gateway(hass, gateway_id):
     return gateways.get(gateway_id)
 
 
+@callback
 def setup_mysensors_platform(
         hass, domain, discovery_info, device_class, device_args=None,
-        add_devices=None):
+        async_add_devices=None):
     """Set up a MySensors platform."""
-    # Only act if called via MySensors by discovery event.
+    # Only act if called via mysensors by discovery event.
     # Otherwise gateway is not setup.
     if not discovery_info:
         return
@@ -552,8 +552,8 @@ def setup_mysensors_platform(
         new_devices.append(devices[dev_id])
     if new_devices:
         _LOGGER.info("Adding new devices: %s", new_devices)
-        if add_devices is not None:
-            add_devices(new_devices, True)
+        if async_add_devices is not None:
+            async_add_devices(new_devices, True)
     return new_devices
 
 
@@ -596,7 +596,7 @@ class MySensorsDevice(object):
 
         return attr
 
-    def update(self):
+    async def async_update(self):
         """Update the controller with the latest value from a sensor."""
         node = self.gateway.sensors[self.node_id]
         child = node.children[self.child_id]
@@ -629,14 +629,13 @@ class MySensorsEntity(MySensorsDevice, Entity):
         return self.value_type in self._values
 
     @callback
-    def _async_update_callback(self):
+    def async_update_callback(self):
         """Update the entity."""
         self.async_schedule_update_ha_state(True)
 
-    @asyncio.coroutine
-    def async_added_to_hass(self):
+    async def async_added_to_hass(self):
         """Register update callback."""
         dev_id = id(self.gateway), self.node_id, self.child_id, self.value_type
         async_dispatcher_connect(
             self.hass, SIGNAL_CALLBACK.format(*dev_id),
-            self._async_update_callback)
+            self.async_update_callback)
diff --git a/homeassistant/components/notify/mysensors.py b/homeassistant/components/notify/mysensors.py
index 8ae697048f5..257b5995446 100644
--- a/homeassistant/components/notify/mysensors.py
+++ b/homeassistant/components/notify/mysensors.py
@@ -9,12 +9,12 @@ from homeassistant.components.notify import (
     ATTR_TARGET, DOMAIN, BaseNotificationService)
 
 
-def get_service(hass, config, discovery_info=None):
+async def async_get_service(hass, config, discovery_info=None):
     """Get the MySensors notification service."""
     new_devices = mysensors.setup_mysensors_platform(
         hass, DOMAIN, discovery_info, MySensorsNotificationDevice)
     if not new_devices:
-        return
+        return None
     return MySensorsNotificationService(hass)
 
 
diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py
index 66c36a8d9b1..669ef3998de 100644
--- a/homeassistant/components/sensor/mysensors.py
+++ b/homeassistant/components/sensor/mysensors.py
@@ -34,10 +34,12 @@ SENSORS = {
 }
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
     """Set up the MySensors platform for sensors."""
     mysensors.setup_mysensors_platform(
-        hass, DOMAIN, discovery_info, MySensorsSensor, add_devices=add_devices)
+        hass, DOMAIN, discovery_info, MySensorsSensor,
+        async_add_devices=async_add_devices)
 
 
 class MySensorsSensor(mysensors.MySensorsEntity):
diff --git a/homeassistant/components/switch/mysensors.py b/homeassistant/components/switch/mysensors.py
index b4a1dcde3e6..c0f45cad861 100644
--- a/homeassistant/components/switch/mysensors.py
+++ b/homeassistant/components/switch/mysensors.py
@@ -20,7 +20,8 @@ SEND_IR_CODE_SERVICE_SCHEMA = vol.Schema({
 })
 
 
-def setup_platform(hass, config, add_devices, discovery_info=None):
+async def async_setup_platform(
+        hass, config, async_add_devices, discovery_info=None):
     """Set up the mysensors platform for switches."""
     device_class_map = {
         'S_DOOR': MySensorsSwitch,
@@ -39,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
     }
     mysensors.setup_mysensors_platform(
         hass, DOMAIN, discovery_info, device_class_map,
-        add_devices=add_devices)
+        async_add_devices=async_add_devices)
 
     def send_ir_code_service(service):
         """Set IR code as device state attribute."""
@@ -59,9 +60,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
         for device in _devices:
             device.turn_on(**kwargs)
 
-    hass.services.register(DOMAIN, SERVICE_SEND_IR_CODE,
-                           send_ir_code_service,
-                           schema=SEND_IR_CODE_SERVICE_SCHEMA)
+    hass.services.async_register(
+        DOMAIN, SERVICE_SEND_IR_CODE, send_ir_code_service,
+        schema=SEND_IR_CODE_SERVICE_SCHEMA)
 
 
 class MySensorsSwitch(mysensors.MySensorsEntity, SwitchDevice):
@@ -143,7 +144,7 @@ class MySensorsIRSwitch(MySensorsSwitch):
             self._values[set_req.V_LIGHT] = STATE_OFF
             self.schedule_update_ha_state()
 
-    def update(self):
+    async def async_update(self):
         """Update the controller with the latest value from a sensor."""
-        super().update()
+        await super().async_update()
         self._ir_code = self._values.get(self.value_type)
-- 
GitLab