UniFi - Make POE control switches configurable (#32781)

* Allow control whether POE switches are to be created or not

* Fix options flow and test
This commit is contained in:
Robert Svensson 2020-04-02 17:53:33 +02:00 committed by GitHub
parent 23e091696e
commit 314bc07cee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 45 deletions

View file

@ -32,7 +32,8 @@
"client_control": {
"data": {
"block_client": "Network access controlled clients",
"new_client": "Add new client for network access control"
"new_client": "Add new client (MAC) for network access control",
"poe_clients": "Allow POE control of clients"
},
"description": "Configure client controls\n\nCreate switches for serial numbers you want to control network access for.",
"title": "UniFi options 2/3"

View file

@ -19,12 +19,14 @@ from .const import (
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
CONF_TRACK_CLIENTS,
CONF_TRACK_DEVICES,
CONF_TRACK_WIRED_CLIENTS,
CONTROLLER_ID,
DEFAULT_POE_CLIENTS,
DOMAIN,
LOGGER,
)
@ -262,6 +264,10 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
step_id="client_control",
data_schema=vol.Schema(
{
vol.Optional(
CONF_POE_CLIENTS,
default=self.options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS),
): bool,
vol.Optional(
CONF_BLOCK_CLIENT, default=self.options[CONF_BLOCK_CLIENT]
): cv.multi_select(clients_to_block),

View file

@ -14,12 +14,14 @@ UNIFI_WIRELESS_CLIENTS = "unifi_wireless_clients"
CONF_ALLOW_BANDWIDTH_SENSORS = "allow_bandwidth_sensors"
CONF_BLOCK_CLIENT = "block_client"
CONF_DETECTION_TIME = "detection_time"
CONF_POE_CLIENTS = "poe_clients"
CONF_TRACK_CLIENTS = "track_clients"
CONF_TRACK_DEVICES = "track_devices"
CONF_TRACK_WIRED_CLIENTS = "track_wired_clients"
CONF_SSID_FILTER = "ssid_filter"
DEFAULT_ALLOW_BANDWIDTH_SENSORS = False
DEFAULT_POE_CLIENTS = True
DEFAULT_TRACK_CLIENTS = True
DEFAULT_TRACK_DEVICES = True
DEFAULT_TRACK_WIRED_CLIENTS = True

View file

@ -24,6 +24,7 @@ from .const import (
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
CONF_TRACK_CLIENTS,
@ -32,6 +33,7 @@ from .const import (
CONTROLLER_ID,
DEFAULT_ALLOW_BANDWIDTH_SENSORS,
DEFAULT_DETECTION_TIME,
DEFAULT_POE_CLIENTS,
DEFAULT_TRACK_CLIENTS,
DEFAULT_TRACK_DEVICES,
DEFAULT_TRACK_WIRED_CLIENTS,
@ -98,6 +100,11 @@ class UniFiController:
"""Config entry option with list of clients to control network access."""
return self.config_entry.options.get(CONF_BLOCK_CLIENT, [])
@property
def option_poe_clients(self):
"""Config entry option to control poe clients."""
return self.config_entry.options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS)
@property
def option_track_clients(self):
"""Config entry option to not track clients."""

View file

@ -43,7 +43,8 @@
"client_control": {
"data": {
"block_client": "Network access controlled clients",
"new_client": "Add new client for network access control"
"new_client": "Add new client for network access control",
"poe_clients": "Allow POE control of clients"
},
"description": "Configure client controls\n\nCreate switches for serial numbers you want to control network access for.",
"title": "UniFi options 2/3"

View file

@ -30,6 +30,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
switches_off = []
option_block_clients = controller.option_block_clients
option_poe_clients = controller.option_poe_clients
entity_registry = await hass.helpers.entity_registry.async_get_registry()
@ -66,6 +67,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
def options_updated():
"""Manage entities affected by config entry options."""
nonlocal option_block_clients
nonlocal option_poe_clients
update = set()
remove = set()
@ -82,16 +84,26 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
else:
remove.add(block_client_id)
for block_client_id in remove:
entity = switches.pop(block_client_id)
if option_poe_clients != controller.option_poe_clients:
option_poe_clients = controller.option_poe_clients
if entity_registry.async_is_registered(entity.entity_id):
entity_registry.async_remove(entity.entity_id)
if option_poe_clients:
update.add("poe_clients_enabled")
else:
for poe_client_id, entity in switches.items():
if isinstance(entity, UniFiPOEClientSwitch):
remove.add(poe_client_id)
hass.async_create_task(entity.async_remove())
for client_id in remove:
entity = switches.pop(client_id)
if len(update) != len(option_block_clients):
update_controller()
if entity_registry.async_is_registered(entity.entity_id):
entity_registry.async_remove(entity.entity_id)
hass.async_create_task(entity.async_remove())
if len(update) != len(option_block_clients):
update_controller()
controller.listeners.append(
async_dispatcher_connect(
@ -109,7 +121,6 @@ def add_entities(controller, async_add_entities, switches, switches_off):
new_switches = []
devices = controller.api.devices
# block client
for client_id in controller.option_block_clients:
client = None
@ -130,49 +141,49 @@ def add_entities(controller, async_add_entities, switches, switches_off):
switches[block_client_id] = UniFiBlockClientSwitch(client, controller)
new_switches.append(switches[block_client_id])
# control POE
for client_id in controller.api.clients:
if controller.option_poe_clients:
for client_id in controller.api.clients:
poe_client_id = f"poe-{client_id}"
poe_client_id = f"poe-{client_id}"
if poe_client_id in switches:
continue
if poe_client_id in switches:
continue
client = controller.api.clients[client_id]
if poe_client_id in switches_off:
pass
# Network device with active POE
elif (
client_id in controller.wireless_clients
or client.sw_mac not in devices
or not devices[client.sw_mac].ports[client.sw_port].port_poe
or not devices[client.sw_mac].ports[client.sw_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():
client = controller.api.clients[client_id]
if poe_client_id in switches_off:
break
if (
client2.is_wired
and client.mac != client2.mac
and client.sw_mac == client2.sw_mac
and client.sw_port == client2.sw_port
pass
# Network device with active POE
elif (
client_id in controller.wireless_clients
or client.sw_mac not in devices
or not devices[client.sw_mac].ports[client.sw_port].port_poe
or not devices[client.sw_mac].ports[client.sw_port].poe_enable
or controller.mac == client.mac
):
multi_clients_on_port = True
break
continue
if multi_clients_on_port:
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():
switches[poe_client_id] = UniFiPOEClientSwitch(client, controller)
new_switches.append(switches[poe_client_id])
if poe_client_id in switches_off:
break
if (
client2.is_wired
and client.mac != client2.mac
and client.sw_mac == client2.sw_mac
and client.sw_port == client2.sw_port
):
multi_clients_on_port = True
break
if multi_clients_on_port:
continue
switches[poe_client_id] = UniFiPOEClientSwitch(client, controller)
new_switches.append(switches[poe_client_id])
if new_switches:
async_add_entities(new_switches)

View file

@ -11,6 +11,7 @@ from homeassistant.components.unifi.const import (
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
CONF_TRACK_CLIENTS,
@ -287,6 +288,7 @@ async def test_option_flow(hass):
user_input={
CONF_BLOCK_CLIENT: clients_to_block,
CONF_NEW_CLIENT: "00:00:00:00:00:01",
CONF_POE_CLIENTS: False,
},
)
@ -327,5 +329,6 @@ async def test_option_flow(hass):
CONF_DETECTION_TIME: 100,
CONF_SSID_FILTER: ["SSID 1"],
CONF_BLOCK_CLIENT: ["00:00:00:00:00:01"],
CONF_POE_CLIENTS: False,
CONF_ALLOW_BANDWIDTH_SENSORS: True,
}