Home Assistant Unofficial Reference 2024.12.1
button.py
Go to the documentation of this file.
1 """Button platform for UniFi Network integration.
2 
3 Support for restarting UniFi devices.
4 """
5 
6 from __future__ import annotations
7 
8 from collections.abc import Callable, Coroutine
9 from dataclasses import dataclass
10 import secrets
11 from typing import TYPE_CHECKING, Any
12 
13 import aiounifi
14 from aiounifi.interfaces.api_handlers import ItemEvent
15 from aiounifi.interfaces.devices import Devices
16 from aiounifi.interfaces.ports import Ports
17 from aiounifi.interfaces.wlans import Wlans
18 from aiounifi.models.api import ApiItemT
19 from aiounifi.models.device import (
20  Device,
21  DevicePowerCyclePortRequest,
22  DeviceRestartRequest,
23 )
24 from aiounifi.models.port import Port
25 from aiounifi.models.wlan import Wlan, WlanChangePasswordRequest
26 
28  ButtonDeviceClass,
29  ButtonEntity,
30  ButtonEntityDescription,
31 )
32 from homeassistant.const import EntityCategory
33 from homeassistant.core import HomeAssistant, callback
34 from homeassistant.helpers.entity_platform import AddEntitiesCallback
35 
36 from . import UnifiConfigEntry
37 from .entity import (
38  HandlerT,
39  UnifiEntity,
40  UnifiEntityDescription,
41  async_device_available_fn,
42  async_device_device_info_fn,
43  async_wlan_available_fn,
44  async_wlan_device_info_fn,
45 )
46 
47 if TYPE_CHECKING:
48  from .hub import UnifiHub
49 
50 
51 @callback
52 def async_port_power_cycle_available_fn(hub: UnifiHub, obj_id: str) -> bool:
53  """Check if port allows power cycle action."""
54  if not async_device_available_fn(hub, obj_id):
55  return False
56  return bool(hub.api.ports[obj_id].poe_enable)
57 
58 
60  api: aiounifi.Controller, obj_id: str
61 ) -> None:
62  """Restart device."""
63  await api.request(DeviceRestartRequest.create(obj_id))
64 
65 
67  api: aiounifi.Controller, obj_id: str
68 ) -> None:
69  """Restart device."""
70  mac, _, index = obj_id.partition("_")
71  await api.request(DevicePowerCyclePortRequest.create(mac, int(index)))
72 
73 
75  api: aiounifi.Controller, obj_id: str
76 ) -> None:
77  """Regenerate WLAN password."""
78  await api.request(
79  WlanChangePasswordRequest.create(obj_id, secrets.token_urlsafe(15))
80  )
81 
82 
83 @dataclass(frozen=True, kw_only=True)
85  ButtonEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
86 ):
87  """Class describing UniFi button entity."""
88 
89  control_fn: Callable[[aiounifi.Controller, str], Coroutine[Any, Any, None]]
90 
91 
92 ENTITY_DESCRIPTIONS: tuple[UnifiButtonEntityDescription, ...] = (
93  UnifiButtonEntityDescription[Devices, Device](
94  key="Device restart",
95  entity_category=EntityCategory.CONFIG,
96  device_class=ButtonDeviceClass.RESTART,
97  api_handler_fn=lambda api: api.devices,
98  available_fn=async_device_available_fn,
99  control_fn=async_restart_device_control_fn,
100  device_info_fn=async_device_device_info_fn,
101  name_fn=lambda _: "Restart",
102  object_fn=lambda api, obj_id: api.devices[obj_id],
103  unique_id_fn=lambda hub, obj_id: f"device_restart-{obj_id}",
104  ),
105  UnifiButtonEntityDescription[Ports, Port](
106  key="PoE power cycle",
107  entity_category=EntityCategory.CONFIG,
108  device_class=ButtonDeviceClass.RESTART,
109  api_handler_fn=lambda api: api.ports,
110  available_fn=async_port_power_cycle_available_fn,
111  control_fn=async_power_cycle_port_control_fn,
112  device_info_fn=async_device_device_info_fn,
113  name_fn=lambda port: f"{port.name} Power Cycle",
114  object_fn=lambda api, obj_id: api.ports[obj_id],
115  supported_fn=lambda hub, obj_id: bool(hub.api.ports[obj_id].port_poe),
116  unique_id_fn=lambda hub, obj_id: f"power_cycle-{obj_id}",
117  ),
118  UnifiButtonEntityDescription[Wlans, Wlan](
119  key="WLAN regenerate password",
120  translation_key="wlan_regenerate_password",
121  device_class=ButtonDeviceClass.UPDATE,
122  entity_category=EntityCategory.CONFIG,
123  entity_registry_enabled_default=False,
124  api_handler_fn=lambda api: api.wlans,
125  available_fn=async_wlan_available_fn,
126  control_fn=async_regenerate_password_control_fn,
127  device_info_fn=async_wlan_device_info_fn,
128  name_fn=lambda wlan: "Regenerate Password",
129  object_fn=lambda api, obj_id: api.wlans[obj_id],
130  unique_id_fn=lambda hub, obj_id: f"regenerate_password-{obj_id}",
131  ),
132 )
133 
134 
136  hass: HomeAssistant,
137  config_entry: UnifiConfigEntry,
138  async_add_entities: AddEntitiesCallback,
139 ) -> None:
140  """Set up button platform for UniFi Network integration."""
141  config_entry.runtime_data.entity_loader.register_platform(
142  async_add_entities, UnifiButtonEntity, ENTITY_DESCRIPTIONS, requires_admin=True
143  )
144 
145 
146 class UnifiButtonEntity(UnifiEntity[HandlerT, ApiItemT], ButtonEntity):
147  """Base representation of a UniFi button."""
148 
149  entity_description: UnifiButtonEntityDescription[HandlerT, ApiItemT]
150 
151  async def async_press(self) -> None:
152  """Press the button."""
153  await self.entity_descriptionentity_description.control_fn(self.apiapi, self._obj_id_obj_id)
154 
155  @callback
156  def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
157  """Update entity state."""
None async_update_state(self, ItemEvent event, str obj_id)
Definition: entity.py:262
None async_power_cycle_port_control_fn(aiounifi.Controller api, str obj_id)
Definition: button.py:68
bool async_port_power_cycle_available_fn(UnifiHub hub, str obj_id)
Definition: button.py:52
None async_setup_entry(HomeAssistant hass, UnifiConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: button.py:139
None async_restart_device_control_fn(aiounifi.Controller api, str obj_id)
Definition: button.py:61
None async_regenerate_password_control_fn(aiounifi.Controller api, str obj_id)
Definition: button.py:76
bool async_device_available_fn(UnifiHub hub, str obj_id)
Definition: entity.py:40