From 19e54debba13966c6c752c56f61b1bf982f10809 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 9 Mar 2024 09:19:38 +0100 Subject: [PATCH] Unifi more polish on entity description (#112281) * Make has_entity_name default value True * Remove previously missed event_is_on and event_to_subscribe * Provide default value for allowed_fn and supported_fn * Provide default value for name_fn * Provide default value for available_fn * Add doc strings to required functions * Fix some missed renames from variations of controller to hub --- homeassistant/components/unifi/button.py | 9 +----- .../components/unifi/device_tracker.py | 7 +--- homeassistant/components/unifi/entity.py | 22 ++++++++++--- homeassistant/components/unifi/image.py | 3 -- homeassistant/components/unifi/sensor.py | 32 ++----------------- homeassistant/components/unifi/switch.py | 27 +++------------- homeassistant/components/unifi/update.py | 4 --- 7 files changed, 27 insertions(+), 77 deletions(-) diff --git a/homeassistant/components/unifi/button.py b/homeassistant/components/unifi/button.py index c8f5d5b33f7..45fc76c73df 100644 --- a/homeassistant/components/unifi/button.py +++ b/homeassistant/components/unifi/button.py @@ -69,33 +69,26 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = ( UnifiButtonEntityDescription[Devices, Device]( key="Device restart", entity_category=EntityCategory.CONFIG, - has_entity_name=True, device_class=ButtonDeviceClass.RESTART, - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.devices, available_fn=async_device_available_fn, control_fn=async_restart_device_control_fn, device_info_fn=async_device_device_info_fn, name_fn=lambda _: "Restart", object_fn=lambda api, obj_id: api.devices[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"device_restart-{obj_id}", ), UnifiButtonEntityDescription[Ports, Port]( key="PoE power cycle", entity_category=EntityCategory.CONFIG, - has_entity_name=True, device_class=ButtonDeviceClass.RESTART, - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.ports, available_fn=async_device_available_fn, control_fn=async_power_cycle_port_control_fn, device_info_fn=async_device_device_info_fn, - event_is_on=None, - event_to_subscribe=None, name_fn=lambda port: f"{port.name} Power Cycle", object_fn=lambda api, obj_id: api.ports[obj_id], - supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe, + supported_fn=lambda hub, obj_id: bool(hub.api.ports[obj_id].port_poe), unique_id_fn=lambda hub, obj_id: f"power_cycle-{obj_id}", ), ) diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index d84691b814c..ffd4566b77c 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -149,10 +149,8 @@ class UnifiTrackerEntityDescription(UnifiEntityDescription[HandlerT, ApiItemT]): ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = ( UnifiTrackerEntityDescription[Clients, Client]( key="Client device scanner", - has_entity_name=True, allowed_fn=async_client_allowed_fn, api_handler_fn=lambda api: api.clients, - available_fn=lambda hub, obj_id: hub.available, device_info_fn=lambda api, obj_id: None, event_is_on=(WIRED_CONNECTION + WIRELESS_CONNECTION), event_to_subscribe=( @@ -165,23 +163,20 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = ( is_connected_fn=async_client_is_connected_fn, name_fn=lambda client: client.name or client.hostname, object_fn=lambda api, obj_id: api.clients[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"{hub.site}-{obj_id}", ip_address_fn=lambda api, obj_id: api.clients[obj_id].ip, hostname_fn=lambda api, obj_id: api.clients[obj_id].hostname, ), UnifiTrackerEntityDescription[Devices, Device]( key="Device scanner", - has_entity_name=True, allowed_fn=lambda hub, obj_id: hub.config.option_track_devices, api_handler_fn=lambda api: api.devices, available_fn=async_device_available_fn, device_info_fn=lambda api, obj_id: None, heartbeat_timedelta_fn=async_device_heartbeat_timedelta_fn, - is_connected_fn=lambda ctrlr, obj_id: ctrlr.api.devices[obj_id].state == 1, + is_connected_fn=lambda hub, obj_id: hub.api.devices[obj_id].state == 1, name_fn=lambda device: device.name or device.model, object_fn=lambda api, obj_id: api.devices[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: obj_id, ip_address_fn=lambda api, obj_id: api.devices[obj_id].ip, hostname_fn=lambda api, obj_id: None, diff --git a/homeassistant/components/unifi/entity.py b/homeassistant/components/unifi/entity.py index 5a626ec56f6..649c9fc0c13 100644 --- a/homeassistant/components/unifi/entity.py +++ b/homeassistant/components/unifi/entity.py @@ -98,16 +98,28 @@ def async_client_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo: class UnifiEntityDescription(EntityDescription, Generic[HandlerT, ApiItemT]): """UniFi Entity Description.""" - allowed_fn: Callable[[UnifiHub, str], bool] api_handler_fn: Callable[[aiounifi.Controller], HandlerT] - available_fn: Callable[[UnifiHub, str], bool] + """Provide api_handler from api.""" device_info_fn: Callable[[UnifiHub, str], DeviceInfo | None] - name_fn: Callable[[ApiItemT], str | None] + """Provide device info object based on hub and obj_id.""" object_fn: Callable[[aiounifi.Controller, str], ApiItemT] - supported_fn: Callable[[UnifiHub, str], bool | None] + """Retrieve object based on api and obj_id.""" unique_id_fn: Callable[[UnifiHub, str], str] + """Provide a unique ID based on hub and obj_id.""" - # Optional + # Optional functions + allowed_fn: Callable[[UnifiHub, str], bool] = lambda hub, obj_id: True + """Determine if config entry options allow creation of entity.""" + available_fn: Callable[[UnifiHub, str], bool] = lambda hub, obj_id: hub.available + """Determine if entity is available, default is if connection is working.""" + name_fn: Callable[[ApiItemT], str | None] = lambda obj: None + """Entity name function, can be used to extend entity name beyond device name.""" + supported_fn: Callable[[UnifiHub, str], bool] = lambda hub, obj_id: True + """Determine if UniFi object supports providing relevant data for entity.""" + + # Optional constants + has_entity_name = True # Part of EntityDescription + """Has entity name defaults to true.""" event_is_on: tuple[EventKey, ...] | None = None """Which UniFi events should be used to consider state 'on'.""" event_to_subscribe: tuple[EventKey, ...] | None = None diff --git a/homeassistant/components/unifi/image.py b/homeassistant/components/unifi/image.py index 8360fb3b095..285477fe133 100644 --- a/homeassistant/components/unifi/image.py +++ b/homeassistant/components/unifi/image.py @@ -50,15 +50,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = ( UnifiImageEntityDescription[Wlans, Wlan]( key="WLAN QR Code", entity_category=EntityCategory.DIAGNOSTIC, - has_entity_name=True, entity_registry_enabled_default=False, - 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, name_fn=lambda wlan: "QR Code", object_fn=lambda api, obj_id: api.wlans[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"qr_code-{obj_id}", image_fn=async_wlan_qr_code_image_fn, value_fn=lambda obj: obj.x_passphrase, diff --git a/homeassistant/components/unifi/sensor.py b/homeassistant/components/unifi/sensor.py index eda4599b02a..818b5e53b6a 100644 --- a/homeassistant/components/unifi/sensor.py +++ b/homeassistant/components/unifi/sensor.py @@ -186,10 +186,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND, icon="mdi:upload", - has_entity_name=True, allowed_fn=async_bandwidth_sensor_allowed_fn, api_handler_fn=lambda api: api.clients, - available_fn=lambda hub, _: hub.available, device_info_fn=async_client_device_info_fn, is_connected_fn=async_client_is_connected_fn, name_fn=lambda _: "RX", @@ -205,10 +203,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfDataRate.MEGABYTES_PER_SECOND, icon="mdi:download", - has_entity_name=True, allowed_fn=async_bandwidth_sensor_allowed_fn, api_handler_fn=lambda api: api.clients, - available_fn=lambda hub, _: hub.available, device_info_fn=async_client_device_info_fn, is_connected_fn=async_client_is_connected_fn, name_fn=lambda _: "TX", @@ -222,15 +218,13 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.POWER, entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=UnitOfPower.WATT, - has_entity_name=True, entity_registry_enabled_default=False, - 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, name_fn=lambda port: f"{port.name} PoE Power", object_fn=lambda api, obj_id: api.ports[obj_id], - supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe, + supported_fn=lambda hub, obj_id: bool(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", ), @@ -238,11 +232,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( key="Client uptime", device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, - has_entity_name=True, entity_registry_enabled_default=False, allowed_fn=async_uptime_sensor_allowed_fn, api_handler_fn=lambda api: api.clients, - available_fn=lambda hub, obj_id: hub.available, device_info_fn=async_client_device_info_fn, name_fn=lambda client: "Uptime", object_fn=lambda api, obj_id: api.clients[obj_id], @@ -253,16 +245,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( UnifiSensorEntityDescription[Wlans, Wlan]( key="WLAN clients", entity_category=EntityCategory.DIAGNOSTIC, - has_entity_name=True, state_class=SensorStateClass.MEASUREMENT, - 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, - name_fn=lambda wlan: None, object_fn=lambda api, obj_id: api.wlans[obj_id], should_poll=True, - 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, ), @@ -271,8 +259,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.POWER, entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=UnitOfPower.WATT, - has_entity_name=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, @@ -289,8 +275,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=UnitOfPower.WATT, suggested_display_precision=1, - has_entity_name=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, @@ -306,8 +290,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=UnitOfPower.WATT, suggested_display_precision=1, - has_entity_name=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, @@ -321,14 +303,11 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( key="Device uptime", device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, - has_entity_name=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, name_fn=lambda device: "Uptime", object_fn=lambda api, obj_id: api.devices[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, @@ -338,29 +317,24 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.TEMPERATURE, entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - has_entity_name=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, name_fn=lambda device: "Temperature", object_fn=lambda api, obj_id: api.devices[obj_id], - supported_fn=lambda ctrlr, obj_id: ctrlr.api.devices[obj_id].has_temperature, + supported_fn=lambda hub, obj_id: hub.api.devices[obj_id].has_temperature, unique_id_fn=lambda hub, obj_id: f"device_temperature-{obj_id}", - value_fn=lambda ctrlr, device: device.general_temperature, + value_fn=lambda hub, device: device.general_temperature, ), UnifiSensorEntityDescription[Devices, Device]( key="Device State", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - has_entity_name=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, name_fn=lambda device: "State", object_fn=lambda api, obj_id: api.devices[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()), diff --git a/homeassistant/components/unifi/switch.py b/homeassistant/components/unifi/switch.py index 92c25b90f06..6e073a655a5 100644 --- a/homeassistant/components/unifi/switch.py +++ b/homeassistant/components/unifi/switch.py @@ -126,7 +126,7 @@ async def async_dpi_group_control_fn(hub: UnifiHub, obj_id: str, target: bool) - @callback -def async_outlet_supports_switching_fn(hub: UnifiHub, obj_id: str) -> bool: +def async_outlet_switching_supported_fn(hub: UnifiHub, obj_id: str) -> bool: """Determine if an outlet supports switching.""" outlet = hub.api.outlets[obj_id] return outlet.has_relay or outlet.caps in (1, 3) @@ -184,43 +184,37 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = ( key="Block client", device_class=SwitchDeviceClass.SWITCH, entity_category=EntityCategory.CONFIG, - has_entity_name=True, icon="mdi:ethernet", allowed_fn=async_block_client_allowed_fn, api_handler_fn=lambda api: api.clients, - available_fn=lambda hub, obj_id: hub.available, control_fn=async_block_client_control_fn, device_info_fn=async_client_device_info_fn, event_is_on=CLIENT_UNBLOCKED, event_to_subscribe=CLIENT_BLOCKED + CLIENT_UNBLOCKED, is_on_fn=lambda hub, client: not client.blocked, - name_fn=lambda client: None, object_fn=lambda api, obj_id: api.clients[obj_id], only_event_for_state_change=True, - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"block-{obj_id}", ), UnifiSwitchEntityDescription[DPIRestrictionGroups, DPIRestrictionGroup]( key="DPI restriction", + has_entity_name=False, entity_category=EntityCategory.CONFIG, icon="mdi:network", allowed_fn=lambda hub, obj_id: hub.config.option_dpi_restrictions, api_handler_fn=lambda api: api.dpi_groups, - available_fn=lambda hub, obj_id: hub.available, control_fn=async_dpi_group_control_fn, custom_subscribe=lambda api: api.dpi_apps.subscribe, device_info_fn=async_dpi_group_device_info_fn, is_on_fn=async_dpi_group_is_on_fn, name_fn=lambda group: group.name, object_fn=lambda api, obj_id: api.dpi_groups[obj_id], - supported_fn=lambda c, obj_id: bool(c.api.dpi_groups[obj_id].dpiapp_ids), + supported_fn=lambda hub, obj_id: bool(hub.api.dpi_groups[obj_id].dpiapp_ids), unique_id_fn=lambda hub, obj_id: obj_id, ), UnifiSwitchEntityDescription[Outlets, Outlet]( key="Outlet control", device_class=SwitchDeviceClass.OUTLET, - has_entity_name=True, - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.outlets, available_fn=async_device_available_fn, control_fn=async_outlet_control_fn, @@ -228,34 +222,28 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = ( is_on_fn=lambda hub, outlet: outlet.relay_state, name_fn=lambda outlet: outlet.name, object_fn=lambda api, obj_id: api.outlets[obj_id], - supported_fn=async_outlet_supports_switching_fn, + supported_fn=async_outlet_switching_supported_fn, unique_id_fn=lambda hub, obj_id: f"outlet-{obj_id}", ), UnifiSwitchEntityDescription[PortForwarding, PortForward]( key="Port forward control", device_class=SwitchDeviceClass.SWITCH, entity_category=EntityCategory.CONFIG, - has_entity_name=True, icon="mdi:upload-network", - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.port_forwarding, - available_fn=lambda hub, obj_id: hub.available, control_fn=async_port_forward_control_fn, device_info_fn=async_port_forward_device_info_fn, is_on_fn=lambda hub, port_forward: port_forward.enabled, name_fn=lambda port_forward: f"{port_forward.name}", object_fn=lambda api, obj_id: api.port_forwarding[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"port_forward-{obj_id}", ), UnifiSwitchEntityDescription[Ports, Port]( key="PoE port control", device_class=SwitchDeviceClass.OUTLET, entity_category=EntityCategory.CONFIG, - has_entity_name=True, entity_registry_enabled_default=False, icon="mdi:ethernet", - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.ports, available_fn=async_device_available_fn, control_fn=async_poe_port_control_fn, @@ -263,24 +251,19 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = ( is_on_fn=lambda hub, port: port.poe_mode != "off", name_fn=lambda port: f"{port.name} PoE", object_fn=lambda api, obj_id: api.ports[obj_id], - supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe, + supported_fn=lambda hub, obj_id: bool(hub.api.ports[obj_id].port_poe), unique_id_fn=lambda hub, obj_id: f"poe-{obj_id}", ), UnifiSwitchEntityDescription[Wlans, Wlan]( key="WLAN control", device_class=SwitchDeviceClass.SWITCH, entity_category=EntityCategory.CONFIG, - has_entity_name=True, icon="mdi:wifi-check", - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.wlans, - available_fn=lambda hub, _: hub.available, control_fn=async_wlan_control_fn, device_info_fn=async_wlan_device_info_fn, is_on_fn=lambda hub, wlan: wlan.enabled, - name_fn=lambda wlan: None, object_fn=lambda api, obj_id: api.wlans[obj_id], - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"wlan-{obj_id}", ), ) diff --git a/homeassistant/components/unifi/update.py b/homeassistant/components/unifi/update.py index f112f47232c..a8fe3c83427 100644 --- a/homeassistant/components/unifi/update.py +++ b/homeassistant/components/unifi/update.py @@ -55,16 +55,12 @@ ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = ( UnifiUpdateEntityDescription[Devices, Device]( key="Upgrade device", device_class=UpdateDeviceClass.FIRMWARE, - has_entity_name=True, - allowed_fn=lambda hub, obj_id: True, api_handler_fn=lambda api: api.devices, available_fn=async_device_available_fn, control_fn=async_device_control_fn, device_info_fn=async_device_device_info_fn, - name_fn=lambda device: None, object_fn=lambda api, obj_id: api.devices[obj_id], state_fn=lambda api, device: device.state == 4, - supported_fn=lambda hub, obj_id: True, unique_id_fn=lambda hub, obj_id: f"device_update-{obj_id}", ), )