Make UniFi use runtime data (#117457)

This commit is contained in:
Robert Svensson 2024-05-14 21:04:26 +02:00 committed by GitHub
parent faff5f4738
commit fa815234be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 77 additions and 173 deletions

View file

@ -14,7 +14,9 @@ from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN as UNIFI_DOMAIN, PLATFORMS, UNIFI_WIRELESS_CLIENTS
from .errors import AuthenticationRequired, CannotConnect
from .hub import UnifiHub, get_unifi_api
from .services import async_setup_services, async_unload_services
from .services import async_setup_services
UnifiConfigEntry = ConfigEntry[UnifiHub]
SAVE_DELAY = 10
STORAGE_KEY = "unifi_data"
@ -25,13 +27,17 @@ CONFIG_SCHEMA = cv.config_entry_only_config_schema(UNIFI_DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Integration doesn't support configuration through configuration.yaml."""
async_setup_services(hass)
hass.data[UNIFI_WIRELESS_CLIENTS] = wireless_clients = UnifiWirelessClients(hass)
await wireless_clients.async_load()
return True
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_setup_entry(
hass: HomeAssistant, config_entry: UnifiConfigEntry
) -> bool:
"""Set up the UniFi Network integration."""
hass.data.setdefault(UNIFI_DOMAIN, {})
@ -44,17 +50,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
except AuthenticationRequired as err:
raise ConfigEntryAuthFailed from err
hub = UnifiHub(hass, config_entry, api)
hub = config_entry.runtime_data = UnifiHub(hass, config_entry, api)
await hub.initialize()
hass.data[UNIFI_DOMAIN][config_entry.entry_id] = hub
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
hub.async_update_device_registry()
hub.entity_loader.load_entities()
if len(hass.data[UNIFI_DOMAIN]) == 1:
async_setup_services(hass)
hub.websocket.start()
config_entry.async_on_unload(
@ -64,21 +66,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_unload_entry(
hass: HomeAssistant, config_entry: UnifiConfigEntry
) -> bool:
"""Unload a config entry."""
hub: UnifiHub = hass.data[UNIFI_DOMAIN].pop(config_entry.entry_id)
if not hass.data[UNIFI_DOMAIN]:
async_unload_services(hass)
return await hub.async_reset()
return await config_entry.runtime_data.async_reset()
async def async_remove_config_entry_device(
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry
hass: HomeAssistant, config_entry: UnifiConfigEntry, device_entry: DeviceEntry
) -> bool:
"""Remove config entry from a device."""
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
return not any(
identifier
for _, identifier in device_entry.connections

View file

@ -29,11 +29,11 @@ from homeassistant.components.button import (
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import UnifiConfigEntry
from .entity import (
HandlerT,
UnifiEntity,
@ -43,7 +43,6 @@ from .entity import (
async_wlan_available_fn,
async_wlan_device_info_fn,
)
from .hub import UnifiHub
async def async_restart_device_control_fn(
@ -123,15 +122,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up button platform for UniFi Network integration."""
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
async_add_entities,
UnifiButtonEntity,
ENTITY_DESCRIPTIONS,
requires_admin=True,
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities, UnifiButtonEntity, ENTITY_DESCRIPTIONS, requires_admin=True
)

View file

@ -36,6 +36,7 @@ from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import format_mac
from . import UnifiConfigEntry
from .const import (
CONF_ALLOW_BANDWIDTH_SENSORS,
CONF_ALLOW_UPTIME_SENSORS,
@ -163,9 +164,7 @@ class UnifiFlowHandler(ConfigFlow, domain=UNIFI_DOMAIN):
abort_reason = "reauth_successful"
if config_entry:
hub: UnifiHub | None = self.hass.data.get(UNIFI_DOMAIN, {}).get(
config_entry.entry_id
)
hub = config_entry.runtime_data
if hub and hub.available:
return self.async_abort(reason="already_configured")
@ -249,7 +248,7 @@ class UnifiOptionsFlowHandler(OptionsFlow):
hub: UnifiHub
def __init__(self, config_entry: ConfigEntry) -> None:
def __init__(self, config_entry: UnifiConfigEntry) -> None:
"""Initialize UniFi Network options flow."""
self.config_entry = config_entry
self.options = dict(config_entry.options)
@ -258,9 +257,7 @@ class UnifiOptionsFlowHandler(OptionsFlow):
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Manage the UniFi Network options."""
if self.config_entry.entry_id not in self.hass.data[UNIFI_DOMAIN]:
return self.async_abort(reason="integration_not_setup")
self.hub = self.hass.data[UNIFI_DOMAIN][self.config_entry.entry_id]
self.hub = self.config_entry.runtime_data
self.options[CONF_BLOCK_CLIENT] = self.hub.config.option_block_clients
if self.show_advanced_options:

View file

@ -18,13 +18,13 @@ from aiounifi.models.device import Device
from aiounifi.models.event import Event, EventKey
from homeassistant.components.device_tracker import DOMAIN, ScannerEntity, SourceType
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import Event as core_Event, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.helpers.entity_registry as er
import homeassistant.util.dt as dt_util
from . import UnifiConfigEntry
from .const import DOMAIN as UNIFI_DOMAIN
from .entity import (
HandlerT,
@ -185,12 +185,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
@callback
def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
def async_update_unique_id(hass: HomeAssistant, config_entry: UnifiConfigEntry) -> None:
"""Normalize client unique ID to have a prefix rather than suffix.
Introduced with release 2023.12.
"""
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
ent_reg = er.async_get(hass)
@callback
@ -210,12 +210,12 @@ def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> No
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up device tracker for UniFi Network integration."""
async_update_unique_id(hass, config_entry)
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities, UnifiScannerEntity, ENTITY_DESCRIPTIONS
)

View file

@ -7,13 +7,11 @@ from itertools import chain
from typing import Any
from homeassistant.components.diagnostics import REDACTED, async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import format_mac
from .const import DOMAIN as UNIFI_DOMAIN
from .hub import UnifiHub
from . import UnifiConfigEntry
TO_REDACT = {CONF_PASSWORD}
REDACT_CONFIG = {CONF_HOST, CONF_PASSWORD, CONF_USERNAME}
@ -73,10 +71,10 @@ def async_replace_list_data(
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
hass: HomeAssistant, config_entry: UnifiConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
diag: dict[str, Any] = {}
macs_to_redact: dict[str, str] = {}

View file

@ -3,10 +3,10 @@
from __future__ import annotations
from datetime import datetime
from typing import TYPE_CHECKING
import aiounifi
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import (
@ -22,12 +22,18 @@ from .entity_helper import UnifiEntityHelper
from .entity_loader import UnifiEntityLoader
from .websocket import UnifiWebsocket
if TYPE_CHECKING:
from .. import UnifiConfigEntry
class UnifiHub:
"""Manages a single UniFi Network instance."""
def __init__(
self, hass: HomeAssistant, config_entry: ConfigEntry, api: aiounifi.Controller
self,
hass: HomeAssistant,
config_entry: UnifiConfigEntry,
api: aiounifi.Controller,
) -> None:
"""Initialize the system."""
self.hass = hass
@ -40,13 +46,6 @@ class UnifiHub:
self.site = config_entry.data[CONF_SITE_ID]
self.is_admin = False
@callback
@staticmethod
def get_hub(hass: HomeAssistant, config_entry: ConfigEntry) -> UnifiHub:
"""Get UniFi hub from config entry."""
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
return hub
@property
def available(self) -> bool:
"""Websocket connection state."""
@ -122,15 +121,14 @@ class UnifiHub:
@staticmethod
async def async_config_entry_updated(
hass: HomeAssistant, config_entry: ConfigEntry
hass: HomeAssistant, config_entry: UnifiConfigEntry
) -> None:
"""Handle signals of config entry being updated.
If config entry is updated due to reauth flow
the entry might already have been reset and thus is not available.
"""
if not (hub := hass.data[UNIFI_DOMAIN].get(config_entry.entry_id)):
return
hub = config_entry.runtime_data
hub.config = UnifiConfig.from_config_entry(config_entry)
async_dispatcher_send(hass, hub.signal_options_update)

View file

@ -14,12 +14,12 @@ from aiounifi.models.api import ApiItemT
from aiounifi.models.wlan import Wlan
from homeassistant.components.image import ImageEntity, ImageEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util
from . import UnifiConfigEntry
from .entity import (
HandlerT,
UnifiEntity,
@ -65,15 +65,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up image platform for UniFi Network integration."""
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
async_add_entities,
UnifiImageEntity,
ENTITY_DESCRIPTIONS,
requires_admin=True,
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities, UnifiImageEntity, ENTITY_DESCRIPTIONS, requires_admin=True
)

View file

@ -32,7 +32,6 @@ from homeassistant.components.sensor import (
SensorStateClass,
UnitOfTemperature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfDataRate, UnitOfPower
from homeassistant.core import Event as core_Event, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -40,6 +39,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
import homeassistant.util.dt as dt_util
from . import UnifiConfigEntry
from .const import DEVICE_STATES
from .entity import (
HandlerT,
@ -420,11 +420,11 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up sensors for UniFi Network integration."""
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities, UnifiSensorEntity, ENTITY_DESCRIPTIONS
)

View file

@ -49,13 +49,6 @@ def async_setup_services(hass: HomeAssistant) -> None:
)
@callback
def async_unload_services(hass: HomeAssistant) -> None:
"""Unload UniFi Network services."""
for service in SUPPORTED_SERVICES:
hass.services.async_remove(UNIFI_DOMAIN, service)
async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
"""Try to get wireless client to reconnect to Wi-Fi."""
device_registry = dr.async_get(hass)
@ -73,9 +66,10 @@ async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) -
if mac == "":
return
for hub in hass.data[UNIFI_DOMAIN].values():
for entry in hass.config_entries.async_entries(UNIFI_DOMAIN):
if (
not hub.available
(hub := entry.runtime_data)
and not hub.available
or (client := hub.api.clients.get(mac)) is None
or client.is_wired
):
@ -91,8 +85,8 @@ async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) ->
- Total time between first seen and last seen is less than 15 minutes.
- Neither IP, hostname nor name is configured.
"""
for hub in hass.data[UNIFI_DOMAIN].values():
if not hub.available:
for entry in hass.config_entries.async_entries(UNIFI_DOMAIN):
if (hub := entry.runtime_data) and not hub.available:
continue
clients_to_remove = []

View file

@ -38,13 +38,13 @@ from homeassistant.components.switch import (
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.helpers.entity_registry as er
from . import UnifiConfigEntry
from .const import ATTR_MANUFACTURER, DOMAIN as UNIFI_DOMAIN
from .entity import (
HandlerT,
@ -270,12 +270,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
@callback
def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
def async_update_unique_id(hass: HomeAssistant, config_entry: UnifiConfigEntry) -> None:
"""Normalize switch unique ID to have a prefix rather than midfix.
Introduced with release 2023.12.
"""
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
ent_reg = er.async_get(hass)
@callback
@ -299,12 +299,12 @@ def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> No
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up switches for UniFi Network integration."""
async_update_unique_id(hass, config_entry)
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities,
UnifiSwitchEntity,
ENTITY_DESCRIPTIONS,

View file

@ -18,17 +18,16 @@ from homeassistant.components.update import (
UpdateEntityDescription,
UpdateEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import UnifiConfigEntry
from .entity import (
UnifiEntity,
UnifiEntityDescription,
async_device_available_fn,
async_device_device_info_fn,
)
from .hub import UnifiHub
LOGGER = logging.getLogger(__name__)
@ -68,11 +67,11 @@ ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: UnifiConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up update entities for UniFi Network integration."""
UnifiHub.get_hub(hass, config_entry).entity_loader.register_platform(
config_entry.runtime_data.entity_loader.register_platform(
async_add_entities,
UnifiDeviceUpdateEntity,
ENTITY_DESCRIPTIONS,

View file

@ -38,7 +38,7 @@ from homeassistant.components.device_automation import ( # noqa: F401
_async_get_device_automation_capabilities as async_get_device_automation_capabilities,
)
from homeassistant.config import async_process_component_config
from homeassistant.config_entries import ConfigEntry, ConfigFlow
from homeassistant.config_entries import ConfigEntry, ConfigFlow, _DataT
from homeassistant.const import (
DEVICE_DEFAULT_NAME,
EVENT_HOMEASSISTANT_CLOSE,
@ -973,9 +973,11 @@ class MockToggleEntity(entity.ToggleEntity):
return None
class MockConfigEntry(config_entries.ConfigEntry):
class MockConfigEntry(config_entries.ConfigEntry[_DataT]):
"""Helper for creating config entries that adds some defaults."""
runtime_data: _DataT
def __init__(
self,
*,

View file

@ -9,7 +9,6 @@ from unittest.mock import patch
from aiounifi.models.message import MessageKey
import pytest
from homeassistant.components.unifi.const import DOMAIN as UNIFI_DOMAIN
from homeassistant.components.unifi.hub.websocket import RETRY_TIMER
from homeassistant.const import CONTENT_TYPE_JSON
from homeassistant.core import HomeAssistant
@ -44,7 +43,9 @@ class WebsocketStateManager(asyncio.Event):
Mock api calls done by 'await self.api.login'.
Fail will make 'await self.api.start_websocket' return immediately.
"""
hub = self.hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
hub = self.hass.config_entries.async_get_entry(
DEFAULT_CONFIG_ENTRY_ID
).runtime_data
self.aioclient_mock.get(
f"https://{hub.config.host}:1234", status=302
) # Check UniFi OS
@ -80,7 +81,7 @@ def mock_unifi_websocket(hass):
data: list[dict] | dict | None = None,
):
"""Generate a websocket call."""
hub = hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
hub = hass.config_entries.async_get_entry(DEFAULT_CONFIG_ENTRY_ID).runtime_data
if data and not message:
hub.api.messages.handler(data)
elif data and message:

View file

@ -278,15 +278,11 @@ async def test_flow_aborts_configuration_updated(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test config flow aborts since a connected config entry already exists."""
entry = MockConfigEntry(
domain=UNIFI_DOMAIN, data={"host": "1.2.3.4", "site": "office"}, unique_id="2"
)
entry.add_to_hass(hass)
entry = MockConfigEntry(
domain=UNIFI_DOMAIN, data={"host": "1.2.3.4", "site": "site_id"}, unique_id="1"
)
entry.add_to_hass(hass)
entry.runtime_data = None
result = await hass.config_entries.flow.async_init(
UNIFI_DOMAIN, context={"source": config_entries.SOURCE_USER}
@ -393,7 +389,7 @@ async def test_reauth_flow_update_configuration(
) -> None:
"""Verify reauth flow can update hub configuration."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
hub.websocket.available = False
result = await hass.config_entries.flow.async_init(
@ -572,19 +568,6 @@ async def test_simple_option_flow(
}
async def test_option_flow_integration_not_setup(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test advanced config flow options."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
hass.data[UNIFI_DOMAIN].pop(config_entry.entry_id)
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "integration_not_setup"
async def test_form_ssdp(hass: HomeAssistant) -> None:
"""Test we get the form with ssdp source."""

View file

@ -235,9 +235,6 @@ async def setup_unifi_integration(
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
if config_entry.entry_id not in hass.data[UNIFI_DOMAIN]:
return None
return config_entry
@ -254,7 +251,7 @@ async def test_hub_setup(
config_entry = await setup_unifi_integration(
hass, aioclient_mock, system_information_response=SYSTEM_INFORMATION
)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
entry = hub.config.entry
assert len(forward_entry_setup.mock_calls) == 1
@ -333,7 +330,7 @@ async def test_config_entry_updated(
) -> None:
"""Calling reset when the entry has been setup."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
event_call = Mock()
unsub = async_dispatcher_connect(hass, hub.signal_options_update, event_call)
@ -356,7 +353,7 @@ async def test_reset_after_successful_setup(
) -> None:
"""Calling reset when the entry has been setup."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
result = await hub.async_reset()
await hass.async_block_till_done()
@ -369,7 +366,7 @@ async def test_reset_fails(
) -> None:
"""Calling reset when the entry has been setup can return false."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
with patch(
"homeassistant.config_entries.ConfigEntries.async_forward_entry_unload",

View file

@ -31,14 +31,6 @@ async def test_setup_with_no_config(hass: HomeAssistant) -> None:
assert UNIFI_DOMAIN not in hass.data
async def test_successful_config_entry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test that configured options for a host are loaded via config entry."""
await setup_unifi_integration(hass, aioclient_mock)
assert hass.data[UNIFI_DOMAIN]
async def test_setup_entry_fails_config_entry_not_ready(hass: HomeAssistant) -> None:
"""Failed authentication trigger a reauthentication flow."""
with patch(
@ -65,17 +57,6 @@ async def test_setup_entry_fails_trigger_reauth_flow(hass: HomeAssistant) -> Non
assert hass.data[UNIFI_DOMAIN] == {}
async def test_unload_entry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test being able to unload an entry."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
assert hass.data[UNIFI_DOMAIN]
assert await hass.config_entries.async_unload(config_entry.entry_id)
assert not hass.data[UNIFI_DOMAIN]
async def test_wireless_clients(
hass: HomeAssistant,
hass_storage: dict[str, Any],

View file

@ -1,12 +1,9 @@
"""deCONZ service tests."""
from unittest.mock import patch
from homeassistant.components.unifi.const import CONF_SITE_ID, DOMAIN as UNIFI_DOMAIN
from homeassistant.components.unifi.services import (
SERVICE_RECONNECT_CLIENT,
SERVICE_REMOVE_CLIENTS,
SUPPORTED_SERVICES,
)
from homeassistant.const import ATTR_DEVICE_ID, CONF_HOST
from homeassistant.core import HomeAssistant
@ -17,41 +14,6 @@ from .test_hub import setup_unifi_integration
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_service_setup_and_unload(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Verify service setup works."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
for service in SUPPORTED_SERVICES:
assert hass.services.has_service(UNIFI_DOMAIN, service)
assert await hass.config_entries.async_unload(config_entry.entry_id)
for service in SUPPORTED_SERVICES:
assert not hass.services.has_service(UNIFI_DOMAIN, service)
@patch("homeassistant.core.ServiceRegistry.async_remove")
@patch("homeassistant.core.ServiceRegistry.async_register")
async def test_service_setup_and_unload_not_called_if_multiple_integrations_detected(
register_service_mock,
remove_service_mock,
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
) -> None:
"""Make sure that services are only setup and removed once."""
config_entry = await setup_unifi_integration(hass, aioclient_mock)
register_service_mock.reset_mock()
config_entry_2 = await setup_unifi_integration(
hass, aioclient_mock, config_entry_id=2
)
register_service_mock.assert_not_called()
assert await hass.config_entries.async_unload(config_entry_2.entry_id)
remove_service_mock.assert_not_called()
assert await hass.config_entries.async_unload(config_entry.entry_id)
assert remove_service_mock.call_count == 2
async def test_reconnect_client(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
@ -144,7 +106,7 @@ async def test_reconnect_client_hub_unavailable(
config_entry = await setup_unifi_integration(
hass, aioclient_mock, clients_response=clients
)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
hub.websocket.available = False
aioclient_mock.clear_requests()
@ -293,7 +255,7 @@ async def test_remove_clients_hub_unavailable(
config_entry = await setup_unifi_integration(
hass, aioclient_mock, clients_all_response=clients
)
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
hub = config_entry.runtime_data
hub.websocket.available = False
aioclient_mock.clear_requests()