mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Unifi rename controller to hub (#110976)
* Rename controller.py to hub.py * Rename UniFiController to UnifiHub * Rename controller instances into hub * Rename controller to hub in tests * Rename aiounifi Controller references to api * Update strings * Rename test_controller test_hub * Narrow scope of test_remove_sensors
This commit is contained in:
parent
2b3f5319d6
commit
2f026ca963
@ -11,8 +11,8 @@ from homeassistant.helpers.storage import Store
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import DOMAIN as UNIFI_DOMAIN, PLATFORMS, UNIFI_WIRELESS_CLIENTS
|
||||
from .controller import UniFiController, get_unifi_controller
|
||||
from .errors import AuthenticationRequired, CannotConnect
|
||||
from .hub import UnifiHub, get_unifi_api
|
||||
from .services import async_setup_services, async_unload_services
|
||||
|
||||
SAVE_DELAY = 10
|
||||
@ -35,7 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||
hass.data.setdefault(UNIFI_DOMAIN, {})
|
||||
|
||||
try:
|
||||
api = await get_unifi_controller(hass, config_entry.data)
|
||||
api = await get_unifi_api(hass, config_entry.data)
|
||||
|
||||
except CannotConnect as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
@ -43,20 +43,20 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||
except AuthenticationRequired as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
|
||||
controller = UniFiController(hass, config_entry, api)
|
||||
await controller.initialize()
|
||||
hass.data[UNIFI_DOMAIN][config_entry.entry_id] = controller
|
||||
hub = 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)
|
||||
controller.async_update_device_registry()
|
||||
hub.async_update_device_registry()
|
||||
|
||||
if len(hass.data[UNIFI_DOMAIN]) == 1:
|
||||
async_setup_services(hass)
|
||||
|
||||
controller.start_websocket()
|
||||
hub.start_websocket()
|
||||
|
||||
config_entry.async_on_unload(
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, controller.shutdown)
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, hub.shutdown)
|
||||
)
|
||||
|
||||
return True
|
||||
@ -64,12 +64,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN].pop(config_entry.entry_id)
|
||||
hub: UnifiHub = hass.data[UNIFI_DOMAIN].pop(config_entry.entry_id)
|
||||
|
||||
if not hass.data[UNIFI_DOMAIN]:
|
||||
async_unload_services(hass)
|
||||
|
||||
return await controller.async_reset()
|
||||
return await hub.async_reset()
|
||||
|
||||
|
||||
class UnifiWirelessClients:
|
||||
|
@ -30,7 +30,6 @@ from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .controller import UniFiController
|
||||
from .entity import (
|
||||
HandlerT,
|
||||
UnifiEntity,
|
||||
@ -38,6 +37,7 @@ from .entity import (
|
||||
async_device_available_fn,
|
||||
async_device_device_info_fn,
|
||||
)
|
||||
from .hub import UnifiHub
|
||||
|
||||
|
||||
@callback
|
||||
@ -79,7 +79,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
has_entity_name=True,
|
||||
device_class=ButtonDeviceClass.RESTART,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_restart_device_control_fn,
|
||||
@ -89,15 +89,15 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
name_fn=lambda _: "Restart",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"device_restart-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"device_restart-{obj_id}",
|
||||
),
|
||||
UnifiButtonEntityDescription[Ports, Port](
|
||||
key="PoE power cycle",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
has_entity_name=True,
|
||||
device_class=ButtonDeviceClass.RESTART,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.ports,
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_power_cycle_port_control_fn,
|
||||
@ -107,8 +107,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
name_fn=lambda port: f"{port.name} Power Cycle",
|
||||
object_fn=lambda api, obj_id: api.ports[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: controller.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda controller, obj_id: f"power_cycle-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda hub, obj_id: f"power_cycle-{obj_id}",
|
||||
),
|
||||
)
|
||||
|
||||
@ -119,7 +119,7 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up button platform for UniFi Network integration."""
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
async_add_entities,
|
||||
@ -136,7 +136,7 @@ class UnifiButtonEntity(UnifiEntity[HandlerT, ApiItemT], ButtonEntity):
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
await self.entity_description.control_fn(self.controller.api, self._obj_id)
|
||||
await self.entity_description.control_fn(self.hub.api, self._obj_id)
|
||||
|
||||
@callback
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
|
@ -47,8 +47,8 @@ from .const import (
|
||||
DEFAULT_DPI_RESTRICTIONS,
|
||||
DOMAIN as UNIFI_DOMAIN,
|
||||
)
|
||||
from .controller import UniFiController, get_unifi_controller
|
||||
from .errors import AuthenticationRequired, CannotConnect
|
||||
from .hub import UnifiHub, get_unifi_api
|
||||
|
||||
DEFAULT_PORT = 443
|
||||
DEFAULT_SITE_ID = "default"
|
||||
@ -99,11 +99,9 @@ class UnifiFlowHandler(config_entries.ConfigFlow, domain=UNIFI_DOMAIN):
|
||||
}
|
||||
|
||||
try:
|
||||
controller = await get_unifi_controller(
|
||||
self.hass, MappingProxyType(self.config)
|
||||
)
|
||||
await controller.sites.update()
|
||||
self.sites = controller.sites
|
||||
hub = await get_unifi_api(self.hass, MappingProxyType(self.config))
|
||||
await hub.sites.update()
|
||||
self.sites = hub.sites
|
||||
|
||||
except AuthenticationRequired:
|
||||
errors["base"] = "faulty_credentials"
|
||||
@ -160,11 +158,11 @@ class UnifiFlowHandler(config_entries.ConfigFlow, domain=UNIFI_DOMAIN):
|
||||
abort_reason = "reauth_successful"
|
||||
|
||||
if config_entry:
|
||||
controller: UniFiController | None = self.hass.data.get(
|
||||
UNIFI_DOMAIN, {}
|
||||
).get(config_entry.entry_id)
|
||||
hub: UnifiHub | None = self.hass.data.get(UNIFI_DOMAIN, {}).get(
|
||||
config_entry.entry_id
|
||||
)
|
||||
|
||||
if controller and controller.available:
|
||||
if hub and hub.available:
|
||||
return self.async_abort(reason="already_configured")
|
||||
|
||||
return self.async_update_reload_and_abort(
|
||||
@ -240,7 +238,7 @@ class UnifiFlowHandler(config_entries.ConfigFlow, domain=UNIFI_DOMAIN):
|
||||
class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Handle Unifi Network options."""
|
||||
|
||||
controller: UniFiController
|
||||
hub: UnifiHub
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
||||
"""Initialize UniFi Network options flow."""
|
||||
@ -253,8 +251,8 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""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.controller = self.hass.data[UNIFI_DOMAIN][self.config_entry.entry_id]
|
||||
self.options[CONF_BLOCK_CLIENT] = self.controller.option_block_clients
|
||||
self.hub = self.hass.data[UNIFI_DOMAIN][self.config_entry.entry_id]
|
||||
self.options[CONF_BLOCK_CLIENT] = self.hub.option_block_clients
|
||||
|
||||
if self.show_advanced_options:
|
||||
return await self.async_step_configure_entity_sources()
|
||||
@ -271,7 +269,7 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
clients_to_block = {}
|
||||
|
||||
for client in self.controller.api.clients.values():
|
||||
for client in self.hub.api.clients.values():
|
||||
clients_to_block[
|
||||
client.mac
|
||||
] = f"{client.name or client.hostname} ({client.mac})"
|
||||
@ -282,11 +280,11 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_TRACK_CLIENTS,
|
||||
default=self.controller.option_track_clients,
|
||||
default=self.hub.option_track_clients,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_TRACK_DEVICES,
|
||||
default=self.controller.option_track_devices,
|
||||
default=self.hub.option_track_devices,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_BLOCK_CLIENT, default=self.options[CONF_BLOCK_CLIENT]
|
||||
@ -306,7 +304,7 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
clients = {
|
||||
client.mac: f"{client.name or client.hostname} ({client.mac})"
|
||||
for client in self.controller.api.clients.values()
|
||||
for client in self.hub.api.clients.values()
|
||||
}
|
||||
clients |= {
|
||||
mac: f"Unknown ({mac})"
|
||||
@ -338,16 +336,16 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
return await self.async_step_client_control()
|
||||
|
||||
ssids = (
|
||||
{wlan.name for wlan in self.controller.api.wlans.values()}
|
||||
{wlan.name for wlan in self.hub.api.wlans.values()}
|
||||
| {
|
||||
f"{wlan.name}{wlan.name_combine_suffix}"
|
||||
for wlan in self.controller.api.wlans.values()
|
||||
for wlan in self.hub.api.wlans.values()
|
||||
if not wlan.name_combine_enabled
|
||||
and wlan.name_combine_suffix is not None
|
||||
}
|
||||
| {
|
||||
wlan["name"]
|
||||
for ap in self.controller.api.devices.values()
|
||||
for ap in self.hub.api.devices.values()
|
||||
for wlan in ap.wlan_overrides
|
||||
if "name" in wlan
|
||||
}
|
||||
@ -355,7 +353,7 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
ssid_filter = {ssid: ssid for ssid in sorted(ssids)}
|
||||
|
||||
selected_ssids_to_filter = [
|
||||
ssid for ssid in self.controller.option_ssid_filter if ssid in ssid_filter
|
||||
ssid for ssid in self.hub.option_ssid_filter if ssid in ssid_filter
|
||||
]
|
||||
|
||||
return self.async_show_form(
|
||||
@ -364,28 +362,26 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_TRACK_CLIENTS,
|
||||
default=self.controller.option_track_clients,
|
||||
default=self.hub.option_track_clients,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_TRACK_WIRED_CLIENTS,
|
||||
default=self.controller.option_track_wired_clients,
|
||||
default=self.hub.option_track_wired_clients,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_TRACK_DEVICES,
|
||||
default=self.controller.option_track_devices,
|
||||
default=self.hub.option_track_devices,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_SSID_FILTER, default=selected_ssids_to_filter
|
||||
): cv.multi_select(ssid_filter),
|
||||
vol.Optional(
|
||||
CONF_DETECTION_TIME,
|
||||
default=int(
|
||||
self.controller.option_detection_time.total_seconds()
|
||||
),
|
||||
default=int(self.hub.option_detection_time.total_seconds()),
|
||||
): int,
|
||||
vol.Optional(
|
||||
CONF_IGNORE_WIRED_BUG,
|
||||
default=self.controller.option_ignore_wired_bug,
|
||||
default=self.hub.option_ignore_wired_bug,
|
||||
): bool,
|
||||
}
|
||||
),
|
||||
@ -402,7 +398,7 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
clients_to_block = {}
|
||||
|
||||
for client in self.controller.api.clients.values():
|
||||
for client in self.hub.api.clients.values():
|
||||
clients_to_block[
|
||||
client.mac
|
||||
] = f"{client.name or client.hostname} ({client.mac})"
|
||||
@ -445,11 +441,11 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_ALLOW_BANDWIDTH_SENSORS,
|
||||
default=self.controller.option_allow_bandwidth_sensors,
|
||||
default=self.hub.option_allow_bandwidth_sensors,
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_ALLOW_UPTIME_SENSORS,
|
||||
default=self.controller.option_allow_uptime_sensors,
|
||||
default=self.hub.option_allow_uptime_sensors,
|
||||
): bool,
|
||||
}
|
||||
),
|
||||
|
@ -25,13 +25,13 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.helpers.entity_registry as er
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .controller import UNIFI_DOMAIN, UniFiController
|
||||
from .entity import (
|
||||
HandlerT,
|
||||
UnifiEntity,
|
||||
UnifiEntityDescription,
|
||||
async_device_available_fn,
|
||||
)
|
||||
from .hub import UNIFI_DOMAIN, UnifiHub
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -79,23 +79,23 @@ WIRELESS_DISCONNECTION = (
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_client_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if client is allowed."""
|
||||
if obj_id in controller.option_supported_clients:
|
||||
if obj_id in hub.option_supported_clients:
|
||||
return True
|
||||
|
||||
if not controller.option_track_clients:
|
||||
if not hub.option_track_clients:
|
||||
return False
|
||||
|
||||
client = controller.api.clients[obj_id]
|
||||
if client.mac not in controller.wireless_clients:
|
||||
if not controller.option_track_wired_clients:
|
||||
client = hub.api.clients[obj_id]
|
||||
if client.mac not in hub.wireless_clients:
|
||||
if not hub.option_track_wired_clients:
|
||||
return False
|
||||
|
||||
elif (
|
||||
client.essid
|
||||
and controller.option_ssid_filter
|
||||
and client.essid not in controller.option_ssid_filter
|
||||
and hub.option_ssid_filter
|
||||
and client.essid not in hub.option_ssid_filter
|
||||
):
|
||||
return False
|
||||
|
||||
@ -103,25 +103,25 @@ def async_client_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if device object is disabled."""
|
||||
client = controller.api.clients[obj_id]
|
||||
client = hub.api.clients[obj_id]
|
||||
|
||||
if controller.wireless_clients.is_wireless(client) and client.is_wired:
|
||||
if not controller.option_ignore_wired_bug:
|
||||
if hub.wireless_clients.is_wireless(client) and client.is_wired:
|
||||
if not hub.option_ignore_wired_bug:
|
||||
return False # Wired bug in action
|
||||
|
||||
if (
|
||||
not client.is_wired
|
||||
and client.essid
|
||||
and controller.option_ssid_filter
|
||||
and client.essid not in controller.option_ssid_filter
|
||||
and hub.option_ssid_filter
|
||||
and client.essid not in hub.option_ssid_filter
|
||||
):
|
||||
return False
|
||||
|
||||
if (
|
||||
dt_util.utcnow() - dt_util.utc_from_timestamp(client.last_seen or 0)
|
||||
> controller.option_detection_time
|
||||
> hub.option_detection_time
|
||||
):
|
||||
return False
|
||||
|
||||
@ -129,11 +129,9 @@ def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bo
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_heartbeat_timedelta_fn(
|
||||
controller: UniFiController, obj_id: str
|
||||
) -> timedelta:
|
||||
def async_device_heartbeat_timedelta_fn(hub: UnifiHub, obj_id: str) -> timedelta:
|
||||
"""Check if device object is disabled."""
|
||||
device = controller.api.devices[obj_id]
|
||||
device = hub.api.devices[obj_id]
|
||||
return timedelta(seconds=device.next_interval + 60)
|
||||
|
||||
|
||||
@ -141,9 +139,9 @@ def async_device_heartbeat_timedelta_fn(
|
||||
class UnifiEntityTrackerDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Device tracker local functions."""
|
||||
|
||||
heartbeat_timedelta_fn: Callable[[UniFiController, str], timedelta]
|
||||
heartbeat_timedelta_fn: Callable[[UnifiHub, str], timedelta]
|
||||
ip_address_fn: Callable[[aiounifi.Controller, str], str | None]
|
||||
is_connected_fn: Callable[[UniFiController, str], bool]
|
||||
is_connected_fn: Callable[[UnifiHub, str], bool]
|
||||
hostname_fn: Callable[[aiounifi.Controller, str], str | None]
|
||||
|
||||
|
||||
@ -161,7 +159,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
|
||||
has_entity_name=True,
|
||||
allowed_fn=async_client_allowed_fn,
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda controller, obj_id: controller.available,
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
device_info_fn=lambda api, obj_id: None,
|
||||
event_is_on=(WIRED_CONNECTION + WIRELESS_CONNECTION),
|
||||
event_to_subscribe=(
|
||||
@ -170,20 +168,20 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
|
||||
+ WIRELESS_CONNECTION
|
||||
+ WIRELESS_DISCONNECTION
|
||||
),
|
||||
heartbeat_timedelta_fn=lambda controller, _: controller.option_detection_time,
|
||||
heartbeat_timedelta_fn=lambda hub, _: hub.option_detection_time,
|
||||
is_connected_fn=async_client_is_connected_fn,
|
||||
name_fn=lambda client: client.name or client.hostname,
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"{controller.site}-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"{hub.site}-{obj_id}",
|
||||
ip_address_fn=lambda api, obj_id: api.clients[obj_id].ip,
|
||||
hostname_fn=lambda api, obj_id: api.clients[obj_id].hostname,
|
||||
),
|
||||
UnifiTrackerEntityDescription[Devices, Device](
|
||||
key="Device scanner",
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: controller.option_track_devices,
|
||||
allowed_fn=lambda hub, obj_id: hub.option_track_devices,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=lambda api, obj_id: None,
|
||||
@ -194,8 +192,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
|
||||
name_fn=lambda device: device.name or device.model,
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: obj_id,
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: obj_id,
|
||||
ip_address_fn=lambda api, obj_id: api.devices[obj_id].ip,
|
||||
hostname_fn=lambda api, obj_id: None,
|
||||
),
|
||||
@ -208,21 +206,21 @@ def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> No
|
||||
|
||||
Introduced with release 2023.12.
|
||||
"""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
ent_reg = er.async_get(hass)
|
||||
|
||||
@callback
|
||||
def update_unique_id(obj_id: str) -> None:
|
||||
"""Rework unique ID."""
|
||||
new_unique_id = f"{controller.site}-{obj_id}"
|
||||
new_unique_id = f"{hub.site}-{obj_id}"
|
||||
if ent_reg.async_get_entity_id(DOMAIN, UNIFI_DOMAIN, new_unique_id):
|
||||
return
|
||||
|
||||
unique_id = f"{obj_id}-{controller.site}"
|
||||
unique_id = f"{obj_id}-{hub.site}"
|
||||
if entity_id := ent_reg.async_get_entity_id(DOMAIN, UNIFI_DOMAIN, unique_id):
|
||||
ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
|
||||
|
||||
for obj_id in list(controller.api.clients) + list(controller.api.clients_all):
|
||||
for obj_id in list(hub.api.clients) + list(hub.api.clients_all):
|
||||
update_unique_id(obj_id)
|
||||
|
||||
|
||||
@ -233,7 +231,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up device tracker for UniFi Network integration."""
|
||||
async_update_unique_id(hass, config_entry)
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass, config_entry, async_add_entities, UnifiScannerEntity, ENTITY_DESCRIPTIONS
|
||||
)
|
||||
|
||||
@ -256,12 +254,12 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
description = self.entity_description
|
||||
self._event_is_on = description.event_is_on or ()
|
||||
self._ignore_events = False
|
||||
self._is_connected = description.is_connected_fn(self.controller, self._obj_id)
|
||||
self._is_connected = description.is_connected_fn(self.hub, self._obj_id)
|
||||
if self.is_connected:
|
||||
self.controller.async_heartbeat(
|
||||
self.hub.async_heartbeat(
|
||||
self.unique_id,
|
||||
dt_util.utcnow()
|
||||
+ description.heartbeat_timedelta_fn(self.controller, self._obj_id),
|
||||
+ description.heartbeat_timedelta_fn(self.hub, self._obj_id),
|
||||
)
|
||||
|
||||
@property
|
||||
@ -272,12 +270,12 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
@property
|
||||
def hostname(self) -> str | None:
|
||||
"""Return hostname of the device."""
|
||||
return self.entity_description.hostname_fn(self.controller.api, self._obj_id)
|
||||
return self.entity_description.hostname_fn(self.hub.api, self._obj_id)
|
||||
|
||||
@property
|
||||
def ip_address(self) -> str | None:
|
||||
"""Return the primary ip address of the device."""
|
||||
return self.entity_description.ip_address_fn(self.controller.api, self._obj_id)
|
||||
return self.entity_description.ip_address_fn(self.hub.api, self._obj_id)
|
||||
|
||||
@property
|
||||
def mac_address(self) -> str:
|
||||
@ -304,7 +302,7 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
"""Update entity state.
|
||||
|
||||
Remove heartbeat check if controller state has changed
|
||||
Remove heartbeat check if hub connection state has changed
|
||||
and entity is unavailable.
|
||||
Update is_connected.
|
||||
Schedule new heartbeat check if connected.
|
||||
@ -319,15 +317,15 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
# From unifi.entity.async_signal_reachable_callback
|
||||
# Controller connection state has changed and entity is unavailable
|
||||
# Cancel heartbeat
|
||||
self.controller.async_heartbeat(self.unique_id)
|
||||
self.hub.async_heartbeat(self.unique_id)
|
||||
return
|
||||
|
||||
if is_connected := description.is_connected_fn(self.controller, self._obj_id):
|
||||
if is_connected := description.is_connected_fn(self.hub, self._obj_id):
|
||||
self._is_connected = is_connected
|
||||
self.controller.async_heartbeat(
|
||||
self.hub.async_heartbeat(
|
||||
self.unique_id,
|
||||
dt_util.utcnow()
|
||||
+ description.heartbeat_timedelta_fn(self.controller, self._obj_id),
|
||||
+ description.heartbeat_timedelta_fn(self.hub, self._obj_id),
|
||||
)
|
||||
|
||||
@callback
|
||||
@ -337,17 +335,15 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
return
|
||||
|
||||
if event.key in self._event_is_on:
|
||||
self.controller.async_heartbeat(self.unique_id)
|
||||
self.hub.async_heartbeat(self.unique_id)
|
||||
self._is_connected = True
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
|
||||
self.controller.async_heartbeat(
|
||||
self.hub.async_heartbeat(
|
||||
self.unique_id,
|
||||
dt_util.utcnow()
|
||||
+ self.entity_description.heartbeat_timedelta_fn(
|
||||
self.controller, self._obj_id
|
||||
),
|
||||
+ self.entity_description.heartbeat_timedelta_fn(self.hub, self._obj_id),
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@ -356,7 +352,7 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"{self.controller.signal_heartbeat_missed}_{self.unique_id}",
|
||||
f"{self.hub.signal_heartbeat_missed}_{self.unique_id}",
|
||||
self._make_disconnected,
|
||||
)
|
||||
)
|
||||
@ -364,7 +360,7 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Disconnect object when removed."""
|
||||
await super().async_will_remove_from_hass()
|
||||
self.controller.async_heartbeat(self.unique_id)
|
||||
self.hub.async_heartbeat(self.unique_id)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||
@ -372,7 +368,7 @@ class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
|
||||
if self.entity_description.key != "Client device scanner":
|
||||
return None
|
||||
|
||||
client = self.entity_description.object_fn(self.controller.api, self._obj_id)
|
||||
client = self.entity_description.object_fn(self.hub.api, self._obj_id)
|
||||
raw = client.raw
|
||||
|
||||
attributes_to_check = CLIENT_STATIC_ATTRIBUTES
|
||||
|
@ -12,7 +12,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
|
||||
from .const import DOMAIN as UNIFI_DOMAIN
|
||||
from .controller import UniFiController
|
||||
from .hub import UnifiHub
|
||||
|
||||
TO_REDACT = {CONF_PASSWORD}
|
||||
REDACT_CONFIG = {CONF_HOST, CONF_PASSWORD, CONF_USERNAME}
|
||||
@ -75,16 +75,16 @@ async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
diag: dict[str, Any] = {}
|
||||
macs_to_redact: dict[str, str] = {}
|
||||
|
||||
counter = 0
|
||||
for mac in chain(controller.api.clients, controller.api.devices):
|
||||
for mac in chain(hub.api.clients, hub.api.devices):
|
||||
macs_to_redact[mac] = format_mac(str(counter).zfill(12))
|
||||
counter += 1
|
||||
|
||||
for device in controller.api.devices.values():
|
||||
for device in hub.api.devices.values():
|
||||
for entry in device.raw.get("ethernet_table", []):
|
||||
mac = entry.get("mac", "")
|
||||
if mac not in macs_to_redact:
|
||||
@ -94,26 +94,26 @@ async def async_get_config_entry_diagnostics(
|
||||
diag["config"] = async_redact_data(
|
||||
async_replace_dict_data(config_entry.as_dict(), macs_to_redact), REDACT_CONFIG
|
||||
)
|
||||
diag["role_is_admin"] = controller.is_admin
|
||||
diag["role_is_admin"] = hub.is_admin
|
||||
diag["clients"] = {
|
||||
macs_to_redact[k]: async_redact_data(
|
||||
async_replace_dict_data(v.raw, macs_to_redact), REDACT_CLIENTS
|
||||
)
|
||||
for k, v in controller.api.clients.items()
|
||||
for k, v in hub.api.clients.items()
|
||||
}
|
||||
diag["devices"] = {
|
||||
macs_to_redact[k]: async_redact_data(
|
||||
async_replace_dict_data(v.raw, macs_to_redact), REDACT_DEVICES
|
||||
)
|
||||
for k, v in controller.api.devices.items()
|
||||
for k, v in hub.api.devices.items()
|
||||
}
|
||||
diag["dpi_apps"] = {k: v.raw for k, v in controller.api.dpi_apps.items()}
|
||||
diag["dpi_groups"] = {k: v.raw for k, v in controller.api.dpi_groups.items()}
|
||||
diag["dpi_apps"] = {k: v.raw for k, v in hub.api.dpi_apps.items()}
|
||||
diag["dpi_groups"] = {k: v.raw for k, v in hub.api.dpi_groups.items()}
|
||||
diag["wlans"] = {
|
||||
k: async_redact_data(
|
||||
async_replace_dict_data(v.raw, macs_to_redact), REDACT_WLANS
|
||||
)
|
||||
for k, v in controller.api.wlans.items()
|
||||
for k, v in hub.api.wlans.items()
|
||||
}
|
||||
|
||||
return diag
|
||||
|
@ -29,36 +29,36 @@ from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
from .const import ATTR_MANUFACTURER, DOMAIN
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .controller import UniFiController
|
||||
from .hub import UnifiHub
|
||||
|
||||
HandlerT = TypeVar("HandlerT", bound=APIHandler)
|
||||
SubscriptionT = Callable[[CallbackType, ItemEvent], UnsubscribeType]
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_available_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_device_available_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if device is available."""
|
||||
if "_" in obj_id: # Sub device (outlet or port)
|
||||
obj_id = obj_id.partition("_")[0]
|
||||
|
||||
device = controller.api.devices[obj_id]
|
||||
return controller.available and not device.disabled
|
||||
device = hub.api.devices[obj_id]
|
||||
return hub.available and not device.disabled
|
||||
|
||||
|
||||
@callback
|
||||
def async_wlan_available_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_wlan_available_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if WLAN is available."""
|
||||
wlan = controller.api.wlans[obj_id]
|
||||
return controller.available and wlan.enabled
|
||||
wlan = hub.api.wlans[obj_id]
|
||||
return hub.available and wlan.enabled
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_device_info_fn(controller: UniFiController, obj_id: str) -> DeviceInfo:
|
||||
def async_device_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
"""Create device registry entry for device."""
|
||||
if "_" in obj_id: # Sub device (outlet or port)
|
||||
obj_id = obj_id.partition("_")[0]
|
||||
|
||||
device = controller.api.devices[obj_id]
|
||||
device = hub.api.devices[obj_id]
|
||||
return DeviceInfo(
|
||||
connections={(CONNECTION_NETWORK_MAC, device.mac)},
|
||||
manufacturer=ATTR_MANUFACTURER,
|
||||
@ -70,9 +70,9 @@ def async_device_device_info_fn(controller: UniFiController, obj_id: str) -> Dev
|
||||
|
||||
|
||||
@callback
|
||||
def async_wlan_device_info_fn(controller: UniFiController, obj_id: str) -> DeviceInfo:
|
||||
def async_wlan_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
"""Create device registry entry for WLAN."""
|
||||
wlan = controller.api.wlans[obj_id]
|
||||
wlan = hub.api.wlans[obj_id]
|
||||
return DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
identifiers={(DOMAIN, wlan.id)},
|
||||
@ -83,9 +83,9 @@ def async_wlan_device_info_fn(controller: UniFiController, obj_id: str) -> Devic
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_device_info_fn(controller: UniFiController, obj_id: str) -> DeviceInfo:
|
||||
def async_client_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
"""Create device registry entry for client."""
|
||||
client = controller.api.clients[obj_id]
|
||||
client = hub.api.clients[obj_id]
|
||||
return DeviceInfo(
|
||||
connections={(CONNECTION_NETWORK_MAC, obj_id)},
|
||||
default_manufacturer=client.oui,
|
||||
@ -97,17 +97,17 @@ def async_client_device_info_fn(controller: UniFiController, obj_id: str) -> Dev
|
||||
class UnifiDescription(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
allowed_fn: Callable[[UniFiController, str], bool]
|
||||
allowed_fn: Callable[[UnifiHub, str], bool]
|
||||
api_handler_fn: Callable[[aiounifi.Controller], HandlerT]
|
||||
available_fn: Callable[[UniFiController, str], bool]
|
||||
device_info_fn: Callable[[UniFiController, str], DeviceInfo | None]
|
||||
available_fn: Callable[[UnifiHub, str], bool]
|
||||
device_info_fn: Callable[[UnifiHub, str], DeviceInfo | None]
|
||||
event_is_on: tuple[EventKey, ...] | None
|
||||
event_to_subscribe: tuple[EventKey, ...] | None
|
||||
name_fn: Callable[[ApiItemT], str | None]
|
||||
object_fn: Callable[[aiounifi.Controller, str], ApiItemT]
|
||||
should_poll: bool
|
||||
supported_fn: Callable[[UniFiController, str], bool | None]
|
||||
unique_id_fn: Callable[[UniFiController, str], str]
|
||||
supported_fn: Callable[[UnifiHub, str], bool | None]
|
||||
unique_id_fn: Callable[[UnifiHub, str], str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -124,36 +124,36 @@ class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
def __init__(
|
||||
self,
|
||||
obj_id: str,
|
||||
controller: UniFiController,
|
||||
hub: UnifiHub,
|
||||
description: UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
) -> None:
|
||||
"""Set up UniFi switch entity."""
|
||||
self._obj_id = obj_id
|
||||
self.controller = controller
|
||||
self.hub = hub
|
||||
self.entity_description = description
|
||||
|
||||
controller.known_objects.add((description.key, obj_id))
|
||||
hub.known_objects.add((description.key, obj_id))
|
||||
|
||||
self._removed = False
|
||||
|
||||
self._attr_available = description.available_fn(controller, obj_id)
|
||||
self._attr_device_info = description.device_info_fn(controller, obj_id)
|
||||
self._attr_available = description.available_fn(hub, obj_id)
|
||||
self._attr_device_info = description.device_info_fn(hub, obj_id)
|
||||
self._attr_should_poll = description.should_poll
|
||||
self._attr_unique_id = description.unique_id_fn(controller, obj_id)
|
||||
self._attr_unique_id = description.unique_id_fn(hub, obj_id)
|
||||
|
||||
obj = description.object_fn(self.controller.api, obj_id)
|
||||
obj = description.object_fn(self.hub.api, obj_id)
|
||||
self._attr_name = description.name_fn(obj)
|
||||
self.async_initiate_state()
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
description = self.entity_description
|
||||
handler = description.api_handler_fn(self.controller.api)
|
||||
handler = description.api_handler_fn(self.hub.api)
|
||||
|
||||
@callback
|
||||
def unregister_object() -> None:
|
||||
"""Remove object ID from known_objects when unloaded."""
|
||||
self.controller.known_objects.discard((description.key, self._obj_id))
|
||||
self.hub.known_objects.discard((description.key, self._obj_id))
|
||||
|
||||
self.async_on_remove(unregister_object)
|
||||
|
||||
@ -165,11 +165,11 @@ class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
)
|
||||
)
|
||||
|
||||
# State change from controller or websocket
|
||||
# State change from hub or websocket
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
self.controller.signal_reachable,
|
||||
self.hub.signal_reachable,
|
||||
self.async_signal_reachable_callback,
|
||||
)
|
||||
)
|
||||
@ -178,7 +178,7 @@ class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
self.controller.signal_options_update,
|
||||
self.hub.signal_options_update,
|
||||
self.async_signal_options_updated,
|
||||
)
|
||||
)
|
||||
@ -186,7 +186,7 @@ class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
# Subscribe to events if defined
|
||||
if description.event_to_subscribe is not None:
|
||||
self.async_on_remove(
|
||||
self.controller.api.events.subscribe(
|
||||
self.hub.api.events.subscribe(
|
||||
self.async_event_callback,
|
||||
description.event_to_subscribe,
|
||||
)
|
||||
@ -200,22 +200,22 @@ class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
return
|
||||
|
||||
description = self.entity_description
|
||||
if not description.supported_fn(self.controller, self._obj_id):
|
||||
if not description.supported_fn(self.hub, self._obj_id):
|
||||
self.hass.async_create_task(self.remove_item({self._obj_id}))
|
||||
return
|
||||
|
||||
self._attr_available = description.available_fn(self.controller, self._obj_id)
|
||||
self._attr_available = description.available_fn(self.hub, self._obj_id)
|
||||
self.async_update_state(event, obj_id)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def async_signal_reachable_callback(self) -> None:
|
||||
"""Call when controller connection state change."""
|
||||
"""Call when hub connection state change."""
|
||||
self.async_signalling_callback(ItemEvent.ADDED, self._obj_id)
|
||||
|
||||
async def async_signal_options_updated(self) -> None:
|
||||
"""Config entry options are updated, remove entity if option is disabled."""
|
||||
if not self.entity_description.allowed_fn(self.controller, self._obj_id):
|
||||
if not self.entity_description.allowed_fn(self.hub, self._obj_id):
|
||||
await self.remove_item({self._obj_id})
|
||||
|
||||
async def remove_item(self, keys: set) -> None:
|
||||
|
@ -15,7 +15,7 @@ class AuthenticationRequired(UnifiException):
|
||||
|
||||
|
||||
class CannotConnect(UnifiException):
|
||||
"""Unable to connect to the controller."""
|
||||
"""Unable to connect to UniFi Network."""
|
||||
|
||||
|
||||
class LoginRequired(UnifiException):
|
||||
|
@ -80,7 +80,7 @@ CHECK_HEARTBEAT_INTERVAL = timedelta(seconds=1)
|
||||
CHECK_WEBSOCKET_INTERVAL = timedelta(minutes=1)
|
||||
|
||||
|
||||
class UniFiController:
|
||||
class UnifiHub:
|
||||
"""Manages a single UniFi Network instance."""
|
||||
|
||||
def __init__(
|
||||
@ -165,7 +165,7 @@ class UniFiController:
|
||||
|
||||
@property
|
||||
def host(self) -> str:
|
||||
"""Return the host of this controller."""
|
||||
"""Return the host of this hub."""
|
||||
host: str = self.config_entry.data[CONF_HOST]
|
||||
return host
|
||||
|
||||
@ -180,10 +180,10 @@ class UniFiController:
|
||||
requires_admin: bool = False,
|
||||
) -> None:
|
||||
"""Register platform for UniFi entity management."""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
if requires_admin and not controller.is_admin:
|
||||
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
if requires_admin and not hub.is_admin:
|
||||
return
|
||||
controller.register_platform_add_entities(
|
||||
hub.register_platform_add_entities(
|
||||
entity_class, descriptions, async_add_entities
|
||||
)
|
||||
|
||||
@ -351,7 +351,7 @@ class UniFiController:
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""UniFi controller device info."""
|
||||
"""UniFi Network device info."""
|
||||
assert self.config_entry.unique_id is not None
|
||||
|
||||
version: str | None = None
|
||||
@ -384,10 +384,10 @@ class UniFiController:
|
||||
If config entry is updated due to reauth flow
|
||||
the entry might already have been reset and thus is not available.
|
||||
"""
|
||||
if not (controller := hass.data[UNIFI_DOMAIN].get(config_entry.entry_id)):
|
||||
if not (hub := hass.data[UNIFI_DOMAIN].get(config_entry.entry_id)):
|
||||
return
|
||||
controller.load_config_entry_options()
|
||||
async_dispatcher_send(hass, controller.signal_options_update)
|
||||
hub.load_config_entry_options()
|
||||
async_dispatcher_send(hass, hub.signal_options_update)
|
||||
|
||||
@callback
|
||||
def start_websocket(self) -> None:
|
||||
@ -449,7 +449,7 @@ class UniFiController:
|
||||
self.ws_task.cancel()
|
||||
|
||||
async def async_reset(self) -> bool:
|
||||
"""Reset this controller to default state.
|
||||
"""Reset this hub to default state.
|
||||
|
||||
Will cancel any scheduled setup retry and will unload
|
||||
the config entry.
|
||||
@ -489,11 +489,11 @@ class UniFiController:
|
||||
return True
|
||||
|
||||
|
||||
async def get_unifi_controller(
|
||||
async def get_unifi_api(
|
||||
hass: HomeAssistant,
|
||||
config: MappingProxyType[str, Any],
|
||||
) -> aiounifi.Controller:
|
||||
"""Create a controller object and verify authentication."""
|
||||
"""Create a aiounifi object and verify authentication."""
|
||||
ssl_context: ssl.SSLContext | Literal[False] = False
|
||||
|
||||
if verify_ssl := config.get(CONF_VERIFY_SSL):
|
||||
@ -505,7 +505,7 @@ async def get_unifi_controller(
|
||||
hass, verify_ssl=False, cookie_jar=CookieJar(unsafe=True)
|
||||
)
|
||||
|
||||
controller = aiounifi.Controller(
|
||||
api = aiounifi.Controller(
|
||||
Configuration(
|
||||
session,
|
||||
host=config[CONF_HOST],
|
||||
@ -519,8 +519,8 @@ async def get_unifi_controller(
|
||||
|
||||
try:
|
||||
async with asyncio.timeout(10):
|
||||
await controller.login()
|
||||
return controller
|
||||
await api.login()
|
||||
return api
|
||||
|
||||
except aiounifi.Unauthorized as err:
|
||||
LOGGER.warning(
|
@ -20,7 +20,6 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .controller import UniFiController
|
||||
from .entity import (
|
||||
HandlerT,
|
||||
UnifiEntity,
|
||||
@ -28,19 +27,20 @@ from .entity import (
|
||||
async_wlan_available_fn,
|
||||
async_wlan_device_info_fn,
|
||||
)
|
||||
from .hub import UnifiHub
|
||||
|
||||
|
||||
@callback
|
||||
def async_wlan_qr_code_image_fn(controller: UniFiController, wlan: Wlan) -> bytes:
|
||||
def async_wlan_qr_code_image_fn(hub: UnifiHub, wlan: Wlan) -> bytes:
|
||||
"""Calculate receiving data transfer value."""
|
||||
return controller.api.wlans.generate_wlan_qr_code(wlan)
|
||||
return hub.api.wlans.generate_wlan_qr_code(wlan)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiImageEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
image_fn: Callable[[UniFiController, ApiItemT], bytes]
|
||||
image_fn: Callable[[UnifiHub, ApiItemT], bytes]
|
||||
value_fn: Callable[[ApiItemT], str | None]
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
has_entity_name=True,
|
||||
entity_registry_enabled_default=False,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.wlans,
|
||||
available_fn=async_wlan_available_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
@ -68,8 +68,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
|
||||
name_fn=lambda wlan: "QR Code",
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"qr_code-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"qr_code-{obj_id}",
|
||||
image_fn=async_wlan_qr_code_image_fn,
|
||||
value_fn=lambda obj: obj.x_passphrase,
|
||||
),
|
||||
@ -82,7 +82,7 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up image platform for UniFi Network integration."""
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
async_add_entities,
|
||||
@ -104,26 +104,26 @@ class UnifiImageEntity(UnifiEntity[HandlerT, ApiItemT], ImageEntity):
|
||||
def __init__(
|
||||
self,
|
||||
obj_id: str,
|
||||
controller: UniFiController,
|
||||
hub: UnifiHub,
|
||||
description: UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
) -> None:
|
||||
"""Initiatlize UniFi Image entity."""
|
||||
super().__init__(obj_id, controller, description)
|
||||
ImageEntity.__init__(self, controller.hass)
|
||||
super().__init__(obj_id, hub, description)
|
||||
ImageEntity.__init__(self, hub.hass)
|
||||
|
||||
def image(self) -> bytes | None:
|
||||
"""Return bytes of image."""
|
||||
if self.current_image is None:
|
||||
description = self.entity_description
|
||||
obj = description.object_fn(self.controller.api, self._obj_id)
|
||||
self.current_image = description.image_fn(self.controller, obj)
|
||||
obj = description.object_fn(self.hub.api, self._obj_id)
|
||||
self.current_image = description.image_fn(self.hub, obj)
|
||||
return self.current_image
|
||||
|
||||
@callback
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
"""Update entity state."""
|
||||
description = self.entity_description
|
||||
obj = description.object_fn(self.controller.api, self._obj_id)
|
||||
obj = description.object_fn(self.hub.api, self._obj_id)
|
||||
if (value := description.value_fn(obj)) != self.previous_value:
|
||||
self.previous_value = value
|
||||
self.current_image = None
|
||||
|
@ -40,7 +40,6 @@ from homeassistant.helpers.typing import StateType
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .const import DEVICE_STATES
|
||||
from .controller import UniFiController
|
||||
from .entity import (
|
||||
HandlerT,
|
||||
UnifiEntity,
|
||||
@ -51,44 +50,43 @@ from .entity import (
|
||||
async_wlan_available_fn,
|
||||
async_wlan_device_info_fn,
|
||||
)
|
||||
from .hub import UnifiHub
|
||||
|
||||
|
||||
@callback
|
||||
def async_bandwidth_sensor_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_bandwidth_sensor_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if client is allowed."""
|
||||
if obj_id in controller.option_supported_clients:
|
||||
if obj_id in hub.option_supported_clients:
|
||||
return True
|
||||
return controller.option_allow_bandwidth_sensors
|
||||
return hub.option_allow_bandwidth_sensors
|
||||
|
||||
|
||||
@callback
|
||||
def async_uptime_sensor_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_uptime_sensor_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if client is allowed."""
|
||||
if obj_id in controller.option_supported_clients:
|
||||
if obj_id in hub.option_supported_clients:
|
||||
return True
|
||||
return controller.option_allow_uptime_sensors
|
||||
return hub.option_allow_uptime_sensors
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_rx_value_fn(controller: UniFiController, client: Client) -> float:
|
||||
def async_client_rx_value_fn(hub: UnifiHub, client: Client) -> float:
|
||||
"""Calculate receiving data transfer value."""
|
||||
if controller.wireless_clients.is_wireless(client):
|
||||
if hub.wireless_clients.is_wireless(client):
|
||||
return client.rx_bytes_r / 1000000
|
||||
return client.wired_rx_bytes_r / 1000000
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_tx_value_fn(controller: UniFiController, client: Client) -> float:
|
||||
def async_client_tx_value_fn(hub: UnifiHub, client: Client) -> float:
|
||||
"""Calculate transmission data transfer value."""
|
||||
if controller.wireless_clients.is_wireless(client):
|
||||
if hub.wireless_clients.is_wireless(client):
|
||||
return client.tx_bytes_r / 1000000
|
||||
return client.wired_tx_bytes_r / 1000000
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_uptime_value_fn(
|
||||
controller: UniFiController, client: Client
|
||||
) -> datetime:
|
||||
def async_client_uptime_value_fn(hub: UnifiHub, client: Client) -> datetime:
|
||||
"""Calculate the uptime of the client."""
|
||||
if client.uptime < 1000000000:
|
||||
return dt_util.now() - timedelta(seconds=client.uptime)
|
||||
@ -96,23 +94,21 @@ def async_client_uptime_value_fn(
|
||||
|
||||
|
||||
@callback
|
||||
def async_wlan_client_value_fn(controller: UniFiController, wlan: Wlan) -> int:
|
||||
def async_wlan_client_value_fn(hub: UnifiHub, wlan: Wlan) -> int:
|
||||
"""Calculate the amount of clients connected to a wlan."""
|
||||
return len(
|
||||
[
|
||||
client.mac
|
||||
for client in controller.api.clients.values()
|
||||
for client in hub.api.clients.values()
|
||||
if client.essid == wlan.name
|
||||
and dt_util.utcnow() - dt_util.utc_from_timestamp(client.last_seen or 0)
|
||||
< controller.option_detection_time
|
||||
< hub.option_detection_time
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_uptime_value_fn(
|
||||
controller: UniFiController, device: Device
|
||||
) -> datetime | None:
|
||||
def async_device_uptime_value_fn(hub: UnifiHub, device: Device) -> datetime | None:
|
||||
"""Calculate the approximate time the device started (based on uptime returned from API, in seconds)."""
|
||||
if device.uptime <= 0:
|
||||
# Library defaults to 0 if uptime is not provided, e.g. when offline
|
||||
@ -131,29 +127,27 @@ def async_device_uptime_value_changed_fn(
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_outlet_power_supported_fn(
|
||||
controller: UniFiController, obj_id: str
|
||||
) -> bool:
|
||||
def async_device_outlet_power_supported_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Determine if an outlet has the power property."""
|
||||
# At this time, an outlet_caps value of 3 is expected to indicate that the outlet
|
||||
# supports metering
|
||||
return controller.api.outlets[obj_id].caps == 3
|
||||
return hub.api.outlets[obj_id].caps == 3
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_outlet_supported_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_device_outlet_supported_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Determine if a device supports reading overall power metrics."""
|
||||
return controller.api.devices[obj_id].outlet_ac_power_budget is not None
|
||||
return hub.api.devices[obj_id].outlet_ac_power_budget is not None
|
||||
|
||||
|
||||
@callback
|
||||
def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if client was last seen recently."""
|
||||
client = controller.api.clients[obj_id]
|
||||
client = hub.api.clients[obj_id]
|
||||
|
||||
if (
|
||||
dt_util.utcnow() - dt_util.utc_from_timestamp(client.last_seen or 0)
|
||||
> controller.option_detection_time
|
||||
> hub.option_detection_time
|
||||
):
|
||||
return False
|
||||
|
||||
@ -164,11 +158,11 @@ def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bo
|
||||
class UnifiSensorEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
value_fn: Callable[[UniFiController, ApiItemT], datetime | float | str | None]
|
||||
value_fn: Callable[[UnifiHub, ApiItemT], datetime | float | str | None]
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_state_value_fn(controller: UniFiController, device: Device) -> str:
|
||||
def async_device_state_value_fn(hub: UnifiHub, device: Device) -> str:
|
||||
"""Retrieve the state of the device."""
|
||||
return DEVICE_STATES[device.state]
|
||||
|
||||
@ -181,7 +175,7 @@ class UnifiSensorEntityDescription(
|
||||
):
|
||||
"""Class describing UniFi sensor entity."""
|
||||
|
||||
is_connected_fn: Callable[[UniFiController, str], bool] | None = None
|
||||
is_connected_fn: Callable[[UnifiHub, str], bool] | None = None
|
||||
# Custom function to determine whether a state change should be recorded
|
||||
value_changed_fn: Callable[
|
||||
[StateType | date | datetime | Decimal, datetime | float | str | None],
|
||||
@ -200,7 +194,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
has_entity_name=True,
|
||||
allowed_fn=async_bandwidth_sensor_allowed_fn,
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda controller, _: controller.available,
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
@ -208,8 +202,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda _: "RX",
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, _: controller.option_allow_bandwidth_sensors,
|
||||
unique_id_fn=lambda controller, obj_id: f"rx-{obj_id}",
|
||||
supported_fn=lambda hub, _: hub.option_allow_bandwidth_sensors,
|
||||
unique_id_fn=lambda hub, obj_id: f"rx-{obj_id}",
|
||||
value_fn=async_client_rx_value_fn,
|
||||
),
|
||||
UnifiSensorEntityDescription[Clients, Client](
|
||||
@ -222,7 +216,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
has_entity_name=True,
|
||||
allowed_fn=async_bandwidth_sensor_allowed_fn,
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda controller, _: controller.available,
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
@ -230,8 +224,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda _: "TX",
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, _: controller.option_allow_bandwidth_sensors,
|
||||
unique_id_fn=lambda controller, obj_id: f"tx-{obj_id}",
|
||||
supported_fn=lambda hub, _: hub.option_allow_bandwidth_sensors,
|
||||
unique_id_fn=lambda hub, obj_id: f"tx-{obj_id}",
|
||||
value_fn=async_client_tx_value_fn,
|
||||
),
|
||||
UnifiSensorEntityDescription[Ports, Port](
|
||||
@ -241,7 +235,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement=UnitOfPower.WATT,
|
||||
has_entity_name=True,
|
||||
entity_registry_enabled_default=False,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.ports,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -250,8 +244,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda port: f"{port.name} PoE Power",
|
||||
object_fn=lambda api, obj_id: api.ports[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: controller.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda controller, obj_id: f"poe_power-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda hub, obj_id: f"poe_power-{obj_id}",
|
||||
value_fn=lambda _, obj: obj.poe_power if obj.poe_mode != "off" else "0",
|
||||
),
|
||||
UnifiSensorEntityDescription[Clients, Client](
|
||||
@ -262,15 +256,15 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
entity_registry_enabled_default=False,
|
||||
allowed_fn=async_uptime_sensor_allowed_fn,
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda controller, obj_id: controller.available,
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda client: "Uptime",
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, _: controller.option_allow_uptime_sensors,
|
||||
unique_id_fn=lambda controller, obj_id: f"uptime-{obj_id}",
|
||||
supported_fn=lambda hub, _: hub.option_allow_uptime_sensors,
|
||||
unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}",
|
||||
value_fn=async_client_uptime_value_fn,
|
||||
),
|
||||
UnifiSensorEntityDescription[Wlans, Wlan](
|
||||
@ -278,7 +272,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
has_entity_name=True,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.wlans,
|
||||
available_fn=async_wlan_available_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
@ -287,8 +281,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda wlan: None,
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=True,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"wlan_clients-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"wlan_clients-{obj_id}",
|
||||
value_fn=async_wlan_client_value_fn,
|
||||
),
|
||||
UnifiSensorEntityDescription[Outlets, Outlet](
|
||||
@ -297,7 +291,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfPower.WATT,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.outlets,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -307,7 +301,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.outlets[obj_id],
|
||||
should_poll=True,
|
||||
supported_fn=async_device_outlet_power_supported_fn,
|
||||
unique_id_fn=lambda controller, obj_id: f"outlet_power-{obj_id}",
|
||||
unique_id_fn=lambda hub, obj_id: f"outlet_power-{obj_id}",
|
||||
value_fn=lambda _, obj: obj.power if obj.relay_state else "0",
|
||||
),
|
||||
UnifiSensorEntityDescription[Devices, Device](
|
||||
@ -317,7 +311,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement=UnitOfPower.WATT,
|
||||
suggested_display_precision=1,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -327,8 +321,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=async_device_outlet_supported_fn,
|
||||
unique_id_fn=lambda controller, obj_id: f"ac_power_budget-{obj_id}",
|
||||
value_fn=lambda controller, device: device.outlet_ac_power_budget,
|
||||
unique_id_fn=lambda hub, obj_id: f"ac_power_budget-{obj_id}",
|
||||
value_fn=lambda hub, device: device.outlet_ac_power_budget,
|
||||
),
|
||||
UnifiSensorEntityDescription[Devices, Device](
|
||||
key="SmartPower AC power consumption",
|
||||
@ -337,7 +331,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement=UnitOfPower.WATT,
|
||||
suggested_display_precision=1,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -347,15 +341,15 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=async_device_outlet_supported_fn,
|
||||
unique_id_fn=lambda controller, obj_id: f"ac_power_conumption-{obj_id}",
|
||||
value_fn=lambda controller, device: device.outlet_ac_power_consumption,
|
||||
unique_id_fn=lambda hub, obj_id: f"ac_power_conumption-{obj_id}",
|
||||
value_fn=lambda hub, device: device.outlet_ac_power_consumption,
|
||||
),
|
||||
UnifiSensorEntityDescription[Devices, Device](
|
||||
key="Device uptime",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -364,8 +358,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda device: "Uptime",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"device_uptime-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"device_uptime-{obj_id}",
|
||||
value_fn=async_device_uptime_value_fn,
|
||||
value_changed_fn=async_device_uptime_value_changed_fn,
|
||||
),
|
||||
@ -375,7 +369,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -385,7 +379,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda ctrlr, obj_id: ctrlr.api.devices[obj_id].has_temperature,
|
||||
unique_id_fn=lambda controller, obj_id: f"device_temperature-{obj_id}",
|
||||
unique_id_fn=lambda hub, obj_id: f"device_temperature-{obj_id}",
|
||||
value_fn=lambda ctrlr, device: device.general_temperature,
|
||||
),
|
||||
UnifiSensorEntityDescription[Devices, Device](
|
||||
@ -393,7 +387,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
@ -402,8 +396,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
name_fn=lambda device: "State",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"device_state-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"device_state-{obj_id}",
|
||||
value_fn=async_device_state_value_fn,
|
||||
options=list(DEVICE_STATES.values()),
|
||||
),
|
||||
@ -416,7 +410,7 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up sensors for UniFi Network integration."""
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass, config_entry, async_add_entities, UnifiSensorEntity, ENTITY_DESCRIPTIONS
|
||||
)
|
||||
|
||||
@ -443,19 +437,19 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
|
||||
Update native_value.
|
||||
"""
|
||||
description = self.entity_description
|
||||
obj = description.object_fn(self.controller.api, self._obj_id)
|
||||
obj = description.object_fn(self.hub.api, self._obj_id)
|
||||
# Update the value only if value is considered to have changed relative to its previous state
|
||||
if description.value_changed_fn(
|
||||
self.native_value, (value := description.value_fn(self.controller, obj))
|
||||
self.native_value, (value := description.value_fn(self.hub, obj))
|
||||
):
|
||||
self._attr_native_value = value
|
||||
|
||||
if description.is_connected_fn is not None:
|
||||
# Send heartbeat if client is connected
|
||||
if description.is_connected_fn(self.controller, self._obj_id):
|
||||
self.controller.async_heartbeat(
|
||||
if description.is_connected_fn(self.hub, self._obj_id):
|
||||
self.hub.async_heartbeat(
|
||||
self._attr_unique_id,
|
||||
dt_util.utcnow() + self.controller.option_detection_time,
|
||||
dt_util.utcnow() + self.hub.option_detection_time,
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@ -467,7 +461,7 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"{self.controller.signal_heartbeat_missed}_{self.unique_id}",
|
||||
f"{self.hub.signal_heartbeat_missed}_{self.unique_id}",
|
||||
self._make_disconnected,
|
||||
)
|
||||
)
|
||||
@ -478,4 +472,4 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
|
||||
|
||||
if self.entity_description.is_connected_fn is not None:
|
||||
# Remove heartbeat registration
|
||||
self.controller.async_heartbeat(self._attr_unique_id)
|
||||
self.hub.async_heartbeat(self._attr_unique_id)
|
||||
|
@ -72,31 +72,31 @@ async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) -
|
||||
if mac == "":
|
||||
return
|
||||
|
||||
for controller in hass.data[UNIFI_DOMAIN].values():
|
||||
for hub in hass.data[UNIFI_DOMAIN].values():
|
||||
if (
|
||||
not controller.available
|
||||
or (client := controller.api.clients.get(mac)) is None
|
||||
not hub.available
|
||||
or (client := hub.api.clients.get(mac)) is None
|
||||
or client.is_wired
|
||||
):
|
||||
continue
|
||||
|
||||
await controller.api.request(ClientReconnectRequest.create(mac))
|
||||
await hub.api.request(ClientReconnectRequest.create(mac))
|
||||
|
||||
|
||||
async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
|
||||
"""Remove select clients from controller.
|
||||
"""Remove select clients from UniFi Network.
|
||||
|
||||
Validates based on:
|
||||
- Total time between first seen and last seen is less than 15 minutes.
|
||||
- Neither IP, hostname nor name is configured.
|
||||
"""
|
||||
for controller in hass.data[UNIFI_DOMAIN].values():
|
||||
if not controller.available:
|
||||
for hub in hass.data[UNIFI_DOMAIN].values():
|
||||
if not hub.available:
|
||||
continue
|
||||
|
||||
clients_to_remove = []
|
||||
|
||||
for client in controller.api.clients_all.values():
|
||||
for client in hub.api.clients_all.values():
|
||||
if (
|
||||
client.last_seen
|
||||
and client.first_seen
|
||||
@ -110,4 +110,4 @@ async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) ->
|
||||
clients_to_remove.append(client.mac)
|
||||
|
||||
if clients_to_remove:
|
||||
await controller.api.request(ClientRemoveRequest.create(clients_to_remove))
|
||||
await hub.api.request(ClientRemoveRequest.create(clients_to_remove))
|
||||
|
@ -45,7 +45,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.helpers.entity_registry as er
|
||||
|
||||
from .const import ATTR_MANUFACTURER
|
||||
from .controller import UNIFI_DOMAIN, UniFiController
|
||||
from .entity import (
|
||||
HandlerT,
|
||||
SubscriptionT,
|
||||
@ -56,25 +55,24 @@ from .entity import (
|
||||
async_device_device_info_fn,
|
||||
async_wlan_device_info_fn,
|
||||
)
|
||||
from .hub import UNIFI_DOMAIN, UnifiHub
|
||||
|
||||
CLIENT_BLOCKED = (EventKey.WIRED_CLIENT_BLOCKED, EventKey.WIRELESS_CLIENT_BLOCKED)
|
||||
CLIENT_UNBLOCKED = (EventKey.WIRED_CLIENT_UNBLOCKED, EventKey.WIRELESS_CLIENT_UNBLOCKED)
|
||||
|
||||
|
||||
@callback
|
||||
def async_block_client_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
|
||||
def async_block_client_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Check if client is allowed."""
|
||||
if obj_id in controller.option_supported_clients:
|
||||
if obj_id in hub.option_supported_clients:
|
||||
return True
|
||||
return obj_id in controller.option_block_clients
|
||||
return obj_id in hub.option_block_clients
|
||||
|
||||
|
||||
@callback
|
||||
def async_dpi_group_is_on_fn(
|
||||
controller: UniFiController, dpi_group: DPIRestrictionGroup
|
||||
) -> bool:
|
||||
def async_dpi_group_is_on_fn(hub: UnifiHub, dpi_group: DPIRestrictionGroup) -> bool:
|
||||
"""Calculate if all apps are enabled."""
|
||||
api = controller.api
|
||||
api = hub.api
|
||||
return all(
|
||||
api.dpi_apps[app_id].enabled
|
||||
for app_id in dpi_group.dpiapp_ids or []
|
||||
@ -83,9 +81,7 @@ def async_dpi_group_is_on_fn(
|
||||
|
||||
|
||||
@callback
|
||||
def async_dpi_group_device_info_fn(
|
||||
controller: UniFiController, obj_id: str
|
||||
) -> DeviceInfo:
|
||||
def async_dpi_group_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
"""Create device registry entry for DPI group."""
|
||||
return DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
@ -97,11 +93,9 @@ def async_dpi_group_device_info_fn(
|
||||
|
||||
|
||||
@callback
|
||||
def async_port_forward_device_info_fn(
|
||||
controller: UniFiController, obj_id: str
|
||||
) -> DeviceInfo:
|
||||
def async_port_forward_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
"""Create device registry entry for port forward."""
|
||||
unique_id = controller.config_entry.unique_id
|
||||
unique_id = hub.config_entry.unique_id
|
||||
assert unique_id is not None
|
||||
return DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
@ -113,79 +107,67 @@ def async_port_forward_device_info_fn(
|
||||
|
||||
|
||||
async def async_block_client_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
hub: UnifiHub, obj_id: str, target: bool
|
||||
) -> None:
|
||||
"""Control network access of client."""
|
||||
await controller.api.request(ClientBlockRequest.create(obj_id, not target))
|
||||
await hub.api.request(ClientBlockRequest.create(obj_id, not target))
|
||||
|
||||
|
||||
async def async_dpi_group_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
) -> None:
|
||||
async def async_dpi_group_control_fn(hub: UnifiHub, obj_id: str, target: bool) -> None:
|
||||
"""Enable or disable DPI group."""
|
||||
dpi_group = controller.api.dpi_groups[obj_id]
|
||||
dpi_group = hub.api.dpi_groups[obj_id]
|
||||
await asyncio.gather(
|
||||
*[
|
||||
controller.api.request(
|
||||
DPIRestrictionAppEnableRequest.create(app_id, target)
|
||||
)
|
||||
hub.api.request(DPIRestrictionAppEnableRequest.create(app_id, target))
|
||||
for app_id in dpi_group.dpiapp_ids or []
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_outlet_supports_switching_fn(
|
||||
controller: UniFiController, obj_id: str
|
||||
) -> bool:
|
||||
def async_outlet_supports_switching_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
"""Determine if an outlet supports switching."""
|
||||
outlet = controller.api.outlets[obj_id]
|
||||
outlet = hub.api.outlets[obj_id]
|
||||
return outlet.has_relay or outlet.caps in (1, 3)
|
||||
|
||||
|
||||
async def async_outlet_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
) -> None:
|
||||
async def async_outlet_control_fn(hub: UnifiHub, obj_id: str, target: bool) -> None:
|
||||
"""Control outlet relay."""
|
||||
mac, _, index = obj_id.partition("_")
|
||||
device = controller.api.devices[mac]
|
||||
await controller.api.request(
|
||||
device = hub.api.devices[mac]
|
||||
await hub.api.request(
|
||||
DeviceSetOutletRelayRequest.create(device, int(index), target)
|
||||
)
|
||||
|
||||
|
||||
async def async_poe_port_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
) -> None:
|
||||
async def async_poe_port_control_fn(hub: UnifiHub, obj_id: str, target: bool) -> None:
|
||||
"""Control poe state."""
|
||||
mac, _, index = obj_id.partition("_")
|
||||
port = controller.api.ports[obj_id]
|
||||
port = hub.api.ports[obj_id]
|
||||
on_state = "auto" if port.raw["poe_caps"] != 8 else "passthrough"
|
||||
state = on_state if target else "off"
|
||||
controller.async_queue_poe_port_command(mac, int(index), state)
|
||||
hub.async_queue_poe_port_command(mac, int(index), state)
|
||||
|
||||
|
||||
async def async_port_forward_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
hub: UnifiHub, obj_id: str, target: bool
|
||||
) -> None:
|
||||
"""Control port forward state."""
|
||||
port_forward = controller.api.port_forwarding[obj_id]
|
||||
await controller.api.request(PortForwardEnableRequest.create(port_forward, target))
|
||||
port_forward = hub.api.port_forwarding[obj_id]
|
||||
await hub.api.request(PortForwardEnableRequest.create(port_forward, target))
|
||||
|
||||
|
||||
async def async_wlan_control_fn(
|
||||
controller: UniFiController, obj_id: str, target: bool
|
||||
) -> None:
|
||||
async def async_wlan_control_fn(hub: UnifiHub, obj_id: str, target: bool) -> None:
|
||||
"""Control outlet relay."""
|
||||
await controller.api.request(WlanEnableRequest.create(obj_id, target))
|
||||
await hub.api.request(WlanEnableRequest.create(obj_id, target))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiSwitchEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
control_fn: Callable[[UniFiController, str, bool], Coroutine[Any, Any, None]]
|
||||
is_on_fn: Callable[[UniFiController, ApiItemT], bool]
|
||||
control_fn: Callable[[UnifiHub, str, bool], Coroutine[Any, Any, None]]
|
||||
is_on_fn: Callable[[UnifiHub, ApiItemT], bool]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -209,26 +191,26 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
icon="mdi:ethernet",
|
||||
allowed_fn=async_block_client_allowed_fn,
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda controller, obj_id: controller.available,
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
control_fn=async_block_client_control_fn,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=CLIENT_UNBLOCKED,
|
||||
event_to_subscribe=CLIENT_BLOCKED + CLIENT_UNBLOCKED,
|
||||
is_on_fn=lambda controller, client: not client.blocked,
|
||||
is_on_fn=lambda hub, client: not client.blocked,
|
||||
name_fn=lambda client: None,
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
only_event_for_state_change=True,
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"block-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"block-{obj_id}",
|
||||
),
|
||||
UnifiSwitchEntityDescription[DPIRestrictionGroups, DPIRestrictionGroup](
|
||||
key="DPI restriction",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
icon="mdi:network",
|
||||
allowed_fn=lambda controller, obj_id: controller.option_dpi_restrictions,
|
||||
allowed_fn=lambda hub, obj_id: hub.option_dpi_restrictions,
|
||||
api_handler_fn=lambda api: api.dpi_groups,
|
||||
available_fn=lambda controller, obj_id: controller.available,
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
control_fn=async_dpi_group_control_fn,
|
||||
custom_subscribe=lambda api: api.dpi_apps.subscribe,
|
||||
device_info_fn=async_dpi_group_device_info_fn,
|
||||
@ -239,25 +221,25 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.dpi_groups[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda c, obj_id: bool(c.api.dpi_groups[obj_id].dpiapp_ids),
|
||||
unique_id_fn=lambda controller, obj_id: obj_id,
|
||||
unique_id_fn=lambda hub, obj_id: obj_id,
|
||||
),
|
||||
UnifiSwitchEntityDescription[Outlets, Outlet](
|
||||
key="Outlet control",
|
||||
device_class=SwitchDeviceClass.OUTLET,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.outlets,
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_outlet_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_on_fn=lambda controller, outlet: outlet.relay_state,
|
||||
is_on_fn=lambda hub, outlet: outlet.relay_state,
|
||||
name_fn=lambda outlet: outlet.name,
|
||||
object_fn=lambda api, obj_id: api.outlets[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=async_outlet_supports_switching_fn,
|
||||
unique_id_fn=lambda controller, obj_id: f"outlet-{obj_id}",
|
||||
unique_id_fn=lambda hub, obj_id: f"outlet-{obj_id}",
|
||||
),
|
||||
UnifiSwitchEntityDescription[PortForwarding, PortForward](
|
||||
key="Port forward control",
|
||||
@ -265,19 +247,19 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
has_entity_name=True,
|
||||
icon="mdi:upload-network",
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.port_forwarding,
|
||||
available_fn=lambda controller, obj_id: controller.available,
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
control_fn=async_port_forward_control_fn,
|
||||
device_info_fn=async_port_forward_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_on_fn=lambda controller, port_forward: port_forward.enabled,
|
||||
is_on_fn=lambda hub, port_forward: port_forward.enabled,
|
||||
name_fn=lambda port_forward: f"{port_forward.name}",
|
||||
object_fn=lambda api, obj_id: api.port_forwarding[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"port_forward-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"port_forward-{obj_id}",
|
||||
),
|
||||
UnifiSwitchEntityDescription[Ports, Port](
|
||||
key="PoE port control",
|
||||
@ -286,19 +268,19 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
has_entity_name=True,
|
||||
entity_registry_enabled_default=False,
|
||||
icon="mdi:ethernet",
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.ports,
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_poe_port_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_on_fn=lambda controller, port: port.poe_mode != "off",
|
||||
is_on_fn=lambda hub, port: port.poe_mode != "off",
|
||||
name_fn=lambda port: f"{port.name} PoE",
|
||||
object_fn=lambda api, obj_id: api.ports[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: controller.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda controller, obj_id: f"poe-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda hub, obj_id: f"poe-{obj_id}",
|
||||
),
|
||||
UnifiSwitchEntityDescription[Wlans, Wlan](
|
||||
key="WLAN control",
|
||||
@ -306,19 +288,19 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
has_entity_name=True,
|
||||
icon="mdi:wifi-check",
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.wlans,
|
||||
available_fn=lambda controller, _: controller.available,
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
control_fn=async_wlan_control_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_on_fn=lambda controller, wlan: wlan.enabled,
|
||||
is_on_fn=lambda hub, wlan: wlan.enabled,
|
||||
name_fn=lambda wlan: None,
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"wlan-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"wlan-{obj_id}",
|
||||
),
|
||||
)
|
||||
|
||||
@ -329,7 +311,7 @@ def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> No
|
||||
|
||||
Introduced with release 2023.12.
|
||||
"""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub: UnifiHub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
ent_reg = er.async_get(hass)
|
||||
|
||||
@callback
|
||||
@ -344,10 +326,10 @@ def async_update_unique_id(hass: HomeAssistant, config_entry: ConfigEntry) -> No
|
||||
if entity_id := ent_reg.async_get_entity_id(DOMAIN, UNIFI_DOMAIN, unique_id):
|
||||
ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
|
||||
|
||||
for obj_id in controller.api.outlets:
|
||||
for obj_id in hub.api.outlets:
|
||||
update_unique_id(obj_id, "outlet")
|
||||
|
||||
for obj_id in controller.api.ports:
|
||||
for obj_id in hub.api.ports:
|
||||
update_unique_id(obj_id, "poe")
|
||||
|
||||
|
||||
@ -358,7 +340,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up switches for UniFi Network integration."""
|
||||
async_update_unique_id(hass, config_entry)
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
async_add_entities,
|
||||
@ -384,11 +366,11 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on switch."""
|
||||
await self.entity_description.control_fn(self.controller, self._obj_id, True)
|
||||
await self.entity_description.control_fn(self.hub, self._obj_id, True)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off switch."""
|
||||
await self.entity_description.control_fn(self.controller, self._obj_id, False)
|
||||
await self.entity_description.control_fn(self.hub, self._obj_id, False)
|
||||
|
||||
@callback
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
@ -400,8 +382,8 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
return
|
||||
|
||||
description = self.entity_description
|
||||
obj = description.object_fn(self.controller.api, self._obj_id)
|
||||
if (is_on := description.is_on_fn(self.controller, obj)) != self.is_on:
|
||||
obj = description.object_fn(self.hub.api, self._obj_id)
|
||||
if (is_on := description.is_on_fn(self.hub, obj)) != self.is_on:
|
||||
self._attr_is_on = is_on
|
||||
|
||||
@callback
|
||||
@ -416,7 +398,7 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
|
||||
if event.key in description.event_to_subscribe:
|
||||
self._attr_is_on = event.key in description.event_is_on
|
||||
self._attr_available = description.available_fn(self.controller, self._obj_id)
|
||||
self._attr_available = description.available_fn(self.hub, self._obj_id)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@ -425,7 +407,7 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
|
||||
if self.entity_description.custom_subscribe is not None:
|
||||
self.async_on_remove(
|
||||
self.entity_description.custom_subscribe(self.controller.api)(
|
||||
self.entity_description.custom_subscribe(self.hub.api)(
|
||||
self.async_signalling_callback, ItemEvent.CHANGED
|
||||
),
|
||||
)
|
||||
|
@ -21,13 +21,13 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .controller import UniFiController
|
||||
from .entity import (
|
||||
UnifiEntity,
|
||||
UnifiEntityDescription,
|
||||
async_device_available_fn,
|
||||
async_device_device_info_fn,
|
||||
)
|
||||
from .hub import UnifiHub
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -62,7 +62,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = (
|
||||
key="Upgrade device",
|
||||
device_class=UpdateDeviceClass.FIRMWARE,
|
||||
has_entity_name=True,
|
||||
allowed_fn=lambda controller, obj_id: True,
|
||||
allowed_fn=lambda hub, obj_id: True,
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_device_control_fn,
|
||||
@ -73,8 +73,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = (
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
state_fn=lambda api, device: device.state == 4,
|
||||
supported_fn=lambda controller, obj_id: True,
|
||||
unique_id_fn=lambda controller, obj_id: f"device_update-{obj_id}",
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"device_update-{obj_id}",
|
||||
),
|
||||
)
|
||||
|
||||
@ -85,7 +85,7 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up update entities for UniFi Network integration."""
|
||||
UniFiController.register_platform(
|
||||
UnifiHub.register_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
async_add_entities,
|
||||
@ -103,7 +103,7 @@ class UnifiDeviceUpdateEntity(UnifiEntity[_HandlerT, _DataT], UpdateEntity):
|
||||
def async_initiate_state(self) -> None:
|
||||
"""Initiate entity state."""
|
||||
self._attr_supported_features = UpdateEntityFeature.PROGRESS
|
||||
if self.controller.is_admin:
|
||||
if self.hub.is_admin:
|
||||
self._attr_supported_features |= UpdateEntityFeature.INSTALL
|
||||
|
||||
self.async_update_state(ItemEvent.ADDED, self._obj_id)
|
||||
@ -112,7 +112,7 @@ class UnifiDeviceUpdateEntity(UnifiEntity[_HandlerT, _DataT], UpdateEntity):
|
||||
self, version: str | None, backup: bool, **kwargs: Any
|
||||
) -> None:
|
||||
"""Install an update."""
|
||||
await self.entity_description.control_fn(self.controller.api, self._obj_id)
|
||||
await self.entity_description.control_fn(self.hub.api, self._obj_id)
|
||||
|
||||
@callback
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
@ -122,7 +122,7 @@ class UnifiDeviceUpdateEntity(UnifiEntity[_HandlerT, _DataT], UpdateEntity):
|
||||
"""
|
||||
description = self.entity_description
|
||||
|
||||
obj = description.object_fn(self.controller.api, self._obj_id)
|
||||
self._attr_in_progress = description.state_fn(self.controller.api, obj)
|
||||
obj = description.object_fn(self.hub.api, self._obj_id)
|
||||
self._attr_in_progress = description.state_fn(self.hub.api, obj)
|
||||
self._attr_installed_version = obj.version
|
||||
self._attr_latest_version = obj.upgrade_to_firmware or obj.version
|
||||
|
@ -9,14 +9,14 @@ from aiounifi.models.message import MessageKey
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.unifi.const import DOMAIN as UNIFI_DOMAIN
|
||||
from homeassistant.components.unifi.controller import RETRY_TIMER
|
||||
from homeassistant.components.unifi.hub import RETRY_TIMER
|
||||
from homeassistant.const import CONTENT_TYPE_JSON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.components.unifi.test_controller import DEFAULT_CONFIG_ENTRY_ID
|
||||
from tests.components.unifi.test_hub import DEFAULT_CONFIG_ENTRY_ID
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@ -43,12 +43,12 @@ class WebsocketStateManager(asyncio.Event):
|
||||
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]
|
||||
hub = self.hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
|
||||
self.aioclient_mock.get(
|
||||
f"https://{controller.host}:1234", status=302
|
||||
f"https://{hub.host}:1234", status=302
|
||||
) # Check UniFi OS
|
||||
self.aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/login",
|
||||
f"https://{hub.host}:1234/api/login",
|
||||
json={"data": "login successful", "meta": {"rc": "ok"}},
|
||||
headers={"content-type": CONTENT_TYPE_JSON},
|
||||
)
|
||||
@ -79,13 +79,13 @@ def mock_unifi_websocket(hass):
|
||||
data: list[dict] | dict | None = None,
|
||||
):
|
||||
"""Generate a websocket call."""
|
||||
controller = hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
|
||||
hub = hass.data[UNIFI_DOMAIN][DEFAULT_CONFIG_ENTRY_ID]
|
||||
if data and not message:
|
||||
controller.api.messages.handler(data)
|
||||
hub.api.messages.handler(data)
|
||||
elif data and message:
|
||||
if not isinstance(data, list):
|
||||
data = [data]
|
||||
controller.api.messages.handler(
|
||||
hub.api.messages.handler(
|
||||
{
|
||||
"meta": {"message": message.value},
|
||||
"data": data,
|
||||
|
@ -6,7 +6,7 @@ from homeassistant.const import ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, EntityCate
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@ -36,7 +36,7 @@ async def test_restart_device_button(
|
||||
}
|
||||
],
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(BUTTON_DOMAIN)) == 1
|
||||
|
||||
@ -52,7 +52,7 @@ async def test_restart_device_button(
|
||||
# Send restart device command
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/devmgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/devmgr",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -120,7 +120,7 @@ async def test_power_cycle_poe(
|
||||
}
|
||||
],
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(BUTTON_DOMAIN)) == 2
|
||||
|
||||
@ -136,7 +136,7 @@ async def test_power_cycle_poe(
|
||||
# Send restart device command
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/devmgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/devmgr",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
|
@ -33,7 +33,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
@ -356,7 +356,7 @@ async def test_flow_fails_user_credentials_faulty(
|
||||
assert result["errors"] == {"base": "faulty_credentials"}
|
||||
|
||||
|
||||
async def test_flow_fails_controller_unavailable(
|
||||
async def test_flow_fails_hub_unavailable(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test config flow."""
|
||||
@ -388,10 +388,10 @@ async def test_flow_fails_controller_unavailable(
|
||||
async def test_reauth_flow_update_configuration(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Verify reauth flow can update controller configuration."""
|
||||
"""Verify reauth flow can update hub configuration."""
|
||||
config_entry = await setup_unifi_integration(hass, aioclient_mock)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
controller.available = False
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub.available = False
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
UNIFI_DOMAIN,
|
||||
|
@ -21,7 +21,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .test_controller import ENTRY_CONFIG, setup_unifi_integration
|
||||
from .test_hub import ENTRY_CONFIG, setup_unifi_integration
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
@ -55,7 +55,7 @@ async def test_tracked_wireless_clients(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=[client]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
|
||||
assert hass.states.get("device_tracker.client").state == STATE_NOT_HOME
|
||||
@ -70,7 +70,7 @@ async def test_tracked_wireless_clients(
|
||||
|
||||
# Change time to mark client as away
|
||||
|
||||
new_time = dt_util.utcnow() + controller.option_detection_time
|
||||
new_time = dt_util.utcnow() + hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
@ -194,7 +194,7 @@ async def test_tracked_wireless_clients_event_source(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=[client]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
|
||||
assert hass.states.get("device_tracker.client").state == STATE_NOT_HOME
|
||||
|
||||
@ -243,7 +243,7 @@ async def test_tracked_wireless_clients_event_source(
|
||||
assert hass.states.get("device_tracker.client").state == STATE_HOME
|
||||
|
||||
# Change time to mark client as away
|
||||
freezer.tick(controller.option_detection_time + timedelta(seconds=1))
|
||||
freezer.tick(hub.option_detection_time + timedelta(seconds=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@ -282,7 +282,7 @@ async def test_tracked_wireless_clients_event_source(
|
||||
assert hass.states.get("device_tracker.client").state == STATE_HOME
|
||||
|
||||
# Change time to mark client as away
|
||||
freezer.tick(controller.option_detection_time + timedelta(seconds=1))
|
||||
freezer.tick(hub.option_detection_time + timedelta(seconds=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@ -407,13 +407,13 @@ async def test_remove_clients(
|
||||
assert hass.states.get("device_tracker.client_2")
|
||||
|
||||
|
||||
async def test_controller_state_change(
|
||||
async def test_hub_state_change(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
websocket_mock,
|
||||
mock_device_registry,
|
||||
) -> None:
|
||||
"""Verify entities state reflect on controller becoming unavailable."""
|
||||
"""Verify entities state reflect on hub connection becoming unavailable."""
|
||||
client = {
|
||||
"essid": "ssid",
|
||||
"hostname": "client",
|
||||
@ -682,7 +682,7 @@ async def test_option_ssid_filter(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=[client, client_on_ssid2]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
|
||||
|
||||
@ -711,7 +711,7 @@ async def test_option_ssid_filter(
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT, data=client_on_ssid2)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
new_time = dt_util.utcnow() + controller.option_detection_time
|
||||
new_time = dt_util.utcnow() + hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
@ -739,7 +739,7 @@ async def test_option_ssid_filter(
|
||||
|
||||
# Time pass to mark client as away
|
||||
|
||||
new_time += controller.option_detection_time
|
||||
new_time += hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
@ -758,7 +758,7 @@ async def test_option_ssid_filter(
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT, data=client_on_ssid2)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
new_time += controller.option_detection_time
|
||||
new_time += hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
@ -788,7 +788,7 @@ async def test_wireless_client_go_wired_issue(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=[client]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
|
||||
|
||||
@ -807,7 +807,7 @@ async def test_wireless_client_go_wired_issue(
|
||||
assert client_state.state == STATE_HOME
|
||||
|
||||
# Pass time
|
||||
new_time = dt_util.utcnow() + controller.option_detection_time
|
||||
new_time = dt_util.utcnow() + hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
@ -859,7 +859,7 @@ async def test_option_ignore_wired_bug(
|
||||
options={CONF_IGNORE_WIRED_BUG: True},
|
||||
clients_response=[client],
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
|
||||
|
||||
# Client is wireless
|
||||
@ -876,7 +876,7 @@ async def test_option_ignore_wired_bug(
|
||||
assert client_state.state == STATE_HOME
|
||||
|
||||
# pass time
|
||||
new_time = dt_util.utcnow() + controller.option_detection_time
|
||||
new_time = dt_util.utcnow() + hub.option_detection_time
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -7,7 +7,7 @@ from homeassistant.components.unifi.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
@ -26,8 +26,8 @@ from homeassistant.components.unifi.const import (
|
||||
PLATFORMS,
|
||||
UNIFI_WIRELESS_CLIENTS,
|
||||
)
|
||||
from homeassistant.components.unifi.controller import get_unifi_controller
|
||||
from homeassistant.components.unifi.errors import AuthenticationRequired, CannotConnect
|
||||
from homeassistant.components.unifi.hub import get_unifi_api
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
@ -194,7 +194,6 @@ async def setup_unifi_integration(
|
||||
system_information_response=None,
|
||||
wlans_response=None,
|
||||
known_wireless_clients=None,
|
||||
controllers=None,
|
||||
unique_id="1",
|
||||
config_entry_id=DEFAULT_CONFIG_ENTRY_ID,
|
||||
):
|
||||
@ -241,7 +240,7 @@ async def setup_unifi_integration(
|
||||
return config_entry
|
||||
|
||||
|
||||
async def test_controller_setup(
|
||||
async def test_hub_setup(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
@ -254,9 +253,9 @@ async def test_controller_setup(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, system_information_response=SYSTEM_INFORMATION
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entry = controller.config_entry
|
||||
entry = hub.config_entry
|
||||
assert len(forward_entry_setup.mock_calls) == len(PLATFORMS)
|
||||
assert forward_entry_setup.mock_calls[0][1] == (entry, BUTTON_DOMAIN)
|
||||
assert forward_entry_setup.mock_calls[1][1] == (entry, TRACKER_DOMAIN)
|
||||
@ -264,21 +263,21 @@ async def test_controller_setup(
|
||||
assert forward_entry_setup.mock_calls[3][1] == (entry, SENSOR_DOMAIN)
|
||||
assert forward_entry_setup.mock_calls[4][1] == (entry, SWITCH_DOMAIN)
|
||||
|
||||
assert controller.host == ENTRY_CONFIG[CONF_HOST]
|
||||
assert controller.is_admin == (SITE[0]["role"] == "admin")
|
||||
assert hub.host == ENTRY_CONFIG[CONF_HOST]
|
||||
assert hub.is_admin == (SITE[0]["role"] == "admin")
|
||||
|
||||
assert controller.option_allow_bandwidth_sensors == DEFAULT_ALLOW_BANDWIDTH_SENSORS
|
||||
assert controller.option_allow_uptime_sensors == DEFAULT_ALLOW_UPTIME_SENSORS
|
||||
assert isinstance(controller.option_block_clients, list)
|
||||
assert controller.option_track_clients == DEFAULT_TRACK_CLIENTS
|
||||
assert controller.option_track_devices == DEFAULT_TRACK_DEVICES
|
||||
assert controller.option_track_wired_clients == DEFAULT_TRACK_WIRED_CLIENTS
|
||||
assert controller.option_detection_time == timedelta(seconds=DEFAULT_DETECTION_TIME)
|
||||
assert isinstance(controller.option_ssid_filter, set)
|
||||
assert hub.option_allow_bandwidth_sensors == DEFAULT_ALLOW_BANDWIDTH_SENSORS
|
||||
assert hub.option_allow_uptime_sensors == DEFAULT_ALLOW_UPTIME_SENSORS
|
||||
assert isinstance(hub.option_block_clients, list)
|
||||
assert hub.option_track_clients == DEFAULT_TRACK_CLIENTS
|
||||
assert hub.option_track_devices == DEFAULT_TRACK_DEVICES
|
||||
assert hub.option_track_wired_clients == DEFAULT_TRACK_WIRED_CLIENTS
|
||||
assert hub.option_detection_time == timedelta(seconds=DEFAULT_DETECTION_TIME)
|
||||
assert isinstance(hub.option_ssid_filter, set)
|
||||
|
||||
assert controller.signal_reachable == "unifi-reachable-1"
|
||||
assert controller.signal_options_update == "unifi-options-1"
|
||||
assert controller.signal_heartbeat_missed == "unifi-heartbeat-missed"
|
||||
assert hub.signal_reachable == "unifi-reachable-1"
|
||||
assert hub.signal_options_update == "unifi-options-1"
|
||||
assert hub.signal_heartbeat_missed == "unifi-heartbeat-missed"
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
@ -288,20 +287,20 @@ async def test_controller_setup(
|
||||
assert device_entry.sw_version == "7.4.162"
|
||||
|
||||
|
||||
async def test_controller_not_accessible(hass: HomeAssistant) -> None:
|
||||
async def test_hub_not_accessible(hass: HomeAssistant) -> None:
|
||||
"""Retry to login gets scheduled when connection fails."""
|
||||
with patch(
|
||||
"homeassistant.components.unifi.controller.get_unifi_controller",
|
||||
"homeassistant.components.unifi.hub.get_unifi_api",
|
||||
side_effect=CannotConnect,
|
||||
):
|
||||
await setup_unifi_integration(hass)
|
||||
assert hass.data[UNIFI_DOMAIN] == {}
|
||||
|
||||
|
||||
async def test_controller_trigger_reauth_flow(hass: HomeAssistant) -> None:
|
||||
async def test_hub_trigger_reauth_flow(hass: HomeAssistant) -> None:
|
||||
"""Failed authentication trigger a reauthentication flow."""
|
||||
with patch(
|
||||
"homeassistant.components.unifi.get_unifi_controller",
|
||||
"homeassistant.components.unifi.get_unifi_api",
|
||||
side_effect=AuthenticationRequired,
|
||||
), patch.object(hass.config_entries.flow, "async_init") as mock_flow_init:
|
||||
await setup_unifi_integration(hass)
|
||||
@ -309,10 +308,10 @@ async def test_controller_trigger_reauth_flow(hass: HomeAssistant) -> None:
|
||||
assert hass.data[UNIFI_DOMAIN] == {}
|
||||
|
||||
|
||||
async def test_controller_unknown_error(hass: HomeAssistant) -> None:
|
||||
async def test_hub_unknown_error(hass: HomeAssistant) -> None:
|
||||
"""Unknown errors are handled."""
|
||||
with patch(
|
||||
"homeassistant.components.unifi.controller.get_unifi_controller",
|
||||
"homeassistant.components.unifi.hub.get_unifi_api",
|
||||
side_effect=Exception,
|
||||
):
|
||||
await setup_unifi_integration(hass)
|
||||
@ -324,10 +323,10 @@ async def test_config_entry_updated(
|
||||
) -> None:
|
||||
"""Calling reset when the entry has been setup."""
|
||||
config_entry = await setup_unifi_integration(hass, aioclient_mock)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
event_call = Mock()
|
||||
unsub = async_dispatcher_connect(hass, controller.signal_options_update, event_call)
|
||||
unsub = async_dispatcher_connect(hass, hub.signal_options_update, event_call)
|
||||
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry, options={CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False}
|
||||
@ -347,9 +346,9 @@ 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)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
result = await controller.async_reset()
|
||||
result = await hub.async_reset()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result is True
|
||||
@ -360,13 +359,13 @@ 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)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
with patch(
|
||||
"homeassistant.config_entries.ConfigEntries.async_forward_entry_unload",
|
||||
return_value=False,
|
||||
):
|
||||
result = await controller.async_reset()
|
||||
result = await hub.async_reset()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result is False
|
||||
@ -435,7 +434,7 @@ async def test_reconnect_mechanism_exceptions(
|
||||
await setup_unifi_integration(hass, aioclient_mock)
|
||||
|
||||
with patch("aiounifi.Controller.login", side_effect=exception), patch(
|
||||
"homeassistant.components.unifi.controller.UniFiController.reconnect"
|
||||
"homeassistant.components.unifi.hub.UnifiHub.reconnect"
|
||||
) as mock_reconnect:
|
||||
await websocket_mock.disconnect()
|
||||
|
||||
@ -443,18 +442,18 @@ async def test_reconnect_mechanism_exceptions(
|
||||
mock_reconnect.assert_called_once()
|
||||
|
||||
|
||||
async def test_get_unifi_controller(hass: HomeAssistant) -> None:
|
||||
async def test_get_unifi_api(hass: HomeAssistant) -> None:
|
||||
"""Successful call."""
|
||||
with patch("aiounifi.Controller.login", return_value=True):
|
||||
assert await get_unifi_controller(hass, ENTRY_CONFIG)
|
||||
assert await get_unifi_api(hass, ENTRY_CONFIG)
|
||||
|
||||
|
||||
async def test_get_unifi_controller_verify_ssl_false(hass: HomeAssistant) -> None:
|
||||
async def test_get_unifi_api_verify_ssl_false(hass: HomeAssistant) -> None:
|
||||
"""Successful call with verify ssl set to false."""
|
||||
controller_data = dict(ENTRY_CONFIG)
|
||||
controller_data[CONF_VERIFY_SSL] = False
|
||||
hub_data = dict(ENTRY_CONFIG)
|
||||
hub_data[CONF_VERIFY_SSL] = False
|
||||
with patch("aiounifi.Controller.login", return_value=True):
|
||||
assert await get_unifi_controller(hass, controller_data)
|
||||
assert await get_unifi_api(hass, hub_data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -471,11 +470,11 @@ async def test_get_unifi_controller_verify_ssl_false(hass: HomeAssistant) -> Non
|
||||
(aiounifi.AiounifiException, AuthenticationRequired),
|
||||
],
|
||||
)
|
||||
async def test_get_unifi_controller_fails_to_connect(
|
||||
async def test_get_unifi_api_fails_to_connect(
|
||||
hass: HomeAssistant, side_effect, raised_exception
|
||||
) -> None:
|
||||
"""Check that get_unifi_controller can handle controller being unavailable."""
|
||||
"""Check that get_unifi_api can handle UniFi Network being unavailable."""
|
||||
with patch("aiounifi.Controller.login", side_effect=side_effect), pytest.raises(
|
||||
raised_exception
|
||||
):
|
||||
await get_unifi_controller(hass, ENTRY_CONFIG)
|
||||
await get_unifi_api(hass, ENTRY_CONFIG)
|
@ -15,7 +15,7 @@ from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_registry import RegistryEntryDisabler
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
@ -8,14 +8,14 @@ from homeassistant.components.unifi.errors import AuthenticationRequired, Cannot
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .test_controller import DEFAULT_CONFIG_ENTRY_ID, setup_unifi_integration
|
||||
from .test_hub import DEFAULT_CONFIG_ENTRY_ID, setup_unifi_integration
|
||||
|
||||
from tests.common import flush_store
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
async def test_setup_with_no_config(hass: HomeAssistant) -> None:
|
||||
"""Test that we do not discover anything or try to set up a controller."""
|
||||
"""Test that we do not discover anything or try to set up a hub."""
|
||||
assert await async_setup_component(hass, UNIFI_DOMAIN, {}) is True
|
||||
assert UNIFI_DOMAIN not in hass.data
|
||||
|
||||
@ -31,7 +31,7 @@ async def test_successful_config_entry(
|
||||
async def test_setup_entry_fails_config_entry_not_ready(hass: HomeAssistant) -> None:
|
||||
"""Failed authentication trigger a reauthentication flow."""
|
||||
with patch(
|
||||
"homeassistant.components.unifi.get_unifi_controller",
|
||||
"homeassistant.components.unifi.get_unifi_api",
|
||||
side_effect=CannotConnect,
|
||||
):
|
||||
await setup_unifi_integration(hass)
|
||||
@ -42,7 +42,7 @@ async def test_setup_entry_fails_config_entry_not_ready(hass: HomeAssistant) ->
|
||||
async def test_setup_entry_fails_trigger_reauth_flow(hass: HomeAssistant) -> None:
|
||||
"""Failed authentication trigger a reauthentication flow."""
|
||||
with patch(
|
||||
"homeassistant.components.unifi.get_unifi_controller",
|
||||
"homeassistant.components.unifi.get_unifi_api",
|
||||
side_effect=AuthenticationRequired,
|
||||
), patch.object(hass.config_entries.flow, "async_init") as mock_flow_init:
|
||||
await setup_unifi_integration(hass)
|
||||
|
@ -8,7 +8,6 @@ from aiounifi.models.message import MessageKey
|
||||
from freezegun.api import FrozenDateTimeFactory, freeze_time
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.device_tracker import DOMAIN as TRACKER_DOMAIN
|
||||
from homeassistant.components.sensor import (
|
||||
ATTR_STATE_CLASS,
|
||||
DOMAIN as SENSOR_DOMAIN,
|
||||
@ -31,7 +30,7 @@ from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_registry import RegistryEntryDisabler
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
@ -396,7 +395,7 @@ async def test_bandwidth_sensors(
|
||||
|
||||
# Verify reset sensor after heartbeat expires
|
||||
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
new_time = dt_util.utcnow()
|
||||
wireless_client["last_seen"] = dt_util.as_timestamp(new_time)
|
||||
|
||||
@ -410,7 +409,7 @@ async def test_bandwidth_sensors(
|
||||
assert hass.states.get("sensor.wireless_client_rx").state == "3456.0"
|
||||
assert hass.states.get("sensor.wireless_client_tx").state == "7891.0"
|
||||
|
||||
new_time = new_time + controller.option_detection_time + timedelta(seconds=1)
|
||||
new_time = new_time + hub.option_detection_time + timedelta(seconds=1)
|
||||
|
||||
with freeze_time(new_time):
|
||||
async_fire_time_changed(hass, new_time)
|
||||
@ -578,9 +577,7 @@ async def test_remove_sensors(
|
||||
clients_response=[wired_client, wireless_client],
|
||||
)
|
||||
|
||||
assert len(hass.states.async_all()) == 9
|
||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 6
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2
|
||||
assert hass.states.get("sensor.wired_client_rx")
|
||||
assert hass.states.get("sensor.wired_client_tx")
|
||||
assert hass.states.get("sensor.wired_client_uptime")
|
||||
@ -593,9 +590,7 @@ async def test_remove_sensors(
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT_REMOVED, data=wired_client)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 5
|
||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 3
|
||||
assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 1
|
||||
assert hass.states.get("sensor.wired_client_rx") is None
|
||||
assert hass.states.get("sensor.wired_client_tx") is None
|
||||
assert hass.states.get("sensor.wired_client_uptime") is None
|
||||
|
@ -11,7 +11,7 @@ from homeassistant.const import ATTR_DEVICE_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from .test_controller import setup_unifi_integration
|
||||
from .test_hub import setup_unifi_integration
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@ -66,11 +66,11 @@ async def test_reconnect_client(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=clients
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/stamgr",
|
||||
)
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
@ -128,12 +128,12 @@ async def test_reconnect_device_without_mac(
|
||||
assert aioclient_mock.call_count == 0
|
||||
|
||||
|
||||
async def test_reconnect_client_controller_unavailable(
|
||||
async def test_reconnect_client_hub_unavailable(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Verify no call is made if controller is unavailable."""
|
||||
"""Verify no call is made if hub is unavailable."""
|
||||
clients = [
|
||||
{
|
||||
"is_wired": False,
|
||||
@ -143,12 +143,12 @@ async def test_reconnect_client_controller_unavailable(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_response=clients
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
controller.available = False
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub.available = False
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/stamgr",
|
||||
)
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
@ -170,14 +170,14 @@ async def test_reconnect_client_unknown_mac(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Verify no call is made if trying to reconnect a mac unknown to controller."""
|
||||
"""Verify no call is made if trying to reconnect a mac unknown to hub."""
|
||||
config_entry = await setup_unifi_integration(hass, aioclient_mock)
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "mac unknown to controller")},
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "mac unknown to hub")},
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -261,11 +261,11 @@ async def test_remove_clients(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_all_response=clients
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/stamgr",
|
||||
)
|
||||
|
||||
await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True)
|
||||
@ -277,10 +277,10 @@ async def test_remove_clients(
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
|
||||
async def test_remove_clients_controller_unavailable(
|
||||
async def test_remove_clients_hub_unavailable(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Verify no call is made if controller is unavailable."""
|
||||
"""Verify no call is made if UniFi Network is unavailable."""
|
||||
clients = [
|
||||
{
|
||||
"first_seen": 100,
|
||||
@ -291,8 +291,8 @@ async def test_remove_clients_controller_unavailable(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, clients_all_response=clients
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
controller.available = False
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub.available = False
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
|
||||
|
@ -33,12 +33,7 @@ from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_registry import RegistryEntryDisabler
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .test_controller import (
|
||||
CONTROLLER_HOST,
|
||||
ENTRY_CONFIG,
|
||||
SITE,
|
||||
setup_unifi_integration,
|
||||
)
|
||||
from .test_hub import CONTROLLER_HOST, ENTRY_CONFIG, SITE, setup_unifi_integration
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
@ -780,10 +775,10 @@ async def test_no_clients(
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
|
||||
|
||||
|
||||
async def test_controller_not_client(
|
||||
async def test_hub_not_client(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test that the controller doesn't become a switch."""
|
||||
"""Test that the cloud key doesn't become a switch."""
|
||||
await setup_unifi_integration(
|
||||
hass,
|
||||
aioclient_mock,
|
||||
@ -834,7 +829,7 @@ async def test_switches(
|
||||
dpigroup_response=DPI_GROUPS,
|
||||
dpiapp_response=DPI_APPS,
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 3
|
||||
|
||||
@ -862,7 +857,7 @@ async def test_switches(
|
||||
# Block and unblock client
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/stamgr",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -886,7 +881,7 @@ async def test_switches(
|
||||
# Enable and disable DPI
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/rest/dpiapp/5f976f62e3c58f018ec7e17d",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/rest/dpiapp/5f976f62e3c58f018ec7e17d",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -956,7 +951,7 @@ async def test_block_switches(
|
||||
clients_response=[UNBLOCKED],
|
||||
clients_all_response=[BLOCKED],
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||
|
||||
@ -986,7 +981,7 @@ async def test_block_switches(
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.post(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/cmd/stamgr",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -1147,7 +1142,7 @@ async def test_outlet_switches(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, devices_response=[test_data]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == expected_switches
|
||||
# Validate state object
|
||||
switch_1 = hass.states.get(f"switch.{entity_id}")
|
||||
@ -1166,7 +1161,7 @@ async def test_outlet_switches(
|
||||
device_id = test_data["device_id"]
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/rest/device/{device_id}",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/rest/device/{device_id}",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -1338,7 +1333,7 @@ async def test_poe_port_switches(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, devices_response=[DEVICE_1]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
|
||||
|
||||
@ -1377,7 +1372,7 @@ async def test_poe_port_switches(
|
||||
# Turn off PoE
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/rest/device/mock-id",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}/rest/device/mock-id",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -1450,7 +1445,7 @@ async def test_wlan_switches(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, wlans_response=[WLAN]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
@ -1474,8 +1469,7 @@ async def test_wlan_switches(
|
||||
# Disable WLAN
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}"
|
||||
+ f"/rest/wlanconf/{WLAN['_id']}",
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}" + f"/rest/wlanconf/{WLAN['_id']}",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
@ -1531,7 +1525,7 @@ async def test_port_forwarding_switches(
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass, aioclient_mock, port_forward_response=[_data.copy()]
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
hub = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
@ -1555,7 +1549,7 @@ async def test_port_forwarding_switches(
|
||||
# Disable port forward
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}"
|
||||
f"https://{hub.host}:1234/api/s/{hub.site}"
|
||||
+ f"/rest/portforward/{data['_id']}",
|
||||
)
|
||||
|
||||
|
@ -25,7 +25,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .test_controller import SITE, setup_unifi_integration
|
||||
from .test_hub import SITE, setup_unifi_integration
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@ -183,10 +183,10 @@ async def test_install(
|
||||
)
|
||||
|
||||
|
||||
async def test_controller_state_change(
|
||||
async def test_hub_state_change(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, websocket_mock
|
||||
) -> None:
|
||||
"""Verify entities state reflect on controller becoming unavailable."""
|
||||
"""Verify entities state reflect on hub becoming unavailable."""
|
||||
await setup_unifi_integration(hass, aioclient_mock, devices_response=[DEVICE_1])
|
||||
|
||||
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user