Use runtime_data in deconz (#136412)

* Use runtime_data in deconz

* Adjust master logic

* Simplify

* Move DeconzConfigEntry definition

* More TYPE_CHECKING

* Apply suggestions from code review
This commit is contained in:
epenet 2025-01-27 10:16:57 +01:00 committed by GitHub
parent acb9d68706
commit 439a393816
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 113 additions and 95 deletions

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]] = {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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