From d5c7a0475100312fdeb8aa3d48b61a3f220f7c99 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:34:10 +0200 Subject: [PATCH] Use runtime_data in openuv integration (#167029) Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- homeassistant/components/openuv/__init__.py | 23 ++++++++----------- .../components/openuv/binary_sensor.py | 12 ++++------ .../components/openuv/config_flow.py | 7 ++++-- .../components/openuv/coordinator.py | 6 +++-- .../components/openuv/diagnostics.py | 8 +++---- homeassistant/components/openuv/sensor.py | 8 +++---- tests/components/openuv/conftest.py | 6 ++++- tests/components/openuv/test_config_flow.py | 6 ++++- 8 files changed, 40 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/openuv/__init__.py b/homeassistant/components/openuv/__init__.py index 6edb42427f3..be6c99b3288 100644 --- a/homeassistant/components/openuv/__init__.py +++ b/homeassistant/components/openuv/__init__.py @@ -7,7 +7,6 @@ from typing import Any from pyopenuv import Client -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_API_KEY, CONF_BINARY_SENSORS, @@ -27,15 +26,18 @@ from .const import ( DATA_UV, DEFAULT_FROM_WINDOW, DEFAULT_TO_WINDOW, - DOMAIN, LOGGER, ) -from .coordinator import OpenUvCoordinator, OpenUvProtectionWindowCoordinator +from .coordinator import ( + OpenUvConfigEntry, + OpenUvCoordinator, + OpenUvProtectionWindowCoordinator, +) PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: OpenUvConfigEntry) -> bool: """Set up OpenUV as config entry.""" websession = aiohttp_client.async_get_clientsession(hass) client = Client( @@ -78,24 +80,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ] await asyncio.gather(*init_tasks) - hass.data.setdefault(DOMAIN, {}) - hass.data[DOMAIN][entry.entry_id] = coordinators + entry.runtime_data = coordinators await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: OpenUvConfigEntry) -> bool: """Unload an OpenUV config entry.""" - unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - if unload_ok: - hass.data[DOMAIN].pop(entry.entry_id) - - return unload_ok + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) -async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_migrate_entry(hass: HomeAssistant, entry: OpenUvConfigEntry) -> bool: """Migrate the config entry upon new versions.""" version = entry.version data = {**entry.data} diff --git a/homeassistant/components/openuv/binary_sensor.py b/homeassistant/components/openuv/binary_sensor.py index 8165c66e7dd..30418d8398e 100644 --- a/homeassistant/components/openuv/binary_sensor.py +++ b/homeassistant/components/openuv/binary_sensor.py @@ -4,13 +4,12 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntity, BinarySensorEntityDescription, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.util.dt import as_local -from .const import DATA_PROTECTION_WINDOW, DOMAIN, LOGGER, TYPE_PROTECTION_WINDOW -from .coordinator import OpenUvCoordinator +from .const import DATA_PROTECTION_WINDOW, LOGGER, TYPE_PROTECTION_WINDOW +from .coordinator import OpenUvConfigEntry from .entity import OpenUvEntity ATTR_PROTECTION_WINDOW_ENDING_TIME = "end_time" @@ -26,12 +25,11 @@ BINARY_SENSOR_DESCRIPTION_PROTECTION_WINDOW = BinarySensorEntityDescription( async def async_setup_entry( hass: HomeAssistant, - entry: ConfigEntry, + entry: OpenUvConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: - # Once we've successfully authenticated, we re-enable client request retries: - """Set up an OpenUV sensor based on a config entry.""" - coordinators: dict[str, OpenUvCoordinator] = hass.data[DOMAIN][entry.entry_id] + """Set up OpenUV binary sensors for a config entry.""" + coordinators = entry.runtime_data async_add_entities( [ diff --git a/homeassistant/components/openuv/config_flow.py b/homeassistant/components/openuv/config_flow.py index 52e369fd6df..5d432d22e39 100644 --- a/homeassistant/components/openuv/config_flow.py +++ b/homeassistant/components/openuv/config_flow.py @@ -10,7 +10,7 @@ from pyopenuv import Client from pyopenuv.errors import OpenUvError import voluptuous as vol -from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.const import ( CONF_API_KEY, CONF_ELEVATION, @@ -31,6 +31,7 @@ from .const import ( DEFAULT_TO_WINDOW, DOMAIN, ) +from .coordinator import OpenUvConfigEntry STEP_REAUTH_SCHEMA = vol.Schema( { @@ -133,7 +134,9 @@ class OpenUvFlowHandler(ConfigFlow, domain=DOMAIN): @staticmethod @callback - def async_get_options_flow(config_entry: ConfigEntry) -> SchemaOptionsFlowHandler: + def async_get_options_flow( + config_entry: OpenUvConfigEntry, + ) -> SchemaOptionsFlowHandler: """Define the config flow to handle options.""" return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW) diff --git a/homeassistant/components/openuv/coordinator.py b/homeassistant/components/openuv/coordinator.py index b29d272b0ec..7a3dc6cdb3d 100644 --- a/homeassistant/components/openuv/coordinator.py +++ b/homeassistant/components/openuv/coordinator.py @@ -20,18 +20,20 @@ from .const import LOGGER DEFAULT_DEBOUNCER_COOLDOWN_SECONDS = 15 * 60 +type OpenUvConfigEntry = ConfigEntry[dict[str, OpenUvCoordinator]] + class OpenUvCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Define an OpenUV data coordinator.""" - config_entry: ConfigEntry + config_entry: OpenUvConfigEntry update_method: Callable[[], Awaitable[dict[str, Any]]] def __init__( self, hass: HomeAssistant, *, - entry: ConfigEntry, + entry: OpenUvConfigEntry, name: str, latitude: str, longitude: str, diff --git a/homeassistant/components/openuv/diagnostics.py b/homeassistant/components/openuv/diagnostics.py index e16316d4148..005d84f7629 100644 --- a/homeassistant/components/openuv/diagnostics.py +++ b/homeassistant/components/openuv/diagnostics.py @@ -5,7 +5,6 @@ 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_LATITUDE, @@ -14,8 +13,7 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant -from .const import DOMAIN -from .coordinator import OpenUvCoordinator +from .coordinator import OpenUvConfigEntry CONF_COORDINATES = "coordinates" CONF_TITLE = "title" @@ -31,10 +29,10 @@ TO_REDACT = { async def async_get_config_entry_diagnostics( - hass: HomeAssistant, entry: ConfigEntry + hass: HomeAssistant, entry: OpenUvConfigEntry ) -> dict[str, Any]: """Return diagnostics for a config entry.""" - coordinators: dict[str, OpenUvCoordinator] = hass.data[DOMAIN][entry.entry_id] + coordinators = entry.runtime_data return async_redact_data( { diff --git a/homeassistant/components/openuv/sensor.py b/homeassistant/components/openuv/sensor.py index 5b681655e2b..7fdeaeb382b 100644 --- a/homeassistant/components/openuv/sensor.py +++ b/homeassistant/components/openuv/sensor.py @@ -12,7 +12,6 @@ from homeassistant.components.sensor import ( SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import UV_INDEX, UnitOfTime from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback @@ -20,7 +19,6 @@ from homeassistant.util.dt import as_local, parse_datetime from .const import ( DATA_UV, - DOMAIN, TYPE_CURRENT_OZONE_LEVEL, TYPE_CURRENT_UV_INDEX, TYPE_CURRENT_UV_LEVEL, @@ -32,7 +30,7 @@ from .const import ( TYPE_SAFE_EXPOSURE_TIME_5, TYPE_SAFE_EXPOSURE_TIME_6, ) -from .coordinator import OpenUvCoordinator +from .coordinator import OpenUvConfigEntry from .entity import OpenUvEntity ATTR_MAX_UV_TIME = "time" @@ -167,11 +165,11 @@ SENSOR_DESCRIPTIONS = ( async def async_setup_entry( hass: HomeAssistant, - entry: ConfigEntry, + entry: OpenUvConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up a OpenUV sensor based on a config entry.""" - coordinators: dict[str, OpenUvCoordinator] = hass.data[DOMAIN][entry.entry_id] + coordinators = entry.runtime_data async_add_entities( [ diff --git a/tests/components/openuv/conftest.py b/tests/components/openuv/conftest.py index 739af42c87d..c4ba6080693 100644 --- a/tests/components/openuv/conftest.py +++ b/tests/components/openuv/conftest.py @@ -7,7 +7,11 @@ from unittest.mock import AsyncMock, Mock, patch import pytest -from homeassistant.components.openuv import CONF_FROM_WINDOW, CONF_TO_WINDOW, DOMAIN +from homeassistant.components.openuv.const import ( + CONF_FROM_WINDOW, + CONF_TO_WINDOW, + DOMAIN, +) from homeassistant.const import ( CONF_API_KEY, CONF_ELEVATION, diff --git a/tests/components/openuv/test_config_flow.py b/tests/components/openuv/test_config_flow.py index 182f66c887f..eeee4e9882f 100644 --- a/tests/components/openuv/test_config_flow.py +++ b/tests/components/openuv/test_config_flow.py @@ -6,7 +6,11 @@ from pyopenuv.errors import InvalidApiKeyError import pytest import voluptuous as vol -from homeassistant.components.openuv import CONF_FROM_WINDOW, CONF_TO_WINDOW, DOMAIN +from homeassistant.components.openuv.const import ( + CONF_FROM_WINDOW, + CONF_TO_WINDOW, + DOMAIN, +) from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( CONF_API_KEY,