From 94c803d83b59918d457062f69b26003e8dd90659 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 16 Apr 2021 18:01:24 -1000 Subject: [PATCH] Cancel tuya updates on the stop event (#49324) --- homeassistant/components/tuya/__init__.py | 46 +++++++++++++++-------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index 1f16d131e39..6dacc2e2749 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -14,7 +14,12 @@ from tuyaha.tuyaapi import ( import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import CONF_PASSWORD, CONF_PLATFORM, CONF_USERNAME +from homeassistant.const import ( + CONF_PASSWORD, + CONF_PLATFORM, + CONF_USERNAME, + EVENT_HOMEASSISTANT_STOP, +) from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv @@ -61,6 +66,7 @@ TUYA_TYPE_TO_HA = { } TUYA_TRACKER = "tuya_tracker" +STOP_CANCEL = "stop_event_cancel" CONFIG_SCHEMA = vol.Schema( vol.All( @@ -139,8 +145,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): raise ConfigEntryNotReady() from exc except TuyaAPIRateLimitException as exc: - _LOGGER.error("Tuya login rate limited") - raise ConfigEntryNotReady() from exc + raise ConfigEntryNotReady("Tuya login rate limited") from exc except TuyaAPIException as exc: _LOGGER.error( @@ -149,7 +154,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) return False - hass.data[DOMAIN] = { + domain_data = hass.data[DOMAIN] = { TUYA_DATA: tuya, TUYA_DEVICES_CONF: entry.options.copy(), TUYA_TRACKER: None, @@ -174,22 +179,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): dev_type = device.device_type() if ( dev_type in TUYA_TYPE_TO_HA - and device.object_id() not in hass.data[DOMAIN]["entities"] + and device.object_id() not in domain_data["entities"] ): ha_type = TUYA_TYPE_TO_HA[dev_type] if ha_type not in device_type_list: device_type_list[ha_type] = [] device_type_list[ha_type].append(device.object_id()) - hass.data[DOMAIN]["entities"][device.object_id()] = None + domain_data["entities"][device.object_id()] = None for ha_type, dev_ids in device_type_list.items(): config_entries_key = f"{ha_type}.tuya" - if config_entries_key not in hass.data[DOMAIN][ENTRY_IS_SETUP]: - hass.data[DOMAIN]["pending"][ha_type] = dev_ids + if config_entries_key not in domain_data[ENTRY_IS_SETUP]: + domain_data["pending"][ha_type] = dev_ids hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, ha_type) ) - hass.data[DOMAIN][ENTRY_IS_SETUP].add(config_entries_key) + domain_data[ENTRY_IS_SETUP].add(config_entries_key) else: async_dispatcher_send(hass, TUYA_DISCOVERY_NEW.format(ha_type), dev_ids) @@ -212,15 +217,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): newlist_ids = [] for device in device_list: newlist_ids.append(device.object_id()) - for dev_id in list(hass.data[DOMAIN]["entities"]): + for dev_id in list(domain_data["entities"]): if dev_id not in newlist_ids: async_dispatcher_send(hass, SIGNAL_DELETE_ENTITY, dev_id) - hass.data[DOMAIN]["entities"].pop(dev_id) + domain_data["entities"].pop(dev_id) - hass.data[DOMAIN][TUYA_TRACKER] = async_track_time_interval( + domain_data[TUYA_TRACKER] = async_track_time_interval( hass, async_poll_devices_update, timedelta(minutes=2) ) + @callback + def _async_cancel_tuya_tracker(event): + domain_data[TUYA_TRACKER]() + + domain_data[STOP_CANCEL] = hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STOP, _async_cancel_tuya_tracker + ) + hass.services.async_register( DOMAIN, SERVICE_PULL_DEVICES, async_poll_devices_update ) @@ -236,19 +249,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unloading the Tuya platforms.""" + domain_data = hass.data[DOMAIN] + unload_ok = all( await asyncio.gather( *[ hass.config_entries.async_forward_entry_unload( entry, platform.split(".", 1)[0] ) - for platform in hass.data[DOMAIN][ENTRY_IS_SETUP] + for platform in domain_data[ENTRY_IS_SETUP] ] ) ) if unload_ok: - hass.data[DOMAIN]["listener"]() - hass.data[DOMAIN][TUYA_TRACKER]() + domain_data["listener"]() + domain_data[STOP_CANCEL]() + domain_data[TUYA_TRACKER]() hass.services.async_remove(DOMAIN, SERVICE_FORCE_UPDATE) hass.services.async_remove(DOMAIN, SERVICE_PULL_DEVICES) hass.data.pop(DOMAIN)