diff --git a/homeassistant/components/foscam/__init__.py b/homeassistant/components/foscam/__init__.py index 09df989447a..9643f333bb5 100644 --- a/homeassistant/components/foscam/__init__.py +++ b/homeassistant/components/foscam/__init__.py @@ -2,7 +2,6 @@ from libpyfoscam import FoscamCamera -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, @@ -14,13 +13,13 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries from .config_flow import DEFAULT_RTSP_PORT -from .const import CONF_RTSP_PORT, DOMAIN, LOGGER, SERVICE_PTZ, SERVICE_PTZ_PRESET -from .coordinator import FoscamCoordinator +from .const import CONF_RTSP_PORT, LOGGER +from .coordinator import FoscamConfigEntry, FoscamCoordinator PLATFORMS = [Platform.CAMERA, Platform.SWITCH] -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: FoscamConfigEntry) -> bool: """Set up foscam from a config entry.""" session = FoscamCamera( @@ -30,11 +29,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: entry.data[CONF_PASSWORD], verbose=False, ) - coordinator = FoscamCoordinator(hass, session) + coordinator = FoscamCoordinator(hass, entry, session) await coordinator.async_config_entry_first_refresh() - hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator + entry.runtime_data = coordinator # Migrate to correct unique IDs for switches await async_migrate_entities(hass, entry) @@ -44,20 +43,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: FoscamConfigEntry) -> bool: """Unload a config entry.""" - unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - if unload_ok: - hass.data[DOMAIN].pop(entry.entry_id) - - if not hass.data[DOMAIN]: - hass.services.async_remove(domain=DOMAIN, service=SERVICE_PTZ) - hass.services.async_remove(domain=DOMAIN, service=SERVICE_PTZ_PRESET) - - 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: FoscamConfigEntry) -> bool: """Migrate old entry.""" LOGGER.debug("Migrating from version %s", entry.version) @@ -97,7 +88,7 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return True -async def async_migrate_entities(hass: HomeAssistant, entry: ConfigEntry) -> None: +async def async_migrate_entities(hass: HomeAssistant, entry: FoscamConfigEntry) -> None: """Migrate old entry.""" @callback diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index 075848f6ffb..ed5ba1d4c21 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -7,21 +7,13 @@ import asyncio import voluptuous as vol from homeassistant.components.camera import Camera, CameraEntityFeature -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import ( - CONF_RTSP_PORT, - CONF_STREAM, - DOMAIN, - LOGGER, - SERVICE_PTZ, - SERVICE_PTZ_PRESET, -) -from .coordinator import FoscamCoordinator +from .const import CONF_RTSP_PORT, CONF_STREAM, LOGGER, SERVICE_PTZ, SERVICE_PTZ_PRESET +from .coordinator import FoscamConfigEntry, FoscamCoordinator from .entity import FoscamEntity DIR_UP = "up" @@ -56,7 +48,7 @@ PTZ_GOTO_PRESET_COMMAND = "ptz_goto_preset" async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: FoscamConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Add a Foscam IP camera from a config entry.""" @@ -89,7 +81,7 @@ async def async_setup_entry( "async_perform_ptz_preset", ) - coordinator: FoscamCoordinator = hass.data[DOMAIN][config_entry.entry_id] + coordinator = config_entry.runtime_data async_add_entities([HassFoscamCamera(coordinator, config_entry)]) @@ -103,7 +95,7 @@ class HassFoscamCamera(FoscamEntity, Camera): def __init__( self, coordinator: FoscamCoordinator, - config_entry: ConfigEntry, + config_entry: FoscamConfigEntry, ) -> None: """Initialize a Foscam camera.""" super().__init__(coordinator, config_entry.entry_id) diff --git a/homeassistant/components/foscam/coordinator.py b/homeassistant/components/foscam/coordinator.py index e7a8abf7d30..92eb7615e2a 100644 --- a/homeassistant/components/foscam/coordinator.py +++ b/homeassistant/components/foscam/coordinator.py @@ -6,11 +6,14 @@ from typing import Any from libpyfoscam import FoscamCamera +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN, LOGGER +type FoscamConfigEntry = ConfigEntry[FoscamCoordinator] + class FoscamCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Foscam coordinator.""" @@ -18,12 +21,14 @@ class FoscamCoordinator(DataUpdateCoordinator[dict[str, Any]]): def __init__( self, hass: HomeAssistant, + entry: FoscamConfigEntry, session: FoscamCamera, ) -> None: """Initialize my coordinator.""" super().__init__( hass, LOGGER, + config_entry=entry, name=DOMAIN, update_interval=timedelta(seconds=30), ) diff --git a/homeassistant/components/foscam/switch.py b/homeassistant/components/foscam/switch.py index dfc51aaa064..189271d2746 100644 --- a/homeassistant/components/foscam/switch.py +++ b/homeassistant/components/foscam/switch.py @@ -5,24 +5,23 @@ from __future__ import annotations from typing import Any from homeassistant.components.switch import SwitchEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import FoscamCoordinator -from .const import DOMAIN, LOGGER +from .const import LOGGER +from .coordinator import FoscamConfigEntry, FoscamCoordinator from .entity import FoscamEntity async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: FoscamConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up foscam switch from a config entry.""" - coordinator: FoscamCoordinator = hass.data[DOMAIN][config_entry.entry_id] + coordinator = config_entry.runtime_data await coordinator.async_config_entry_first_refresh() @@ -36,7 +35,7 @@ class FoscamSleepSwitch(FoscamEntity, SwitchEntity): def __init__( self, coordinator: FoscamCoordinator, - config_entry: ConfigEntry, + config_entry: FoscamConfigEntry, ) -> None: """Initialize a Foscam Sleep Switch.""" super().__init__(coordinator, config_entry.entry_id) diff --git a/tests/components/foscam/test_init.py b/tests/components/foscam/test_init.py index 0b82ed3b02a..a7b6a8c8f0b 100644 --- a/tests/components/foscam/test_init.py +++ b/tests/components/foscam/test_init.py @@ -2,7 +2,7 @@ from unittest.mock import patch -from homeassistant.components.foscam import DOMAIN, config_flow +from homeassistant.components.foscam.const import DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -18,9 +18,7 @@ async def test_unique_id_new_entry( entity_registry: er.EntityRegistry, ) -> None: """Test unique ID for a newly added device is correct.""" - entry = MockConfigEntry( - domain=config_flow.DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID - ) + entry = MockConfigEntry(domain=DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID) entry.add_to_hass(hass) with ( @@ -46,7 +44,7 @@ async def test_switch_unique_id_migration_ok( ) -> None: """Test that the unique ID for a sleep switch is migrated to the new format.""" entry = MockConfigEntry( - domain=config_flow.DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID, version=1 + domain=DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID, version=1 ) entry.add_to_hass(hass) @@ -57,7 +55,7 @@ async def test_switch_unique_id_migration_ok( # Update config entry with version 2 entry = MockConfigEntry( - domain=config_flow.DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID, version=2 + domain=DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID, version=2 ) entry.add_to_hass(hass) @@ -84,9 +82,7 @@ async def test_unique_id_migration_not_needed( entity_registry: er.EntityRegistry, ) -> None: """Test that the unique ID for a sleep switch is not executed if already in right format.""" - entry = MockConfigEntry( - domain=config_flow.DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID - ) + entry = MockConfigEntry(domain=DOMAIN, data=VALID_CONFIG, entry_id=ENTRY_ID) entry.add_to_hass(hass) entity_registry.async_get_or_create(