From 176d3253db925fc40048e2bca10af84c6c9840fd Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:32:47 -0700 Subject: [PATCH 1/9] Add init_device function to device classes * Read from storage as async * Write to storage as async --- custom_components/tekmar_482/hub.py | 125 +++++++++++++++++----------- 1 file changed, 76 insertions(+), 49 deletions(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 3e9db68..564c465 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -2,7 +2,6 @@ import logging import pickle from os.path import exists -from threading import Lock from typing import Any, Callable, Dict, Optional from homeassistant.core import HomeAssistant @@ -58,7 +57,6 @@ def __init__( f"{format(DOMAIN)}.{format(self._name)}.pickle" ) self._storage = StoredData(self._data_file) - self.storage_put(f"{format(DOMAIN)}.{format(self._name)}.pickle", True) self._tha_inventory = {} self.tha_gateway = [] @@ -80,6 +78,8 @@ def __init__( async def async_init_tha(self) -> None: self._inSetup = True + await self.storage_put(f"{format(DOMAIN)}.{format(self._name)}.pickle", True) + if await self._sock.open() is False: _LOGGER.error(self._sock.error) ir.async_create_issue( @@ -269,8 +269,10 @@ async def async_init_tha(self) -> None: pass else: + new_gateway = TekmarGateway(f"{self._id}", f"{self._host}", self) + new_gateway.init_device() self.tha_gateway = [ - TekmarGateway(f"{self._id}", f"{self._host}", self), + new_gateway, ] for address in self._tha_inventory: @@ -282,28 +284,34 @@ async def async_init_tha(self) -> None: DEVICE_TYPES[self._tha_inventory[address]["type"]] == ThaType.THERMOSTAT ): - self.tha_devices.append( - TekmarThermostat(address, self._tha_inventory[address], self) + new_thermostat = TekmarThermostat( + address, self._tha_inventory[address], self ) + await new_thermostat.init_device() + self.tha_devices.append(new_thermostat) elif ( DEVICE_TYPES[self._tha_inventory[address]["type"]] == ThaType.SETPOINT ): - self.tha_devices.append( - TekmarSetpoint(address, self._tha_inventory[address], self) + new_setpoint = TekmarSetpoint( + address, self._tha_inventory[address], self ) + new_setpoint.init_device() + self.tha_devices.append(new_setpoint) elif ( DEVICE_TYPES[self._tha_inventory[address]["type"]] == ThaType.SNOWMELT ): - self.tha_devices.append( - TekmarSnowmelt(address, self._tha_inventory[address], self) + new_snowmelt = TekmarSnowmelt( + address, self._tha_inventory[address], self ) + new_snowmelt.init_device() + self.tha_devices.append(new_snowmelt) else: - _LOGGER.error(f"Unknown device at address {address}") + _LOGGER.warning(f"Unknown device at address {address}") self.online = True @@ -592,11 +600,11 @@ def tha_setback_enable(self) -> bool: else: return False - def storage_get(self, key: Any) -> Any: - return self._storage.get_setting(key) + async def storage_get(self, key: Any) -> Any: + return await self._storage.get_setting(key) - def storage_put(self, key: Any, value: Any) -> None: - self._storage.put_setting(key, value) + async def storage_put(self, key: Any, value: Any) -> None: + await self._storage.put_setting(key, value) class TekmarThermostat: @@ -614,25 +622,14 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: self._tha_mode_setting = None self._tha_humidity_setpoint_min = None self._tha_humidity_setpoint_max = None - - self._config_vent_mode = self.hub.storage_get(f"{self._id}_config_vent_mode") - self._config_emergency_heat = self.hub.storage_get( - f"{self._id}_config_emergency_heat" - ) - self._config_cooling = self.hub.storage_get(f"{self._id}_config_cooling") - self._config_heating = self.hub.storage_get(f"{self._id}_config_heating") - self._config_cool_setpoint_max = self.hub.storage_get( - f"{self._id}_config_cool_setpoint_max" - ) - self._config_cool_setpoint_min = self.hub.storage_get( - f"{self._id}_config_cool_setpoint_min" - ) - self._config_heat_setpoint_max = self.hub.storage_get( - f"{self._id}_config_heat_setpoint_max" - ) - self._config_heat_setpoint_min = self.hub.storage_get( - f"{self._id}_config_heat_setpoint_min" - ) + self._config_vent_mode = None + self._config_emergency_heat = None + self._config_cooling = None + self._config_heating = None + self._config_cool_setpoint_max = None + self._config_cool_setpoint_min = None + self._config_heat_setpoint_max = None + self._config_heat_setpoint_min = None self._tha_heat_setpoints = { # degE 0x00: None, # day @@ -656,6 +653,29 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: 0x01: None, } + async def init_device(self) -> None: + + self._config_vent_mode = await self.hub.storage_get( + f"{self._id}_config_vent_mode" + ) + self._config_emergency_heat = await self.hub.storage_get( + f"{self._id}_config_emergency_heat" + ) + self._config_cooling = await self.hub.storage_get(f"{self._id}_config_cooling") + self._config_heating = await self.hub.storage_get(f"{self._id}_config_heating") + self._config_cool_setpoint_max = await self.hub.storage_get( + f"{self._id}_config_cool_setpoint_max" + ) + self._config_cool_setpoint_min = await self.hub.storage_get( + f"{self._id}_config_cool_setpoint_min" + ) + self._config_heat_setpoint_max = await self.hub.storage_get( + f"{self._id}_config_heat_setpoint_max" + ) + self._config_heat_setpoint_min = await self.hub.storage_get( + f"{self._id}_config_heat_setpoint_min" + ) + # Some static information about this device self._device_type = DEVICE_TYPES[self.tha_device["type"]] self._tha_full_device_name = self.tha_device["entity"] @@ -665,7 +685,7 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: self._device_info = { "identifiers": {(DOMAIN, self._id)}, "name": ( - f"{hub.hub_id.capitalize()} {self._device_type.capitalize()} " + f"{self.hub.hub_id.capitalize()} {self._device_type.capitalize()} " f"{self.model} {self._id}" ), "manufacturer": ATTR_MANUFACTURER, @@ -807,7 +827,9 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: ) ) - if DEVICE_FEATURES[self.tha_device["type"]]["humid"] and hub.tha_pr_ver in [ + if DEVICE_FEATURES[self.tha_device["type"]][ + "humid" + ] and self.hub.tha_pr_ver in [ 2, 3, ]: @@ -978,12 +1000,12 @@ def humidity_setpoint_max(self) -> str: async def set_config_emer_heat(self, value: bool) -> None: self._config_emergency_heat = value - self.hub.storage_put(f"{self._id}_config_emergency_heat", value) + await self.hub.storage_put(f"{self._id}_config_emergency_heat", value) await self.publish_updates() async def set_config_vent_mode(self, value: bool) -> None: self._config_vent_mode = value - self.hub.storage_put(f"{self._id}_config_vent_mode", value) + await self.hub.storage_put(f"{self._id}_config_vent_mode", value) await self.publish_updates() async def set_current_temperature(self, temp: int) -> None: @@ -1065,7 +1087,7 @@ async def set_mode_setting(self, mode: int) -> None: self._tha_mode_setting = mode if mode == 0x06: - self.hub.storage_put(f"{self._id}_config_emergency_heat", True) + await self.hub.storage_put(f"{self._id}_config_emergency_heat", True) self._config_emergency_heat = True await self.publish_updates() @@ -1154,7 +1176,7 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: self._device_info = { "identifiers": {(DOMAIN, self._id)}, "name": ( - f"{hub.hub_id.capitalize()} {self._device_type.capitalize()} " + f"{self.hub.hub_id.capitalize()} {self._device_type.capitalize()} " f"{self.model} {self._id}" ), "manufacturer": ATTR_MANUFACTURER, @@ -1162,6 +1184,7 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: "sw_version": self.firmware_version, } + def init_device(self) -> None: self.hub.queue_message( TrpcPacket( service="Request", @@ -1300,7 +1323,7 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: self._device_info = { "identifiers": {(DOMAIN, self._id)}, "name": ( - f"{hub.hub_id.capitalize()} {self._device_type.capitalize()} " + f"{self.hub.hub_id.capitalize()} {self._device_type.capitalize()} " f"{self.model} {self._id}" ), "manufacturer": ATTR_MANUFACTURER, @@ -1308,6 +1331,9 @@ def __init__(self, address: int, tha_device: [], hub: TekmarHub) -> None: "sw_version": self.firmware_version, } + def init_device(self) -> None: + pass + @property def device_id(self) -> str: return self._id @@ -1373,17 +1399,18 @@ def __init__(self, gatewayid: str, host: str, hub: TekmarHub) -> None: } # Some static information about this device - self.firmware_version = f"{hub.tha_fw_ver} protocol {hub.tha_pr_ver}" + self.firmware_version = f"{self.hub.tha_fw_ver} protocol {self.hub.tha_pr_ver}" self.model = "482" self._device_info = { "identifiers": {(DOMAIN, self.hub.hub_id)}, - "name": f"{hub.hub_id.capitalize()} Gateway", + "name": f"{self.hub.hub_id.capitalize()} Gateway", "manufacturer": ATTR_MANUFACTURER, "model": self.model, "sw_version": self.firmware_version, } + def init_device(self) -> None: self.hub.queue_message( TrpcPacket(service="Request", method="OutdoorTemperature") ) @@ -1479,30 +1506,30 @@ class StoredData(object): def __init__(self, data_file): """Initialize pickle data storage.""" self._data_file = data_file - self._lock = Lock() + self._lock = asyncio.Lock() self._cache_outdated = True self._data = {} self._fetch_data() - def _fetch_data(self): + async def _fetch_data(self): """Fetch data stored into pickle file.""" if self._cache_outdated and exists(self._data_file): try: _LOGGER.debug(f"Fetching data from file {self._data_file}") - with self._lock, open(self._data_file, "rb") as myfile: + async with self._lock, open(self._data_file, "rb") as myfile: self._data = pickle.load(myfile) or {} self._cache_outdated = False except Exception: _LOGGER.error(f"Error loading data from pickled file {self._data_file}") - def get_setting(self, key): - self._fetch_data() + async def get_setting(self, key): + await self._fetch_data() return self._data.get(key) - def put_setting(self, key, value): + async def put_setting(self, key, value): self._fetch_data() - with self._lock, open(self._data_file, "wb") as myfile: + async with self._lock, open(self._data_file, "wb") as myfile: self._data.update({key: value}) _LOGGER.debug(f"Writing {key}:{value} in storage file {self._data_file}") try: From 03034445133c69d5819dfe996b59861aeee01b36 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Tue, 11 Jun 2024 18:17:23 -0700 Subject: [PATCH 2/9] Migrate from pickle to storage helper --- custom_components/tekmar_482/const.py | 3 ++ custom_components/tekmar_482/hub.py | 65 +++++++++++---------------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/custom_components/tekmar_482/const.py b/custom_components/tekmar_482/const.py index b25760f..08036fe 100644 --- a/custom_components/tekmar_482/const.py +++ b/custom_components/tekmar_482/const.py @@ -31,6 +31,9 @@ class StrEnum(str, Enum): DEFAULT_SETBACK_ENABLE = False CONF_SETBACK_ENABLE = "setback_enable" +STORAGE_VERSION_MAJOR = 1 +STORAGE_KEY = DOMAIN + # from voluptuous/validators.py DOMAIN_REGEX = re.compile( # start anchor, because fullmatch is not available in python 2.7 diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 564c465..8d12938 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -1,12 +1,11 @@ import asyncio import logging -import pickle -from os.path import exists from typing import Any, Callable, Dict, Optional from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers.storage import Store from homeassistant.util import dt from .const import ( @@ -18,6 +17,8 @@ DOMAIN, SETBACK_FAN_MAP, SETBACK_SETPOINT_MAP, + STORAGE_KEY, + STORAGE_VERSION_MAJOR, ThaDefault, ThaSetback, ThaType, @@ -53,10 +54,7 @@ def __init__( self._id = name.lower() self._sock = TrpcSocket(host, port) - self._data_file = hass.config.path( - f"{format(DOMAIN)}.{format(self._name)}.pickle" - ) - self._storage = StoredData(self._data_file) + self._storage = StoredData(self._hass) self._tha_inventory = {} self.tha_gateway = [] @@ -78,7 +76,7 @@ def __init__( async def async_init_tha(self) -> None: self._inSetup = True - await self.storage_put(f"{format(DOMAIN)}.{format(self._name)}.pickle", True) + await self.storage_put(f"{DOMAIN}_{self._name}_storage", True) if await self._sock.open() is False: _LOGGER.error(self._sock.error) @@ -1501,41 +1499,28 @@ def device_info(self) -> Optional[Dict[str, Any]]: class StoredData(object): - """Abstraction over pickle data storage.""" - - def __init__(self, data_file): - """Initialize pickle data storage.""" - self._data_file = data_file - self._lock = asyncio.Lock() - self._cache_outdated = True - self._data = {} - self._fetch_data() - - async def _fetch_data(self): - """Fetch data stored into pickle file.""" - if self._cache_outdated and exists(self._data_file): - try: - _LOGGER.debug(f"Fetching data from file {self._data_file}") - async with self._lock, open(self._data_file, "rb") as myfile: - self._data = pickle.load(myfile) or {} - self._cache_outdated = False + """Abstraction over Home Assistant Store.""" - except Exception: - _LOGGER.error(f"Error loading data from pickled file {self._data_file}") + def __init__(self, hass: HomeAssistant) -> None: + self._hass = hass + self._data = None - async def get_setting(self, key): - await self._fetch_data() - return self._data.get(key) + self.store: Store[dict[str, Any]] = Store( + self._hass, + STORAGE_VERSION_MAJOR, + STORAGE_KEY, + ) - async def put_setting(self, key, value): - self._fetch_data() - async with self._lock, open(self._data_file, "wb") as myfile: - self._data.update({key: value}) - _LOGGER.debug(f"Writing {key}:{value} in storage file {self._data_file}") - try: - pickle.dump(self._data, myfile) + async def get_setting(self, key: str) -> Any: + if self._data is None: + self._data = await self.store.async_load() + + return self._data.get(key) - except Exception: - _LOGGER.error(f"Error saving pickled data to {self._data_file}") + async def put_setting(self, key: str, value: Any) -> None: + self._data = await self.store.async_load() + if self._data is None: + self._data = {} - self._cache_outdated = True + self._data.update({key: value}) + await self.store.async_save(self._data) From 5d7f998c49c5d5ec62a784e66e7b1acbc48653da Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:10:13 -0700 Subject: [PATCH 3/9] Update hub.py --- custom_components/tekmar_482/hub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 8d12938..495d487 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -76,7 +76,7 @@ def __init__( async def async_init_tha(self) -> None: self._inSetup = True - await self.storage_put(f"{DOMAIN}_{self._name}_storage", True) + await self.storage_put(f"{self._name}", {"storage", True}) if await self._sock.open() is False: _LOGGER.error(self._sock.error) From 15ccb35fc9ab71cf31e1351dc7680337937085b6 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Thu, 13 Jun 2024 07:54:39 -0700 Subject: [PATCH 4/9] Update hub.py --- custom_components/tekmar_482/hub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 495d487..8da9f00 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -76,7 +76,7 @@ def __init__( async def async_init_tha(self) -> None: self._inSetup = True - await self.storage_put(f"{self._name}", {"storage", True}) + await self.storage_put(f"{self._name}", {"storage": True}) if await self._sock.open() is False: _LOGGER.error(self._sock.error) From 494ec00b985dfa6f058a429b10498f4ecb0988c1 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:21:00 -0700 Subject: [PATCH 5/9] Update hub.py --- custom_components/tekmar_482/hub.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 8da9f00..a182eda 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -54,7 +54,7 @@ def __init__( self._id = name.lower() self._sock = TrpcSocket(host, port) - self._storage = StoredData(self._hass) + self._storage = StoredData(self._hass, self._name) self._tha_inventory = {} self.tha_gateway = [] @@ -76,7 +76,7 @@ def __init__( async def async_init_tha(self) -> None: self._inSetup = True - await self.storage_put(f"{self._name}", {"storage": True}) + await self.storage_put("storage", True) if await self._sock.open() is False: _LOGGER.error(self._sock.error) @@ -1501,8 +1501,9 @@ def device_info(self) -> Optional[Dict[str, Any]]: class StoredData(object): """Abstraction over Home Assistant Store.""" - def __init__(self, hass: HomeAssistant) -> None: + def __init__(self, hass: HomeAssistant, name: str) -> None: self._hass = hass + self._name = name self._data = None self.store: Store[dict[str, Any]] = Store( @@ -1515,12 +1516,12 @@ async def get_setting(self, key: str) -> Any: if self._data is None: self._data = await self.store.async_load() - return self._data.get(key) + return self._data.get(self._name).get(key) async def put_setting(self, key: str, value: Any) -> None: self._data = await self.store.async_load() if self._data is None: self._data = {} - self._data.update({key: value}) + self._data[self._name].update({key: value}) await self.store.async_save(self._data) From 7cec8e89e23159f2c84e42c8484a853940e41bff Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:46:14 -0700 Subject: [PATCH 6/9] Update hub.py --- custom_components/tekmar_482/hub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index a182eda..b0c2ac3 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -1523,5 +1523,5 @@ async def put_setting(self, key: str, value: Any) -> None: if self._data is None: self._data = {} - self._data[self._name].update({key: value}) + self._data.update([(self._name, {key: value})]) await self.store.async_save(self._data) From 353eeee2a87f4c7a3ceee4045a6b8cd10c7aab1a Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jun 2024 09:03:27 -0700 Subject: [PATCH 7/9] Storage migration placeholder --- custom_components/tekmar_482/hub.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index b0c2ac3..5dfd0de 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -1525,3 +1525,13 @@ async def put_setting(self, key: str, value: Any) -> None: self._data.update([(self._name, {key: value})]) await self.store.async_save(self._data) + + +class TekmarStore(Store): + + async def _async_migrate_func( + self, old_major_version: int, old_minor_version: int, old_data: dict[str, Any] + ) -> dict[str, Any]: + """Migrate to the new version.""" + + raise NotImplementedError From 6becd93e64c30064bcd617cc5540d0c94533cfec Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jun 2024 09:05:54 -0700 Subject: [PATCH 8/9] Use entry ID for storage key --- custom_components/tekmar_482/hub.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/tekmar_482/hub.py b/custom_components/tekmar_482/hub.py index 5dfd0de..415c3af 100644 --- a/custom_components/tekmar_482/hub.py +++ b/custom_components/tekmar_482/hub.py @@ -54,7 +54,7 @@ def __init__( self._id = name.lower() self._sock = TrpcSocket(host, port) - self._storage = StoredData(self._hass, self._name) + self._storage = StoredData(self._hass, self._entry_id) self._tha_inventory = {} self.tha_gateway = [] @@ -1501,12 +1501,12 @@ def device_info(self) -> Optional[Dict[str, Any]]: class StoredData(object): """Abstraction over Home Assistant Store.""" - def __init__(self, hass: HomeAssistant, name: str) -> None: + def __init__(self, hass: HomeAssistant, entry_id: str) -> None: self._hass = hass - self._name = name + self._entry_id = entry_id self._data = None - self.store: Store[dict[str, Any]] = Store( + self.store: Store[dict[str, Any]] = TekmarStore( self._hass, STORAGE_VERSION_MAJOR, STORAGE_KEY, @@ -1516,14 +1516,14 @@ async def get_setting(self, key: str) -> Any: if self._data is None: self._data = await self.store.async_load() - return self._data.get(self._name).get(key) + return self._data.get(self._entry_id).get(key) async def put_setting(self, key: str, value: Any) -> None: self._data = await self.store.async_load() if self._data is None: self._data = {} - self._data.update([(self._name, {key: value})]) + self._data.update([(self._entry_id, {key: value})]) await self.store.async_save(self._data) From 4562e844ce95346f5b47b3f3bdd03b8dc98b2f22 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:25:04 -0700 Subject: [PATCH 9/9] Clean up storage entry when removing device --- custom_components/tekmar_482/__init__.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/custom_components/tekmar_482/__init__.py b/custom_components/tekmar_482/__init__.py index 6363c98..ceaac60 100644 --- a/custom_components/tekmar_482/__init__.py +++ b/custom_components/tekmar_482/__init__.py @@ -1,14 +1,16 @@ """The Tekmar 482 Gateway Integration.""" import asyncio +from typing import Any from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceEntry +from homeassistant.helpers.storage import Store from . import hub -from .const import CONF_SETBACK_ENABLE, DOMAIN +from .const import CONF_SETBACK_ENABLE, DOMAIN, STORAGE_KEY, STORAGE_VERSION_MAJOR PLATFORMS: list[str] = [ Platform.SENSOR, @@ -68,3 +70,17 @@ async def async_remove_config_entry_device( """Allow the user to delete a device from the UI.""" return True + + +async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Handle removal of an entry.""" + + store: Store[dict[str, Any]] = Store( + hass, + STORAGE_VERSION_MAJOR, + STORAGE_KEY, + ) + + data = await store.async_load() + del data[entry.entry_id] + await store.async_save(data)