diff --git a/homeassistant/components/devialet/__init__.py b/homeassistant/components/devialet/__init__.py index 2eccdb2a4b6..be641ad58a5 100644 --- a/homeassistant/components/devialet/__init__.py +++ b/homeassistant/components/devialet/__init__.py @@ -4,29 +4,28 @@ from __future__ import annotations from devialet import DevialetApi -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession -from .const import DOMAIN +from .coordinator import DevialetConfigEntry, DevialetCoordinator PLATFORMS = [Platform.MEDIA_PLAYER] -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: DevialetConfigEntry) -> bool: """Set up Devialet from a config entry.""" session = async_get_clientsession(hass) - hass.data.setdefault(DOMAIN, {})[entry.entry_id] = DevialetApi( - entry.data[CONF_HOST], session - ) + client = DevialetApi(entry.data[CONF_HOST], session) + coordinator = DevialetCoordinator(hass, entry, client) + await coordinator.async_config_entry_first_refresh() + + 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: DevialetConfigEntry) -> bool: """Unload Devialet config entry.""" - if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - del hass.data[DOMAIN][entry.entry_id] - return unload_ok + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/devialet/coordinator.py b/homeassistant/components/devialet/coordinator.py index 9cfeb797373..7b022b921f8 100644 --- a/homeassistant/components/devialet/coordinator.py +++ b/homeassistant/components/devialet/coordinator.py @@ -5,6 +5,7 @@ import logging from devialet import DevialetApi +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator @@ -14,15 +15,22 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=5) +type DevialetConfigEntry = ConfigEntry[DevialetCoordinator] + class DevialetCoordinator(DataUpdateCoordinator[None]): """Devialet update coordinator.""" - def __init__(self, hass: HomeAssistant, client: DevialetApi) -> None: + config_entry: DevialetConfigEntry + + def __init__( + self, hass: HomeAssistant, entry: DevialetConfigEntry, client: DevialetApi + ) -> None: """Initialize the coordinator.""" super().__init__( hass, _LOGGER, + config_entry=entry, name=DOMAIN, update_interval=SCAN_INTERVAL, ) diff --git a/homeassistant/components/devialet/diagnostics.py b/homeassistant/components/devialet/diagnostics.py index ae887dd1c8c..75d6e7aa222 100644 --- a/homeassistant/components/devialet/diagnostics.py +++ b/homeassistant/components/devialet/diagnostics.py @@ -4,18 +4,13 @@ from __future__ import annotations from typing import Any -from devialet import DevialetApi - -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DOMAIN +from .coordinator import DevialetConfigEntry async def async_get_config_entry_diagnostics( - hass: HomeAssistant, entry: ConfigEntry + hass: HomeAssistant, entry: DevialetConfigEntry ) -> dict[str, Any]: """Return diagnostics for a config entry.""" - client: DevialetApi = hass.data[DOMAIN][entry.entry_id] - - return await client.async_get_diagnostics() + return await entry.runtime_data.client.async_get_diagnostics() diff --git a/homeassistant/components/devialet/media_player.py b/homeassistant/components/devialet/media_player.py index 8789516650a..04ec58723cf 100644 --- a/homeassistant/components/devialet/media_player.py +++ b/homeassistant/components/devialet/media_player.py @@ -9,7 +9,6 @@ from homeassistant.components.media_player import ( MediaPlayerEntityFeature, MediaPlayerState, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceInfo @@ -17,7 +16,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, MANUFACTURER, SOUND_MODES -from .coordinator import DevialetCoordinator +from .coordinator import DevialetConfigEntry, DevialetCoordinator SUPPORT_DEVIALET = ( MediaPlayerEntityFeature.VOLUME_SET @@ -37,14 +36,12 @@ DEVIALET_TO_HA_FEATURE_MAP = { async def async_setup_entry( - hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, + entry: DevialetConfigEntry, + async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Devialet entry.""" - client = hass.data[DOMAIN][entry.entry_id] - coordinator = DevialetCoordinator(hass, client) - await coordinator.async_config_entry_first_refresh() - - async_add_entities([DevialetMediaPlayerEntity(coordinator, entry)]) + async_add_entities([DevialetMediaPlayerEntity(entry.runtime_data)]) class DevialetMediaPlayerEntity( @@ -55,18 +52,18 @@ class DevialetMediaPlayerEntity( _attr_has_entity_name = True _attr_name = None - def __init__(self, coordinator: DevialetCoordinator, entry: ConfigEntry) -> None: + def __init__(self, coordinator: DevialetCoordinator) -> None: """Initialize the Devialet device.""" - self.coordinator = coordinator super().__init__(coordinator) + entry = coordinator.config_entry self._attr_unique_id = str(entry.unique_id) self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, self._attr_unique_id)}, manufacturer=MANUFACTURER, - model=self.coordinator.client.model, + model=coordinator.client.model, name=entry.data[CONF_NAME], - sw_version=self.coordinator.client.version, + sw_version=coordinator.client.version, ) @callback diff --git a/tests/components/devialet/test_init.py b/tests/components/devialet/test_init.py index a87e8ac05c3..6808ee0983e 100644 --- a/tests/components/devialet/test_init.py +++ b/tests/components/devialet/test_init.py @@ -1,6 +1,5 @@ """Test the Devialet init.""" -from homeassistant.components.devialet.const import DOMAIN from homeassistant.components.media_player import DOMAIN as MP_DOMAIN, MediaPlayerState from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant @@ -16,7 +15,6 @@ async def test_load_unload_config_entry( """Test the Devialet configuration entry loading and unloading.""" entry = await setup_integration(hass, aioclient_mock) - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED assert entry.unique_id is not None @@ -26,7 +24,6 @@ async def test_load_unload_config_entry( await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED @@ -36,7 +33,6 @@ async def test_load_unload_config_entry_when_device_unavailable( """Test the Devialet configuration entry loading and unloading when the device is unavailable.""" entry = await setup_integration(hass, aioclient_mock, state="unavailable") - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED assert entry.unique_id is not None @@ -46,5 +42,4 @@ async def test_load_unload_config_entry_when_device_unavailable( await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED diff --git a/tests/components/devialet/test_media_player.py b/tests/components/devialet/test_media_player.py index 6ca3d23218f..fd593a10a98 100644 --- a/tests/components/devialet/test_media_player.py +++ b/tests/components/devialet/test_media_player.py @@ -6,7 +6,6 @@ from devialet import DevialetApi from devialet.const import UrlSuffix from yarl import URL -from homeassistant.components.devialet.const import DOMAIN from homeassistant.components.devialet.media_player import SUPPORT_DEVIALET from homeassistant.components.homeassistant import SERVICE_UPDATE_ENTITY from homeassistant.components.media_player import ( @@ -108,7 +107,6 @@ async def test_media_player_playing( await async_setup_component(hass, "homeassistant", {}) entry = await setup_integration(hass, aioclient_mock) - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED await hass.services.async_call( @@ -227,7 +225,6 @@ async def test_media_player_playing( await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED @@ -237,7 +234,6 @@ async def test_media_player_offline( """Test the Devialet configuration entry loading and unloading.""" entry = await setup_integration(hass, aioclient_mock, state=STATE_UNAVAILABLE) - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED state = hass.states.get(f"{MP_DOMAIN}.{NAME.lower()}") @@ -247,7 +243,6 @@ async def test_media_player_offline( await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED @@ -257,14 +252,12 @@ async def test_media_player_without_serial( """Test the Devialet configuration entry loading and unloading.""" entry = await setup_integration(hass, aioclient_mock, serial=None) - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED assert entry.unique_id is None await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED @@ -276,7 +269,6 @@ async def test_media_player_services( hass, aioclient_mock, state=MediaPlayerState.PLAYING ) - assert entry.entry_id in hass.data[DOMAIN] assert entry.state is ConfigEntryState.LOADED target = {ATTR_ENTITY_ID: hass.states.get(f"{MP_DOMAIN}.{NAME}").entity_id} @@ -309,5 +301,4 @@ async def test_media_player_services( await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() - assert entry.entry_id not in hass.data[DOMAIN] assert entry.state is ConfigEntryState.NOT_LOADED