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) CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
type DeconzConfigEntry = ConfigEntry[DeconzHub]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up services.""" """Set up services."""
@ -25,14 +27,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True 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. """Set up a deCONZ bridge for a config entry.
Load config, group, light and sensor data for server information. Load config, group, light and sensor data for server information.
Start websocket for push notification of state changes from deCONZ. Start websocket for push notification of state changes from deCONZ.
""" """
hass.data.setdefault(DOMAIN, {})
if not config_entry.options: if not config_entry.options:
await async_update_master_hub(hass, config_entry) 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: except AuthenticationRequired as err:
raise ConfigEntryAuthFailed from 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() await hub.async_update_device_registry()
config_entry.async_on_unload( config_entry.async_on_unload(
@ -62,32 +65,44 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
return True 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.""" """Unload deCONZ config entry."""
hub: DeconzHub = hass.data[DOMAIN].pop(config_entry.entry_id) hub = config_entry.runtime_data
async_unload_events(hub) async_unload_events(hub)
if hass.data[DOMAIN] and hub.master: other_loaded_entries: list[DeconzConfigEntry] = [
await async_update_master_hub(hass, config_entry) e
new_master_hub = next(iter(hass.data[DOMAIN].values())) for e in hass.config_entries.async_loaded_entries(DOMAIN)
await async_update_master_hub(hass, new_master_hub.config_entry) # 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() return await hub.async_reset()
async def async_update_master_hub( async def async_update_master_hub(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant,
config_entry: DeconzConfigEntry,
*,
master: bool | None = None,
) -> None: ) -> None:
"""Update master hub boolean. """Update master hub boolean.
Called by setup_entry and unload_entry. Called by setup_entry and unload_entry.
Makes sure there is always one master available. Makes sure there is always one master available.
""" """
try: if master is None:
master_hub = get_master_hub(hass) try:
master = master_hub.config_entry == config_entry master_hub = get_master_hub(hass)
except ValueError: master = master_hub.config_entry == config_entry
master = True except ValueError:
master = True
options = {**config_entry.options, CONF_MASTER_GATEWAY: master} options = {**config_entry.options, CONF_MASTER_GATEWAY: master}

View File

@ -16,10 +16,10 @@ from homeassistant.components.alarm_control_panel import (
AlarmControlPanelState, AlarmControlPanelState,
CodeFormat, CodeFormat,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub 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( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ alarm control panel devices.""" """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() hub.entities[ALARM_CONTROl_PANEL_DOMAIN] = set()
@callback @callback

View File

@ -23,11 +23,11 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity, BinarySensorEntity,
BinarySensorEntityDescription, BinarySensorEntityDescription,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, EntityCategory from homeassistant.const import ATTR_TEMPERATURE, EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .const import ATTR_DARK, ATTR_ON from .const import ATTR_DARK, ATTR_ON
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -160,11 +160,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzBinarySensorDescription, ...] = (
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ binary sensor.""" """Set up the deCONZ binary sensor."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[BINARY_SENSOR_DOMAIN] = set() hub.entities[BINARY_SENSOR_DOMAIN] = set()
@callback @callback

View File

@ -14,11 +14,11 @@ from homeassistant.components.button import (
ButtonEntity, ButtonEntity,
ButtonEntityDescription, ButtonEntityDescription,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice, DeconzSceneMixin from .entity import DeconzDevice, DeconzSceneMixin
from .hub import DeconzHub from .hub import DeconzHub
@ -46,11 +46,11 @@ ENTITY_DESCRIPTIONS = {
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ button entity.""" """Set up the deCONZ button entity."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[BUTTON_DOMAIN] = set() hub.entities[BUTTON_DOMAIN] = set()
@callback @callback

View File

@ -28,11 +28,11 @@ from homeassistant.components.climate import (
HVACAction, HVACAction,
HVACMode, HVACMode,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .const import ATTR_LOCKED, ATTR_OFFSET, ATTR_VALVE from .const import ATTR_LOCKED, ATTR_OFFSET, ATTR_VALVE
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub 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( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ climate devices.""" """Set up the deCONZ climate devices."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[CLIMATE_DOMAIN] = set() hub.entities[CLIMATE_DOMAIN] = set()
@callback @callback

View File

@ -17,10 +17,10 @@ from homeassistant.components.cover import (
CoverEntity, CoverEntity,
CoverEntityFeature, CoverEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -33,11 +33,11 @@ DECONZ_TYPE_TO_DEVICE_CLASS = {
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up covers for deCONZ component.""" """Set up covers for deCONZ component."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[COVER_DOMAIN] = set() hub.entities[COVER_DOMAIN] = set()
@callback @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.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import DOMAIN from . import DOMAIN, DeconzConfigEntry
from .deconz_event import ( from .deconz_event import (
CONF_DECONZ_EVENT, CONF_DECONZ_EVENT,
CONF_GESTURE, CONF_GESTURE,
@ -31,7 +31,6 @@ from .deconz_event import (
DeconzPresenceEvent, DeconzPresenceEvent,
DeconzRelativeRotaryEvent, DeconzRelativeRotaryEvent,
) )
from .hub import DeconzHub
CONF_SUBTYPE = "subtype" CONF_SUBTYPE = "subtype"
@ -684,9 +683,9 @@ def _get_deconz_event_from_device(
device: dr.DeviceEntry, device: dr.DeviceEntry,
) -> DeconzAlarmEvent | DeconzEvent | DeconzPresenceEvent | DeconzRelativeRotaryEvent: ) -> DeconzAlarmEvent | DeconzEvent | DeconzPresenceEvent | DeconzRelativeRotaryEvent:
"""Resolve deconz event from device.""" """Resolve deconz event from device."""
hubs: dict[str, DeconzHub] = hass.data.get(DOMAIN, {}) entry: DeconzConfigEntry
for hub in hubs.values(): for entry in hass.config_entries.async_loaded_entries(DOMAIN):
for deconz_event in hub.events: for deconz_event in entry.runtime_data.events:
if device.id == deconz_event.device_id: if device.id == deconz_event.device_id:
return deconz_event return deconz_event

View File

@ -5,21 +5,20 @@ from __future__ import annotations
from typing import Any from typing import Any
from homeassistant.components.diagnostics import async_redact_data 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.const import CONF_API_KEY, CONF_UNIQUE_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .hub import DeconzHub from . import DeconzConfigEntry
REDACT_CONFIG = {CONF_API_KEY, CONF_UNIQUE_ID} REDACT_CONFIG = {CONF_API_KEY, CONF_UNIQUE_ID}
REDACT_DECONZ_CONFIG = {"bridgeid", "mac", "panid"} REDACT_DECONZ_CONFIG = {"bridgeid", "mac", "panid"}
async def async_get_config_entry_diagnostics( async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: DeconzConfigEntry
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
diag: dict[str, Any] = {} diag: dict[str, Any] = {}
diag["config"] = async_redact_data(config_entry.as_dict(), REDACT_CONFIG) diag["config"] = async_redact_data(config_entry.as_dict(), REDACT_CONFIG)

View File

@ -12,7 +12,6 @@ from homeassistant.components.fan import (
FanEntity, FanEntity,
FanEntityFeature, FanEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
@ -20,6 +19,7 @@ from homeassistant.util.percentage import (
percentage_to_ordered_list_item, percentage_to_ordered_list_item,
) )
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -33,11 +33,11 @@ ORDERED_NAMED_FAN_SPEEDS: list[LightFanSpeed] = [
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up fans for deCONZ component.""" """Set up fans for deCONZ component."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[FAN_DOMAIN] = set() hub.entities[FAN_DOMAIN] = set()
@callback @callback

View File

@ -3,10 +3,10 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from typing import TYPE_CHECKING
from pydeconz import DeconzSession, errors from pydeconz import DeconzSession, errors
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client from homeassistant.helpers import aiohttp_client
@ -14,9 +14,12 @@ from ..const import LOGGER
from ..errors import AuthenticationRequired, CannotConnect from ..errors import AuthenticationRequired, CannotConnect
from .config import DeconzConfig from .config import DeconzConfig
if TYPE_CHECKING:
from .. import DeconzConfigEntry
async def get_deconz_api( async def get_deconz_api(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: DeconzConfigEntry
) -> DeconzSession: ) -> DeconzSession:
"""Create a gateway object and verify configuration.""" """Create a gateway object and verify configuration."""
session = aiohttp_client.async_get_clientsession(hass) session = aiohttp_client.async_get_clientsession(hass)

View File

@ -3,9 +3,8 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass 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 homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT
from ..const import ( from ..const import (
@ -17,12 +16,15 @@ from ..const import (
DEFAULT_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES,
) )
if TYPE_CHECKING:
from .. import DeconzConfigEntry
@dataclass @dataclass
class DeconzConfig: class DeconzConfig:
"""Represent a deCONZ config entry.""" """Represent a deCONZ config entry."""
entry: ConfigEntry entry: DeconzConfigEntry
host: str host: str
port: int port: int
@ -33,7 +35,7 @@ class DeconzConfig:
allow_new_devices: bool allow_new_devices: bool
@classmethod @classmethod
def from_config_entry(cls, config_entry: ConfigEntry) -> Self: def from_config_entry(cls, config_entry: DeconzConfigEntry) -> Self:
"""Create object from config entry.""" """Create object from config entry."""
config = config_entry.data config = config_entry.data
options = config_entry.options 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.interfaces.groups import GroupHandler
from pydeconz.models.event import EventType 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.core import Event, HomeAssistant, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
@ -26,6 +26,7 @@ from ..const import (
from .config import DeconzConfig from .config import DeconzConfig
if TYPE_CHECKING: if TYPE_CHECKING:
from .. import DeconzConfigEntry
from ..deconz_event import ( from ..deconz_event import (
DeconzAlarmEvent, DeconzAlarmEvent,
DeconzEvent, DeconzEvent,
@ -67,7 +68,7 @@ class DeconzHub:
"""Manages a single deCONZ gateway.""" """Manages a single deCONZ gateway."""
def __init__( def __init__(
self, hass: HomeAssistant, config_entry: ConfigEntry, api: DeconzSession self, hass: HomeAssistant, config_entry: DeconzConfigEntry, api: DeconzSession
) -> None: ) -> None:
"""Initialize the system.""" """Initialize the system."""
self.hass = hass self.hass = hass
@ -94,12 +95,6 @@ class DeconzHub:
self.deconz_groups: set[tuple[Callable[[EventType, str], None], str]] = set() self.deconz_groups: set[tuple[Callable[[EventType, str], None], str]] = set()
self.ignored_devices: 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 @property
def bridgeid(self) -> str: def bridgeid(self) -> str:
"""Return the unique identifier of the gateway.""" """Return the unique identifier of the gateway."""
@ -208,7 +203,7 @@ class DeconzHub:
@staticmethod @staticmethod
async def async_config_entry_updated( async def async_config_entry_updated(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: DeconzConfigEntry
) -> None: ) -> None:
"""Handle signals of config entry being updated. """Handle signals of config entry being updated.
@ -217,11 +212,7 @@ class DeconzHub:
Causes for this is either discovery updating host address or Causes for this is either discovery updating host address or
config entry options changing. config entry options changing.
""" """
if config_entry.entry_id not in hass.data[DECONZ_DOMAIN]: hub = config_entry.runtime_data
# A race condition can occur if multiple config entries are
# unloaded in parallel
return
hub = DeconzHub.get_hub(hass, config_entry)
previous_config = hub.config previous_config = hub.config
hub.config = DeconzConfig.from_config_entry(config_entry) hub.config = DeconzConfig.from_config_entry(config_entry)
if previous_config.host != hub.config.host: if previous_config.host != hub.config.host:

View File

@ -28,7 +28,6 @@ from homeassistant.components.light import (
LightEntity, LightEntity,
LightEntityFeature, LightEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -38,6 +37,7 @@ from homeassistant.util.color import (
color_temperature_mired_to_kelvin, color_temperature_mired_to_kelvin,
) )
from . import DeconzConfigEntry
from .const import DOMAIN as DECONZ_DOMAIN, POWER_PLUGS from .const import DOMAIN as DECONZ_DOMAIN, POWER_PLUGS
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -141,11 +141,11 @@ def update_color_state(
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ lights and groups from a config entry.""" """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() hub.entities[LIGHT_DOMAIN] = set()
@callback @callback

View File

@ -9,21 +9,20 @@ from pydeconz.models.light.lock import Lock
from pydeconz.models.sensor.door_lock import DoorLock from pydeconz.models.sensor.door_lock import DoorLock
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockEntity from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up locks for deCONZ component.""" """Set up locks for deCONZ component."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[LOCK_DOMAIN] = set() hub.entities[LOCK_DOMAIN] = set()
@callback @callback

View File

@ -17,11 +17,11 @@ from homeassistant.components.number import (
NumberEntity, NumberEntity,
NumberEntityDescription, NumberEntityDescription,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -69,11 +69,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzNumberDescription, ...] = (
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ number entity.""" """Set up the deCONZ number entity."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[NUMBER_DOMAIN] = set() hub.entities[NUMBER_DOMAIN] = set()
@callback @callback

View File

@ -7,21 +7,20 @@ from typing import Any
from pydeconz.models.event import EventType from pydeconz.models.event import EventType
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, Scene from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, Scene
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzSceneMixin from .entity import DeconzSceneMixin
from .hub import DeconzHub
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up scenes for deCONZ integration.""" """Set up scenes for deCONZ integration."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[SCENE_DOMAIN] = set() hub.entities[SCENE_DOMAIN] = set()
@callback @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.components.select import DOMAIN as SELECT_DOMAIN, SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub
SENSITIVITY_TO_DECONZ = { SENSITIVITY_TO_DECONZ = {
"High": PresenceConfigSensitivity.HIGH.value, "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( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ button entity.""" """Set up the deCONZ button entity."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[SELECT_DOMAIN] = set() hub.entities[SELECT_DOMAIN] = set()
@callback @callback

View File

@ -34,7 +34,6 @@ from homeassistant.components.sensor import (
SensorEntityDescription, SensorEntityDescription,
SensorStateClass, SensorStateClass,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
ATTR_VOLTAGE, ATTR_VOLTAGE,
@ -55,6 +54,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from . import DeconzConfigEntry
from .const import ATTR_DARK, ATTR_ON from .const import ATTR_DARK, ATTR_ON
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub from .hub import DeconzHub
@ -331,11 +331,11 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the deCONZ sensors.""" """Set up the deCONZ sensors."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[SENSOR_DOMAIN] = set() hub.entities[SENSOR_DOMAIN] = set()
known_device_entities: dict[str, set[str]] = { known_device_entities: dict[str, set[str]] = {

View File

@ -1,5 +1,7 @@
"""deCONZ services.""" """deCONZ services."""
from typing import TYPE_CHECKING
from pydeconz.utils import normalize_bridge_id from pydeconz.utils import normalize_bridge_id
import voluptuous as vol import voluptuous as vol
@ -16,6 +18,10 @@ from .const import CONF_BRIDGE_ID, DOMAIN, LOGGER
from .hub import DeconzHub from .hub import DeconzHub
from .util import get_master_hub from .util import get_master_hub
if TYPE_CHECKING:
from . import DeconzConfigEntry
DECONZ_SERVICES = "deconz_services" DECONZ_SERVICES = "deconz_services"
SERVICE_FIELD = "field" SERVICE_FIELD = "field"
@ -65,7 +71,9 @@ def async_setup_services(hass: HomeAssistant) -> None:
found_hub = False found_hub = False
bridge_id = normalize_bridge_id(service_data[CONF_BRIDGE_ID]) 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: if possible_hub.bridgeid == bridge_id:
hub = possible_hub hub = possible_hub
found_hub = True found_hub = True

View File

@ -13,21 +13,20 @@ from homeassistant.components.siren import (
SirenEntity, SirenEntity,
SirenEntityFeature, SirenEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up sirens for deCONZ component.""" """Set up sirens for deCONZ component."""
hub = DeconzHub.get_hub(hass, config_entry) hub = config_entry.runtime_data
hub.entities[SIREN_DOMAIN] = set() hub.entities[SIREN_DOMAIN] = set()
@callback @callback

View File

@ -8,25 +8,24 @@ from pydeconz.models.event import EventType
from pydeconz.models.light.light import Light from pydeconz.models.light.light import Light
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DeconzConfigEntry
from .const import POWER_PLUGS from .const import POWER_PLUGS
from .entity import DeconzDevice from .entity import DeconzDevice
from .hub import DeconzHub
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: DeconzConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up switches for deCONZ component. """Set up switches for deCONZ component.
Switches are based on the same device class as lights in deCONZ. 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() hub.entities[SWITCH_DOMAIN] = set()
@callback @callback

View File

@ -2,11 +2,16 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from .const import DOMAIN from .const import DOMAIN
from .hub import DeconzHub from .hub import DeconzHub
if TYPE_CHECKING:
from . import DeconzConfigEntry
def serial_from_unique_id(unique_id: str | None) -> str | None: def serial_from_unique_id(unique_id: str | None) -> str | None:
"""Get a device serial number from a unique ID, if possible.""" """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 @callback
def get_master_hub(hass: HomeAssistant) -> DeconzHub: def get_master_hub(hass: HomeAssistant) -> DeconzHub:
"""Return the gateway which is marked as master.""" """Return the gateway which is marked as master."""
entry: DeconzConfigEntry
hub: DeconzHub hub: DeconzHub
for hub in hass.data[DOMAIN].values(): for entry in hass.config_entries.async_loaded_entries(DOMAIN):
if hub.master: if (hub := entry.runtime_data).master:
return hub return hub
raise ValueError raise ValueError