diff --git a/homeassistant/components/switcher_kis/__init__.py b/homeassistant/components/switcher_kis/__init__.py index abc9091742a..60b3b18b0b0 100644 --- a/homeassistant/components/switcher_kis/__init__.py +++ b/homeassistant/components/switcher_kis/__init__.py @@ -4,15 +4,14 @@ from __future__ import annotations import logging +from aioswitcher.bridge import SwitcherBridge from aioswitcher.device import SwitcherBase from homeassistant.config_entries import ConfigEntry from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform from homeassistant.core import Event, HomeAssistant, callback -from .const import DATA_DEVICE, DOMAIN from .coordinator import SwitcherDataUpdateCoordinator -from .utils import async_start_bridge, async_stop_bridge PLATFORMS = [ Platform.BUTTON, @@ -25,20 +24,20 @@ PLATFORMS = [ _LOGGER = logging.getLogger(__name__) -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +type SwitcherConfigEntry = ConfigEntry[dict[str, SwitcherDataUpdateCoordinator]] + + +async def async_setup_entry(hass: HomeAssistant, entry: SwitcherConfigEntry) -> bool: """Set up Switcher from a config entry.""" - hass.data.setdefault(DOMAIN, {}) - hass.data[DOMAIN][DATA_DEVICE] = {} @callback def on_device_data_callback(device: SwitcherBase) -> None: """Use as a callback for device data.""" + coordinators = entry.runtime_data + # Existing device update device data - if device.device_id in hass.data[DOMAIN][DATA_DEVICE]: - coordinator: SwitcherDataUpdateCoordinator = hass.data[DOMAIN][DATA_DEVICE][ - device.device_id - ] + if coordinator := coordinators.get(device.device_id): coordinator.async_set_updated_data(device) return @@ -52,18 +51,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: device.device_type.hex_rep, ) - coordinator = hass.data[DOMAIN][DATA_DEVICE][device.device_id] = ( - SwitcherDataUpdateCoordinator(hass, entry, device) - ) + coordinator = SwitcherDataUpdateCoordinator(hass, entry, device) coordinator.async_setup() + coordinators[device.device_id] = coordinator # Must be ready before dispatcher is called await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - await async_start_bridge(hass, on_device_data_callback) + entry.runtime_data = {} + bridge = SwitcherBridge(on_device_data_callback) + await bridge.start() - async def stop_bridge(event: Event) -> None: - await async_stop_bridge(hass) + async def stop_bridge(event: Event | None = None) -> None: + await bridge.stop() + + entry.async_on_unload(stop_bridge) entry.async_on_unload( hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_bridge) @@ -72,12 +74,6 @@ 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: SwitcherConfigEntry) -> bool: """Unload a config entry.""" - await async_stop_bridge(hass) - - unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - if unload_ok: - hass.data[DOMAIN].pop(DATA_DEVICE) - - return unload_ok + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/switcher_kis/button.py b/homeassistant/components/switcher_kis/button.py index b787043f86c..9454dcabc49 100644 --- a/homeassistant/components/switcher_kis/button.py +++ b/homeassistant/components/switcher_kis/button.py @@ -15,7 +15,6 @@ from aioswitcher.api.remotes import SwitcherBreezeRemote from aioswitcher.device import DeviceCategory 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.exceptions import HomeAssistantError @@ -25,6 +24,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity +from . import SwitcherConfigEntry from .const import SIGNAL_DEVICE_ADD from .coordinator import SwitcherDataUpdateCoordinator from .utils import get_breeze_remote_manager @@ -78,7 +78,7 @@ THERMOSTAT_BUTTONS = [ async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: SwitcherConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Switcher button from config entry.""" diff --git a/homeassistant/components/switcher_kis/climate.py b/homeassistant/components/switcher_kis/climate.py index efcb9c81f0a..9797873c73b 100644 --- a/homeassistant/components/switcher_kis/climate.py +++ b/homeassistant/components/switcher_kis/climate.py @@ -25,7 +25,6 @@ from homeassistant.components.climate import ( ClimateEntityFeature, HVACMode, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError @@ -35,6 +34,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity +from . import SwitcherConfigEntry from .const import SIGNAL_DEVICE_ADD from .coordinator import SwitcherDataUpdateCoordinator from .utils import get_breeze_remote_manager @@ -61,7 +61,7 @@ HA_TO_DEVICE_FAN = {value: key for key, value in DEVICE_FAN_TO_HA.items()} async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: SwitcherConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Switcher climate from config entry.""" diff --git a/homeassistant/components/switcher_kis/const.py b/homeassistant/components/switcher_kis/const.py index 76eb2a3e497..9edc69e4946 100644 --- a/homeassistant/components/switcher_kis/const.py +++ b/homeassistant/components/switcher_kis/const.py @@ -2,9 +2,6 @@ DOMAIN = "switcher_kis" -DATA_BRIDGE = "bridge" -DATA_DEVICE = "device" - DISCOVERY_TIME_SEC = 12 SIGNAL_DEVICE_ADD = "switcher_device_add" diff --git a/homeassistant/components/switcher_kis/diagnostics.py b/homeassistant/components/switcher_kis/diagnostics.py index 441f45198a2..a81e3e25bb9 100644 --- a/homeassistant/components/switcher_kis/diagnostics.py +++ b/homeassistant/components/switcher_kis/diagnostics.py @@ -6,24 +6,23 @@ from dataclasses import asdict from typing import Any from homeassistant.components.diagnostics import async_redact_data -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DATA_DEVICE, DOMAIN +from . import SwitcherConfigEntry TO_REDACT = {"device_id", "device_key", "ip_address", "mac_address"} async def async_get_config_entry_diagnostics( - hass: HomeAssistant, entry: ConfigEntry + hass: HomeAssistant, entry: SwitcherConfigEntry ) -> dict[str, Any]: """Return diagnostics for a config entry.""" - devices = hass.data[DOMAIN][DATA_DEVICE] + coordinators = entry.runtime_data return async_redact_data( { "entry": entry.as_dict(), - "devices": [asdict(devices[d].data) for d in devices], + "devices": [asdict(coordinators[d].data) for d in coordinators], }, TO_REDACT, ) diff --git a/homeassistant/components/switcher_kis/utils.py b/homeassistant/components/switcher_kis/utils.py index 79ac565a737..ad23d51e44d 100644 --- a/homeassistant/components/switcher_kis/utils.py +++ b/homeassistant/components/switcher_kis/utils.py @@ -3,9 +3,7 @@ from __future__ import annotations import asyncio -from collections.abc import Callable import logging -from typing import Any from aioswitcher.api.remotes import SwitcherBreezeRemoteManager from aioswitcher.bridge import SwitcherBase, SwitcherBridge @@ -13,29 +11,11 @@ from aioswitcher.bridge import SwitcherBase, SwitcherBridge from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import singleton -from .const import DATA_BRIDGE, DISCOVERY_TIME_SEC, DOMAIN +from .const import DISCOVERY_TIME_SEC _LOGGER = logging.getLogger(__name__) -async def async_start_bridge( - hass: HomeAssistant, on_device_callback: Callable[[SwitcherBase], Any] -) -> None: - """Start switcher UDP bridge.""" - bridge = hass.data[DOMAIN][DATA_BRIDGE] = SwitcherBridge(on_device_callback) - _LOGGER.debug("Starting Switcher bridge") - await bridge.start() - - -async def async_stop_bridge(hass: HomeAssistant) -> None: - """Stop switcher UDP bridge.""" - bridge: SwitcherBridge = hass.data[DOMAIN].get(DATA_BRIDGE) - if bridge is not None: - _LOGGER.debug("Stopping Switcher bridge") - await bridge.stop() - hass.data[DOMAIN].pop(DATA_BRIDGE) - - async def async_has_devices(hass: HomeAssistant) -> bool: """Discover Switcher devices.""" _LOGGER.debug("Starting discovery") diff --git a/tests/components/switcher_kis/conftest.py b/tests/components/switcher_kis/conftest.py index 5f04df7dc66..eb3b92120e1 100644 --- a/tests/components/switcher_kis/conftest.py +++ b/tests/components/switcher_kis/conftest.py @@ -18,9 +18,15 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]: @pytest.fixture def mock_bridge(request): """Return a mocked SwitcherBridge.""" - with patch( - "homeassistant.components.switcher_kis.utils.SwitcherBridge", autospec=True - ) as bridge_mock: + with ( + patch( + "homeassistant.components.switcher_kis.SwitcherBridge", autospec=True + ) as bridge_mock, + patch( + "homeassistant.components.switcher_kis.utils.SwitcherBridge", + new=bridge_mock, + ), + ): bridge = bridge_mock.return_value bridge.devices = [] diff --git a/tests/components/switcher_kis/test_init.py b/tests/components/switcher_kis/test_init.py index 70eb518820c..14217a7e044 100644 --- a/tests/components/switcher_kis/test_init.py +++ b/tests/components/switcher_kis/test_init.py @@ -4,11 +4,7 @@ from datetime import timedelta import pytest -from homeassistant.components.switcher_kis.const import ( - DATA_DEVICE, - DOMAIN, - MAX_UPDATE_INTERVAL_SEC, -) +from homeassistant.components.switcher_kis.const import MAX_UPDATE_INTERVAL_SEC from homeassistant.config_entries import ConfigEntryState from homeassistant.const import STATE_UNAVAILABLE from homeassistant.core import HomeAssistant @@ -24,15 +20,14 @@ async def test_update_fail( hass: HomeAssistant, mock_bridge, caplog: pytest.LogCaptureFixture ) -> None: """Test entities state unavailable when updates fail..""" - await init_integration(hass) + entry = await init_integration(hass) assert mock_bridge mock_bridge.mock_callbacks(DUMMY_SWITCHER_DEVICES) await hass.async_block_till_done() assert mock_bridge.is_running is True - assert len(hass.data[DOMAIN]) == 2 - assert len(hass.data[DOMAIN][DATA_DEVICE]) == 2 + assert len(entry.runtime_data) == 2 async_fire_time_changed( hass, dt_util.utcnow() + timedelta(seconds=MAX_UPDATE_INTERVAL_SEC + 1) @@ -77,11 +72,9 @@ async def test_entry_unload(hass: HomeAssistant, mock_bridge) -> None: assert entry.state is ConfigEntryState.LOADED assert mock_bridge.is_running is True - assert len(hass.data[DOMAIN]) == 2 await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() assert entry.state is ConfigEntryState.NOT_LOADED assert mock_bridge.is_running is False - assert len(hass.data[DOMAIN]) == 0 diff --git a/tests/components/switcher_kis/test_sensor.py b/tests/components/switcher_kis/test_sensor.py index f61cdd5a010..bfe1b2c84dd 100644 --- a/tests/components/switcher_kis/test_sensor.py +++ b/tests/components/switcher_kis/test_sensor.py @@ -2,7 +2,6 @@ import pytest -from homeassistant.components.switcher_kis.const import DATA_DEVICE, DOMAIN from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.util import slugify @@ -32,12 +31,11 @@ DEVICE_SENSORS_TUPLE = ( @pytest.mark.parametrize("mock_bridge", [DUMMY_SWITCHER_DEVICES], indirect=True) async def test_sensor_platform(hass: HomeAssistant, mock_bridge) -> None: """Test sensor platform.""" - await init_integration(hass) + entry = await init_integration(hass) assert mock_bridge assert mock_bridge.is_running is True - assert len(hass.data[DOMAIN]) == 2 - assert len(hass.data[DOMAIN][DATA_DEVICE]) == 2 + assert len(entry.runtime_data) == 2 for device, sensors in DEVICE_SENSORS_TUPLE: for sensor, field in sensors: