diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 42c81e69740..7de091c1292 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -18,6 +18,8 @@ from .util import get_master_hub CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) +type DeconzConfigEntry = ConfigEntry[DeconzHub] + async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up services.""" @@ -25,14 +27,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True -async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: +async def async_setup_entry( + hass: HomeAssistant, config_entry: DeconzConfigEntry +) -> bool: """Set up a deCONZ bridge for a config entry. Load config, group, light and sensor data for server information. Start websocket for push notification of state changes from deCONZ. """ - hass.data.setdefault(DOMAIN, {}) - if not config_entry.options: await async_update_master_hub(hass, config_entry) @@ -43,7 +45,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b except AuthenticationRequired as err: raise ConfigEntryAuthFailed from err - hub = hass.data[DOMAIN][config_entry.entry_id] = DeconzHub(hass, config_entry, api) + hub = DeconzHub(hass, config_entry, api) + config_entry.runtime_data = hub await hub.async_update_device_registry() config_entry.async_on_unload( @@ -62,32 +65,44 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b return True -async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: +async def async_unload_entry( + hass: HomeAssistant, config_entry: DeconzConfigEntry +) -> bool: """Unload deCONZ config entry.""" - hub: DeconzHub = hass.data[DOMAIN].pop(config_entry.entry_id) + hub = config_entry.runtime_data async_unload_events(hub) - if hass.data[DOMAIN] and hub.master: - await async_update_master_hub(hass, config_entry) - new_master_hub = next(iter(hass.data[DOMAIN].values())) - await async_update_master_hub(hass, new_master_hub.config_entry) + other_loaded_entries: list[DeconzConfigEntry] = [ + e + for e in hass.config_entries.async_loaded_entries(DOMAIN) + # exclude the config entry being unloaded + if e.entry_id != config_entry.entry_id + ] + if other_loaded_entries and hub.master: + await async_update_master_hub(hass, config_entry, master=False) + new_master_hub = next(iter(other_loaded_entries)).runtime_data + await async_update_master_hub(hass, new_master_hub.config_entry, master=True) return await hub.async_reset() async def async_update_master_hub( - hass: HomeAssistant, config_entry: ConfigEntry + hass: HomeAssistant, + config_entry: DeconzConfigEntry, + *, + master: bool | None = None, ) -> None: """Update master hub boolean. Called by setup_entry and unload_entry. Makes sure there is always one master available. """ - try: - master_hub = get_master_hub(hass) - master = master_hub.config_entry == config_entry - except ValueError: - master = True + if master is None: + try: + master_hub = get_master_hub(hass) + master = master_hub.config_entry == config_entry + except ValueError: + master = True options = {**config_entry.options, CONF_MASTER_GATEWAY: master} diff --git a/homeassistant/components/deconz/alarm_control_panel.py b/homeassistant/components/deconz/alarm_control_panel.py index 678e441a7a9..94f4cd1ddd6 100644 --- a/homeassistant/components/deconz/alarm_control_panel.py +++ b/homeassistant/components/deconz/alarm_control_panel.py @@ -16,10 +16,10 @@ from homeassistant.components.alarm_control_panel import ( AlarmControlPanelState, CodeFormat, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice from .hub import DeconzHub @@ -47,11 +47,11 @@ def get_alarm_system_id_for_unique_id(hub: DeconzHub, unique_id: str) -> str | N async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ alarm control panel devices.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[ALARM_CONTROl_PANEL_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index a5496d3bc10..e3b0fc2f2c0 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -23,11 +23,11 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntity, BinarySensorEntityDescription, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .const import ATTR_DARK, ATTR_ON from .entity import DeconzDevice from .hub import DeconzHub @@ -160,11 +160,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzBinarySensorDescription, ...] = ( async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ binary sensor.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[BINARY_SENSOR_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/button.py b/homeassistant/components/deconz/button.py index ecf28b5e22c..9fea1d02ab8 100644 --- a/homeassistant/components/deconz/button.py +++ b/homeassistant/components/deconz/button.py @@ -14,11 +14,11 @@ from homeassistant.components.button import ( ButtonEntity, ButtonEntityDescription, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice, DeconzSceneMixin from .hub import DeconzHub @@ -46,11 +46,11 @@ ENTITY_DESCRIPTIONS = { async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ button entity.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[BUTTON_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/climate.py b/homeassistant/components/deconz/climate.py index 690f943379d..aa274e6c0c1 100644 --- a/homeassistant/components/deconz/climate.py +++ b/homeassistant/components/deconz/climate.py @@ -28,11 +28,11 @@ from homeassistant.components.climate import ( HVACAction, HVACMode, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .const import ATTR_LOCKED, ATTR_OFFSET, ATTR_VALVE from .entity import DeconzDevice from .hub import DeconzHub @@ -76,11 +76,11 @@ DECONZ_TO_PRESET_MODE = {value: key for key, value in PRESET_MODE_TO_DECONZ.item async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ climate devices.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[CLIMATE_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index 030c4b12709..6dee00248ff 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -17,10 +17,10 @@ from homeassistant.components.cover import ( CoverEntity, CoverEntityFeature, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice from .hub import DeconzHub @@ -33,11 +33,11 @@ DECONZ_TYPE_TO_DEVICE_CLASS = { async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up covers for deCONZ component.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[COVER_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/device_trigger.py b/homeassistant/components/deconz/device_trigger.py index 2aeeece3ac5..158ac391b9b 100644 --- a/homeassistant/components/deconz/device_trigger.py +++ b/homeassistant/components/deconz/device_trigger.py @@ -22,7 +22,7 @@ from homeassistant.helpers import device_registry as dr from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo from homeassistant.helpers.typing import ConfigType -from . import DOMAIN +from . import DOMAIN, DeconzConfigEntry from .deconz_event import ( CONF_DECONZ_EVENT, CONF_GESTURE, @@ -31,7 +31,6 @@ from .deconz_event import ( DeconzPresenceEvent, DeconzRelativeRotaryEvent, ) -from .hub import DeconzHub CONF_SUBTYPE = "subtype" @@ -684,9 +683,9 @@ def _get_deconz_event_from_device( device: dr.DeviceEntry, ) -> DeconzAlarmEvent | DeconzEvent | DeconzPresenceEvent | DeconzRelativeRotaryEvent: """Resolve deconz event from device.""" - hubs: dict[str, DeconzHub] = hass.data.get(DOMAIN, {}) - for hub in hubs.values(): - for deconz_event in hub.events: + entry: DeconzConfigEntry + for entry in hass.config_entries.async_loaded_entries(DOMAIN): + for deconz_event in entry.runtime_data.events: if device.id == deconz_event.device_id: return deconz_event diff --git a/homeassistant/components/deconz/diagnostics.py b/homeassistant/components/deconz/diagnostics.py index fcd5dec120f..284b538d1dd 100644 --- a/homeassistant/components/deconz/diagnostics.py +++ b/homeassistant/components/deconz/diagnostics.py @@ -5,21 +5,20 @@ from __future__ import annotations from typing import Any from homeassistant.components.diagnostics import async_redact_data -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_UNIQUE_ID from homeassistant.core import HomeAssistant -from .hub import DeconzHub +from . import DeconzConfigEntry REDACT_CONFIG = {CONF_API_KEY, CONF_UNIQUE_ID} REDACT_DECONZ_CONFIG = {"bridgeid", "mac", "panid"} async def async_get_config_entry_diagnostics( - hass: HomeAssistant, config_entry: ConfigEntry + hass: HomeAssistant, config_entry: DeconzConfigEntry ) -> dict[str, Any]: """Return diagnostics for a config entry.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data diag: dict[str, Any] = {} diag["config"] = async_redact_data(config_entry.as_dict(), REDACT_CONFIG) diff --git a/homeassistant/components/deconz/fan.py b/homeassistant/components/deconz/fan.py index 26e4d3328b8..aec078f771f 100644 --- a/homeassistant/components/deconz/fan.py +++ b/homeassistant/components/deconz/fan.py @@ -12,7 +12,6 @@ from homeassistant.components.fan import ( FanEntity, FanEntityFeature, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.percentage import ( @@ -20,6 +19,7 @@ from homeassistant.util.percentage import ( percentage_to_ordered_list_item, ) +from . import DeconzConfigEntry from .entity import DeconzDevice from .hub import DeconzHub @@ -33,11 +33,11 @@ ORDERED_NAMED_FAN_SPEEDS: list[LightFanSpeed] = [ async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up fans for deCONZ component.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[FAN_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/hub/api.py b/homeassistant/components/deconz/hub/api.py index 916c34672d8..c00a2178eb0 100644 --- a/homeassistant/components/deconz/hub/api.py +++ b/homeassistant/components/deconz/hub/api.py @@ -3,10 +3,10 @@ from __future__ import annotations import asyncio +from typing import TYPE_CHECKING from pydeconz import DeconzSession, errors -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers import aiohttp_client @@ -14,9 +14,12 @@ from ..const import LOGGER from ..errors import AuthenticationRequired, CannotConnect from .config import DeconzConfig +if TYPE_CHECKING: + from .. import DeconzConfigEntry + async def get_deconz_api( - hass: HomeAssistant, config_entry: ConfigEntry + hass: HomeAssistant, config_entry: DeconzConfigEntry ) -> DeconzSession: """Create a gateway object and verify configuration.""" session = aiohttp_client.async_get_clientsession(hass) diff --git a/homeassistant/components/deconz/hub/config.py b/homeassistant/components/deconz/hub/config.py index 06d2dc10542..5acbe816833 100644 --- a/homeassistant/components/deconz/hub/config.py +++ b/homeassistant/components/deconz/hub/config.py @@ -3,9 +3,8 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Self +from typing import TYPE_CHECKING, Self -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT from ..const import ( @@ -17,12 +16,15 @@ from ..const import ( DEFAULT_ALLOW_NEW_DEVICES, ) +if TYPE_CHECKING: + from .. import DeconzConfigEntry + @dataclass class DeconzConfig: """Represent a deCONZ config entry.""" - entry: ConfigEntry + entry: DeconzConfigEntry host: str port: int @@ -33,7 +35,7 @@ class DeconzConfig: allow_new_devices: bool @classmethod - def from_config_entry(cls, config_entry: ConfigEntry) -> Self: + def from_config_entry(cls, config_entry: DeconzConfigEntry) -> Self: """Create object from config entry.""" config = config_entry.data options = config_entry.options diff --git a/homeassistant/components/deconz/hub/hub.py b/homeassistant/components/deconz/hub/hub.py index ff958bbda50..3020d624f97 100644 --- a/homeassistant/components/deconz/hub/hub.py +++ b/homeassistant/components/deconz/hub/hub.py @@ -11,7 +11,7 @@ from pydeconz.interfaces.api_handlers import APIHandler, GroupedAPIHandler from pydeconz.interfaces.groups import GroupHandler from pydeconz.models.event import EventType -from homeassistant.config_entries import SOURCE_HASSIO, ConfigEntry +from homeassistant.config_entries import SOURCE_HASSIO from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC @@ -26,6 +26,7 @@ from ..const import ( from .config import DeconzConfig if TYPE_CHECKING: + from .. import DeconzConfigEntry from ..deconz_event import ( DeconzAlarmEvent, DeconzEvent, @@ -67,7 +68,7 @@ class DeconzHub: """Manages a single deCONZ gateway.""" def __init__( - self, hass: HomeAssistant, config_entry: ConfigEntry, api: DeconzSession + self, hass: HomeAssistant, config_entry: DeconzConfigEntry, api: DeconzSession ) -> None: """Initialize the system.""" self.hass = hass @@ -94,12 +95,6 @@ class DeconzHub: self.deconz_groups: set[tuple[Callable[[EventType, str], None], str]] = set() self.ignored_devices: set[tuple[Callable[[EventType, str], None], str]] = set() - @callback - @staticmethod - def get_hub(hass: HomeAssistant, config_entry: ConfigEntry) -> DeconzHub: - """Return hub with a matching config entry ID.""" - return cast(DeconzHub, hass.data[DECONZ_DOMAIN][config_entry.entry_id]) - @property def bridgeid(self) -> str: """Return the unique identifier of the gateway.""" @@ -208,7 +203,7 @@ class DeconzHub: @staticmethod async def async_config_entry_updated( - hass: HomeAssistant, config_entry: ConfigEntry + hass: HomeAssistant, config_entry: DeconzConfigEntry ) -> None: """Handle signals of config entry being updated. @@ -217,11 +212,7 @@ class DeconzHub: Causes for this is either discovery updating host address or config entry options changing. """ - if config_entry.entry_id not in hass.data[DECONZ_DOMAIN]: - # A race condition can occur if multiple config entries are - # unloaded in parallel - return - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data previous_config = hub.config hub.config = DeconzConfig.from_config_entry(config_entry) if previous_config.host != hub.config.host: diff --git a/homeassistant/components/deconz/light.py b/homeassistant/components/deconz/light.py index d82c05f14eb..72ba7035c8e 100644 --- a/homeassistant/components/deconz/light.py +++ b/homeassistant/components/deconz/light.py @@ -28,7 +28,6 @@ from homeassistant.components.light import ( LightEntity, LightEntityFeature, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -38,6 +37,7 @@ from homeassistant.util.color import ( color_temperature_mired_to_kelvin, ) +from . import DeconzConfigEntry from .const import DOMAIN as DECONZ_DOMAIN, POWER_PLUGS from .entity import DeconzDevice from .hub import DeconzHub @@ -141,11 +141,11 @@ def update_color_state( async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ lights and groups from a config entry.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[LIGHT_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/lock.py b/homeassistant/components/deconz/lock.py index 50375e99778..e5e2faf1d57 100644 --- a/homeassistant/components/deconz/lock.py +++ b/homeassistant/components/deconz/lock.py @@ -9,21 +9,20 @@ from pydeconz.models.light.lock import Lock from pydeconz.models.sensor.door_lock import DoorLock from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice -from .hub import DeconzHub async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up locks for deCONZ component.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[LOCK_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/number.py b/homeassistant/components/deconz/number.py index 53461960573..9de86c1c79b 100644 --- a/homeassistant/components/deconz/number.py +++ b/homeassistant/components/deconz/number.py @@ -17,11 +17,11 @@ from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice from .hub import DeconzHub @@ -69,11 +69,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzNumberDescription, ...] = ( async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ number entity.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[NUMBER_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/scene.py b/homeassistant/components/deconz/scene.py index 70b9f3f21b5..3f29b12b05f 100644 --- a/homeassistant/components/deconz/scene.py +++ b/homeassistant/components/deconz/scene.py @@ -7,21 +7,20 @@ from typing import Any from pydeconz.models.event import EventType from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, Scene -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzSceneMixin -from .hub import DeconzHub async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up scenes for deCONZ integration.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[SCENE_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/select.py b/homeassistant/components/deconz/select.py index cbd96a4faf9..a3109a278fc 100644 --- a/homeassistant/components/deconz/select.py +++ b/homeassistant/components/deconz/select.py @@ -12,13 +12,12 @@ from pydeconz.models.sensor.presence import ( ) from homeassistant.components.select import DOMAIN as SELECT_DOMAIN, SelectEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice -from .hub import DeconzHub SENSITIVITY_TO_DECONZ = { "High": PresenceConfigSensitivity.HIGH.value, @@ -30,11 +29,11 @@ DECONZ_TO_SENSITIVITY = {value: key for key, value in SENSITIVITY_TO_DECONZ.item async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ button entity.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[SELECT_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index 241ba015c67..576d356bca9 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -34,7 +34,6 @@ from homeassistant.components.sensor import ( SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_TEMPERATURE, ATTR_VOLTAGE, @@ -55,6 +54,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType import homeassistant.util.dt as dt_util +from . import DeconzConfigEntry from .const import ATTR_DARK, ATTR_ON from .entity import DeconzDevice from .hub import DeconzHub @@ -331,11 +331,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = ( async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the deCONZ sensors.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[SENSOR_DOMAIN] = set() known_device_entities: dict[str, set[str]] = { diff --git a/homeassistant/components/deconz/services.py b/homeassistant/components/deconz/services.py index 6127fe44308..1f032f3866a 100644 --- a/homeassistant/components/deconz/services.py +++ b/homeassistant/components/deconz/services.py @@ -1,5 +1,7 @@ """deCONZ services.""" +from typing import TYPE_CHECKING + from pydeconz.utils import normalize_bridge_id import voluptuous as vol @@ -16,6 +18,10 @@ from .const import CONF_BRIDGE_ID, DOMAIN, LOGGER from .hub import DeconzHub from .util import get_master_hub +if TYPE_CHECKING: + from . import DeconzConfigEntry + + DECONZ_SERVICES = "deconz_services" SERVICE_FIELD = "field" @@ -65,7 +71,9 @@ def async_setup_services(hass: HomeAssistant) -> None: found_hub = False bridge_id = normalize_bridge_id(service_data[CONF_BRIDGE_ID]) - for possible_hub in hass.data[DOMAIN].values(): + entry: DeconzConfigEntry + for entry in hass.config_entries.async_loaded_entries(DOMAIN): + possible_hub = entry.runtime_data if possible_hub.bridgeid == bridge_id: hub = possible_hub found_hub = True diff --git a/homeassistant/components/deconz/siren.py b/homeassistant/components/deconz/siren.py index 982a0bd1b9e..28b606e30ba 100644 --- a/homeassistant/components/deconz/siren.py +++ b/homeassistant/components/deconz/siren.py @@ -13,21 +13,20 @@ from homeassistant.components.siren import ( SirenEntity, SirenEntityFeature, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .entity import DeconzDevice -from .hub import DeconzHub async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up sirens for deCONZ component.""" - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[SIREN_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/switch.py b/homeassistant/components/deconz/switch.py index c79cd7b28db..cd28871e35b 100644 --- a/homeassistant/components/deconz/switch.py +++ b/homeassistant/components/deconz/switch.py @@ -8,25 +8,24 @@ from pydeconz.models.event import EventType from pydeconz.models.light.light import Light from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import DeconzConfigEntry from .const import POWER_PLUGS from .entity import DeconzDevice -from .hub import DeconzHub async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: DeconzConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up switches for deCONZ component. Switches are based on the same device class as lights in deCONZ. """ - hub = DeconzHub.get_hub(hass, config_entry) + hub = config_entry.runtime_data hub.entities[SWITCH_DOMAIN] = set() @callback diff --git a/homeassistant/components/deconz/util.py b/homeassistant/components/deconz/util.py index bcf338b2d6d..c4dc9df08ce 100644 --- a/homeassistant/components/deconz/util.py +++ b/homeassistant/components/deconz/util.py @@ -2,11 +2,16 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from homeassistant.core import HomeAssistant, callback from .const import DOMAIN from .hub import DeconzHub +if TYPE_CHECKING: + from . import DeconzConfigEntry + def serial_from_unique_id(unique_id: str | None) -> str | None: """Get a device serial number from a unique ID, if possible.""" @@ -18,8 +23,9 @@ def serial_from_unique_id(unique_id: str | None) -> str | None: @callback def get_master_hub(hass: HomeAssistant) -> DeconzHub: """Return the gateway which is marked as master.""" + entry: DeconzConfigEntry hub: DeconzHub - for hub in hass.data[DOMAIN].values(): - if hub.master: + for entry in hass.config_entries.async_loaded_entries(DOMAIN): + if (hub := entry.runtime_data).master: return hub raise ValueError