mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 17:04:04 -04:00
Type the lookin UDP manager with a HassKey (#181098)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
"""The lookin integration."""
|
||||
# pylint: disable=home-assistant-use-runtime-data # Uses legacy hass.data[DOMAIN] pattern
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable, Coroutine
|
||||
@@ -23,6 +22,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
@@ -37,8 +37,6 @@ from .models import LookinConfigEntry, LookinData
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
UDP_MANAGER = "udp_manager"
|
||||
|
||||
|
||||
def _async_climate_updater(
|
||||
lookin_protocol: LookInHttpProtocol,
|
||||
@@ -90,9 +88,13 @@ class LookinUDPManager:
|
||||
self._subscriptions = None
|
||||
|
||||
|
||||
# One UDP listener serves every lookin device, so the manager is shared between
|
||||
# config entries rather than owned by any one of them.
|
||||
UDP_MANAGER: HassKey[LookinUDPManager] = HassKey(DOMAIN)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: LookinConfigEntry) -> bool:
|
||||
"""Set up lookin from a config entry."""
|
||||
domain_data = hass.data.setdefault(DOMAIN, {})
|
||||
host = entry.data[CONF_HOST]
|
||||
lookin_protocol = LookInHttpProtocol(
|
||||
api_uri=f"http://{host}", session=async_get_clientsession(hass)
|
||||
@@ -159,10 +161,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: LookinConfigEntry) -> bo
|
||||
meteo.update_from_value(event.value)
|
||||
meteo_coordinator.async_set_updated_data(meteo)
|
||||
|
||||
if UDP_MANAGER not in domain_data:
|
||||
manager = domain_data[UDP_MANAGER] = LookinUDPManager()
|
||||
else:
|
||||
manager = domain_data[UDP_MANAGER]
|
||||
if (manager := hass.data.get(UDP_MANAGER)) is None:
|
||||
manager = hass.data[UDP_MANAGER] = LookinUDPManager()
|
||||
|
||||
lookin_udp_subs = await manager.async_get_subscriptions()
|
||||
|
||||
@@ -200,7 +200,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: LookinConfigEntry) -> b
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
if not hass.config_entries.async_loaded_entries(DOMAIN):
|
||||
manager: LookinUDPManager = hass.data[DOMAIN][UDP_MANAGER]
|
||||
manager = hass.data[UDP_MANAGER]
|
||||
await manager.async_stop()
|
||||
return unload_ok
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from homeassistant.components.lookin import UDP_MANAGER
|
||||
from homeassistant.components.lookin.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST
|
||||
@@ -81,3 +82,37 @@ async def test_controlled_device_links_to_lookin_device(
|
||||
)
|
||||
assert controlled_device is not None
|
||||
assert controlled_device.via_device_id == lookin_device.id
|
||||
|
||||
|
||||
async def test_udp_manager_outlives_the_config_entry(hass: HomeAssistant) -> None:
|
||||
"""Test the shared UDP manager is reused rather than rebuilt per entry."""
|
||||
device = _mocked_device()
|
||||
remote = _mocked_remote()
|
||||
protocol = _mocked_protocol(device, remote)
|
||||
|
||||
subscriptions = MagicMock()
|
||||
subscriptions.subscribe_event = MagicMock(return_value=MagicMock())
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: IP_ADDRESS}, unique_id=DEVICE_ID
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
patch(f"{MODULE}.LookInHttpProtocol", return_value=protocol),
|
||||
patch(f"{MODULE}.LookinUDPSubscriptions", return_value=subscriptions),
|
||||
patch(f"{MODULE}.start_lookin_udp", AsyncMock(return_value=MagicMock())),
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
manager = hass.data[UDP_MANAGER]
|
||||
assert manager is not None
|
||||
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
# The manager is keyed globally, not on the entry, so a reload reuses it
|
||||
# instead of leaving a second listener behind.
|
||||
assert hass.data[UDP_MANAGER] is manager
|
||||
|
||||
Reference in New Issue
Block a user