Store runtime data inside the config entry in Radarr (#119749)

* Store runtime data inside the config entry in Radarr

* move entry typing outside constructor
This commit is contained in:
Robert Hillis 2024-06-17 07:47:49 -04:00 committed by GitHub
parent 9f46b582d3
commit dcca749d50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 49 additions and 43 deletions

View file

@ -2,7 +2,8 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, cast from dataclasses import dataclass, fields
from typing import cast
from aiopyarr.models.host_configuration import PyArrHostConfiguration from aiopyarr.models.host_configuration import PyArrHostConfiguration
from aiopyarr.radarr_client import RadarrClient from aiopyarr.radarr_client import RadarrClient
@ -34,9 +35,22 @@ from .coordinator import (
) )
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CALENDAR, Platform.SENSOR] PLATFORMS = [Platform.BINARY_SENSOR, Platform.CALENDAR, Platform.SENSOR]
type RadarrConfigEntry = ConfigEntry[RadarrData]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @dataclass(kw_only=True, slots=True)
class RadarrData:
"""Radarr data type."""
calendar: CalendarUpdateCoordinator
disk_space: DiskSpaceDataUpdateCoordinator
health: HealthDataUpdateCoordinator
movie: MoviesDataUpdateCoordinator
queue: QueueDataUpdateCoordinator
status: StatusDataUpdateCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: RadarrConfigEntry) -> bool:
"""Set up Radarr from a config entry.""" """Set up Radarr from a config entry."""
host_configuration = PyArrHostConfiguration( host_configuration = PyArrHostConfiguration(
api_token=entry.data[CONF_API_KEY], api_token=entry.data[CONF_API_KEY],
@ -47,27 +61,25 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
host_configuration=host_configuration, host_configuration=host_configuration,
session=async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL]), session=async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL]),
) )
coordinators: dict[str, RadarrDataUpdateCoordinator[Any]] = { data = RadarrData(
"calendar": CalendarUpdateCoordinator(hass, host_configuration, radarr), calendar=CalendarUpdateCoordinator(hass, host_configuration, radarr),
"disk_space": DiskSpaceDataUpdateCoordinator(hass, host_configuration, radarr), disk_space=DiskSpaceDataUpdateCoordinator(hass, host_configuration, radarr),
"health": HealthDataUpdateCoordinator(hass, host_configuration, radarr), health=HealthDataUpdateCoordinator(hass, host_configuration, radarr),
"movie": MoviesDataUpdateCoordinator(hass, host_configuration, radarr), movie=MoviesDataUpdateCoordinator(hass, host_configuration, radarr),
"queue": QueueDataUpdateCoordinator(hass, host_configuration, radarr), queue=QueueDataUpdateCoordinator(hass, host_configuration, radarr),
"status": StatusDataUpdateCoordinator(hass, host_configuration, radarr), status=StatusDataUpdateCoordinator(hass, host_configuration, radarr),
} )
for coordinator in coordinators.values(): for field in fields(data):
await coordinator.async_config_entry_first_refresh() await getattr(data, field.name).async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinators entry.runtime_data = data
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: RadarrConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
class RadarrEntity(CoordinatorEntity[RadarrDataUpdateCoordinator[T]]): class RadarrEntity(CoordinatorEntity[RadarrDataUpdateCoordinator[T]]):

View file

@ -9,13 +9,12 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity, BinarySensorEntity,
BinarySensorEntityDescription, BinarySensorEntityDescription,
) )
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 AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import RadarrEntity from . import RadarrConfigEntry, RadarrEntity
from .const import DOMAIN, HEALTH_ISSUES from .const import HEALTH_ISSUES
BINARY_SENSOR_TYPE = BinarySensorEntityDescription( BINARY_SENSOR_TYPE = BinarySensorEntityDescription(
key="health", key="health",
@ -27,11 +26,11 @@ BINARY_SENSOR_TYPE = BinarySensorEntityDescription(
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: RadarrConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up Radarr sensors based on a config entry.""" """Set up Radarr sensors based on a config entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]["health"] coordinator = entry.runtime_data.health
async_add_entities([RadarrBinarySensor(coordinator, BINARY_SENSOR_TYPE)]) async_add_entities([RadarrBinarySensor(coordinator, BINARY_SENSOR_TYPE)])

View file

@ -5,13 +5,11 @@ from __future__ import annotations
from datetime import datetime from datetime import datetime
from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.components.calendar import CalendarEntity, CalendarEvent
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import RadarrEntity from . import RadarrConfigEntry, RadarrEntity
from .const import DOMAIN
from .coordinator import CalendarUpdateCoordinator, RadarrEvent from .coordinator import CalendarUpdateCoordinator, RadarrEvent
CALENDAR_TYPE = EntityDescription( CALENDAR_TYPE = EntityDescription(
@ -21,10 +19,12 @@ CALENDAR_TYPE = EntityDescription(
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant,
entry: RadarrConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Radarr calendar entity.""" """Set up the Radarr calendar entity."""
coordinator = hass.data[DOMAIN][entry.entry_id]["calendar"] coordinator = entry.runtime_data.calendar
async_add_entities([RadarrCalendarEntity(coordinator, CALENDAR_TYPE)]) async_add_entities([RadarrCalendarEntity(coordinator, CALENDAR_TYPE)])

View file

@ -11,11 +11,12 @@ from aiopyarr.models.host_configuration import PyArrHostConfiguration
from aiopyarr.radarr_client import RadarrClient from aiopyarr.radarr_client import RadarrClient
import voluptuous as vol 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_URL, CONF_VERIFY_SSL from homeassistant.const import CONF_API_KEY, CONF_URL, CONF_VERIFY_SSL
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from . import RadarrConfigEntry
from .const import DEFAULT_NAME, DEFAULT_URL, DOMAIN from .const import DEFAULT_NAME, DEFAULT_URL, DOMAIN
@ -23,10 +24,7 @@ class RadarrConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Radarr.""" """Handle a config flow for Radarr."""
VERSION = 1 VERSION = 1
entry: RadarrConfigEntry | None = None
def __init__(self) -> None:
"""Initialize the flow."""
self.entry: ConfigEntry | None = None
async def async_step_reauth(self, _: Mapping[str, Any]) -> ConfigFlowResult: async def async_step_reauth(self, _: Mapping[str, Any]) -> ConfigFlowResult:
"""Handle configuration by re-auth.""" """Handle configuration by re-auth."""

View file

@ -6,7 +6,7 @@ from abc import ABC, abstractmethod
import asyncio import asyncio
from dataclasses import dataclass from dataclasses import dataclass
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from typing import Generic, TypeVar, cast from typing import TYPE_CHECKING, Generic, TypeVar, cast
from aiopyarr import ( from aiopyarr import (
Health, Health,
@ -20,13 +20,15 @@ from aiopyarr.models.host_configuration import PyArrHostConfiguration
from aiopyarr.radarr_client import RadarrClient from aiopyarr.radarr_client import RadarrClient
from homeassistant.components.calendar import CalendarEvent from homeassistant.components.calendar import CalendarEvent
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DEFAULT_MAX_RECORDS, DOMAIN, LOGGER from .const import DEFAULT_MAX_RECORDS, DOMAIN, LOGGER
if TYPE_CHECKING:
from . import RadarrConfigEntry
T = TypeVar("T", bound=SystemStatus | list[RootFolder] | list[Health] | int | None) T = TypeVar("T", bound=SystemStatus | list[RootFolder] | list[Health] | int | None)
@ -45,7 +47,7 @@ class RadarrEvent(CalendarEvent, RadarrEventMixIn):
class RadarrDataUpdateCoordinator(DataUpdateCoordinator[T], Generic[T], ABC): class RadarrDataUpdateCoordinator(DataUpdateCoordinator[T], Generic[T], ABC):
"""Data update coordinator for the Radarr integration.""" """Data update coordinator for the Radarr integration."""
config_entry: ConfigEntry config_entry: RadarrConfigEntry
_update_interval = timedelta(seconds=30) _update_interval = timedelta(seconds=30)
def __init__( def __init__(

View file

@ -15,13 +15,11 @@ from homeassistant.components.sensor import (
SensorEntityDescription, SensorEntityDescription,
SensorStateClass, SensorStateClass,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, UnitOfInformation from homeassistant.const import EntityCategory, UnitOfInformation
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import RadarrEntity from . import RadarrConfigEntry, RadarrEntity
from .const import DOMAIN
from .coordinator import RadarrDataUpdateCoordinator, T from .coordinator import RadarrDataUpdateCoordinator, T
@ -117,16 +115,13 @@ PARALLEL_UPDATES = 1
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: RadarrConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up Radarr sensors based on a config entry.""" """Set up Radarr sensors based on a config entry."""
coordinators: dict[str, RadarrDataUpdateCoordinator[Any]] = hass.data[DOMAIN][
entry.entry_id
]
entities: list[RadarrSensor[Any]] = [] entities: list[RadarrSensor[Any]] = []
for coordinator_type, description in SENSOR_TYPES.items(): for coordinator_type, description in SENSOR_TYPES.items():
coordinator = coordinators[coordinator_type] coordinator = getattr(entry.runtime_data, coordinator_type)
if coordinator_type != "disk_space": if coordinator_type != "disk_space":
entities.append(RadarrSensor(coordinator, description)) entities.append(RadarrSensor(coordinator, description))
else: else: