Unifi rename controller to hub (#110976)

* Rename controller.py to hub.py

* Rename UniFiController to UnifiHub

* Rename controller instances into hub

* Rename controller to hub in tests

* Rename aiounifi Controller references to api

* Update strings

* Rename test_controller test_hub

* Narrow scope of test_remove_sensors
This commit is contained in:
Robert Svensson 2024-02-20 08:51:22 +01:00 committed by GitHub
parent 2b3f5319d6
commit 2f026ca963
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 432 additions and 476 deletions

View file

@ -40,7 +40,6 @@ from homeassistant.helpers.typing import StateType
import homeassistant.util.dt as dt_util
from .const import DEVICE_STATES
from .controller import UniFiController
from .entity import (
HandlerT,
UnifiEntity,
@ -51,44 +50,43 @@ from .entity import (
async_wlan_available_fn,
async_wlan_device_info_fn,
)
from .hub import UnifiHub
@callback
def async_bandwidth_sensor_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
def async_bandwidth_sensor_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Check if client is allowed."""
if obj_id in controller.option_supported_clients:
if obj_id in hub.option_supported_clients:
return True
return controller.option_allow_bandwidth_sensors
return hub.option_allow_bandwidth_sensors
@callback
def async_uptime_sensor_allowed_fn(controller: UniFiController, obj_id: str) -> bool:
def async_uptime_sensor_allowed_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Check if client is allowed."""
if obj_id in controller.option_supported_clients:
if obj_id in hub.option_supported_clients:
return True
return controller.option_allow_uptime_sensors
return hub.option_allow_uptime_sensors
@callback
def async_client_rx_value_fn(controller: UniFiController, client: Client) -> float:
def async_client_rx_value_fn(hub: UnifiHub, client: Client) -> float:
"""Calculate receiving data transfer value."""
if controller.wireless_clients.is_wireless(client):
if hub.wireless_clients.is_wireless(client):
return client.rx_bytes_r / 1000000
return client.wired_rx_bytes_r / 1000000
@callback
def async_client_tx_value_fn(controller: UniFiController, client: Client) -> float:
def async_client_tx_value_fn(hub: UnifiHub, client: Client) -> float:
"""Calculate transmission data transfer value."""
if controller.wireless_clients.is_wireless(client):
if hub.wireless_clients.is_wireless(client):
return client.tx_bytes_r / 1000000
return client.wired_tx_bytes_r / 1000000
@callback
def async_client_uptime_value_fn(
controller: UniFiController, client: Client
) -> datetime:
def async_client_uptime_value_fn(hub: UnifiHub, client: Client) -> datetime:
"""Calculate the uptime of the client."""
if client.uptime < 1000000000:
return dt_util.now() - timedelta(seconds=client.uptime)
@ -96,23 +94,21 @@ def async_client_uptime_value_fn(
@callback
def async_wlan_client_value_fn(controller: UniFiController, wlan: Wlan) -> int:
def async_wlan_client_value_fn(hub: UnifiHub, wlan: Wlan) -> int:
"""Calculate the amount of clients connected to a wlan."""
return len(
[
client.mac
for client in controller.api.clients.values()
for client in hub.api.clients.values()
if client.essid == wlan.name
and dt_util.utcnow() - dt_util.utc_from_timestamp(client.last_seen or 0)
< controller.option_detection_time
< hub.option_detection_time
]
)
@callback
def async_device_uptime_value_fn(
controller: UniFiController, device: Device
) -> datetime | None:
def async_device_uptime_value_fn(hub: UnifiHub, device: Device) -> datetime | None:
"""Calculate the approximate time the device started (based on uptime returned from API, in seconds)."""
if device.uptime <= 0:
# Library defaults to 0 if uptime is not provided, e.g. when offline
@ -131,29 +127,27 @@ def async_device_uptime_value_changed_fn(
@callback
def async_device_outlet_power_supported_fn(
controller: UniFiController, obj_id: str
) -> bool:
def async_device_outlet_power_supported_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Determine if an outlet has the power property."""
# At this time, an outlet_caps value of 3 is expected to indicate that the outlet
# supports metering
return controller.api.outlets[obj_id].caps == 3
return hub.api.outlets[obj_id].caps == 3
@callback
def async_device_outlet_supported_fn(controller: UniFiController, obj_id: str) -> bool:
def async_device_outlet_supported_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Determine if a device supports reading overall power metrics."""
return controller.api.devices[obj_id].outlet_ac_power_budget is not None
return hub.api.devices[obj_id].outlet_ac_power_budget is not None
@callback
def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bool:
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Check if client was last seen recently."""
client = controller.api.clients[obj_id]
client = hub.api.clients[obj_id]
if (
dt_util.utcnow() - dt_util.utc_from_timestamp(client.last_seen or 0)
> controller.option_detection_time
> hub.option_detection_time
):
return False
@ -164,11 +158,11 @@ def async_client_is_connected_fn(controller: UniFiController, obj_id: str) -> bo
class UnifiSensorEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
"""Validate and load entities from different UniFi handlers."""
value_fn: Callable[[UniFiController, ApiItemT], datetime | float | str | None]
value_fn: Callable[[UnifiHub, ApiItemT], datetime | float | str | None]
@callback
def async_device_state_value_fn(controller: UniFiController, device: Device) -> str:
def async_device_state_value_fn(hub: UnifiHub, device: Device) -> str:
"""Retrieve the state of the device."""
return DEVICE_STATES[device.state]
@ -181,7 +175,7 @@ class UnifiSensorEntityDescription(
):
"""Class describing UniFi sensor entity."""
is_connected_fn: Callable[[UniFiController, str], bool] | None = None
is_connected_fn: Callable[[UnifiHub, str], bool] | None = None
# Custom function to determine whether a state change should be recorded
value_changed_fn: Callable[
[StateType | date | datetime | Decimal, datetime | float | str | None],
@ -200,7 +194,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
has_entity_name=True,
allowed_fn=async_bandwidth_sensor_allowed_fn,
api_handler_fn=lambda api: api.clients,
available_fn=lambda controller, _: controller.available,
available_fn=lambda hub, _: hub.available,
device_info_fn=async_client_device_info_fn,
event_is_on=None,
event_to_subscribe=None,
@ -208,8 +202,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda _: "RX",
object_fn=lambda api, obj_id: api.clients[obj_id],
should_poll=False,
supported_fn=lambda controller, _: controller.option_allow_bandwidth_sensors,
unique_id_fn=lambda controller, obj_id: f"rx-{obj_id}",
supported_fn=lambda hub, _: hub.option_allow_bandwidth_sensors,
unique_id_fn=lambda hub, obj_id: f"rx-{obj_id}",
value_fn=async_client_rx_value_fn,
),
UnifiSensorEntityDescription[Clients, Client](
@ -222,7 +216,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
has_entity_name=True,
allowed_fn=async_bandwidth_sensor_allowed_fn,
api_handler_fn=lambda api: api.clients,
available_fn=lambda controller, _: controller.available,
available_fn=lambda hub, _: hub.available,
device_info_fn=async_client_device_info_fn,
event_is_on=None,
event_to_subscribe=None,
@ -230,8 +224,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda _: "TX",
object_fn=lambda api, obj_id: api.clients[obj_id],
should_poll=False,
supported_fn=lambda controller, _: controller.option_allow_bandwidth_sensors,
unique_id_fn=lambda controller, obj_id: f"tx-{obj_id}",
supported_fn=lambda hub, _: hub.option_allow_bandwidth_sensors,
unique_id_fn=lambda hub, obj_id: f"tx-{obj_id}",
value_fn=async_client_tx_value_fn,
),
UnifiSensorEntityDescription[Ports, Port](
@ -241,7 +235,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
native_unit_of_measurement=UnitOfPower.WATT,
has_entity_name=True,
entity_registry_enabled_default=False,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.ports,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -250,8 +244,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda port: f"{port.name} PoE Power",
object_fn=lambda api, obj_id: api.ports[obj_id],
should_poll=False,
supported_fn=lambda controller, obj_id: controller.api.ports[obj_id].port_poe,
unique_id_fn=lambda controller, obj_id: f"poe_power-{obj_id}",
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
unique_id_fn=lambda hub, obj_id: f"poe_power-{obj_id}",
value_fn=lambda _, obj: obj.poe_power if obj.poe_mode != "off" else "0",
),
UnifiSensorEntityDescription[Clients, Client](
@ -262,15 +256,15 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
entity_registry_enabled_default=False,
allowed_fn=async_uptime_sensor_allowed_fn,
api_handler_fn=lambda api: api.clients,
available_fn=lambda controller, obj_id: controller.available,
available_fn=lambda hub, obj_id: hub.available,
device_info_fn=async_client_device_info_fn,
event_is_on=None,
event_to_subscribe=None,
name_fn=lambda client: "Uptime",
object_fn=lambda api, obj_id: api.clients[obj_id],
should_poll=False,
supported_fn=lambda controller, _: controller.option_allow_uptime_sensors,
unique_id_fn=lambda controller, obj_id: f"uptime-{obj_id}",
supported_fn=lambda hub, _: hub.option_allow_uptime_sensors,
unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}",
value_fn=async_client_uptime_value_fn,
),
UnifiSensorEntityDescription[Wlans, Wlan](
@ -278,7 +272,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
has_entity_name=True,
state_class=SensorStateClass.MEASUREMENT,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.wlans,
available_fn=async_wlan_available_fn,
device_info_fn=async_wlan_device_info_fn,
@ -287,8 +281,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda wlan: None,
object_fn=lambda api, obj_id: api.wlans[obj_id],
should_poll=True,
supported_fn=lambda controller, obj_id: True,
unique_id_fn=lambda controller, obj_id: f"wlan_clients-{obj_id}",
supported_fn=lambda hub, obj_id: True,
unique_id_fn=lambda hub, obj_id: f"wlan_clients-{obj_id}",
value_fn=async_wlan_client_value_fn,
),
UnifiSensorEntityDescription[Outlets, Outlet](
@ -297,7 +291,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=UnitOfPower.WATT,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.outlets,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -307,7 +301,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
object_fn=lambda api, obj_id: api.outlets[obj_id],
should_poll=True,
supported_fn=async_device_outlet_power_supported_fn,
unique_id_fn=lambda controller, obj_id: f"outlet_power-{obj_id}",
unique_id_fn=lambda hub, obj_id: f"outlet_power-{obj_id}",
value_fn=lambda _, obj: obj.power if obj.relay_state else "0",
),
UnifiSensorEntityDescription[Devices, Device](
@ -317,7 +311,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
native_unit_of_measurement=UnitOfPower.WATT,
suggested_display_precision=1,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -327,8 +321,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
object_fn=lambda api, obj_id: api.devices[obj_id],
should_poll=False,
supported_fn=async_device_outlet_supported_fn,
unique_id_fn=lambda controller, obj_id: f"ac_power_budget-{obj_id}",
value_fn=lambda controller, device: device.outlet_ac_power_budget,
unique_id_fn=lambda hub, obj_id: f"ac_power_budget-{obj_id}",
value_fn=lambda hub, device: device.outlet_ac_power_budget,
),
UnifiSensorEntityDescription[Devices, Device](
key="SmartPower AC power consumption",
@ -337,7 +331,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
native_unit_of_measurement=UnitOfPower.WATT,
suggested_display_precision=1,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -347,15 +341,15 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
object_fn=lambda api, obj_id: api.devices[obj_id],
should_poll=False,
supported_fn=async_device_outlet_supported_fn,
unique_id_fn=lambda controller, obj_id: f"ac_power_conumption-{obj_id}",
value_fn=lambda controller, device: device.outlet_ac_power_consumption,
unique_id_fn=lambda hub, obj_id: f"ac_power_conumption-{obj_id}",
value_fn=lambda hub, device: device.outlet_ac_power_consumption,
),
UnifiSensorEntityDescription[Devices, Device](
key="Device uptime",
device_class=SensorDeviceClass.TIMESTAMP,
entity_category=EntityCategory.DIAGNOSTIC,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -364,8 +358,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda device: "Uptime",
object_fn=lambda api, obj_id: api.devices[obj_id],
should_poll=False,
supported_fn=lambda controller, obj_id: True,
unique_id_fn=lambda controller, obj_id: f"device_uptime-{obj_id}",
supported_fn=lambda hub, obj_id: True,
unique_id_fn=lambda hub, obj_id: f"device_uptime-{obj_id}",
value_fn=async_device_uptime_value_fn,
value_changed_fn=async_device_uptime_value_changed_fn,
),
@ -375,7 +369,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -385,7 +379,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
object_fn=lambda api, obj_id: api.devices[obj_id],
should_poll=False,
supported_fn=lambda ctrlr, obj_id: ctrlr.api.devices[obj_id].has_temperature,
unique_id_fn=lambda controller, obj_id: f"device_temperature-{obj_id}",
unique_id_fn=lambda hub, obj_id: f"device_temperature-{obj_id}",
value_fn=lambda ctrlr, device: device.general_temperature,
),
UnifiSensorEntityDescription[Devices, Device](
@ -393,7 +387,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ENUM,
entity_category=EntityCategory.DIAGNOSTIC,
has_entity_name=True,
allowed_fn=lambda controller, obj_id: True,
allowed_fn=lambda hub, obj_id: True,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
@ -402,8 +396,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
name_fn=lambda device: "State",
object_fn=lambda api, obj_id: api.devices[obj_id],
should_poll=False,
supported_fn=lambda controller, obj_id: True,
unique_id_fn=lambda controller, obj_id: f"device_state-{obj_id}",
supported_fn=lambda hub, obj_id: True,
unique_id_fn=lambda hub, obj_id: f"device_state-{obj_id}",
value_fn=async_device_state_value_fn,
options=list(DEVICE_STATES.values()),
),
@ -416,7 +410,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up sensors for UniFi Network integration."""
UniFiController.register_platform(
UnifiHub.register_platform(
hass, config_entry, async_add_entities, UnifiSensorEntity, ENTITY_DESCRIPTIONS
)
@ -443,19 +437,19 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
Update native_value.
"""
description = self.entity_description
obj = description.object_fn(self.controller.api, self._obj_id)
obj = description.object_fn(self.hub.api, self._obj_id)
# Update the value only if value is considered to have changed relative to its previous state
if description.value_changed_fn(
self.native_value, (value := description.value_fn(self.controller, obj))
self.native_value, (value := description.value_fn(self.hub, obj))
):
self._attr_native_value = value
if description.is_connected_fn is not None:
# Send heartbeat if client is connected
if description.is_connected_fn(self.controller, self._obj_id):
self.controller.async_heartbeat(
if description.is_connected_fn(self.hub, self._obj_id):
self.hub.async_heartbeat(
self._attr_unique_id,
dt_util.utcnow() + self.controller.option_detection_time,
dt_util.utcnow() + self.hub.option_detection_time,
)
async def async_added_to_hass(self) -> None:
@ -467,7 +461,7 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{self.controller.signal_heartbeat_missed}_{self.unique_id}",
f"{self.hub.signal_heartbeat_missed}_{self.unique_id}",
self._make_disconnected,
)
)
@ -478,4 +472,4 @@ class UnifiSensorEntity(UnifiEntity[HandlerT, ApiItemT], SensorEntity):
if self.entity_description.is_connected_fn is not None:
# Remove heartbeat registration
self.controller.async_heartbeat(self._attr_unique_id)
self.hub.async_heartbeat(self._attr_unique_id)