Remove old UniFi POE client implementation (#81749)
Remove all references to POE client implementation
This commit is contained in:
parent
3444d2af1a
commit
23bed25e52
7 changed files with 66 additions and 487 deletions
|
@ -6,6 +6,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.storage import Store
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
|
@ -36,6 +37,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||
"""Set up the UniFi Network integration."""
|
||||
hass.data.setdefault(UNIFI_DOMAIN, {})
|
||||
|
||||
# Removal of legacy PoE control was introduced with 2022.12
|
||||
async_remove_poe_client_entities(hass, config_entry)
|
||||
|
||||
# Flat configuration was introduced with 2021.3
|
||||
await async_flatten_entry_data(hass, config_entry)
|
||||
|
||||
|
@ -82,6 +86,24 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
|||
return await controller.async_reset()
|
||||
|
||||
|
||||
@callback
|
||||
def async_remove_poe_client_entities(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> None:
|
||||
"""Remove PoE client entities."""
|
||||
ent_reg = er.async_get(hass)
|
||||
|
||||
entity_ids_to_be_removed = [
|
||||
entry.entity_id
|
||||
for entry in ent_reg.entities.values()
|
||||
if entry.config_entry_id == config_entry.entry_id
|
||||
and entry.unique_id.startswith("poe-")
|
||||
]
|
||||
|
||||
for entity_id in entity_ids_to_be_removed:
|
||||
ent_reg.async_remove(entity_id)
|
||||
|
||||
|
||||
async def async_flatten_entry_data(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> None:
|
||||
|
|
|
@ -37,14 +37,12 @@ from .const import (
|
|||
CONF_DETECTION_TIME,
|
||||
CONF_DPI_RESTRICTIONS,
|
||||
CONF_IGNORE_WIRED_BUG,
|
||||
CONF_POE_CLIENTS,
|
||||
CONF_SITE_ID,
|
||||
CONF_SSID_FILTER,
|
||||
CONF_TRACK_CLIENTS,
|
||||
CONF_TRACK_DEVICES,
|
||||
CONF_TRACK_WIRED_CLIENTS,
|
||||
DEFAULT_DPI_RESTRICTIONS,
|
||||
DEFAULT_POE_CLIENTS,
|
||||
DOMAIN as UNIFI_DOMAIN,
|
||||
)
|
||||
from .controller import UniFiController, get_unifi_controller
|
||||
|
@ -396,10 +394,6 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
vol.Optional(
|
||||
CONF_BLOCK_CLIENT, default=selected_clients_to_block
|
||||
): cv.multi_select(clients_to_block),
|
||||
vol.Optional(
|
||||
CONF_POE_CLIENTS,
|
||||
default=self.options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS),
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_DPI_RESTRICTIONS,
|
||||
default=self.options.get(
|
||||
|
|
|
@ -25,7 +25,6 @@ CONF_BLOCK_CLIENT = "block_client"
|
|||
CONF_DETECTION_TIME = "detection_time"
|
||||
CONF_DPI_RESTRICTIONS = "dpi_restrictions"
|
||||
CONF_IGNORE_WIRED_BUG = "ignore_wired_bug"
|
||||
CONF_POE_CLIENTS = "poe_clients"
|
||||
CONF_TRACK_CLIENTS = "track_clients"
|
||||
CONF_TRACK_DEVICES = "track_devices"
|
||||
CONF_TRACK_WIRED_CLIENTS = "track_wired_clients"
|
||||
|
@ -35,7 +34,6 @@ DEFAULT_ALLOW_BANDWIDTH_SENSORS = False
|
|||
DEFAULT_ALLOW_UPTIME_SENSORS = False
|
||||
DEFAULT_DPI_RESTRICTIONS = True
|
||||
DEFAULT_IGNORE_WIRED_BUG = False
|
||||
DEFAULT_POE_CLIENTS = True
|
||||
DEFAULT_TRACK_CLIENTS = True
|
||||
DEFAULT_TRACK_DEVICES = True
|
||||
DEFAULT_TRACK_WIRED_CLIENTS = True
|
||||
|
@ -45,5 +43,4 @@ ATTR_MANUFACTURER = "Ubiquiti Networks"
|
|||
|
||||
BLOCK_SWITCH = "block"
|
||||
DPI_SWITCH = "dpi"
|
||||
POE_SWITCH = "poe"
|
||||
OUTLET_SWITCH = "outlet"
|
||||
|
|
|
@ -44,7 +44,6 @@ from .const import (
|
|||
CONF_DETECTION_TIME,
|
||||
CONF_DPI_RESTRICTIONS,
|
||||
CONF_IGNORE_WIRED_BUG,
|
||||
CONF_POE_CLIENTS,
|
||||
CONF_SITE_ID,
|
||||
CONF_SSID_FILTER,
|
||||
CONF_TRACK_CLIENTS,
|
||||
|
@ -55,14 +54,12 @@ from .const import (
|
|||
DEFAULT_DETECTION_TIME,
|
||||
DEFAULT_DPI_RESTRICTIONS,
|
||||
DEFAULT_IGNORE_WIRED_BUG,
|
||||
DEFAULT_POE_CLIENTS,
|
||||
DEFAULT_TRACK_CLIENTS,
|
||||
DEFAULT_TRACK_DEVICES,
|
||||
DEFAULT_TRACK_WIRED_CLIENTS,
|
||||
DOMAIN as UNIFI_DOMAIN,
|
||||
LOGGER,
|
||||
PLATFORMS,
|
||||
POE_SWITCH,
|
||||
UNIFI_WIRELESS_CLIENTS,
|
||||
)
|
||||
from .errors import AuthenticationRequired, CannotConnect
|
||||
|
@ -140,8 +137,6 @@ class UniFiController:
|
|||
|
||||
# Client control options
|
||||
|
||||
# Config entry option to control poe clients.
|
||||
self.option_poe_clients = options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS)
|
||||
# Config entry option with list of clients to control network access.
|
||||
self.option_block_clients = options.get(CONF_BLOCK_CLIENT, [])
|
||||
# Config entry option to control DPI restriction groups.
|
||||
|
@ -305,9 +300,8 @@ class UniFiController:
|
|||
):
|
||||
if entry.domain == Platform.DEVICE_TRACKER:
|
||||
mac = entry.unique_id.split("-", 1)[0]
|
||||
elif entry.domain == Platform.SWITCH and (
|
||||
entry.unique_id.startswith(BLOCK_SWITCH)
|
||||
or entry.unique_id.startswith(POE_SWITCH)
|
||||
elif entry.domain == Platform.SWITCH and entry.unique_id.startswith(
|
||||
BLOCK_SWITCH
|
||||
):
|
||||
mac = entry.unique_id.split("-", 1)[1]
|
||||
else:
|
||||
|
|
|
@ -44,11 +44,9 @@ from homeassistant.helpers.device_registry import (
|
|||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from .const import ATTR_MANUFACTURER, DOMAIN as UNIFI_DOMAIN, POE_SWITCH
|
||||
from .const import ATTR_MANUFACTURER, DOMAIN as UNIFI_DOMAIN
|
||||
from .controller import UniFiController
|
||||
from .unifi_client import UniFiClient
|
||||
|
||||
CLIENT_BLOCKED = (EventKey.WIRED_CLIENT_BLOCKED, EventKey.WIRELESS_CLIENT_BLOCKED)
|
||||
CLIENT_UNBLOCKED = (EventKey.WIRED_CLIENT_UNBLOCKED, EventKey.WIRELESS_CLIENT_UNBLOCKED)
|
||||
|
@ -268,49 +266,15 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up switches for UniFi Network integration."""
|
||||
controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
controller.entities[DOMAIN] = {POE_SWITCH: set()}
|
||||
|
||||
if controller.site_role != "admin":
|
||||
return
|
||||
|
||||
# Store previously known POE control entities in case their POE are turned off.
|
||||
known_poe_clients = []
|
||||
entity_registry = er.async_get(hass)
|
||||
for entry in er.async_entries_for_config_entry(
|
||||
entity_registry, config_entry.entry_id
|
||||
):
|
||||
|
||||
if not entry.unique_id.startswith(POE_SWITCH):
|
||||
continue
|
||||
|
||||
mac = entry.unique_id.replace(f"{POE_SWITCH}-", "")
|
||||
if mac not in controller.api.clients:
|
||||
continue
|
||||
|
||||
known_poe_clients.append(mac)
|
||||
|
||||
for mac in controller.option_block_clients:
|
||||
if mac not in controller.api.clients and mac in controller.api.clients_all:
|
||||
client = controller.api.clients_all[mac]
|
||||
controller.api.clients.process_raw([client.raw])
|
||||
|
||||
@callback
|
||||
def items_added(
|
||||
clients: set = controller.api.clients,
|
||||
devices: set = controller.api.devices,
|
||||
) -> None:
|
||||
"""Update the values of the controller."""
|
||||
if controller.option_poe_clients:
|
||||
add_poe_entities(controller, async_add_entities, clients, known_poe_clients)
|
||||
|
||||
for signal in (controller.signal_update, controller.signal_options_update):
|
||||
config_entry.async_on_unload(
|
||||
async_dispatcher_connect(hass, signal, items_added)
|
||||
)
|
||||
|
||||
items_added()
|
||||
known_poe_clients.clear()
|
||||
|
||||
@callback
|
||||
def async_load_entities(description: UnifiEntityDescription) -> None:
|
||||
"""Load and subscribe to UniFi devices."""
|
||||
|
@ -341,153 +305,6 @@ async def async_setup_entry(
|
|||
async_load_entities(description)
|
||||
|
||||
|
||||
@callback
|
||||
def add_poe_entities(controller, async_add_entities, clients, known_poe_clients):
|
||||
"""Add new switch entities from the controller."""
|
||||
switches = []
|
||||
|
||||
devices = controller.api.devices
|
||||
|
||||
for mac in clients:
|
||||
if mac in controller.entities[DOMAIN][POE_SWITCH]:
|
||||
continue
|
||||
|
||||
client = controller.api.clients[mac]
|
||||
|
||||
# Try to identify new clients powered by POE.
|
||||
# Known POE clients have been created in previous HASS sessions.
|
||||
# If port_poe is None the port does not support POE
|
||||
# If poe_enable is False we can't know if a POE client is available for control.
|
||||
if mac not in known_poe_clients and (
|
||||
mac in controller.wireless_clients
|
||||
or client.switch_mac not in devices
|
||||
or not devices[client.switch_mac].ports[client.switch_port].port_poe
|
||||
or not devices[client.switch_mac].ports[client.switch_port].poe_enable
|
||||
or controller.mac == client.mac
|
||||
):
|
||||
continue
|
||||
|
||||
# Multiple POE-devices on same port means non UniFi POE driven switch
|
||||
multi_clients_on_port = False
|
||||
for client2 in controller.api.clients.values():
|
||||
|
||||
if mac in known_poe_clients:
|
||||
break
|
||||
|
||||
if (
|
||||
client2.is_wired
|
||||
and client.mac != client2.mac
|
||||
and client.switch_mac == client2.switch_mac
|
||||
and client.switch_port == client2.switch_port
|
||||
):
|
||||
multi_clients_on_port = True
|
||||
break
|
||||
|
||||
if multi_clients_on_port:
|
||||
continue
|
||||
|
||||
switches.append(UniFiPOEClientSwitch(client, controller))
|
||||
|
||||
async_add_entities(switches)
|
||||
|
||||
|
||||
class UniFiPOEClientSwitch(UniFiClient, SwitchEntity, RestoreEntity):
|
||||
"""Representation of a client that uses POE."""
|
||||
|
||||
DOMAIN = DOMAIN
|
||||
TYPE = POE_SWITCH
|
||||
|
||||
_attr_entity_category = EntityCategory.CONFIG
|
||||
|
||||
def __init__(self, client, controller):
|
||||
"""Set up POE switch."""
|
||||
super().__init__(client, controller)
|
||||
|
||||
self.poe_mode = None
|
||||
if client.switch_port and self.port.poe_mode != "off":
|
||||
self.poe_mode = self.port.poe_mode
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Call when entity about to be added to Home Assistant."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
if self.poe_mode: # POE is enabled and client in a known state
|
||||
return
|
||||
|
||||
if (state := await self.async_get_last_state()) is None:
|
||||
return
|
||||
|
||||
self.poe_mode = state.attributes.get("poe_mode")
|
||||
|
||||
if not self.client.switch_mac:
|
||||
self.client.raw["sw_mac"] = state.attributes.get("switch")
|
||||
|
||||
if not self.client.switch_port:
|
||||
self.client.raw["sw_port"] = state.attributes.get("port")
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if POE is active."""
|
||||
return self.port.poe_mode != "off"
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if switch is available.
|
||||
|
||||
Poe_mode None means its POE state is unknown.
|
||||
Sw_mac unavailable means restored client.
|
||||
"""
|
||||
return (
|
||||
self.poe_mode is not None
|
||||
and self.controller.available
|
||||
and self.client.switch_port
|
||||
and self.client.switch_mac
|
||||
and self.client.switch_mac in self.controller.api.devices
|
||||
)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Enable POE for client."""
|
||||
await self.controller.api.request(
|
||||
DeviceSetPoePortModeRequest.create(
|
||||
self.device, self.client.switch_port, self.poe_mode
|
||||
)
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Disable POE for client."""
|
||||
await self.controller.api.request(
|
||||
DeviceSetPoePortModeRequest.create(
|
||||
self.device, self.client.switch_port, "off"
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
attributes = {
|
||||
"power": self.port.poe_power,
|
||||
"switch": self.client.switch_mac,
|
||||
"port": self.client.switch_port,
|
||||
"poe_mode": self.poe_mode,
|
||||
}
|
||||
return attributes
|
||||
|
||||
@property
|
||||
def device(self):
|
||||
"""Shortcut to the switch that client is connected to."""
|
||||
return self.controller.api.devices[self.client.switch_mac]
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
"""Shortcut to the switch port that client is connected to."""
|
||||
return self.device.ports[self.client.switch_port]
|
||||
|
||||
async def options_updated(self) -> None:
|
||||
"""Config entry options are updated, remove entity if option is disabled."""
|
||||
if not self.controller.option_poe_clients:
|
||||
await self.remove_item({self.client.mac})
|
||||
|
||||
|
||||
class UnifiSwitchEntity(SwitchEntity):
|
||||
"""Base representation of a UniFi switch."""
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ from homeassistant.components.unifi.const import (
|
|||
CONF_DETECTION_TIME,
|
||||
CONF_DPI_RESTRICTIONS,
|
||||
CONF_IGNORE_WIRED_BUG,
|
||||
CONF_POE_CLIENTS,
|
||||
CONF_SITE_ID,
|
||||
CONF_SSID_FILTER,
|
||||
CONF_TRACK_CLIENTS,
|
||||
|
@ -473,7 +472,6 @@ async def test_advanced_option_flow(hass, aioclient_mock):
|
|||
result["flow_id"],
|
||||
user_input={
|
||||
CONF_BLOCK_CLIENT: [CLIENTS[0]["mac"]],
|
||||
CONF_POE_CLIENTS: False,
|
||||
CONF_DPI_RESTRICTIONS: False,
|
||||
},
|
||||
)
|
||||
|
@ -498,7 +496,6 @@ async def test_advanced_option_flow(hass, aioclient_mock):
|
|||
CONF_SSID_FILTER: ["SSID 1", "SSID 2_IOT", "SSID 3"],
|
||||
CONF_DETECTION_TIME: 100,
|
||||
CONF_IGNORE_WIRED_BUG: False,
|
||||
CONF_POE_CLIENTS: False,
|
||||
CONF_DPI_RESTRICTIONS: False,
|
||||
CONF_BLOCK_CLIENT: [CLIENTS[0]["mac"]],
|
||||
CONF_ALLOW_BANDWIDTH_SENSORS: True,
|
||||
|
|
|
@ -6,7 +6,7 @@ from datetime import timedelta
|
|||
from aiounifi.models.message import MessageKey
|
||||
from aiounifi.websocket import WebsocketState
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.switch import (
|
||||
DOMAIN as SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
|
@ -16,12 +16,10 @@ from homeassistant.components.switch import (
|
|||
from homeassistant.components.unifi.const import (
|
||||
CONF_BLOCK_CLIENT,
|
||||
CONF_DPI_RESTRICTIONS,
|
||||
CONF_POE_CLIENTS,
|
||||
CONF_TRACK_CLIENTS,
|
||||
CONF_TRACK_DEVICES,
|
||||
DOMAIN as UNIFI_DOMAIN,
|
||||
)
|
||||
from homeassistant.components.unifi.switch import POE_SWITCH
|
||||
from homeassistant.config_entries import RELOAD_AFTER_UPDATE_DELAY
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
|
@ -38,13 +36,12 @@ from homeassistant.util import dt
|
|||
|
||||
from .test_controller import (
|
||||
CONTROLLER_HOST,
|
||||
DEFAULT_CONFIG_ENTRY_ID,
|
||||
DESCRIPTION,
|
||||
ENTRY_CONFIG,
|
||||
setup_unifi_integration,
|
||||
)
|
||||
|
||||
from tests.common import async_fire_time_changed, mock_restore_cache
|
||||
from tests.common import async_fire_time_changed
|
||||
|
||||
CLIENT_1 = {
|
||||
"hostname": "client_1",
|
||||
|
@ -636,23 +633,14 @@ async def test_switches(hass, aioclient_mock):
|
|||
CONF_TRACK_CLIENTS: False,
|
||||
CONF_TRACK_DEVICES: False,
|
||||
},
|
||||
clients_response=[CLIENT_1, CLIENT_4],
|
||||
devices_response=[DEVICE_1],
|
||||
clients_response=[CLIENT_4],
|
||||
clients_all_response=[BLOCKED, UNBLOCKED, CLIENT_1],
|
||||
dpigroup_response=DPI_GROUPS,
|
||||
dpiapp_response=DPI_APPS,
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4
|
||||
|
||||
switch_1 = hass.states.get("switch.poe_client_1")
|
||||
assert switch_1 is not None
|
||||
assert switch_1.state == "on"
|
||||
assert switch_1.attributes["power"] == "2.56"
|
||||
assert switch_1.attributes[SWITCH_DOMAIN] == "10:00:00:00:01:01"
|
||||
assert switch_1.attributes["port"] == 1
|
||||
assert switch_1.attributes["poe_mode"] == "auto"
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 3
|
||||
|
||||
switch_4 = hass.states.get("switch.poe_client_4")
|
||||
assert switch_4 is None
|
||||
|
@ -671,11 +659,7 @@ async def test_switches(hass, aioclient_mock):
|
|||
assert dpi_switch.attributes["icon"] == "mdi:network"
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
for entry_id in (
|
||||
"switch.poe_client_1",
|
||||
"switch.block_client_1",
|
||||
"switch.block_media_streaming",
|
||||
):
|
||||
for entry_id in ("switch.block_client_1", "switch.block_media_streaming"):
|
||||
assert ent_reg.async_get(entry_id).entity_category is EntityCategory.CONFIG
|
||||
|
||||
# Block and unblock client
|
||||
|
@ -729,7 +713,7 @@ async def test_switches(hass, aioclient_mock):
|
|||
# Make sure no duplicates arise on generic signal update
|
||||
async_dispatcher_send(hass, controller.signal_update)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 3
|
||||
|
||||
|
||||
async def test_remove_switches(hass, aioclient_mock, mock_unifi_websocket):
|
||||
|
@ -738,24 +722,21 @@ async def test_remove_switches(hass, aioclient_mock, mock_unifi_websocket):
|
|||
hass,
|
||||
aioclient_mock,
|
||||
options={CONF_BLOCK_CLIENT: [UNBLOCKED["mac"]]},
|
||||
clients_response=[CLIENT_1, UNBLOCKED],
|
||||
devices_response=[DEVICE_1],
|
||||
clients_response=[UNBLOCKED],
|
||||
dpigroup_response=DPI_GROUPS,
|
||||
dpiapp_response=DPI_APPS,
|
||||
)
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 3
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||
|
||||
assert hass.states.get("switch.poe_client_1") is not None
|
||||
assert hass.states.get("switch.block_client_2") is not None
|
||||
assert hass.states.get("switch.block_media_streaming") is not None
|
||||
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT_REMOVED, data=[CLIENT_1, UNBLOCKED])
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT_REMOVED, data=[UNBLOCKED])
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
assert hass.states.get("switch.poe_client_1") is None
|
||||
assert hass.states.get("switch.block_client_2") is None
|
||||
assert hass.states.get("switch.block_media_streaming") is not None
|
||||
|
||||
|
@ -1089,273 +1070,20 @@ async def test_option_remove_switches(hass, aioclient_mock):
|
|||
CONF_TRACK_DEVICES: False,
|
||||
},
|
||||
clients_response=[CLIENT_1],
|
||||
devices_response=[DEVICE_1],
|
||||
dpigroup_response=DPI_GROUPS,
|
||||
dpiapp_response=DPI_APPS,
|
||||
)
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
# Disable DPI Switches
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
options={CONF_DPI_RESTRICTIONS: False, CONF_POE_CLIENTS: False},
|
||||
options={CONF_DPI_RESTRICTIONS: False},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 0
|
||||
|
||||
|
||||
async def test_new_client_discovered_on_poe_control(
|
||||
hass, aioclient_mock, mock_unifi_websocket
|
||||
):
|
||||
"""Test if 2nd update has a new client."""
|
||||
config_entry = await setup_unifi_integration(
|
||||
hass,
|
||||
aioclient_mock,
|
||||
options={CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False},
|
||||
clients_response=[CLIENT_1],
|
||||
devices_response=[DEVICE_1],
|
||||
)
|
||||
controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id]
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
mock_unifi_websocket(message=MessageKey.CLIENT, data=CLIENT_2)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
mock_unifi_websocket(message=MessageKey.EVENT, data=EVENT_CLIENT_2_CONNECTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||
switch_2 = hass.states.get("switch.poe_client_2")
|
||||
assert switch_2 is not None
|
||||
|
||||
aioclient_mock.put(
|
||||
f"https://{controller.host}:1234/api/s/{controller.site}/rest/device/mock-id",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.poe_client_1"}, blocking=True
|
||||
)
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||
assert aioclient_mock.call_count == 11
|
||||
assert aioclient_mock.mock_calls[10][2] == {
|
||||
"port_overrides": [{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "off"}]
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.poe_client_1"}, blocking=True
|
||||
)
|
||||
assert aioclient_mock.call_count == 12
|
||||
assert aioclient_mock.mock_calls[11][2] == {
|
||||
"port_overrides": [{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "auto"}]
|
||||
}
|
||||
|
||||
|
||||
async def test_ignore_multiple_poe_clients_on_same_port(hass, aioclient_mock):
|
||||
"""Ignore when there are multiple POE driven clients on same port.
|
||||
|
||||
If there is a non-UniFi switch powered by POE,
|
||||
clients will be transparently marked as having POE as well.
|
||||
"""
|
||||
await setup_unifi_integration(
|
||||
hass,
|
||||
aioclient_mock,
|
||||
clients_response=POE_SWITCH_CLIENTS,
|
||||
devices_response=[DEVICE_1],
|
||||
)
|
||||
|
||||
switch_1 = hass.states.get("switch.poe_client_1")
|
||||
switch_2 = hass.states.get("switch.poe_client_2")
|
||||
assert switch_1 is None
|
||||
assert switch_2 is None
|
||||
|
||||
|
||||
async def test_restore_client_succeed(hass, aioclient_mock):
|
||||
"""Test that RestoreEntity works as expected."""
|
||||
POE_DEVICE = {
|
||||
"device_id": "12345",
|
||||
"ip": "1.0.1.1",
|
||||
"mac": "00:00:00:00:01:01",
|
||||
"last_seen": 1562600145,
|
||||
"model": "US16P150",
|
||||
"name": "POE Switch",
|
||||
"port_overrides": [
|
||||
{
|
||||
"poe_mode": "off",
|
||||
"port_idx": 1,
|
||||
"portconf_id": "5f3edd2aba4cc806a19f2db2",
|
||||
}
|
||||
],
|
||||
"port_table": [
|
||||
{
|
||||
"media": "GE",
|
||||
"name": "Port 1",
|
||||
"op_mode": "switch",
|
||||
"poe_caps": 7,
|
||||
"poe_class": "Unknown",
|
||||
"poe_current": "0.00",
|
||||
"poe_enable": False,
|
||||
"poe_good": False,
|
||||
"poe_mode": "off",
|
||||
"poe_power": "0.00",
|
||||
"poe_voltage": "0.00",
|
||||
"port_idx": 1,
|
||||
"port_poe": True,
|
||||
"portconf_id": "5f3edd2aba4cc806a19f2db2",
|
||||
"up": False,
|
||||
},
|
||||
],
|
||||
"state": 1,
|
||||
"type": "usw",
|
||||
"version": "4.0.42.10433",
|
||||
}
|
||||
POE_CLIENT = {
|
||||
"hostname": "poe_client",
|
||||
"ip": "1.0.0.1",
|
||||
"is_wired": True,
|
||||
"last_seen": 1562600145,
|
||||
"mac": "00:00:00:00:00:01",
|
||||
"name": "POE Client",
|
||||
"oui": "Producer",
|
||||
}
|
||||
|
||||
fake_state = core.State(
|
||||
"switch.poe_client",
|
||||
"off",
|
||||
{
|
||||
"power": "0.00",
|
||||
"switch": POE_DEVICE["mac"],
|
||||
"port": 1,
|
||||
"poe_mode": "auto",
|
||||
},
|
||||
)
|
||||
mock_restore_cache(hass, (fake_state,))
|
||||
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
version=1,
|
||||
domain=UNIFI_DOMAIN,
|
||||
title="Mock Title",
|
||||
data=ENTRY_CONFIG,
|
||||
source="test",
|
||||
options={},
|
||||
entry_id=DEFAULT_CONFIG_ENTRY_ID,
|
||||
)
|
||||
|
||||
registry = er.async_get(hass)
|
||||
registry.async_get_or_create(
|
||||
SWITCH_DOMAIN,
|
||||
UNIFI_DOMAIN,
|
||||
f'{POE_SWITCH}-{POE_CLIENT["mac"]}',
|
||||
suggested_object_id=POE_CLIENT["hostname"],
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
await setup_unifi_integration(
|
||||
hass,
|
||||
aioclient_mock,
|
||||
options={
|
||||
CONF_TRACK_CLIENTS: False,
|
||||
CONF_TRACK_DEVICES: False,
|
||||
},
|
||||
clients_response=[],
|
||||
devices_response=[POE_DEVICE],
|
||||
clients_all_response=[POE_CLIENT],
|
||||
)
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
poe_client = hass.states.get("switch.poe_client")
|
||||
assert poe_client.state == "off"
|
||||
|
||||
|
||||
async def test_restore_client_no_old_state(hass, aioclient_mock):
|
||||
"""Test that RestoreEntity without old state makes entity unavailable."""
|
||||
POE_DEVICE = {
|
||||
"device_id": "12345",
|
||||
"ip": "1.0.1.1",
|
||||
"mac": "00:00:00:00:01:01",
|
||||
"last_seen": 1562600145,
|
||||
"model": "US16P150",
|
||||
"name": "POE Switch",
|
||||
"port_overrides": [
|
||||
{
|
||||
"poe_mode": "off",
|
||||
"port_idx": 1,
|
||||
"portconf_id": "5f3edd2aba4cc806a19f2db2",
|
||||
}
|
||||
],
|
||||
"port_table": [
|
||||
{
|
||||
"media": "GE",
|
||||
"name": "Port 1",
|
||||
"op_mode": "switch",
|
||||
"poe_caps": 7,
|
||||
"poe_class": "Unknown",
|
||||
"poe_current": "0.00",
|
||||
"poe_enable": False,
|
||||
"poe_good": False,
|
||||
"poe_mode": "off",
|
||||
"poe_power": "0.00",
|
||||
"poe_voltage": "0.00",
|
||||
"port_idx": 1,
|
||||
"port_poe": True,
|
||||
"portconf_id": "5f3edd2aba4cc806a19f2db2",
|
||||
"up": False,
|
||||
},
|
||||
],
|
||||
"state": 1,
|
||||
"type": "usw",
|
||||
"version": "4.0.42.10433",
|
||||
}
|
||||
POE_CLIENT = {
|
||||
"hostname": "poe_client",
|
||||
"ip": "1.0.0.1",
|
||||
"is_wired": True,
|
||||
"last_seen": 1562600145,
|
||||
"mac": "00:00:00:00:00:01",
|
||||
"name": "POE Client",
|
||||
"oui": "Producer",
|
||||
}
|
||||
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
version=1,
|
||||
domain=UNIFI_DOMAIN,
|
||||
title="Mock Title",
|
||||
data=ENTRY_CONFIG,
|
||||
source="test",
|
||||
options={},
|
||||
entry_id=DEFAULT_CONFIG_ENTRY_ID,
|
||||
)
|
||||
|
||||
registry = er.async_get(hass)
|
||||
registry.async_get_or_create(
|
||||
SWITCH_DOMAIN,
|
||||
UNIFI_DOMAIN,
|
||||
f'{POE_SWITCH}-{POE_CLIENT["mac"]}',
|
||||
suggested_object_id=POE_CLIENT["hostname"],
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
await setup_unifi_integration(
|
||||
hass,
|
||||
aioclient_mock,
|
||||
options={
|
||||
CONF_TRACK_CLIENTS: False,
|
||||
CONF_TRACK_DEVICES: False,
|
||||
},
|
||||
clients_response=[],
|
||||
devices_response=[POE_DEVICE],
|
||||
clients_all_response=[POE_CLIENT],
|
||||
)
|
||||
|
||||
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1
|
||||
|
||||
poe_client = hass.states.get("switch.poe_client")
|
||||
assert poe_client.state == "unavailable" # self.poe_mode is None
|
||||
|
||||
|
||||
async def test_poe_port_switches(hass, aioclient_mock, mock_unifi_websocket):
|
||||
"""Test the update_items function with some clients."""
|
||||
config_entry = await setup_unifi_integration(
|
||||
|
@ -1447,3 +1175,33 @@ async def test_poe_port_switches(hass, aioclient_mock, mock_unifi_websocket):
|
|||
mock_unifi_websocket(message=MessageKey.DEVICE, data=device_1)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("switch.mock_name_port_1_poe").state == STATE_OFF
|
||||
|
||||
|
||||
async def test_remove_poe_client_switches(hass, aioclient_mock):
|
||||
"""Test old PoE client switches are removed."""
|
||||
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
version=1,
|
||||
domain=UNIFI_DOMAIN,
|
||||
title="Mock Title",
|
||||
data=ENTRY_CONFIG,
|
||||
source="test",
|
||||
options={},
|
||||
entry_id="1",
|
||||
)
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg.async_get_or_create(
|
||||
SWITCH_DOMAIN,
|
||||
UNIFI_DOMAIN,
|
||||
"poe-123",
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
await setup_unifi_integration(hass, aioclient_mock)
|
||||
|
||||
assert not [
|
||||
entry
|
||||
for entry in ent_reg.entities.values()
|
||||
if entry.config_entry_id == config_entry.entry_id
|
||||
]
|
||||
|
|
Loading…
Add table
Reference in a new issue