mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 09:17:53 +00:00
Streamline UniFi entity descriptions (#112136)
* Use kw_only=True to get rid of Mixins * Clarify which inputs are optional and make them have default values Add doc strings to optional inputs
This commit is contained in:
parent
d7507fd8a3
commit
99414d8b85
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Generic
|
||||
from typing import Any
|
||||
|
||||
import aiounifi
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
@ -57,21 +57,14 @@ async def async_power_cycle_port_control_fn(
|
||||
await api.request(DevicePowerCyclePortRequest.create(mac, int(index)))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiButtonEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
control_fn: Callable[[aiounifi.Controller, str], Coroutine[Any, Any, None]]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiButtonEntityDescription(
|
||||
ButtonEntityDescription,
|
||||
UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
UnifiButtonEntityDescriptionMixin[HandlerT, ApiItemT],
|
||||
ButtonEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
|
||||
):
|
||||
"""Class describing UniFi button entity."""
|
||||
|
||||
control_fn: Callable[[aiounifi.Controller, str], Coroutine[Any, Any, None]]
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
UnifiButtonEntityDescription[Devices, Device](
|
||||
@ -84,11 +77,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_restart_device_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda _: "Restart",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"device_restart-{obj_id}",
|
||||
),
|
||||
@ -106,7 +96,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda port: f"{port.name} Power Cycle",
|
||||
object_fn=lambda api, obj_id: api.ports[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda hub, obj_id: f"power_cycle-{obj_id}",
|
||||
),
|
||||
|
@ -6,7 +6,7 @@ from collections.abc import Callable, Mapping
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any, Generic
|
||||
from typing import Any
|
||||
|
||||
import aiounifi
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
@ -136,9 +136,9 @@ def async_device_heartbeat_timedelta_fn(hub: UnifiHub, obj_id: str) -> timedelta
|
||||
return timedelta(seconds=device.next_interval + 60)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiEntityTrackerDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Device tracker local functions."""
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiTrackerEntityDescription(UnifiEntityDescription[HandlerT, ApiItemT]):
|
||||
"""Class describing UniFi device tracker entity."""
|
||||
|
||||
heartbeat_timedelta_fn: Callable[[UnifiHub, str], timedelta]
|
||||
ip_address_fn: Callable[[aiounifi.Controller, str], str | None]
|
||||
@ -146,14 +146,6 @@ class UnifiEntityTrackerDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
hostname_fn: Callable[[aiounifi.Controller, str], str | None]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiTrackerEntityDescription(
|
||||
UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
UnifiEntityTrackerDescriptionMixin[HandlerT, ApiItemT],
|
||||
):
|
||||
"""Class describing UniFi device tracker entity."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
|
||||
UnifiTrackerEntityDescription[Clients, Client](
|
||||
key="Client device scanner",
|
||||
@ -173,7 +165,6 @@ 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],
|
||||
should_poll=False,
|
||||
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,
|
||||
@ -186,13 +177,10 @@ ENTITY_DESCRIPTIONS: tuple[UnifiTrackerEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=lambda api, obj_id: None,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
heartbeat_timedelta_fn=async_device_heartbeat_timedelta_fn,
|
||||
is_connected_fn=lambda ctrlr, obj_id: ctrlr.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],
|
||||
should_poll=False,
|
||||
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,
|
||||
|
@ -93,26 +93,26 @@ def async_client_device_info_fn(hub: UnifiHub, obj_id: str) -> DeviceInfo:
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiDescription(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
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]
|
||||
device_info_fn: Callable[[UnifiHub, str], DeviceInfo | None]
|
||||
event_is_on: tuple[EventKey, ...] | None
|
||||
event_to_subscribe: tuple[EventKey, ...] | None
|
||||
name_fn: Callable[[ApiItemT], str | None]
|
||||
object_fn: Callable[[aiounifi.Controller, str], ApiItemT]
|
||||
should_poll: bool
|
||||
supported_fn: Callable[[UnifiHub, str], bool | None]
|
||||
unique_id_fn: Callable[[UnifiHub, str], str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiEntityDescription(EntityDescription, UnifiDescription[HandlerT, ApiItemT]):
|
||||
"""UniFi Entity Description."""
|
||||
# Optional
|
||||
event_is_on: tuple[EventKey, ...] | None = None
|
||||
"""Which UniFi events should be used to consider state 'on'."""
|
||||
event_to_subscribe: tuple[EventKey, ...] | None = None
|
||||
"""Which UniFi events to listen on."""
|
||||
should_poll: bool = False
|
||||
"""If entity needs to do regular checks on state."""
|
||||
|
||||
|
||||
class UnifiEntity(Entity, Generic[HandlerT, ApiItemT]):
|
||||
|
@ -6,7 +6,6 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Generic
|
||||
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
from aiounifi.interfaces.wlans import Wlans
|
||||
@ -36,23 +35,16 @@ def async_wlan_qr_code_image_fn(hub: UnifiHub, wlan: Wlan) -> bytes:
|
||||
return hub.api.wlans.generate_wlan_qr_code(wlan)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiImageEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiImageEntityDescription(
|
||||
ImageEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
|
||||
):
|
||||
"""Class describing UniFi image entity."""
|
||||
|
||||
image_fn: Callable[[UnifiHub, ApiItemT], bytes]
|
||||
value_fn: Callable[[ApiItemT], str | None]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiImageEntityDescription(
|
||||
ImageEntityDescription,
|
||||
UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
UnifiImageEntityDescriptionMixin[HandlerT, ApiItemT],
|
||||
):
|
||||
"""Class describing UniFi image entity."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
|
||||
UnifiImageEntityDescription[Wlans, Wlan](
|
||||
key="WLAN QR Code",
|
||||
@ -63,11 +55,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.wlans,
|
||||
available_fn=async_wlan_available_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda wlan: "QR Code",
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=False,
|
||||
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,
|
||||
|
@ -9,7 +9,6 @@ from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Generic
|
||||
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
from aiounifi.interfaces.clients import Clients
|
||||
@ -154,33 +153,28 @@ def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiSensorEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
|
||||
value_fn: Callable[[UnifiHub, ApiItemT], datetime | float | str | None]
|
||||
|
||||
|
||||
@callback
|
||||
def async_device_state_value_fn(hub: UnifiHub, device: Device) -> str:
|
||||
"""Retrieve the state of the device."""
|
||||
return DEVICE_STATES[device.state]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiSensorEntityDescription(
|
||||
SensorEntityDescription,
|
||||
UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
UnifiSensorEntityDescriptionMixin[HandlerT, ApiItemT],
|
||||
SensorEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
|
||||
):
|
||||
"""Class describing UniFi sensor entity."""
|
||||
|
||||
value_fn: Callable[[UnifiHub, ApiItemT], datetime | float | str | None]
|
||||
|
||||
# Optional
|
||||
is_connected_fn: Callable[[UnifiHub, str], bool] | None = None
|
||||
# Custom function to determine whether a state change should be recorded
|
||||
"""Calculate if source is connected."""
|
||||
value_changed_fn: Callable[
|
||||
[StateType | date | datetime | Decimal, datetime | float | str | None],
|
||||
bool,
|
||||
] = lambda old, new: old != new
|
||||
"""Calculate whether a state change should be recorded."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
@ -196,12 +190,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_connected_fn=async_client_is_connected_fn,
|
||||
name_fn=lambda _: "RX",
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
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,
|
||||
@ -218,12 +209,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
device_info_fn=async_client_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_connected_fn=async_client_is_connected_fn,
|
||||
name_fn=lambda _: "TX",
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
should_poll=False,
|
||||
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,
|
||||
@ -239,11 +227,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.ports,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
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 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",
|
||||
@ -258,11 +243,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.clients,
|
||||
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 hub, _: hub.option_allow_uptime_sensors,
|
||||
unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}",
|
||||
value_fn=async_client_uptime_value_fn,
|
||||
@ -276,8 +258,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.wlans,
|
||||
available_fn=async_wlan_available_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda wlan: None,
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=True,
|
||||
@ -295,8 +275,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.outlets,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda outlet: f"{outlet.name} Outlet Power",
|
||||
object_fn=lambda api, obj_id: api.outlets[obj_id],
|
||||
should_poll=True,
|
||||
@ -315,11 +293,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: "AC Power Budget",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=async_device_outlet_supported_fn,
|
||||
unique_id_fn=lambda hub, obj_id: f"ac_power_budget-{obj_id}",
|
||||
value_fn=lambda hub, device: device.outlet_ac_power_budget,
|
||||
@ -335,11 +310,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: "AC Power Consumption",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=async_device_outlet_supported_fn,
|
||||
unique_id_fn=lambda hub, obj_id: f"ac_power_conumption-{obj_id}",
|
||||
value_fn=lambda hub, device: device.outlet_ac_power_consumption,
|
||||
@ -353,11 +325,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: "Uptime",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
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,
|
||||
@ -373,11 +342,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: "Temperature",
|
||||
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 hub, obj_id: f"device_temperature-{obj_id}",
|
||||
value_fn=lambda ctrlr, device: device.general_temperature,
|
||||
@ -391,11 +357,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
|
||||
api_handler_fn=lambda api: api.devices,
|
||||
available_fn=async_device_available_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: "State",
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
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,
|
||||
|
@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from collections.abc import Callable, Coroutine
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Generic
|
||||
from typing import Any
|
||||
|
||||
import aiounifi
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
@ -162,24 +162,20 @@ async def async_wlan_control_fn(hub: UnifiHub, obj_id: str, target: bool) -> Non
|
||||
await hub.api.request(WlanEnableRequest.create(obj_id, target))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiSwitchEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiSwitchEntityDescription(
|
||||
SwitchEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
|
||||
):
|
||||
"""Class describing UniFi switch entity."""
|
||||
|
||||
control_fn: Callable[[UnifiHub, str, bool], Coroutine[Any, Any, None]]
|
||||
is_on_fn: Callable[[UnifiHub, ApiItemT], bool]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiSwitchEntityDescription(
|
||||
SwitchEntityDescription,
|
||||
UnifiEntityDescription[HandlerT, ApiItemT],
|
||||
UnifiSwitchEntityDescriptionMixin[HandlerT, ApiItemT],
|
||||
):
|
||||
"""Class describing UniFi switch entity."""
|
||||
|
||||
# Optional
|
||||
custom_subscribe: Callable[[aiounifi.Controller], SubscriptionT] | None = None
|
||||
"""Callback for additional subscriptions to any UniFi handler."""
|
||||
only_event_for_state_change: bool = False
|
||||
"""Use only UniFi events to trigger state changes."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
@ -200,7 +196,6 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
name_fn=lambda client: None,
|
||||
object_fn=lambda api, obj_id: api.clients[obj_id],
|
||||
only_event_for_state_change=True,
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"block-{obj_id}",
|
||||
),
|
||||
@ -214,12 +209,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
control_fn=async_dpi_group_control_fn,
|
||||
custom_subscribe=lambda api: api.dpi_apps.subscribe,
|
||||
device_info_fn=async_dpi_group_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
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],
|
||||
should_poll=False,
|
||||
supported_fn=lambda c, obj_id: bool(c.api.dpi_groups[obj_id].dpiapp_ids),
|
||||
unique_id_fn=lambda hub, obj_id: obj_id,
|
||||
),
|
||||
@ -232,12 +224,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_outlet_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
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],
|
||||
should_poll=False,
|
||||
supported_fn=async_outlet_supports_switching_fn,
|
||||
unique_id_fn=lambda hub, obj_id: f"outlet-{obj_id}",
|
||||
),
|
||||
@ -252,12 +241,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
available_fn=lambda hub, obj_id: hub.available,
|
||||
control_fn=async_port_forward_control_fn,
|
||||
device_info_fn=async_port_forward_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
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],
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"port_forward-{obj_id}",
|
||||
),
|
||||
@ -273,12 +259,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_poe_port_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
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],
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: hub.api.ports[obj_id].port_poe,
|
||||
unique_id_fn=lambda hub, obj_id: f"poe-{obj_id}",
|
||||
),
|
||||
@ -293,12 +276,9 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSwitchEntityDescription, ...] = (
|
||||
available_fn=lambda hub, _: hub.available,
|
||||
control_fn=async_wlan_control_fn,
|
||||
device_info_fn=async_wlan_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
is_on_fn=lambda hub, wlan: wlan.enabled,
|
||||
name_fn=lambda wlan: None,
|
||||
object_fn=lambda api, obj_id: api.wlans[obj_id],
|
||||
should_poll=False,
|
||||
supported_fn=lambda hub, obj_id: True,
|
||||
unique_id_fn=lambda hub, obj_id: f"wlan-{obj_id}",
|
||||
),
|
||||
@ -354,15 +334,11 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
"""Base representation of a UniFi switch."""
|
||||
|
||||
entity_description: UnifiSwitchEntityDescription[HandlerT, ApiItemT]
|
||||
only_event_for_state_change = False
|
||||
|
||||
@callback
|
||||
def async_initiate_state(self) -> None:
|
||||
"""Initiate entity state."""
|
||||
self.async_update_state(ItemEvent.ADDED, self._obj_id)
|
||||
self.only_event_for_state_change = (
|
||||
self.entity_description.only_event_for_state_change
|
||||
)
|
||||
self.async_update_state(ItemEvent.ADDED, self._obj_id, first_update=True)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on switch."""
|
||||
@ -373,12 +349,14 @@ class UnifiSwitchEntity(UnifiEntity[HandlerT, ApiItemT], SwitchEntity):
|
||||
await self.entity_description.control_fn(self.hub, self._obj_id, False)
|
||||
|
||||
@callback
|
||||
def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
|
||||
def async_update_state(
|
||||
self, event: ItemEvent, obj_id: str, first_update: bool = False
|
||||
) -> None:
|
||||
"""Update entity state.
|
||||
|
||||
Update attr_is_on.
|
||||
"""
|
||||
if self.only_event_for_state_change:
|
||||
if not first_update and self.entity_description.only_event_for_state_change:
|
||||
return
|
||||
|
||||
description = self.entity_description
|
||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
from collections.abc import Callable, Coroutine
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any, Generic, TypeVar
|
||||
from typing import Any, TypeVar
|
||||
|
||||
import aiounifi
|
||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||
@ -40,23 +40,16 @@ async def async_device_control_fn(api: aiounifi.Controller, obj_id: str) -> None
|
||||
await api.request(DeviceUpgradeRequest.create(obj_id))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiUpdateEntityDescriptionMixin(Generic[_HandlerT, _DataT]):
|
||||
"""Validate and load entities from different UniFi handlers."""
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class UnifiUpdateEntityDescription(
|
||||
UpdateEntityDescription, UnifiEntityDescription[_HandlerT, _DataT]
|
||||
):
|
||||
"""Class describing UniFi update entity."""
|
||||
|
||||
control_fn: Callable[[aiounifi.Controller, str], Coroutine[Any, Any, None]]
|
||||
state_fn: Callable[[aiounifi.Controller, _DataT], bool]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiUpdateEntityDescription(
|
||||
UpdateEntityDescription,
|
||||
UnifiEntityDescription[_HandlerT, _DataT],
|
||||
UnifiUpdateEntityDescriptionMixin[_HandlerT, _DataT],
|
||||
):
|
||||
"""Class describing UniFi update entity."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = (
|
||||
UnifiUpdateEntityDescription[Devices, Device](
|
||||
key="Upgrade device",
|
||||
@ -67,11 +60,8 @@ ENTITY_DESCRIPTIONS: tuple[UnifiUpdateEntityDescription, ...] = (
|
||||
available_fn=async_device_available_fn,
|
||||
control_fn=async_device_control_fn,
|
||||
device_info_fn=async_device_device_info_fn,
|
||||
event_is_on=None,
|
||||
event_to_subscribe=None,
|
||||
name_fn=lambda device: None,
|
||||
object_fn=lambda api, obj_id: api.devices[obj_id],
|
||||
should_poll=False,
|
||||
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}",
|
||||
|
Loading…
x
Reference in New Issue
Block a user