Compare commits

...

2 Commits

Author SHA1 Message Date
epenet
5d2092e436 Apply suggestions from code review
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2026-04-02 14:56:22 +02:00
epenet
a684ec455e Migrate qnap_qsw to use runtime_data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 12:51:34 +00:00
11 changed files with 61 additions and 61 deletions

View File

@@ -6,14 +6,17 @@ import logging
from aioqsw.localapi import ConnectionOptions, QnapQswApi
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client
from .const import DOMAIN, QSW_COORD_DATA, QSW_COORD_FW
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
from .coordinator import (
QnapQswConfigEntry,
QnapQswData,
QswDataCoordinator,
QswFirmwareCoordinator,
)
_LOGGER = logging.getLogger(__name__)
@@ -25,7 +28,7 @@ PLATFORMS: list[Platform] = [
]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: QnapQswConfigEntry) -> bool:
"""Set up QNAP QSW from a config entry."""
options = ConnectionOptions(
entry.data[CONF_URL],
@@ -44,19 +47,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except ConfigEntryNotReady as error:
_LOGGER.warning(error)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
QSW_COORD_DATA: coord_data,
QSW_COORD_FW: coord_fw,
}
entry.runtime_data = QnapQswData(
data_coordinator=coord_data,
firmware_coordinator=coord_fw,
)
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: QnapQswConfigEntry) -> 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)

View File

@@ -20,14 +20,13 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import UNDEFINED
from .const import ATTR_MESSAGE, DOMAIN, QSW_COORD_DATA
from .coordinator import QswDataCoordinator
from .const import ATTR_MESSAGE
from .coordinator import QnapQswConfigEntry, QswDataCoordinator
from .entity import QswEntityDescription, QswEntityType, QswSensorEntity
@@ -79,11 +78,11 @@ PORT_BINARY_SENSOR_TYPES: Final[tuple[QswBinarySensorEntityDescription, ...]] =
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add QNAP QSW binary sensors from a config_entry."""
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
coordinator = entry.runtime_data.data_coordinator
entities: list[QswBinarySensor] = [
QswBinarySensor(coordinator, description, entry)
@@ -138,7 +137,7 @@ class QswBinarySensor(QswSensorEntity, BinarySensorEntity):
self,
coordinator: QswDataCoordinator,
description: QswBinarySensorEntityDescription,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
type_id: int | None = None,
) -> None:
"""Initialize."""

View File

@@ -13,13 +13,12 @@ from homeassistant.components.button import (
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN, QSW_COORD_DATA, QSW_REBOOT
from .coordinator import QswDataCoordinator
from .const import QSW_REBOOT
from .coordinator import QnapQswConfigEntry, QswDataCoordinator
from .entity import QswDataEntity
@@ -42,11 +41,11 @@ BUTTON_TYPES: Final[tuple[QswButtonDescription, ...]] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add QNAP QSW buttons from a config_entry."""
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
coordinator = entry.runtime_data.data_coordinator
async_add_entities(
QswButton(coordinator, description, entry) for description in BUTTON_TYPES
)
@@ -63,7 +62,7 @@ class QswButton(QswDataEntity, ButtonEntity):
self,
coordinator: QswDataCoordinator,
description: QswButtonDescription,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
) -> None:
"""Initialize."""
super().__init__(coordinator, entry)

View File

@@ -10,8 +10,6 @@ MANUFACTURER: Final = "QNAP"
RPM: Final = "rpm"
QSW_COORD_DATA: Final = "coordinator-data"
QSW_COORD_FW: Final = "coordinator-firmware"
QSW_REBOOT = "reboot"
QSW_TIMEOUT_SEC: Final = 25
QSW_UPDATE: Final = "update"

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Any
@@ -22,13 +23,24 @@ FW_SCAN_INTERVAL = timedelta(hours=12)
_LOGGER = logging.getLogger(__name__)
@dataclass
class QnapQswData:
"""Data for the QNAP QSW integration."""
data_coordinator: QswDataCoordinator
firmware_coordinator: QswFirmwareCoordinator
type QnapQswConfigEntry = ConfigEntry[QnapQswData]
class QswDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Class to manage fetching data from the QNAP QSW device."""
config_entry: ConfigEntry
config_entry: QnapQswConfigEntry
def __init__(
self, hass: HomeAssistant, config_entry: ConfigEntry, qsw: QnapQswApi
self, hass: HomeAssistant, config_entry: QnapQswConfigEntry, qsw: QnapQswApi
) -> None:
"""Initialize."""
self.qsw = qsw
@@ -54,10 +66,10 @@ class QswDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
class QswFirmwareCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Class to manage fetching firmware data from the QNAP QSW device."""
config_entry: ConfigEntry
config_entry: QnapQswConfigEntry
def __init__(
self, hass: HomeAssistant, config_entry: ConfigEntry, qsw: QnapQswApi
self, hass: HomeAssistant, config_entry: QnapQswConfigEntry, qsw: QnapQswApi
) -> None:
"""Initialize."""
self.qsw = qsw

View File

@@ -7,12 +7,10 @@ from typing import Any
from aioqsw.const import QSD_MAC, QSD_SERIAL
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME
from homeassistant.core import HomeAssistant
from .const import DOMAIN, QSW_COORD_DATA, QSW_COORD_FW
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
from .coordinator import QnapQswConfigEntry
TO_REDACT_CONFIG = [
CONF_USERNAME,
@@ -27,15 +25,15 @@ TO_REDACT_DATA = [
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
hass: HomeAssistant, config_entry: QnapQswConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
entry_data = hass.data[DOMAIN][config_entry.entry_id]
coord_data: QswDataCoordinator = entry_data[QSW_COORD_DATA]
coord_fw: QswFirmwareCoordinator = entry_data[QSW_COORD_FW]
return {
"config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT_CONFIG),
"coord_data": async_redact_data(coord_data.data, TO_REDACT_DATA),
"coord_fw": async_redact_data(coord_fw.data, TO_REDACT_DATA),
"coord_data": async_redact_data(
config_entry.runtime_data.data_coordinator.data, TO_REDACT_DATA
),
"coord_fw": async_redact_data(
config_entry.runtime_data.firmware_coordinator.data, TO_REDACT_DATA
),
}

View File

@@ -16,7 +16,6 @@ from aioqsw.const import (
QSD_SYSTEM_BOARD,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_URL
from homeassistant.core import callback
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
@@ -24,7 +23,7 @@ from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import MANUFACTURER
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
from .coordinator import QnapQswConfigEntry, QswDataCoordinator, QswFirmwareCoordinator
class QswEntityType(StrEnum):
@@ -40,7 +39,7 @@ class QswDataEntity(CoordinatorEntity[QswDataCoordinator]):
def __init__(
self,
coordinator: QswDataCoordinator,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
type_id: int | None = None,
) -> None:
"""Initialize."""
@@ -127,7 +126,7 @@ class QswFirmwareEntity(CoordinatorEntity[QswFirmwareCoordinator]):
def __init__(
self,
coordinator: QswFirmwareCoordinator,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
) -> None:
"""Initialize."""
super().__init__(coordinator)

View File

@@ -36,7 +36,6 @@ from homeassistant.components.sensor import (
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
EntityCategory,
UnitOfDataRate,
@@ -48,8 +47,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import UNDEFINED, StateType
from homeassistant.util import dt as dt_util
from .const import ATTR_MAX, DOMAIN, QSW_COORD_DATA, RPM
from .coordinator import QswDataCoordinator
from .const import ATTR_MAX, RPM
from .coordinator import QnapQswConfigEntry, QswDataCoordinator
from .entity import QswEntityDescription, QswEntityType, QswSensorEntity
@@ -287,11 +286,11 @@ PORT_SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add QNAP QSW sensors from a config_entry."""
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
coordinator = entry.runtime_data.data_coordinator
entities: list[QswSensor] = [
QswSensor(coordinator, description, entry)
@@ -354,7 +353,7 @@ class QswSensor(QswSensorEntity, SensorEntity):
self,
coordinator: QswDataCoordinator,
description: QswSensorEntityDescription,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
type_id: int | None = None,
) -> None:
"""Initialize."""

View File

@@ -17,13 +17,12 @@ from homeassistant.components.update import (
UpdateEntityDescription,
UpdateEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN, QSW_COORD_FW, QSW_UPDATE
from .coordinator import QswFirmwareCoordinator
from .const import QSW_UPDATE
from .coordinator import QnapQswConfigEntry, QswFirmwareCoordinator
from .entity import QswFirmwareEntity
UPDATE_TYPES: Final[tuple[UpdateEntityDescription, ...]] = (
@@ -37,13 +36,11 @@ UPDATE_TYPES: Final[tuple[UpdateEntityDescription, ...]] = (
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add QNAP QSW updates from a config_entry."""
coordinator: QswFirmwareCoordinator = hass.data[DOMAIN][entry.entry_id][
QSW_COORD_FW
]
coordinator = entry.runtime_data.firmware_coordinator
async_add_entities(
QswUpdate(coordinator, description, entry) for description in UPDATE_TYPES
)
@@ -59,7 +56,7 @@ class QswUpdate(QswFirmwareEntity, UpdateEntity):
self,
coordinator: QswFirmwareCoordinator,
description: UpdateEntityDescription,
entry: ConfigEntry,
entry: QnapQswConfigEntry,
) -> None:
"""Initialize."""
super().__init__(coordinator, entry)

View File

@@ -53,7 +53,6 @@ async def test_config_entry_diagnostics(
) -> None:
"""Test config entry diagnostics."""
await async_init_integration(hass)
assert hass.data[DOMAIN]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)

View File

@@ -47,7 +47,7 @@ from aioqsw.const import (
API_VERSION,
)
from homeassistant.components.qnap_qsw import DOMAIN
from homeassistant.components.qnap_qsw.const import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
from homeassistant.core import HomeAssistant