diff --git a/homeassistant/components/unifi/.translations/en.json b/homeassistant/components/unifi/.translations/en.json index 8fdde34470b..0124ca1cc24 100644 --- a/homeassistant/components/unifi/.translations/en.json +++ b/homeassistant/components/unifi/.translations/en.json @@ -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" diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index e0bb1c3bb9f..781fcdeae82 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -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), diff --git a/homeassistant/components/unifi/const.py b/homeassistant/components/unifi/const.py index fd94601db50..4acf75fbdd9 100644 --- a/homeassistant/components/unifi/const.py +++ b/homeassistant/components/unifi/const.py @@ -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 diff --git a/homeassistant/components/unifi/controller.py b/homeassistant/components/unifi/controller.py index 50b758f01af..03e079c0170 100644 --- a/homeassistant/components/unifi/controller.py +++ b/homeassistant/components/unifi/controller.py @@ -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.""" diff --git a/homeassistant/components/unifi/strings.json b/homeassistant/components/unifi/strings.json index 58728225de7..61116adfb60 100644 --- a/homeassistant/components/unifi/strings.json +++ b/homeassistant/components/unifi/strings.json @@ -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" diff --git a/homeassistant/components/unifi/switch.py b/homeassistant/components/unifi/switch.py index 0df019de02c..0547e35f064 100644 --- a/homeassistant/components/unifi/switch.py +++ b/homeassistant/components/unifi/switch.py @@ -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) diff --git a/tests/components/unifi/test_config_flow.py b/tests/components/unifi/test_config_flow.py index 9a280ffe9e6..b89dbfeb700 100644 --- a/tests/components/unifi/test_config_flow.py +++ b/tests/components/unifi/test_config_flow.py @@ -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, }