mirror of
https://github.com/home-assistant/core.git
synced 2025-04-27 10:47:51 +00:00
Rework UniFi websocket (#100614)
* Rework websocket management * remove unnecessary fixture * Remove controller from mock_unifi_websocket * Mock api.login in reconnect method * Remove unnecessary edits * Minor clean up * Bump aiounifi to v63 * Wait on task cancellation
This commit is contained in:
parent
134c005168
commit
01b5854968
@ -52,7 +52,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
if len(hass.data[UNIFI_DOMAIN]) == 1:
|
if len(hass.data[UNIFI_DOMAIN]) == 1:
|
||||||
async_setup_services(hass)
|
async_setup_services(hass)
|
||||||
|
|
||||||
api.start_websocket()
|
controller.start_websocket()
|
||||||
|
|
||||||
config_entry.async_on_unload(
|
config_entry.async_on_unload(
|
||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, controller.shutdown)
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, controller.shutdown)
|
||||||
|
@ -12,7 +12,6 @@ import aiounifi
|
|||||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||||
from aiounifi.models.configuration import Configuration
|
from aiounifi.models.configuration import Configuration
|
||||||
from aiounifi.models.device import DeviceSetPoePortModeRequest
|
from aiounifi.models.device import DeviceSetPoePortModeRequest
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -81,7 +80,7 @@ class UniFiController:
|
|||||||
self.config_entry = config_entry
|
self.config_entry = config_entry
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
api.ws_state_callback = self.async_unifi_ws_state_callback
|
self.ws_task: asyncio.Task | None = None
|
||||||
|
|
||||||
self.available = True
|
self.available = True
|
||||||
self.wireless_clients = hass.data[UNIFI_WIRELESS_CLIENTS]
|
self.wireless_clients = hass.data[UNIFI_WIRELESS_CLIENTS]
|
||||||
@ -223,23 +222,6 @@ class UniFiController:
|
|||||||
for description in descriptions:
|
for description in descriptions:
|
||||||
async_load_entities(description)
|
async_load_entities(description)
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_unifi_ws_state_callback(self, state: WebsocketState) -> None:
|
|
||||||
"""Handle messages back from UniFi library."""
|
|
||||||
if state == WebsocketState.DISCONNECTED and self.available:
|
|
||||||
LOGGER.warning("Lost connection to UniFi Network")
|
|
||||||
|
|
||||||
if (state == WebsocketState.RUNNING and not self.available) or (
|
|
||||||
state == WebsocketState.DISCONNECTED and self.available
|
|
||||||
):
|
|
||||||
self.available = state == WebsocketState.RUNNING
|
|
||||||
async_dispatcher_send(self.hass, self.signal_reachable)
|
|
||||||
|
|
||||||
if not self.available:
|
|
||||||
self.hass.loop.call_later(RETRY_TIMER, self.reconnect, True)
|
|
||||||
else:
|
|
||||||
LOGGER.info("Connected to UniFi Network")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def signal_reachable(self) -> str:
|
def signal_reachable(self) -> str:
|
||||||
"""Integration specific event to signal a change in connection status."""
|
"""Integration specific event to signal a change in connection status."""
|
||||||
@ -367,6 +349,19 @@ class UniFiController:
|
|||||||
controller.load_config_entry_options()
|
controller.load_config_entry_options()
|
||||||
async_dispatcher_send(hass, controller.signal_options_update)
|
async_dispatcher_send(hass, controller.signal_options_update)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def start_websocket(self) -> None:
|
||||||
|
"""Start up connection to websocket."""
|
||||||
|
|
||||||
|
async def _websocket_runner() -> None:
|
||||||
|
"""Start websocket."""
|
||||||
|
await self.api.start_websocket()
|
||||||
|
self.available = False
|
||||||
|
async_dispatcher_send(self.hass, self.signal_reachable)
|
||||||
|
self.hass.loop.call_later(RETRY_TIMER, self.reconnect, True)
|
||||||
|
|
||||||
|
self.ws_task = self.hass.loop.create_task(_websocket_runner())
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def reconnect(self, log: bool = False) -> None:
|
def reconnect(self, log: bool = False) -> None:
|
||||||
"""Prepare to reconnect UniFi session."""
|
"""Prepare to reconnect UniFi session."""
|
||||||
@ -379,7 +374,11 @@ class UniFiController:
|
|||||||
try:
|
try:
|
||||||
async with asyncio.timeout(5):
|
async with asyncio.timeout(5):
|
||||||
await self.api.login()
|
await self.api.login()
|
||||||
self.api.start_websocket()
|
self.start_websocket()
|
||||||
|
|
||||||
|
if not self.available:
|
||||||
|
self.available = True
|
||||||
|
async_dispatcher_send(self.hass, self.signal_reachable)
|
||||||
|
|
||||||
except (
|
except (
|
||||||
asyncio.TimeoutError,
|
asyncio.TimeoutError,
|
||||||
@ -395,7 +394,8 @@ class UniFiController:
|
|||||||
|
|
||||||
Used as an argument to EventBus.async_listen_once.
|
Used as an argument to EventBus.async_listen_once.
|
||||||
"""
|
"""
|
||||||
self.api.stop_websocket()
|
if self.ws_task is not None:
|
||||||
|
self.ws_task.cancel()
|
||||||
|
|
||||||
async def async_reset(self) -> bool:
|
async def async_reset(self) -> bool:
|
||||||
"""Reset this controller to default state.
|
"""Reset this controller to default state.
|
||||||
@ -403,7 +403,18 @@ class UniFiController:
|
|||||||
Will cancel any scheduled setup retry and will unload
|
Will cancel any scheduled setup retry and will unload
|
||||||
the config entry.
|
the config entry.
|
||||||
"""
|
"""
|
||||||
self.api.stop_websocket()
|
if self.ws_task is not None:
|
||||||
|
self.ws_task.cancel()
|
||||||
|
|
||||||
|
_, pending = await asyncio.wait([self.ws_task], timeout=10)
|
||||||
|
|
||||||
|
if pending:
|
||||||
|
LOGGER.warning(
|
||||||
|
"Unloading %s (%s) config entry. Task %s did not complete in time",
|
||||||
|
self.config_entry.title,
|
||||||
|
self.config_entry.domain,
|
||||||
|
self.ws_task,
|
||||||
|
)
|
||||||
|
|
||||||
unload_ok = await self.hass.config_entries.async_unload_platforms(
|
unload_ok = await self.hass.config_entries.async_unload_platforms(
|
||||||
self.config_entry, PLATFORMS
|
self.config_entry, PLATFORMS
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["aiounifi"],
|
"loggers": ["aiounifi"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"requirements": ["aiounifi==62"],
|
"requirements": ["aiounifi==63"],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"manufacturer": "Ubiquiti Networks",
|
"manufacturer": "Ubiquiti Networks",
|
||||||
|
@ -363,7 +363,7 @@ aiosyncthing==0.5.1
|
|||||||
aiotractive==0.5.6
|
aiotractive==0.5.6
|
||||||
|
|
||||||
# homeassistant.components.unifi
|
# homeassistant.components.unifi
|
||||||
aiounifi==62
|
aiounifi==63
|
||||||
|
|
||||||
# homeassistant.components.vlc_telnet
|
# homeassistant.components.vlc_telnet
|
||||||
aiovlc==0.1.0
|
aiovlc==0.1.0
|
||||||
|
@ -338,7 +338,7 @@ aiosyncthing==0.5.1
|
|||||||
aiotractive==0.5.6
|
aiotractive==0.5.6
|
||||||
|
|
||||||
# homeassistant.components.unifi
|
# homeassistant.components.unifi
|
||||||
aiounifi==62
|
aiounifi==63
|
||||||
|
|
||||||
# homeassistant.components.vlc_telnet
|
# homeassistant.components.vlc_telnet
|
||||||
aiovlc==0.1.0
|
aiovlc==0.1.0
|
||||||
|
@ -1,47 +1,100 @@
|
|||||||
"""Fixtures for UniFi Network methods."""
|
"""Fixtures for UniFi Network methods."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from datetime import timedelta
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketSignal, WebsocketState
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.unifi.const import DOMAIN as UNIFI_DOMAIN
|
||||||
|
from homeassistant.components.unifi.controller import RETRY_TIMER
|
||||||
|
from homeassistant.const import CONTENT_TYPE_JSON
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||||
|
from tests.components.unifi.test_controller import DEFAULT_CONFIG_ENTRY_ID
|
||||||
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
|
|
||||||
|
|
||||||
|
class WebsocketStateManager(asyncio.Event):
|
||||||
|
"""Keep an async event that simules websocket context manager.
|
||||||
|
|
||||||
|
Prepares disconnect and reconnect flows.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, aioclient_mock: AiohttpClientMocker):
|
||||||
|
"""Store hass object and initialize asyncio.Event."""
|
||||||
|
self.hass = hass
|
||||||
|
self.aioclient_mock = aioclient_mock
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
async def disconnect(self):
|
||||||
|
"""Mark future as done to make 'await self.api.start_websocket' return."""
|
||||||
|
self.set()
|
||||||
|
await self.hass.async_block_till_done()
|
||||||
|
|
||||||
|
async def reconnect(self, fail=False):
|
||||||
|
"""Set up new future to make 'await self.api.start_websocket' block.
|
||||||
|
|
||||||
|
Mock api calls done by 'await self.api.login'.
|
||||||
|
Fail will make 'await self.api.start_websocket' return immediately.
|
||||||
|
"""
|
||||||
|
controller = self.hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
|
||||||
|
self.aioclient_mock.get(
|
||||||
|
f"https://{controller.host}:1234", status=302
|
||||||
|
) # Check UniFi OS
|
||||||
|
self.aioclient_mock.post(
|
||||||
|
f"https://{controller.host}:1234/api/login",
|
||||||
|
json={"data": "login successful", "meta": {"rc": "ok"}},
|
||||||
|
headers={"content-type": CONTENT_TYPE_JSON},
|
||||||
|
)
|
||||||
|
|
||||||
|
if not fail:
|
||||||
|
self.clear()
|
||||||
|
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
|
||||||
|
async_fire_time_changed(self.hass, new_time)
|
||||||
|
await self.hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_unifi_websocket():
|
def websocket_mock(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker):
|
||||||
"""No real websocket allowed."""
|
"""Mock 'await self.api.start_websocket' in 'UniFiController.start_websocket'."""
|
||||||
with patch("aiounifi.controller.WSClient") as mock:
|
websocket_state_manager = WebsocketStateManager(hass, aioclient_mock)
|
||||||
|
with patch("aiounifi.Controller.start_websocket") as ws_mock:
|
||||||
|
ws_mock.side_effect = websocket_state_manager.wait
|
||||||
|
yield websocket_state_manager
|
||||||
|
|
||||||
def make_websocket_call(
|
|
||||||
*,
|
@pytest.fixture(autouse=True)
|
||||||
message: MessageKey | None = None,
|
def mock_unifi_websocket(hass):
|
||||||
data: list[dict] | dict | None = None,
|
"""No real websocket allowed."""
|
||||||
state: WebsocketState | None = None,
|
|
||||||
):
|
def make_websocket_call(
|
||||||
"""Generate a websocket call."""
|
*,
|
||||||
if data and not message:
|
message: MessageKey | None = None,
|
||||||
mock.return_value.data = data
|
data: list[dict] | dict | None = None,
|
||||||
mock.call_args[1]["callback"](WebsocketSignal.DATA)
|
):
|
||||||
elif data and message:
|
"""Generate a websocket call."""
|
||||||
if not isinstance(data, list):
|
controller = hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
|
||||||
data = [data]
|
if data and not message:
|
||||||
mock.return_value.data = {
|
controller.api.messages.handler(data)
|
||||||
|
elif data and message:
|
||||||
|
if not isinstance(data, list):
|
||||||
|
data = [data]
|
||||||
|
controller.api.messages.handler(
|
||||||
|
{
|
||||||
"meta": {"message": message.value},
|
"meta": {"message": message.value},
|
||||||
"data": data,
|
"data": data,
|
||||||
}
|
}
|
||||||
mock.call_args[1]["callback"](WebsocketSignal.DATA)
|
)
|
||||||
elif state:
|
else:
|
||||||
mock.return_value.state = state
|
raise NotImplementedError
|
||||||
mock.call_args[1]["callback"](WebsocketSignal.CONNECTION_STATE)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
yield make_websocket_call
|
return make_websocket_call
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
"""UniFi Network button platform tests."""
|
"""UniFi Network button platform tests."""
|
||||||
|
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
|
|
||||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, ButtonDeviceClass
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, ButtonDeviceClass
|
||||||
from homeassistant.components.unifi.const import DOMAIN as UNIFI_DOMAIN
|
from homeassistant.components.unifi.const import DOMAIN as UNIFI_DOMAIN
|
||||||
from homeassistant.const import ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, EntityCategory
|
from homeassistant.const import ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, EntityCategory
|
||||||
@ -14,7 +12,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker
|
|||||||
|
|
||||||
|
|
||||||
async def test_restart_device_button(
|
async def test_restart_device_button(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, websocket_mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test restarting device button."""
|
"""Test restarting device button."""
|
||||||
config_entry = await setup_unifi_integration(
|
config_entry = await setup_unifi_integration(
|
||||||
@ -71,11 +69,9 @@ async def test_restart_device_button(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("button.switch_restart").state == STATE_UNAVAILABLE
|
assert hass.states.get("button.switch_restart").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("button.switch_restart").state != STATE_UNAVAILABLE
|
assert hass.states.get("button.switch_restart").state != STATE_UNAVAILABLE
|
||||||
|
@ -6,7 +6,6 @@ from http import HTTPStatus
|
|||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import aiounifi
|
import aiounifi
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
||||||
@ -28,7 +27,7 @@ from homeassistant.components.unifi.const import (
|
|||||||
PLATFORMS,
|
PLATFORMS,
|
||||||
UNIFI_WIRELESS_CLIENTS,
|
UNIFI_WIRELESS_CLIENTS,
|
||||||
)
|
)
|
||||||
from homeassistant.components.unifi.controller import RETRY_TIMER, get_unifi_controller
|
from homeassistant.components.unifi.controller import get_unifi_controller
|
||||||
from homeassistant.components.unifi.errors import AuthenticationRequired, CannotConnect
|
from homeassistant.components.unifi.errors import AuthenticationRequired, CannotConnect
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
@ -44,7 +43,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
from tests.common import MockConfigEntry
|
||||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
|
|
||||||
DEFAULT_CONFIG_ENTRY_ID = "1"
|
DEFAULT_CONFIG_ENTRY_ID = "1"
|
||||||
@ -365,8 +364,8 @@ async def test_reset_fails(
|
|||||||
async def test_connection_state_signalling(
|
async def test_connection_state_signalling(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
mock_unifi_websocket,
|
|
||||||
mock_device_registry,
|
mock_device_registry,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify connection statesignalling and connection state are working."""
|
"""Verify connection statesignalling and connection state are working."""
|
||||||
client = {
|
client = {
|
||||||
@ -381,21 +380,17 @@ async def test_connection_state_signalling(
|
|||||||
# Controller is connected
|
# Controller is connected
|
||||||
assert hass.states.get("device_tracker.client").state == "home"
|
assert hass.states.get("device_tracker.client").state == "home"
|
||||||
|
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
# Controller is disconnected
|
# Controller is disconnected
|
||||||
assert hass.states.get("device_tracker.client").state == "unavailable"
|
assert hass.states.get("device_tracker.client").state == "unavailable"
|
||||||
|
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
# Controller is once again connected
|
# Controller is once again connected
|
||||||
assert hass.states.get("device_tracker.client").state == "home"
|
assert hass.states.get("device_tracker.client").state == "home"
|
||||||
|
|
||||||
|
|
||||||
async def test_reconnect_mechanism(
|
async def test_reconnect_mechanism(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, websocket_mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify reconnect prints only on first reconnection try."""
|
"""Verify reconnect prints only on first reconnection try."""
|
||||||
await setup_unifi_integration(hass, aioclient_mock)
|
await setup_unifi_integration(hass, aioclient_mock)
|
||||||
@ -403,21 +398,13 @@ async def test_reconnect_mechanism(
|
|||||||
aioclient_mock.clear_requests()
|
aioclient_mock.clear_requests()
|
||||||
aioclient_mock.get(f"https://{DEFAULT_HOST}:1234/", status=HTTPStatus.BAD_GATEWAY)
|
aioclient_mock.get(f"https://{DEFAULT_HOST}:1234/", status=HTTPStatus.BAD_GATEWAY)
|
||||||
|
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 0
|
assert aioclient_mock.call_count == 0
|
||||||
|
|
||||||
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
|
await websocket_mock.reconnect(fail=True)
|
||||||
async_fire_time_changed(hass, new_time)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 1
|
assert aioclient_mock.call_count == 1
|
||||||
|
|
||||||
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
|
await websocket_mock.reconnect(fail=True)
|
||||||
async_fire_time_changed(hass, new_time)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 2
|
assert aioclient_mock.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
@ -431,10 +418,7 @@ async def test_reconnect_mechanism(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_reconnect_mechanism_exceptions(
|
async def test_reconnect_mechanism_exceptions(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, websocket_mock, exception
|
||||||
aioclient_mock: AiohttpClientMocker,
|
|
||||||
mock_unifi_websocket,
|
|
||||||
exception,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify async_reconnect calls expected methods."""
|
"""Verify async_reconnect calls expected methods."""
|
||||||
await setup_unifi_integration(hass, aioclient_mock)
|
await setup_unifi_integration(hass, aioclient_mock)
|
||||||
@ -442,11 +426,9 @@ async def test_reconnect_mechanism_exceptions(
|
|||||||
with patch("aiounifi.Controller.login", side_effect=exception), patch(
|
with patch("aiounifi.Controller.login", side_effect=exception), patch(
|
||||||
"homeassistant.components.unifi.controller.UniFiController.reconnect"
|
"homeassistant.components.unifi.controller.UniFiController.reconnect"
|
||||||
) as mock_reconnect:
|
) as mock_reconnect:
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
new_time = dt_util.utcnow() + timedelta(seconds=RETRY_TIMER)
|
await websocket_mock.reconnect()
|
||||||
async_fire_time_changed(hass, new_time)
|
|
||||||
mock_reconnect.assert_called_once()
|
mock_reconnect.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ from datetime import timedelta
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
@ -40,8 +39,8 @@ async def test_no_entities(
|
|||||||
async def test_tracked_wireless_clients(
|
async def test_tracked_wireless_clients(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
mock_unifi_websocket,
|
|
||||||
mock_device_registry,
|
mock_device_registry,
|
||||||
|
mock_unifi_websocket,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify tracking of wireless clients."""
|
"""Verify tracking of wireless clients."""
|
||||||
client = {
|
client = {
|
||||||
@ -402,7 +401,7 @@ async def test_remove_clients(
|
|||||||
async def test_controller_state_change(
|
async def test_controller_state_change(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
mock_unifi_websocket,
|
websocket_mock,
|
||||||
mock_device_registry,
|
mock_device_registry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify entities state reflect on controller becoming unavailable."""
|
"""Verify entities state reflect on controller becoming unavailable."""
|
||||||
@ -443,16 +442,12 @@ async def test_controller_state_change(
|
|||||||
assert hass.states.get("device_tracker.device").state == STATE_HOME
|
assert hass.states.get("device_tracker.device").state == STATE_HOME
|
||||||
|
|
||||||
# Controller unavailable
|
# Controller unavailable
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("device_tracker.client").state == STATE_UNAVAILABLE
|
assert hass.states.get("device_tracker.client").state == STATE_UNAVAILABLE
|
||||||
assert hass.states.get("device_tracker.device").state == STATE_UNAVAILABLE
|
assert hass.states.get("device_tracker.device").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller available
|
# Controller available
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("device_tracker.client").state == STATE_NOT_HOME
|
assert hass.states.get("device_tracker.client").state == STATE_NOT_HOME
|
||||||
assert hass.states.get("device_tracker.device").state == STATE_HOME
|
assert hass.states.get("device_tracker.device").state == STATE_HOME
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ from datetime import timedelta
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
|
from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
|
||||||
@ -65,6 +64,7 @@ async def test_wlan_qr_code(
|
|||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
snapshot: SnapshotAssertion,
|
snapshot: SnapshotAssertion,
|
||||||
mock_unifi_websocket,
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the update_clients function when no clients are found."""
|
"""Test the update_clients function when no clients are found."""
|
||||||
await setup_unifi_integration(hass, aioclient_mock, wlans_response=[WLAN])
|
await setup_unifi_integration(hass, aioclient_mock, wlans_response=[WLAN])
|
||||||
@ -121,13 +121,11 @@ async def test_wlan_qr_code(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("image.ssid_1_qr_code").state == STATE_UNAVAILABLE
|
assert hass.states.get("image.ssid_1_qr_code").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("image.ssid_1_qr_code").state != STATE_UNAVAILABLE
|
assert hass.states.get("image.ssid_1_qr_code").state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
# WLAN gets disabled
|
# WLAN gets disabled
|
||||||
|
@ -4,7 +4,6 @@ from datetime import datetime, timedelta
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
|
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
|
||||||
@ -562,7 +561,10 @@ async def test_remove_sensors(
|
|||||||
|
|
||||||
|
|
||||||
async def test_poe_port_switches(
|
async def test_poe_port_switches(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the update_items function with some clients."""
|
"""Test the update_items function with some clients."""
|
||||||
await setup_unifi_integration(hass, aioclient_mock, devices_response=[DEVICE_1])
|
await setup_unifi_integration(hass, aioclient_mock, devices_response=[DEVICE_1])
|
||||||
@ -607,16 +609,16 @@ async def test_poe_port_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert (
|
assert (
|
||||||
hass.states.get("sensor.mock_name_port_1_poe_power").state == STATE_UNAVAILABLE
|
hass.states.get("sensor.mock_name_port_1_poe_power").state == STATE_UNAVAILABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
assert (
|
||||||
assert hass.states.get("sensor.mock_name_port_1_poe_power")
|
hass.states.get("sensor.mock_name_port_1_poe_power").state != STATE_UNAVAILABLE
|
||||||
|
)
|
||||||
|
|
||||||
# Device gets disabled
|
# Device gets disabled
|
||||||
device_1["disabled"] = True
|
device_1["disabled"] = True
|
||||||
@ -634,7 +636,10 @@ async def test_poe_port_switches(
|
|||||||
|
|
||||||
|
|
||||||
async def test_wlan_client_sensors(
|
async def test_wlan_client_sensors(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify that WLAN client sensors are working as expected."""
|
"""Verify that WLAN client sensors are working as expected."""
|
||||||
wireless_client_1 = {
|
wireless_client_1 = {
|
||||||
@ -720,13 +725,11 @@ async def test_wlan_client_sensors(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("sensor.ssid_1").state == STATE_UNAVAILABLE
|
assert hass.states.get("sensor.ssid_1").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("sensor.ssid_1").state == "0"
|
assert hass.states.get("sensor.ssid_1").state == "0"
|
||||||
|
|
||||||
# WLAN gets disabled
|
# WLAN gets disabled
|
||||||
@ -837,7 +840,6 @@ async def test_device_uptime(
|
|||||||
now = datetime(2021, 1, 1, 1, 1, 0, tzinfo=dt_util.UTC)
|
now = datetime(2021, 1, 1, 1, 1, 0, tzinfo=dt_util.UTC)
|
||||||
with patch("homeassistant.util.dt.now", return_value=now):
|
with patch("homeassistant.util.dt.now", return_value=now):
|
||||||
await setup_unifi_integration(hass, aioclient_mock, devices_response=[device])
|
await setup_unifi_integration(hass, aioclient_mock, devices_response=[device])
|
||||||
|
|
||||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 1
|
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 1
|
||||||
assert hass.states.get("sensor.device_uptime").state == "2021-01-01T01:00:00+00:00"
|
assert hass.states.get("sensor.device_uptime").state == "2021-01-01T01:00:00+00:00"
|
||||||
|
|
||||||
@ -854,7 +856,6 @@ async def test_device_uptime(
|
|||||||
now = datetime(2021, 1, 1, 1, 1, 4, tzinfo=dt_util.UTC)
|
now = datetime(2021, 1, 1, 1, 1, 4, tzinfo=dt_util.UTC)
|
||||||
with patch("homeassistant.util.dt.now", return_value=now):
|
with patch("homeassistant.util.dt.now", return_value=now):
|
||||||
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("sensor.device_uptime").state == "2021-01-01T01:00:00+00:00"
|
assert hass.states.get("sensor.device_uptime").state == "2021-01-01T01:00:00+00:00"
|
||||||
|
|
||||||
@ -865,7 +866,6 @@ async def test_device_uptime(
|
|||||||
now = datetime(2021, 2, 1, 1, 1, 0, tzinfo=dt_util.UTC)
|
now = datetime(2021, 2, 1, 1, 1, 0, tzinfo=dt_util.UTC)
|
||||||
with patch("homeassistant.util.dt.now", return_value=now):
|
with patch("homeassistant.util.dt.now", return_value=now):
|
||||||
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("sensor.device_uptime").state == "2021-02-01T01:00:00+00:00"
|
assert hass.states.get("sensor.device_uptime").state == "2021-02-01T01:00:00+00:00"
|
||||||
|
|
||||||
@ -908,5 +908,4 @@ async def test_device_temperature(
|
|||||||
# Verify new event change temperature
|
# Verify new event change temperature
|
||||||
device["general_temperature"] = 60
|
device["general_temperature"] = 60
|
||||||
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("sensor.device_temperature").state == "60"
|
assert hass.states.get("sensor.device_temperature").state == "60"
|
||||||
|
@ -3,7 +3,6 @@ from copy import deepcopy
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.switch import (
|
from homeassistant.components.switch import (
|
||||||
@ -1001,7 +1000,10 @@ async def test_block_switches(
|
|||||||
|
|
||||||
|
|
||||||
async def test_dpi_switches(
|
async def test_dpi_switches(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the update_items function with some clients."""
|
"""Test the update_items function with some clients."""
|
||||||
await setup_unifi_integration(
|
await setup_unifi_integration(
|
||||||
@ -1026,13 +1028,11 @@ async def test_dpi_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.block_media_streaming").state == STATE_UNAVAILABLE
|
assert hass.states.get("switch.block_media_streaming").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.block_media_streaming").state == STATE_OFF
|
assert hass.states.get("switch.block_media_streaming").state == STATE_OFF
|
||||||
|
|
||||||
# Remove app
|
# Remove app
|
||||||
@ -1128,6 +1128,7 @@ async def test_outlet_switches(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
mock_unifi_websocket,
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
test_data: any,
|
test_data: any,
|
||||||
outlet_index: int,
|
outlet_index: int,
|
||||||
@ -1192,13 +1193,11 @@ async def test_outlet_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get(f"switch.{entity_id}").state == STATE_UNAVAILABLE
|
assert hass.states.get(f"switch.{entity_id}").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get(f"switch.{entity_id}").state == STATE_OFF
|
assert hass.states.get(f"switch.{entity_id}").state == STATE_OFF
|
||||||
|
|
||||||
# Device gets disabled
|
# Device gets disabled
|
||||||
@ -1320,7 +1319,10 @@ async def test_option_remove_switches(
|
|||||||
|
|
||||||
|
|
||||||
async def test_poe_port_switches(
|
async def test_poe_port_switches(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the update_items function with some clients."""
|
"""Test the update_items function with some clients."""
|
||||||
config_entry = await setup_unifi_integration(
|
config_entry = await setup_unifi_integration(
|
||||||
@ -1408,13 +1410,11 @@ async def test_poe_port_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.mock_name_port_1_poe").state == STATE_UNAVAILABLE
|
assert hass.states.get("switch.mock_name_port_1_poe").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.mock_name_port_1_poe").state == STATE_OFF
|
assert hass.states.get("switch.mock_name_port_1_poe").state == STATE_OFF
|
||||||
|
|
||||||
# Device gets disabled
|
# Device gets disabled
|
||||||
@ -1431,7 +1431,10 @@ async def test_poe_port_switches(
|
|||||||
|
|
||||||
|
|
||||||
async def test_wlan_switches(
|
async def test_wlan_switches(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test control of UniFi WLAN availability."""
|
"""Test control of UniFi WLAN availability."""
|
||||||
config_entry = await setup_unifi_integration(
|
config_entry = await setup_unifi_integration(
|
||||||
@ -1488,18 +1491,19 @@ async def test_wlan_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.ssid_1").state == STATE_UNAVAILABLE
|
assert hass.states.get("switch.ssid_1").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.ssid_1").state == STATE_OFF
|
assert hass.states.get("switch.ssid_1").state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
async def test_port_forwarding_switches(
|
async def test_port_forwarding_switches(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant,
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
mock_unifi_websocket,
|
||||||
|
websocket_mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test control of UniFi port forwarding."""
|
"""Test control of UniFi port forwarding."""
|
||||||
_data = {
|
_data = {
|
||||||
@ -1570,13 +1574,11 @@ async def test_port_forwarding_switches(
|
|||||||
# Availability signalling
|
# Availability signalling
|
||||||
|
|
||||||
# Controller disconnects
|
# Controller disconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.unifi_network_plex").state == STATE_UNAVAILABLE
|
assert hass.states.get("switch.unifi_network_plex").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller reconnects
|
# Controller reconnects
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("switch.unifi_network_plex").state == STATE_OFF
|
assert hass.states.get("switch.unifi_network_plex").state == STATE_OFF
|
||||||
|
|
||||||
# Remove entity on deleted message
|
# Remove entity on deleted message
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from aiounifi.models.message import MessageKey
|
from aiounifi.models.message import MessageKey
|
||||||
from aiounifi.websocket import WebsocketState
|
|
||||||
from yarl import URL
|
from yarl import URL
|
||||||
|
|
||||||
from homeassistant.components.unifi.const import CONF_SITE_ID
|
from homeassistant.components.unifi.const import CONF_SITE_ID
|
||||||
@ -185,26 +184,18 @@ async def test_install(
|
|||||||
|
|
||||||
|
|
||||||
async def test_controller_state_change(
|
async def test_controller_state_change(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
|
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, websocket_mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify entities state reflect on controller becoming unavailable."""
|
"""Verify entities state reflect on controller becoming unavailable."""
|
||||||
await setup_unifi_integration(
|
await setup_unifi_integration(hass, aioclient_mock, devices_response=[DEVICE_1])
|
||||||
hass,
|
|
||||||
aioclient_mock,
|
|
||||||
devices_response=[DEVICE_1],
|
|
||||||
)
|
|
||||||
|
|
||||||
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
|
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
|
||||||
assert hass.states.get("update.device_1").state == STATE_ON
|
assert hass.states.get("update.device_1").state == STATE_ON
|
||||||
|
|
||||||
# Controller unavailable
|
# Controller unavailable
|
||||||
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
|
await websocket_mock.disconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("update.device_1").state == STATE_UNAVAILABLE
|
assert hass.states.get("update.device_1").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Controller available
|
# Controller available
|
||||||
mock_unifi_websocket(state=WebsocketState.RUNNING)
|
await websocket_mock.reconnect()
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hass.states.get("update.device_1").state == STATE_ON
|
assert hass.states.get("update.device_1").state == STATE_ON
|
||||||
|
Loading…
x
Reference in New Issue
Block a user