Remove old UniFi POE client implementation (#81749)

Remove all references to POE client implementation
This commit is contained in:
Robert Svensson 2022-11-08 07:48:54 +01:00 committed by GitHub
parent 3444d2af1a
commit 23bed25e52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 487 deletions

View file

@ -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:

View file

@ -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(

View file

@ -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"

View file

@ -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:

View file

@ -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."""

View file

@ -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,

View file

@ -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
]