1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-18 07:56:03 +01:00

Migrate nuki to use runtime_data (#166943)

This commit is contained in:
epenet
2026-03-31 13:55:19 +02:00
committed by GitHub
parent cb8597d62f
commit 7b9b457f15
5 changed files with 35 additions and 48 deletions

View File

@@ -3,7 +3,6 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from dataclasses import dataclass
from http import HTTPStatus from http import HTTPStatus
import logging import logging
@@ -14,7 +13,6 @@ from requests.exceptions import RequestException
from homeassistant import exceptions from homeassistant import exceptions
from homeassistant.components import webhook from homeassistant.components import webhook
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_HOST,
CONF_PORT, CONF_PORT,
@@ -28,7 +26,7 @@ from homeassistant.helpers.network import NoURLAvailableError, get_url
from homeassistant.helpers.update_coordinator import UpdateFailed from homeassistant.helpers.update_coordinator import UpdateFailed
from .const import CONF_ENCRYPT_TOKEN, DEFAULT_TIMEOUT, DOMAIN from .const import CONF_ENCRYPT_TOKEN, DEFAULT_TIMEOUT, DOMAIN
from .coordinator import NukiCoordinator from .coordinator import NukiConfigEntry, NukiCoordinator, NukiEntryData
from .helpers import NukiWebhookException, parse_id from .helpers import NukiWebhookException, parse_id
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -36,22 +34,12 @@ _LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR] PLATFORMS = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR]
@dataclass(slots=True)
class NukiEntryData:
"""Class to hold Nuki data."""
coordinator: NukiCoordinator
bridge: NukiBridge
locks: list[NukiLock]
openers: list[NukiOpener]
def _get_bridge_devices(bridge: NukiBridge) -> tuple[list[NukiLock], list[NukiOpener]]: def _get_bridge_devices(bridge: NukiBridge) -> tuple[list[NukiLock], list[NukiOpener]]:
return bridge.locks, bridge.openers return bridge.locks, bridge.openers
async def _create_webhook( async def _create_webhook(
hass: HomeAssistant, entry: ConfigEntry, bridge: NukiBridge hass: HomeAssistant, entry: NukiConfigEntry, bridge: NukiBridge
) -> None: ) -> None:
# Create HomeAssistant webhook # Create HomeAssistant webhook
async def handle_webhook( async def handle_webhook(
@@ -63,16 +51,14 @@ async def _create_webhook(
except ValueError: except ValueError:
return web.Response(status=HTTPStatus.BAD_REQUEST) return web.Response(status=HTTPStatus.BAD_REQUEST)
entry_data: NukiEntryData = hass.data[DOMAIN][entry.entry_id] locks = entry.runtime_data.locks
locks = entry_data.locks openers = entry.runtime_data.openers
openers = entry_data.openers
devices = [x for x in locks + openers if x.nuki_id == data["nukiId"]] devices = [x for x in locks + openers if x.nuki_id == data["nukiId"]]
if len(devices) == 1: if len(devices) == 1:
devices[0].update_from_callback(data) devices[0].update_from_callback(data)
coordinator = entry_data.coordinator entry.runtime_data.coordinator.async_set_updated_data(None)
coordinator.async_set_updated_data(None)
return web.Response(status=HTTPStatus.OK) return web.Response(status=HTTPStatus.OK)
@@ -157,11 +143,9 @@ def _remove_webhook(bridge: NukiBridge, entry_id: str) -> None:
bridge.callback_remove(item["id"]) bridge.callback_remove(item["id"])
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: NukiConfigEntry) -> bool:
"""Set up the Nuki entry.""" """Set up the Nuki entry."""
hass.data.setdefault(DOMAIN, {})
# Migration of entry unique_id # Migration of entry unique_id
if isinstance(entry.unique_id, int): if isinstance(entry.unique_id, int):
new_id = parse_id(entry.unique_id) new_id = parse_id(entry.unique_id)
@@ -225,7 +209,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
) )
coordinator = NukiCoordinator(hass, entry, bridge, locks, openers) coordinator = NukiCoordinator(hass, entry, bridge, locks, openers)
hass.data[DOMAIN][entry.entry_id] = NukiEntryData( entry.runtime_data = NukiEntryData(
coordinator=coordinator, coordinator=coordinator,
bridge=bridge, bridge=bridge,
locks=locks, locks=locks,
@@ -240,16 +224,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: NukiConfigEntry) -> bool:
"""Unload the Nuki entry.""" """Unload the Nuki entry."""
webhook.async_unregister(hass, entry.entry_id) webhook.async_unregister(hass, entry.entry_id)
entry_data: NukiEntryData = hass.data[DOMAIN][entry.entry_id]
try: try:
async with asyncio.timeout(10): async with asyncio.timeout(10):
await hass.async_add_executor_job( await hass.async_add_executor_job(
_remove_webhook, _remove_webhook,
entry_data.bridge, entry.runtime_data.bridge,
entry.entry_id, entry.entry_id,
) )
except InvalidCredentialsException as err: except InvalidCredentialsException as err:
@@ -261,8 +244,4 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
f"Unable to remove callback. Error communicating with Bridge: {err}" f"Unable to remove callback. Error communicating with Bridge: {err}"
) from err ) from err
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok

View File

@@ -9,23 +9,21 @@ from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass, BinarySensorDeviceClass,
BinarySensorEntity, BinarySensorEntity,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import NukiEntryData from .coordinator import NukiConfigEntry
from .const import DOMAIN
from .entity import NukiEntity from .entity import NukiEntity
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: NukiConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up the Nuki binary sensors.""" """Set up the Nuki binary sensors."""
entry_data: NukiEntryData = hass.data[DOMAIN][entry.entry_id] entry_data = entry.runtime_data
entities: list[NukiEntity] = [] entities: list[NukiEntity] = []

View File

@@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
import logging import logging
@@ -25,16 +26,28 @@ _LOGGER = logging.getLogger(__name__)
UPDATE_INTERVAL = timedelta(seconds=30) UPDATE_INTERVAL = timedelta(seconds=30)
type NukiConfigEntry = ConfigEntry[NukiEntryData]
@dataclass(slots=True)
class NukiEntryData:
"""Class to hold Nuki data."""
coordinator: NukiCoordinator
bridge: NukiBridge
locks: list[NukiLock]
openers: list[NukiOpener]
class NukiCoordinator(DataUpdateCoordinator[None]): class NukiCoordinator(DataUpdateCoordinator[None]):
"""Data Update Coordinator for the Nuki integration.""" """Data Update Coordinator for the Nuki integration."""
config_entry: ConfigEntry config_entry: NukiConfigEntry
def __init__( def __init__(
self, self,
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: NukiConfigEntry,
bridge: NukiBridge, bridge: NukiBridge,
locks: list[NukiLock], locks: list[NukiLock],
openers: list[NukiOpener], openers: list[NukiOpener],

View File

@@ -12,24 +12,23 @@ from requests.exceptions import RequestException
import voluptuous as vol import voluptuous as vol
from homeassistant.components.lock import LockEntity, LockEntityFeature from homeassistant.components.lock import LockEntity, LockEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import NukiEntryData from .const import ATTR_ENABLE, ATTR_UNLATCH, ERROR_STATES
from .const import ATTR_ENABLE, ATTR_UNLATCH, DOMAIN, ERROR_STATES from .coordinator import NukiConfigEntry
from .entity import NukiEntity from .entity import NukiEntity
from .helpers import CannotConnect from .helpers import CannotConnect
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: NukiConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up the Nuki lock platform.""" """Set up the Nuki lock platform."""
entry_data: NukiEntryData = hass.data[DOMAIN][entry.entry_id] entry_data = entry.runtime_data
coordinator = entry_data.coordinator coordinator = entry_data.coordinator
entities: list[NukiDeviceEntity] = [ entities: list[NukiDeviceEntity] = [

View File

@@ -9,23 +9,21 @@ from homeassistant.components.sensor import (
SensorEntity, SensorEntity,
SensorStateClass, SensorStateClass,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, EntityCategory from homeassistant.const import PERCENTAGE, EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import NukiEntryData from .coordinator import NukiConfigEntry
from .const import DOMAIN
from .entity import NukiEntity from .entity import NukiEntity
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: NukiConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up the Nuki lock sensor.""" """Set up the Nuki lock sensor."""
entry_data: NukiEntryData = hass.data[DOMAIN][entry.entry_id] entry_data = entry.runtime_data
async_add_entities( async_add_entities(
NukiBatterySensor(entry_data.coordinator, lock) for lock in entry_data.locks NukiBatterySensor(entry_data.coordinator, lock) for lock in entry_data.locks