Use runtime_data in vallox integration (#168604)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
epenet
2026-04-20 14:41:53 +02:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 0c294b342c
commit d96b626497
9 changed files with 58 additions and 108 deletions
+5 -14
View File
@@ -7,14 +7,13 @@ import ipaddress
from vallox_websocket_api import Vallox
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_NAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
from .const import DEFAULT_NAME, DOMAIN
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .services import async_setup_services
CONFIG_SCHEMA = vol.Schema(
@@ -48,10 +47,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ValloxConfigEntry) -> bool:
"""Set up the client and boot the platforms."""
host = entry.data[CONF_HOST]
name = entry.data[CONF_NAME]
client = Vallox(host)
@@ -59,20 +57,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
"client": client,
"coordinator": coordinator,
"name": name,
}
entry.runtime_data = coordinator
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: ValloxConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
@@ -8,13 +8,11 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.const import CONF_NAME, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -61,14 +59,11 @@ BINARY_SENSOR_ENTITIES: tuple[ValloxBinarySensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the sensors."""
data = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
ValloxBinarySensorEntity(data["name"], data["coordinator"], description)
ValloxBinarySensorEntity(entry.data[CONF_NAME], entry.runtime_data, description)
for description in BINARY_SENSOR_ENTITIES
)
@@ -15,16 +15,18 @@ from .const import STATE_SCAN_INTERVAL
_LOGGER = logging.getLogger(__name__)
type ValloxConfigEntry = ConfigEntry[ValloxDataUpdateCoordinator]
class ValloxDataUpdateCoordinator(DataUpdateCoordinator[MetricData]):
"""The DataUpdateCoordinator for Vallox."""
config_entry: ConfigEntry
config_entry: ValloxConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: ValloxConfigEntry,
client: Vallox,
) -> None:
"""Initialize Vallox data coordinator."""
+6 -17
View File
@@ -4,16 +4,12 @@ from __future__ import annotations
from datetime import date
from vallox_websocket_api import Vallox
from homeassistant.components.date import DateEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.const import CONF_NAME, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -27,13 +23,11 @@ class ValloxFilterChangeDateEntity(ValloxEntity, DateEntity):
self,
name: str,
coordinator: ValloxDataUpdateCoordinator,
client: Vallox,
) -> None:
"""Initialize the Vallox date."""
super().__init__(name, coordinator)
self._attr_unique_id = f"{self._device_uuid}-filter_change_date"
self._client = client
@property
def native_value(self) -> date | None:
@@ -44,23 +38,18 @@ class ValloxFilterChangeDateEntity(ValloxEntity, DateEntity):
async def async_set_value(self, value: date) -> None:
"""Change the date."""
await self._client.set_filter_change_date(value)
await self.coordinator.client.set_filter_change_date(value)
await self.coordinator.async_request_refresh()
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Vallox filter change date entity."""
data = hass.data[DOMAIN][entry.entry_id]
coordinator = entry.runtime_data
async_add_entities(
[
ValloxFilterChangeDateEntity(
data["name"], data["coordinator"], data["client"]
)
]
[ValloxFilterChangeDateEntity(entry.data[CONF_NAME], coordinator)]
)
+9 -19
View File
@@ -5,17 +5,16 @@ from __future__ import annotations
from collections.abc import Mapping
from typing import Any, NamedTuple
from vallox_websocket_api import Vallox, ValloxApiException, ValloxInvalidInputException
from vallox_websocket_api import ValloxApiException, ValloxInvalidInputException
from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import (
DOMAIN,
METRIC_KEY_MODE,
METRIC_KEY_PROFILE_FAN_SPEED_AWAY,
METRIC_KEY_PROFILE_FAN_SPEED_BOOST,
@@ -25,7 +24,7 @@ from .const import (
PRESET_MODE_TO_VALLOX_PROFILE,
VALLOX_PROFILE_TO_PRESET_MODE,
)
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -58,19 +57,13 @@ def _convert_to_int(value: StateType) -> int | None:
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the fan device."""
data = hass.data[DOMAIN][entry.entry_id]
coordinator = entry.runtime_data
client = data["client"]
device = ValloxFanEntity(
data["name"],
client,
data["coordinator"],
)
device = ValloxFanEntity(entry.data[CONF_NAME], coordinator)
async_add_entities([device])
@@ -89,14 +82,11 @@ class ValloxFanEntity(ValloxEntity, FanEntity):
def __init__(
self,
name: str,
client: Vallox,
coordinator: ValloxDataUpdateCoordinator,
) -> None:
"""Initialize the fan."""
super().__init__(name, coordinator)
self._client = client
self._attr_unique_id = str(self._device_uuid)
self._attr_preset_modes = list(PRESET_MODE_TO_VALLOX_PROFILE)
@@ -188,7 +178,7 @@ class ValloxFanEntity(ValloxEntity, FanEntity):
async def _async_set_power(self, mode: bool) -> bool:
try:
await self._client.set_values(
await self.coordinator.client.set_values(
{METRIC_KEY_MODE: MODE_ON if mode else MODE_OFF}
)
except ValloxApiException as err:
@@ -206,7 +196,7 @@ class ValloxFanEntity(ValloxEntity, FanEntity):
try:
profile = PRESET_MODE_TO_VALLOX_PROFILE[preset_mode]
await self._client.set_profile(profile)
await self.coordinator.client.set_profile(profile)
except ValloxApiException as err:
raise HomeAssistantError(f"Failed to set profile: {preset_mode}") from err
@@ -227,7 +217,7 @@ class ValloxFanEntity(ValloxEntity, FanEntity):
)
try:
await self._client.set_fan_speed(vallox_profile, percentage)
await self.coordinator.client.set_fan_speed(vallox_profile, percentage)
except ValloxInvalidInputException as err:
# This can happen if current profile does not support setting the fan speed.
raise ValueError(
+6 -14
View File
@@ -4,20 +4,16 @@ from __future__ import annotations
from dataclasses import dataclass
from vallox_websocket_api import Vallox
from homeassistant.components.number import (
NumberDeviceClass,
NumberEntity,
NumberEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, UnitOfTemperature
from homeassistant.const import CONF_NAME, EntityCategory, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -32,7 +28,6 @@ class ValloxNumberEntity(ValloxEntity, NumberEntity):
name: str,
coordinator: ValloxDataUpdateCoordinator,
description: ValloxNumberEntityDescription,
client: Vallox,
) -> None:
"""Initialize the Vallox number entity."""
super().__init__(name, coordinator)
@@ -40,7 +35,6 @@ class ValloxNumberEntity(ValloxEntity, NumberEntity):
self.entity_description = description
self._attr_unique_id = f"{self._device_uuid}-{description.key}"
self._client = client
@property
def native_value(self) -> float | None:
@@ -54,7 +48,7 @@ class ValloxNumberEntity(ValloxEntity, NumberEntity):
async def async_set_native_value(self, value: float) -> None:
"""Update the current value."""
await self._client.set_values(
await self.coordinator.client.set_values(
{self.entity_description.metric_key: float(value)}
)
await self.coordinator.async_request_refresh()
@@ -103,15 +97,13 @@ NUMBER_ENTITIES: tuple[ValloxNumberEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the sensors."""
data = hass.data[DOMAIN][entry.entry_id]
coordinator = entry.runtime_data
async_add_entities(
ValloxNumberEntity(
data["name"], data["coordinator"], description, data["client"]
)
ValloxNumberEntity(entry.data[CONF_NAME], coordinator, description)
for description in NUMBER_ENTITIES
)
+5 -6
View File
@@ -11,9 +11,9 @@ from homeassistant.components.sensor import (
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONCENTRATION_PARTS_PER_MILLION,
CONF_NAME,
PERCENTAGE,
REVOLUTIONS_PER_MINUTE,
EntityCategory,
@@ -26,13 +26,12 @@ from homeassistant.helpers.typing import StateType
from homeassistant.util import dt as dt_util
from .const import (
DOMAIN,
METRIC_KEY_MODE,
MODE_ON,
VALLOX_CELL_STATE_TO_STR,
VALLOX_PROFILE_TO_PRESET_MODE,
)
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -279,12 +278,12 @@ SENSOR_ENTITIES: tuple[ValloxSensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the sensors."""
name = hass.data[DOMAIN][entry.entry_id]["name"]
coordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"]
name = entry.data[CONF_NAME]
coordinator = entry.runtime_data
async_add_entities(
description.entity_type(name, coordinator, description)
+13 -12
View File
@@ -5,13 +5,13 @@ from __future__ import annotations
from enum import StrEnum, auto
import logging
from vallox_websocket_api import Profile, Vallox, ValloxApiException
from vallox_websocket_api import Profile, ValloxApiException
import voluptuous as vol
from homeassistant.core import HomeAssistant, ServiceCall, callback
from .const import DOMAIN, I18N_KEY_TO_VALLOX_PROFILE
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
@@ -47,16 +47,15 @@ SERVICE_SCHEMA_SET_PROFILE = vol.Schema(
)
def _get_client(
def _get_coordinator(
hass: HomeAssistant,
) -> tuple[Vallox, ValloxDataUpdateCoordinator]:
"""Return (client, coordinator) for Vallox config entry."""
entries = hass.config_entries.async_loaded_entries(DOMAIN)
) -> ValloxDataUpdateCoordinator:
"""Return the coordinator for the Vallox config entry."""
entries: list[ValloxConfigEntry] = hass.config_entries.async_loaded_entries(DOMAIN)
if len(entries) != 1:
raise ValueError("Expected exactly one loaded Vallox config entry")
data = hass.data[DOMAIN][entries[0].entry_id]
return data["client"], data["coordinator"]
return entries[0].runtime_data
async def _async_set_profile_fan_speed(call: ServiceCall, profile: Profile) -> None:
@@ -64,9 +63,9 @@ async def _async_set_profile_fan_speed(call: ServiceCall, profile: Profile) -> N
fan_speed: int = call.data[ATTR_PROFILE_FAN_SPEED]
_LOGGER.debug("Setting %s fan speed to: %d%%", profile.name, fan_speed)
client, coordinator = _get_client(call.hass)
coordinator = _get_coordinator(call.hass)
try:
await client.set_fan_speed(profile, fan_speed)
await coordinator.client.set_fan_speed(profile, fan_speed)
except ValloxApiException as err:
_LOGGER.error("Error setting fan speed for %s profile: %s", profile.name, err)
else:
@@ -94,9 +93,11 @@ async def _async_set_profile(call: ServiceCall) -> None:
duration: int | None = call.data.get(ATTR_DURATION)
_LOGGER.debug("Activating profile %s for %s min", profile_key, duration)
client, coordinator = _get_client(call.hass)
coordinator = _get_coordinator(call.hass)
try:
await client.set_profile(I18N_KEY_TO_VALLOX_PROFILE[profile_key], duration)
await coordinator.client.set_profile(
I18N_KEY_TO_VALLOX_PROFILE[profile_key], duration
)
except ValloxApiException as err:
_LOGGER.error(
"Error setting profile %s for duration %s: %s",
+6 -15
View File
@@ -5,16 +5,12 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from vallox_websocket_api import Vallox
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.const import CONF_NAME, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import ValloxDataUpdateCoordinator
from .coordinator import ValloxConfigEntry, ValloxDataUpdateCoordinator
from .entity import ValloxEntity
@@ -29,7 +25,6 @@ class ValloxSwitchEntity(ValloxEntity, SwitchEntity):
name: str,
coordinator: ValloxDataUpdateCoordinator,
description: ValloxSwitchEntityDescription,
client: Vallox,
) -> None:
"""Initialize the Vallox switch."""
super().__init__(name, coordinator)
@@ -37,7 +32,6 @@ class ValloxSwitchEntity(ValloxEntity, SwitchEntity):
self.entity_description = description
self._attr_unique_id = f"{self._device_uuid}-{description.key}"
self._client = client
@property
def is_on(self) -> bool | None:
@@ -59,7 +53,7 @@ class ValloxSwitchEntity(ValloxEntity, SwitchEntity):
async def _set_value(self, value: bool) -> None:
"""Update the current value."""
metric_key = self.entity_description.metric_key
await self._client.set_values({metric_key: 1 if value else 0})
await self.coordinator.client.set_values({metric_key: 1 if value else 0})
await self.coordinator.async_request_refresh()
@@ -81,16 +75,13 @@ SWITCH_ENTITIES: tuple[ValloxSwitchEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: ValloxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the switches."""
data = hass.data[DOMAIN][entry.entry_id]
coordinator = entry.runtime_data
async_add_entities(
ValloxSwitchEntity(
data["name"], data["coordinator"], description, data["client"]
)
ValloxSwitchEntity(entry.data[CONF_NAME], coordinator, description)
for description in SWITCH_ENTITIES
)