From 34324afbde4fa0cf8309ca55c5be58720b23a8c1 Mon Sep 17 00:00:00 2001 From: carstenschroeder Date: Sat, 30 Mar 2019 18:47:39 +0100 Subject: [PATCH] Prevent toogle to false at restart of ADS platforms (#22522) * Prevent toogle to false at restart * change to asyncio.run_coroutine_threadsafe --- homeassistant/components/ads/binary_sensor.py | 25 ++++++++++++++-- homeassistant/components/ads/light.py | 29 ++++++++++++++++--- homeassistant/components/ads/switch.py | 27 +++++++++++++++-- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/ads/binary_sensor.py b/homeassistant/components/ads/binary_sensor.py index 3b935156d18..91cd60771d9 100644 --- a/homeassistant/components/ads/binary_sensor.py +++ b/homeassistant/components/ads/binary_sensor.py @@ -1,5 +1,7 @@ """Support for ADS binary sensors.""" import logging +import asyncio +import async_timeout import voluptuous as vol @@ -41,10 +43,11 @@ class AdsBinarySensor(BinarySensorDevice): """Initialize ADS binary sensor.""" self._name = name self._unique_id = ads_var - self._state = False + self._state = None self._device_class = device_class or 'moving' self._ads_hub = ads_hub self.ads_var = ads_var + self._event = None async def async_added_to_hass(self): """Register device notification.""" @@ -52,11 +55,24 @@ class AdsBinarySensor(BinarySensorDevice): """Handle device notifications.""" _LOGGER.debug('Variable %s changed its value to %d', name, value) self._state = value + asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) self.schedule_update_ha_state() - self.hass.async_add_job( + async def async_event_set(): + """Set event in async context.""" + self._event.set() + + self._event = asyncio.Event() + + await self.hass.async_add_executor_job( self._ads_hub.add_device_notification, self.ads_var, self._ads_hub.PLCTYPE_BOOL, update) + try: + with async_timeout.timeout(10): + await self._event.wait() + except asyncio.TimeoutError: + _LOGGER.debug('Variable %s: Timeout during first update', + self.ads_var) @property def name(self): @@ -82,3 +98,8 @@ class AdsBinarySensor(BinarySensorDevice): def should_poll(self): """Return False because entity pushes its state to HA.""" return False + + @property + def available(self): + """Return False if state has not been updated yet.""" + return self._state is not None diff --git a/homeassistant/components/ads/light.py b/homeassistant/components/ads/light.py index c61fd813634..2ece1402907 100644 --- a/homeassistant/components/ads/light.py +++ b/homeassistant/components/ads/light.py @@ -1,5 +1,7 @@ """Support for ADS light sources.""" import logging +import asyncio +import async_timeout import voluptuous as vol @@ -30,7 +32,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = config.get(CONF_NAME) add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, - name)], True) + name)]) class AdsLight(Light): @@ -39,12 +41,13 @@ class AdsLight(Light): def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name): """Initialize AdsLight entity.""" self._ads_hub = ads_hub - self._on_state = False + self._on_state = None self._brightness = None self._name = name self._unique_id = ads_var_enable self.ads_var_enable = ads_var_enable self.ads_var_brightness = ads_var_brightness + self._event = None async def async_added_to_hass(self): """Register device notification.""" @@ -52,24 +55,37 @@ class AdsLight(Light): """Handle device notifications for state.""" _LOGGER.debug('Variable %s changed its value to %d', name, value) self._on_state = value + asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) self.schedule_update_ha_state() + async def async_event_set(): + """Set event in async context.""" + self._event.set() + def update_brightness(name, value): """Handle device notification for brightness.""" _LOGGER.debug('Variable %s changed its value to %d', name, value) self._brightness = value self.schedule_update_ha_state() - self.hass.async_add_executor_job( + self._event = asyncio.Event() + + await self.hass.async_add_executor_job( self._ads_hub.add_device_notification, self.ads_var_enable, self._ads_hub.PLCTYPE_BOOL, update_on_state ) if self.ads_var_brightness is not None: - self.hass.async_add_executor_job( + await self.hass.async_add_executor_job( self._ads_hub.add_device_notification, self.ads_var_brightness, self._ads_hub.PLCTYPE_INT, update_brightness ) + try: + with async_timeout.timeout(10): + await self._event.wait() + except asyncio.TimeoutError: + _LOGGER.debug('Variable %s: Timeout during first update', + self.ads_var_enable) @property def name(self): @@ -104,6 +120,11 @@ class AdsLight(Light): support = SUPPORT_BRIGHTNESS return support + @property + def available(self): + """Return False if state has not been updated yet.""" + return self._on_state is not None + def turn_on(self, **kwargs): """Turn the light on or set a specific dimmer value.""" brightness = kwargs.get(ATTR_BRIGHTNESS) diff --git a/homeassistant/components/ads/switch.py b/homeassistant/components/ads/switch.py index 094b4552349..3d2189d2ede 100644 --- a/homeassistant/components/ads/switch.py +++ b/homeassistant/components/ads/switch.py @@ -1,5 +1,7 @@ """Support for ADS switch platform.""" import logging +import asyncio +import async_timeout import voluptuous as vol @@ -29,7 +31,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = config.get(CONF_NAME) ads_var = config.get(CONF_ADS_VAR) - add_entities([AdsSwitch(ads_hub, name, ads_var)], True) + add_entities([AdsSwitch(ads_hub, name, ads_var)]) class AdsSwitch(ToggleEntity): @@ -38,10 +40,11 @@ class AdsSwitch(ToggleEntity): def __init__(self, ads_hub, name, ads_var): """Initialize the AdsSwitch entity.""" self._ads_hub = ads_hub - self._on_state = False + self._on_state = None self._name = name self._unique_id = ads_var self.ads_var = ads_var + self._event = None async def async_added_to_hass(self): """Register device notification.""" @@ -49,11 +52,24 @@ class AdsSwitch(ToggleEntity): """Handle device notification.""" _LOGGER.debug("Variable %s changed its value to %d", name, value) self._on_state = value + asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) self.schedule_update_ha_state() - self.hass.async_add_job( + async def async_event_set(): + """Set event in async context.""" + self._event.set() + + self._event = asyncio.Event() + + await self.hass.async_add_executor_job( self._ads_hub.add_device_notification, self.ads_var, self._ads_hub.PLCTYPE_BOOL, update) + try: + with async_timeout.timeout(10): + await self._event.wait() + except asyncio.TimeoutError: + _LOGGER.debug('Variable %s: Timeout during first update', + self.ads_var) @property def is_on(self): @@ -75,6 +91,11 @@ class AdsSwitch(ToggleEntity): """Return False because entity pushes its state to HA.""" return False + @property + def available(self): + """Return False if state has not been updated yet.""" + return self._on_state is not None + def turn_on(self, **kwargs): """Turn the switch on.""" self._ads_hub.write_by_name(