Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeassistant/components/unifi/.translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"device_tracker": {
"data": {
"detection_time": "Time in seconds from last seen until considered away",
"ignore_wired_bug": "Disable UniFi wired bug logic",
"ssid_filter": "Select SSIDs to track wireless clients on",
"track_clients": "Track network clients",
"track_devices": "Track network devices (Ubiquiti devices)",
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/unifi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC

from .config_flow import get_controller_id_from_config_entry
from .const import ATTR_MANUFACTURER, DOMAIN, UNIFI_WIRELESS_CLIENTS
from .const import ATTR_MANUFACTURER, DOMAIN, LOGGER, UNIFI_WIRELESS_CLIENTS
from .controller import UniFiController

SAVE_DELAY = 10
Expand Down Expand Up @@ -42,6 +42,8 @@ async def async_setup_entry(hass, config_entry):

hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, controller.shutdown)

LOGGER.debug("UniFi config options %s", config_entry.options)

if controller.mac is None:
return True

Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/unifi/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_IGNORE_WIRED_BUG,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
Expand Down Expand Up @@ -216,6 +217,10 @@ async def async_step_device_tracker(self, user_input=None):
self.controller.option_detection_time.total_seconds()
),
): int,
vol.Optional(
CONF_IGNORE_WIRED_BUG,
default=self.controller.option_ignore_wired_bug,
): bool,
}
),
)
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/unifi/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
CONF_ALLOW_BANDWIDTH_SENSORS = "allow_bandwidth_sensors"
CONF_BLOCK_CLIENT = "block_client"
CONF_DETECTION_TIME = "detection_time"
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"
CONF_SSID_FILTER = "ssid_filter"

DEFAULT_ALLOW_BANDWIDTH_SENSORS = False
DEFAULT_IGNORE_WIRED_BUG = False
DEFAULT_POE_CLIENTS = True
DEFAULT_TRACK_CLIENTS = True
DEFAULT_TRACK_DEVICES = True
Expand Down
71 changes: 43 additions & 28 deletions homeassistant/components/unifi/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_IGNORE_WIRED_BUG,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
Expand All @@ -33,6 +34,7 @@
CONTROLLER_ID,
DEFAULT_ALLOW_BANDWIDTH_SENSORS,
DEFAULT_DETECTION_TIME,
DEFAULT_IGNORE_WIRED_BUG,
DEFAULT_POE_CLIENTS,
DEFAULT_TRACK_CLIENTS,
DEFAULT_TRACK_DEVICES,
Expand Down Expand Up @@ -89,39 +91,37 @@ def site_role(self):
return self._site_role

@property
def option_allow_bandwidth_sensors(self):
"""Config entry option to allow bandwidth sensors."""
return self.config_entry.options.get(
CONF_ALLOW_BANDWIDTH_SENSORS, DEFAULT_ALLOW_BANDWIDTH_SENSORS
)

@property
def option_block_clients(self):
"""Config entry option with list of clients to control network access."""
return self.config_entry.options.get(CONF_BLOCK_CLIENT, [])
def mac(self):
"""Return the mac address of this controller."""
for client in self.api.clients.values():
if self.host == client.ip:
return client.mac
return None

@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)
# Device tracker options

@property
def option_track_clients(self):
"""Config entry option to not track clients."""
return self.config_entry.options.get(CONF_TRACK_CLIENTS, DEFAULT_TRACK_CLIENTS)

@property
def option_track_devices(self):
"""Config entry option to not track devices."""
return self.config_entry.options.get(CONF_TRACK_DEVICES, DEFAULT_TRACK_DEVICES)

@property
def option_track_wired_clients(self):
"""Config entry option to not track wired clients."""
return self.config_entry.options.get(
CONF_TRACK_WIRED_CLIENTS, DEFAULT_TRACK_WIRED_CLIENTS
)

@property
def option_track_devices(self):
"""Config entry option to not track devices."""
return self.config_entry.options.get(CONF_TRACK_DEVICES, DEFAULT_TRACK_DEVICES)

@property
def option_ssid_filter(self):
"""Config entry option listing what SSIDs are being used to track clients."""
return self.config_entry.options.get(CONF_SSID_FILTER, [])

@property
def option_detection_time(self):
"""Config entry option defining number of seconds from last seen to away."""
Expand All @@ -132,17 +132,32 @@ def option_detection_time(self):
)

@property
def option_ssid_filter(self):
"""Config entry option listing what SSIDs are being used to track clients."""
return self.config_entry.options.get(CONF_SSID_FILTER, [])
def option_ignore_wired_bug(self):
"""Config entry option to ignore wired bug."""
return self.config_entry.options.get(
CONF_IGNORE_WIRED_BUG, DEFAULT_IGNORE_WIRED_BUG
)

# Client control options

@property
def mac(self):
"""Return the mac address of this controller."""
for client in self.api.clients.values():
if self.host == client.ip:
return client.mac
return None
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_block_clients(self):
"""Config entry option with list of clients to control network access."""
return self.config_entry.options.get(CONF_BLOCK_CLIENT, [])

# Statistics sensor options

@property
def option_allow_bandwidth_sensors(self):
"""Config entry option to allow bandwidth sensors."""
return self.config_entry.options.get(
CONF_ALLOW_BANDWIDTH_SENSORS, DEFAULT_ALLOW_BANDWIDTH_SENSORS
)

@callback
def async_unifi_signalling_callback(self, signal, data):
Expand Down
28 changes: 15 additions & 13 deletions homeassistant/components/unifi/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):

client = controller.api.clients_all[mac]
controller.api.clients.process_raw([client.raw])
LOGGER.debug(
"Restore disconnected client %s (%s)", entity.entity_id, client.mac,
)

@callback
def update_controller():
Expand Down Expand Up @@ -121,20 +124,21 @@ def options_updated():
remove.add(mac)

if option_ssid_filter != controller.option_ssid_filter:
option_ssid_filter = controller.option_ssid_filter
update = True

for mac, entity in tracked.items():
if (
isinstance(entity, UniFiClientTracker)
and not entity.is_wired
and entity.client.essid not in option_ssid_filter
):
remove.add(mac)
if controller.option_ssid_filter:
for mac, entity in tracked.items():
if (
isinstance(entity, UniFiClientTracker)
and not entity.is_wired
and entity.client.essid not in controller.option_ssid_filter
):
remove.add(mac)

option_track_clients = controller.option_track_clients
option_track_devices = controller.option_track_devices
option_track_wired_clients = controller.option_track_wired_clients
option_ssid_filter = controller.option_ssid_filter

for mac in remove:
entity = tracked.pop(mac)
Expand Down Expand Up @@ -308,9 +312,9 @@ def __init__(self, device, controller):

async def async_added_to_hass(self):
"""Subscribe to device events."""
LOGGER.debug("New UniFi device tracker %s (%s)", self.name, self.device.mac)
LOGGER.debug("New device %s (%s)", self.entity_id, self.device.mac)
self.device.register_callback(self.async_update_callback)
self.listeners.append(
self.async_on_remove(
async_dispatcher_connect(
self.hass, self.controller.signal_reachable, self.async_update_callback
)
Expand All @@ -319,13 +323,11 @@ async def async_added_to_hass(self):
async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
self.device.remove_callback(self.async_update_callback)
for unsub_dispatcher in self.listeners:
Comment thread
Kane610 marked this conversation as resolved.
unsub_dispatcher()

@callback
def async_update_callback(self):
"""Update the sensor's state."""
LOGGER.debug("Updating UniFi tracked device %s", self.entity_id)
LOGGER.debug("Updating device %s (%s)", self.entity_id, self.device.mac)

self.async_write_ha_state()

Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/unifi/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class UniFiRxBandwidthSensor(UniFiClient):
@property
def state(self):
"""Return the state of the sensor."""
if self.is_wired:
if self._is_wired:
return self.client.wired_rx_bytes / 1000000
return self.client.raw.get("rx_bytes", 0) / 1000000

Expand All @@ -125,7 +125,7 @@ class UniFiTxBandwidthSensor(UniFiRxBandwidthSensor):
@property
def state(self):
"""Return the state of the sensor."""
if self.is_wired:
if self._is_wired:
return self.client.wired_tx_bytes / 1000000
return self.client.raw.get("tx_bytes", 0) / 1000000

Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/unifi/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"device_tracker": {
"data": {
"detection_time": "Time in seconds from last seen until considered away",
"ignore_wired_bug": "Disable UniFi wired bug logic",
"ssid_filter": "Select SSIDs to track wireless clients on",
"track_clients": "Track network clients",
"track_devices": "Track network devices (Ubiquiti devices)",
Expand Down Expand Up @@ -61,4 +62,4 @@
"error": {
"unknown_client_mac": "No client available in UniFi on that MAC address"
}
}
}
25 changes: 16 additions & 9 deletions homeassistant/components/unifi/unifi_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ def __init__(self, client, controller) -> None:
self.controller = controller
self.listeners = []

self.is_wired = self.client.mac not in controller.wireless_clients
self._is_wired = self.client.mac not in controller.wireless_clients
self.is_blocked = self.client.blocked
self.wired_connection = None
self.wireless_connection = None

async def async_added_to_hass(self) -> None:
"""Client entity created."""
LOGGER.debug("New UniFi client %s (%s)", self.name, self.client.mac)
LOGGER.debug("New client %s (%s)", self.entity_id, self.client.mac)
self.client.register_callback(self.async_update_callback)
self.listeners.append(
Comment thread
Kane610 marked this conversation as resolved.
self.async_on_remove(
async_dispatcher_connect(
self.hass, self.controller.signal_reachable, self.async_update_callback
)
Expand All @@ -59,17 +59,14 @@ async def async_added_to_hass(self) -> None:
async def async_will_remove_from_hass(self) -> None:
"""Disconnect client object when removed."""
self.client.remove_callback(self.async_update_callback)
for unsub_dispatcher in self.listeners:
unsub_dispatcher()

@callback
def async_update_callback(self) -> None:
"""Update the clients state."""
if self.is_wired and self.client.mac in self.controller.wireless_clients:
self.is_wired = False
if self._is_wired and self.client.mac in self.controller.wireless_clients:
self._is_wired = False

if self.client.last_updated == SOURCE_EVENT:

if self.client.event.event in WIRELESS_CLIENT:
self.wireless_connection = self.client.event.event in (
WIRELESS_CLIENT_CONNECTED,
Expand All @@ -84,9 +81,19 @@ def async_update_callback(self) -> None:
elif self.client.event.event in CLIENT_BLOCKED + CLIENT_UNBLOCKED:
self.is_blocked = self.client.event.event in CLIENT_BLOCKED

LOGGER.debug("Updating client %s %s", self.entity_id, self.client.mac)
LOGGER.debug("Updating client %s (%s)", self.entity_id, self.client.mac)
self.async_write_ha_state()

@property
def is_wired(self):
"""Return if the client is wired.

Allows disabling logic to keep track of clients affected by UniFi wired bug marking wireless devices as wired. This is useful when running a network not only containing UniFi APs.
"""
if self.controller.option_ignore_wired_bug:
return self.client.is_wired
return self._is_wired

@property
def name(self) -> str:
"""Return the name of the client."""
Expand Down
6 changes: 4 additions & 2 deletions tests/components/unifi/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
CONF_BLOCK_CLIENT,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_IGNORE_WIRED_BUG,
CONF_POE_CLIENTS,
CONF_SITE_ID,
CONF_SSID_FILTER,
Expand Down Expand Up @@ -338,9 +339,10 @@ async def test_option_flow(hass):
CONF_TRACK_CLIENTS: False,
CONF_TRACK_WIRED_CLIENTS: False,
CONF_TRACK_DEVICES: False,
CONF_DETECTION_TIME: 100,
CONF_SSID_FILTER: ["SSID 1"],
CONF_BLOCK_CLIENT: ["00:00:00:00:00:01"],
CONF_DETECTION_TIME: 100,
CONF_IGNORE_WIRED_BUG: False,
CONF_POE_CLIENTS: False,
CONF_BLOCK_CLIENT: ["00:00:00:00:00:01"],
CONF_ALLOW_BANDWIDTH_SENSORS: True,
}
Loading