From c3d49bac4a517762ca9f5fd17314d4c56a62e899 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sat, 20 Mar 2021 09:39:50 -0400 Subject: [PATCH 1/7] initial configuration options --- homeassistant/components/zha/api.py | 53 ++++++++++++++++++++ homeassistant/components/zha/core/const.py | 11 ++++ homeassistant/components/zha/core/gateway.py | 8 +-- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 7e265d03c0940b..9bd9e55bb09d6f 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -7,6 +7,7 @@ from typing import Any import voluptuous as vol +from zigpy.config.validators import cv_boolean from zigpy.types.named import EUI64 import zigpy.zdo.types as zdo_types @@ -40,6 +41,7 @@ CLUSTER_COMMANDS_SERVER, CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, + CONF_OPTIONS_SCHEMA, DATA_ZHA, DATA_ZHA_GATEWAY, DOMAIN, @@ -882,6 +884,55 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati zdo.debug(fmt, *(log_msg[2] + (outcome,))) +@websocket_api.require_admin +@websocket_api.async_response +@websocket_api.websocket_command({vol.Required(TYPE): "zha/configuration"}) +async def websocket_get_configuration(hass, connection, msg): + """Get ZHA configuration.""" + import voluptuous_serialize # pylint: disable=import-outside-toplevel + + def custom_serializer(schema: Any) -> Any: + """Serialize additional types for voluptuous_serialize.""" + if schema is cv_boolean: + return {"type": "bool"} + if schema is vol.Schema: + return voluptuous_serialize.convert( + schema, custom_serializer=custom_serializer + ) + + return cv.custom_serializer(schema) + + data = { + "schemas": { + "options": voluptuous_serialize.convert( + CONF_OPTIONS_SCHEMA, custom_serializer=custom_serializer + ) + }, + "data": {"options": {}}, + } + connection.send_result(msg[ID], data) + + +@websocket_api.require_admin +@websocket_api.async_response +@websocket_api.websocket_command( + {vol.Required(TYPE): "zha/configuration/update", vol.Required("data"): object} +) +async def websocket_update_zha_configuration(hass, connection, msg): + """Update the ZHA configuration.""" + zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] + old_config_entry_data = zha_gateway.config_entry.data + data_to_save = msg["data"] + + _LOGGER.info( + "Updating ZHA configuration from %s to %s", old_config_entry_data, data_to_save + ) + + # hass.config_entries.async_update_entry(zha_gateway.config_entry, data=data_to_save) + # status = await hass.config_entries.async_reload(zha_gateway.config_entry.entry_id) + # connection.send_result(msg[ID], status) + + @callback def async_load_api(hass): """Set up the web socket API.""" @@ -1189,6 +1240,8 @@ async def warning_device_warn(service): websocket_api.async_register_command(hass, websocket_bind_devices) websocket_api.async_register_command(hass, websocket_unbind_devices) websocket_api.async_register_command(hass, websocket_update_topology) + websocket_api.async_register_command(hass, websocket_get_configuration) + websocket_api.async_register_command(hass, websocket_update_zha_configuration) @callback diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 2c968a5f02d1aa..04959d2fe05329 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -5,6 +5,7 @@ import logging import bellows.zigbee.application +import voluptuous as vol from zigpy.config import CONF_DEVICE_PATH # noqa: F401 # pylint: disable=unused-import import zigpy_cc.zigbee.application import zigpy_deconz.zigbee.application @@ -22,6 +23,7 @@ from homeassistant.components.number import DOMAIN as NUMBER from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.switch import DOMAIN as SWITCH +import homeassistant.helpers.config_validation as cv from .typing import CALLABLE_T @@ -118,13 +120,22 @@ CONF_BAUDRATE = "baudrate" CONF_DATABASE = "database_path" +CONF_DEFAULT_LIGHT_TRANSITION = "default_light_transition" CONF_DEVICE_CONFIG = "device_config" +CONF_ENABLE_IDENTIFY_ON_JOIN = "enable_identify_on_join" CONF_ENABLE_QUIRKS = "enable_quirks" CONF_FLOWCONTROL = "flow_control" CONF_RADIO_TYPE = "radio_type" CONF_USB_PATH = "usb_path" CONF_ZIGPY = "zigpy_config" +CONF_OPTIONS_SCHEMA = vol.Schema( + { + vol.Optional(CONF_DEFAULT_LIGHT_TRANSITION): cv.positive_int, + vol.Optional(CONF_ENABLE_IDENTIFY_ON_JOIN): cv.boolean, + } +) + DATA_DEVICE_CONFIG = "zha_device_config" DATA_ZHA = "zha" DATA_ZHA_CONFIG = "config" diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 96e4a7c3eb8185..4a9e6c2820360c 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -127,7 +127,7 @@ def __init__(self, hass, config, config_entry): } self.debug_enabled = False self._log_relay_handler = LogRelayHandler(hass, self) - self._config_entry = config_entry + self.config_entry = config_entry self._unsubs = [] async def async_initialize(self): @@ -139,7 +139,7 @@ async def async_initialize(self): self.ha_device_registry = await get_dev_reg(self._hass) self.ha_entity_registry = await get_ent_reg(self._hass) - radio_type = self._config_entry.data[CONF_RADIO_TYPE] + radio_type = self.config_entry.data[CONF_RADIO_TYPE] app_controller_cls = RadioType[radio_type].controller self.radio_description = RadioType[radio_type].description @@ -150,7 +150,7 @@ async def async_initialize(self): os.path.join(self._hass.config.config_dir, DEFAULT_DATABASE_NAME), ) app_config[CONF_DATABASE] = database - app_config[CONF_DEVICE] = self._config_entry.data[CONF_DEVICE] + app_config[CONF_DEVICE] = self.config_entry.data[CONF_DEVICE] app_config = app_controller_cls.SCHEMA(app_config) try: @@ -506,7 +506,7 @@ def _async_get_or_create_device( zha_device = ZHADevice.new(self._hass, zigpy_device, self, restored) self._devices[zigpy_device.ieee] = zha_device device_registry_device = self.ha_device_registry.async_get_or_create( - config_entry_id=self._config_entry.entry_id, + config_entry_id=self.config_entry.entry_id, connections={(CONNECTION_ZIGBEE, str(zha_device.ieee))}, identifiers={(DOMAIN, str(zha_device.ieee))}, name=zha_device.name, From f783601f4e0287b0dbddc8d0eedeff5b4c99d2c1 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sat, 27 Mar 2021 17:11:25 -0400 Subject: [PATCH 2/7] first crack at saving the data --- homeassistant/components/zha/api.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 9bd9e55bb09d6f..2738819cea94f8 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -904,11 +904,11 @@ def custom_serializer(schema: Any) -> Any: data = { "schemas": { - "options": voluptuous_serialize.convert( + "zha_options": voluptuous_serialize.convert( CONF_OPTIONS_SCHEMA, custom_serializer=custom_serializer ) }, - "data": {"options": {}}, + "data": {"zha_options": {}}, } connection.send_result(msg[ID], data) @@ -921,16 +921,20 @@ def custom_serializer(schema: Any) -> Any: async def websocket_update_zha_configuration(hass, connection, msg): """Update the ZHA configuration.""" zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] - old_config_entry_data = zha_gateway.config_entry.data - data_to_save = msg["data"] + options = zha_gateway.config_entry.options + data_to_save = {**options, **{"custom_configuration": msg["data"]}} _LOGGER.info( - "Updating ZHA configuration from %s to %s", old_config_entry_data, data_to_save + "Updating ZHA custom configuration options from %s to %s", + options, + data_to_save, ) - # hass.config_entries.async_update_entry(zha_gateway.config_entry, data=data_to_save) - # status = await hass.config_entries.async_reload(zha_gateway.config_entry.entry_id) - # connection.send_result(msg[ID], status) + hass.config_entries.async_update_entry( + zha_gateway.config_entry, options=data_to_save + ) + status = await hass.config_entries.async_reload(zha_gateway.config_entry.entry_id) + connection.send_result(msg[ID], status) @callback From 1e85fd65e2b379bf4d863df34ab5912800a739f6 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sat, 27 Mar 2021 18:16:48 -0400 Subject: [PATCH 3/7] constants --- homeassistant/components/zha/api.py | 3 ++- homeassistant/components/zha/core/const.py | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 2738819cea94f8..107144802a0962 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -42,6 +42,7 @@ CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, CONF_OPTIONS_SCHEMA, + CUSTOM_CONFIGURATION, DATA_ZHA, DATA_ZHA_GATEWAY, DOMAIN, @@ -922,7 +923,7 @@ async def websocket_update_zha_configuration(hass, connection, msg): """Update the ZHA configuration.""" zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] options = zha_gateway.config_entry.options - data_to_save = {**options, **{"custom_configuration": msg["data"]}} + data_to_save = {**options, **{CUSTOM_CONFIGURATION: msg["data"]}} _LOGGER.info( "Updating ZHA custom configuration options from %s to %s", diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 04959d2fe05329..e58ef53d8d4902 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -136,6 +136,8 @@ } ) +CUSTOM_CONFIGURATION = "custom_configuration" + DATA_DEVICE_CONFIG = "zha_device_config" DATA_ZHA = "zha" DATA_ZHA_CONFIG = "config" @@ -187,6 +189,8 @@ PRESET_SCHEDULE = "schedule" PRESET_COMPLEX = "complex" +ZHA_OPTIONS = "zha_options" + class RadioType(enum.Enum): """Possible options for radio type.""" From 4fe25fcc147c44dfcee16968831a15cd159005b2 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sat, 27 Mar 2021 18:28:13 -0400 Subject: [PATCH 4/7] implement initial options --- homeassistant/components/zha/api.py | 6 +++++- homeassistant/components/zha/core/const.py | 2 +- homeassistant/components/zha/core/device.py | 12 ++++++++++-- homeassistant/components/zha/core/helpers.py | 19 ++++++++++++++++++- homeassistant/components/zha/light.py | 19 +++++++++++++++++-- 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 107144802a0962..a886b8f9b0de41 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -890,6 +890,10 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati @websocket_api.websocket_command({vol.Required(TYPE): "zha/configuration"}) async def websocket_get_configuration(hass, connection, msg): """Get ZHA configuration.""" + zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] + custom_configuration = zha_gateway.config_entry.options.get( + CUSTOM_CONFIGURATION, {"zha_options": {}} + ) import voluptuous_serialize # pylint: disable=import-outside-toplevel def custom_serializer(schema: Any) -> Any: @@ -909,7 +913,7 @@ def custom_serializer(schema: Any) -> Any: CONF_OPTIONS_SCHEMA, custom_serializer=custom_serializer ) }, - "data": {"zha_options": {}}, + "data": custom_configuration, } connection.send_result(msg[ID], data) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index e58ef53d8d4902..98874fc0c731e8 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -132,7 +132,7 @@ CONF_OPTIONS_SCHEMA = vol.Schema( { vol.Optional(CONF_DEFAULT_LIGHT_TRANSITION): cv.positive_int, - vol.Optional(CONF_ENABLE_IDENTIFY_ON_JOIN): cv.boolean, + vol.Optional(CONF_ENABLE_IDENTIFY_ON_JOIN, default=True): cv.boolean, } ) diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 65605b2f7a3ff6..ab3c9b3b9e6d3b 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -56,6 +56,7 @@ CLUSTER_COMMANDS_SERVER, CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, + CONF_ENABLE_IDENTIFY_ON_JOIN, EFFECT_DEFAULT_VARIANT, EFFECT_OKAY, POWER_BATTERY_OR_UNKNOWN, @@ -66,7 +67,7 @@ UNKNOWN_MANUFACTURER, UNKNOWN_MODEL, ) -from .helpers import LogMixin +from .helpers import LogMixin, async_get_zha_config_value _LOGGER = logging.getLogger(__name__) CONSIDER_UNAVAILABLE_MAINS = 60 * 60 * 2 # 2 hours @@ -395,13 +396,20 @@ def device_info(self): async def async_configure(self): """Configure the device.""" + should_identify = async_get_zha_config_value( + self._zha_gateway.config_entry, CONF_ENABLE_IDENTIFY_ON_JOIN, True + ) self.debug("started configuration") await self._channels.async_configure() self.debug("completed configuration") entry = self.gateway.zha_storage.async_create_or_update_device(self) self.debug("stored in registry: %s", entry) - if self._channels.identify_ch is not None and not self.skip_configuration: + if ( + should_identify + and self._channels.identify_ch is not None + and not self.skip_configuration + ): await self._channels.identify_ch.trigger_effect( EFFECT_OKAY, EFFECT_DEFAULT_VARIANT ) diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index cf3d040f020538..f8fb12e159627f 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -24,7 +24,14 @@ from homeassistant.core import State, callback -from .const import CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, DATA_ZHA, DATA_ZHA_GATEWAY +from .const import ( + CLUSTER_TYPE_IN, + CLUSTER_TYPE_OUT, + CUSTOM_CONFIGURATION, + DATA_ZHA, + DATA_ZHA_GATEWAY, + ZHA_OPTIONS, +) from .registries import BINDABLE_CLUSTERS from .typing import ZhaDeviceType, ZigpyClusterType @@ -122,6 +129,16 @@ def async_is_bindable_target(source_zha_device, target_zha_device): return False +@callback +def async_get_zha_config_value(config_entry, config_key, default): + """Get the value for the specified configuration from the zha config entry.""" + return ( + config_entry.options.get(CUSTOM_CONFIGURATION, {}) + .get(ZHA_OPTIONS, {}) + .get(config_key, default) + ) + + async def async_get_zha_device(hass, device_id): """Get a ZHA device for the given device registry id.""" device_registry = await hass.helpers.device_registry.async_get_registry() diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 72807458d266ac..6701a9bb3c78de 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -47,6 +47,7 @@ CHANNEL_COLOR, CHANNEL_LEVEL, CHANNEL_ON_OFF, + CONF_DEFAULT_LIGHT_TRANSITION, DATA_ZHA, DATA_ZHA_DISPATCHERS, EFFECT_BLINK, @@ -56,7 +57,7 @@ SIGNAL_ATTR_UPDATED, SIGNAL_SET_LEVEL, ) -from .core.helpers import LogMixin +from .core.helpers import LogMixin, async_get_zha_config_value from .core.registries import ZHA_ENTITIES from .core.typing import ZhaDeviceType from .entity import ZhaEntity, ZhaGroupEntity @@ -139,6 +140,7 @@ def __init__(self, *args, **kwargs): self._level_channel = None self._color_channel = None self._identify_channel = None + self._default_transition = None @property def extra_state_attributes(self) -> dict[str, Any]: @@ -207,7 +209,13 @@ def supported_features(self): async def async_turn_on(self, **kwargs): """Turn the entity on.""" transition = kwargs.get(light.ATTR_TRANSITION) - duration = transition * 10 if transition else DEFAULT_TRANSITION + duration = ( + transition * 10 + if transition + else self._default_transition * 10 + if self._default_transition + else DEFAULT_TRANSITION + ) brightness = kwargs.get(light.ATTR_BRIGHTNESS) effect = kwargs.get(light.ATTR_EFFECT) flash = kwargs.get(light.ATTR_FLASH) @@ -389,6 +397,10 @@ def __init__(self, unique_id, zha_device: ZhaDeviceType, channels, **kwargs): if effect_list: self._effect_list = effect_list + self._default_transition = async_get_zha_config_value( + zha_device.gateway.config_entry, CONF_DEFAULT_LIGHT_TRANSITION, 0 + ) + @callback def async_set_state(self, attr_id, attr_name, value): """Set the state.""" @@ -544,6 +556,9 @@ def __init__( self._color_channel = group.endpoint[Color.cluster_id] self._identify_channel = group.endpoint[Identify.cluster_id] self._debounced_member_refresh = None + self._default_transition = async_get_zha_config_value( + zha_device.gateway.config_entry, CONF_DEFAULT_LIGHT_TRANSITION, 0 + ) async def async_added_to_hass(self): """Run when about to be added to hass.""" From 8a267074dac3965349e6a887c2eecd0377a80860 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sun, 28 Mar 2021 09:59:22 -0400 Subject: [PATCH 5/7] make more dynamic --- homeassistant/components/zha/api.py | 26 +++++++++++----------- homeassistant/components/zha/core/const.py | 5 +++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index a886b8f9b0de41..b5b29534ed9039 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -41,7 +41,6 @@ CLUSTER_COMMANDS_SERVER, CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, - CONF_OPTIONS_SCHEMA, CUSTOM_CONFIGURATION, DATA_ZHA, DATA_ZHA_GATEWAY, @@ -55,6 +54,7 @@ WARNING_DEVICE_SQUAWK_MODE_ARMED, WARNING_DEVICE_STROBE_HIGH, WARNING_DEVICE_STROBE_YES, + ZHA_CONFIG_SCHEMAS, ) from .core.group import GroupMember from .core.helpers import ( @@ -891,9 +891,6 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati async def websocket_get_configuration(hass, connection, msg): """Get ZHA configuration.""" zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] - custom_configuration = zha_gateway.config_entry.options.get( - CUSTOM_CONFIGURATION, {"zha_options": {}} - ) import voluptuous_serialize # pylint: disable=import-outside-toplevel def custom_serializer(schema: Any) -> Any: @@ -907,21 +904,24 @@ def custom_serializer(schema: Any) -> Any: return cv.custom_serializer(schema) - data = { - "schemas": { - "zha_options": voluptuous_serialize.convert( - CONF_OPTIONS_SCHEMA, custom_serializer=custom_serializer - ) - }, - "data": custom_configuration, - } + data = {"schemas": {}, "data": {}} + for section, schema in ZHA_CONFIG_SCHEMAS.items(): + data["schemas"][section] = voluptuous_serialize.convert( + schema, custom_serializer=custom_serializer + ) + data["data"][section] = zha_gateway.config_entry.options.get( + CUSTOM_CONFIGURATION, {} + ).get(section, {}) connection.send_result(msg[ID], data) @websocket_api.require_admin @websocket_api.async_response @websocket_api.websocket_command( - {vol.Required(TYPE): "zha/configuration/update", vol.Required("data"): object} + { + vol.Required(TYPE): "zha/configuration/update", + vol.Required("data"): ZHA_CONFIG_SCHEMAS, + } ) async def websocket_update_zha_configuration(hass, connection, msg): """Update the ZHA configuration.""" diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 98874fc0c731e8..d0a8921909d6c0 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -129,10 +129,10 @@ CONF_USB_PATH = "usb_path" CONF_ZIGPY = "zigpy_config" -CONF_OPTIONS_SCHEMA = vol.Schema( +CONF_ZHA_OPTIONS_SCHEMA = vol.Schema( { vol.Optional(CONF_DEFAULT_LIGHT_TRANSITION): cv.positive_int, - vol.Optional(CONF_ENABLE_IDENTIFY_ON_JOIN, default=True): cv.boolean, + vol.Required(CONF_ENABLE_IDENTIFY_ON_JOIN, default=True): cv.boolean, } ) @@ -190,6 +190,7 @@ PRESET_COMPLEX = "complex" ZHA_OPTIONS = "zha_options" +ZHA_CONFIG_SCHEMAS = {ZHA_OPTIONS: CONF_ZHA_OPTIONS_SCHEMA} class RadioType(enum.Enum): From 1456b0244ba9f490f1ad2599563aa0c384ad33bf Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sun, 11 Apr 2021 07:13:25 -0400 Subject: [PATCH 6/7] fix unload and reload of the config entry --- homeassistant/components/zha/__init__.py | 21 ++++++++++++++++++--- homeassistant/components/zha/core/const.py | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 707e0292c45166..84d314717618fd 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -29,6 +29,7 @@ DATA_ZHA_DISPATCHERS, DATA_ZHA_GATEWAY, DATA_ZHA_PLATFORM_LOADED, + DATA_ZHA_SHUTDOWN_TASK, DOMAIN, PLATFORMS, SIGNAL_ADD_ENTITIES, @@ -121,7 +122,9 @@ async def async_zha_shutdown(event): await zha_data[DATA_ZHA_GATEWAY].shutdown() await zha_data[DATA_ZHA_GATEWAY].async_update_device_storage() - hass.bus.async_listen_once(ha_const.EVENT_HOMEASSISTANT_STOP, async_zha_shutdown) + zha_data[DATA_ZHA_SHUTDOWN_TASK] = hass.bus.async_listen_once( + ha_const.EVENT_HOMEASSISTANT_STOP, async_zha_shutdown + ) asyncio.create_task(async_load_entities(hass)) return True @@ -129,6 +132,7 @@ async def async_zha_shutdown(event): async def async_unload_entry(hass, config_entry): """Unload ZHA config entry.""" await hass.data[DATA_ZHA][DATA_ZHA_GATEWAY].shutdown() + await hass.data[DATA_ZHA][DATA_ZHA_GATEWAY].async_update_device_storage() GROUP_PROBE.cleanup() api.async_unload_api(hass) @@ -137,8 +141,19 @@ async def async_unload_entry(hass, config_entry): for unsub_dispatcher in dispatchers: unsub_dispatcher() - for platform in PLATFORMS: - await hass.config_entries.async_forward_entry_unload(config_entry, platform) + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(config_entry, platform) + for platform in PLATFORMS + ] + ) + ) + + if not unload_ok: + return False + + hass.data[DATA_ZHA][DATA_ZHA_SHUTDOWN_TASK]() return True diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index d0a8921909d6c0..f43d9febc55f09 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -146,6 +146,7 @@ DATA_ZHA_DISPATCHERS = "zha_dispatchers" DATA_ZHA_GATEWAY = "zha_gateway" DATA_ZHA_PLATFORM_LOADED = "platform_loaded" +DATA_ZHA_SHUTDOWN_TASK = "zha_shutdown_task" DEBUG_COMP_BELLOWS = "bellows" DEBUG_COMP_ZHA = "homeassistant.components.zha" From 10eb6d5c1f8fd85870cb60c8fdac564f08660a5b Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Sun, 11 Apr 2021 08:22:11 -0400 Subject: [PATCH 7/7] update unload --- homeassistant/components/zha/__init__.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 84d314717618fd..43b95a9c2f2b8f 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -141,18 +141,14 @@ async def async_unload_entry(hass, config_entry): for unsub_dispatcher in dispatchers: unsub_dispatcher() - unload_ok = all( - await asyncio.gather( - *[ - hass.config_entries.async_forward_entry_unload(config_entry, platform) - for platform in PLATFORMS - ] - ) + # our components don't have unload methods so no need to look at return values + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(config_entry, platform) + for platform in PLATFORMS + ] ) - if not unload_ok: - return False - hass.data[DATA_ZHA][DATA_ZHA_SHUTDOWN_TASK]() return True