Home Assistant Unofficial Reference 2024.12.1
entity_helper.py
Go to the documentation of this file.
1 """UniFi Network entity helper."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime, timedelta
6 
7 import aiounifi
8 from aiounifi.models.device import DeviceSetPoePortModeRequest
9 
10 from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
11 from homeassistant.helpers.dispatcher import async_dispatcher_send
12 from homeassistant.helpers.event import async_call_later, async_track_time_interval
13 import homeassistant.util.dt as dt_util
14 
15 
17  """UniFi Network integration handling platforms for entity registration."""
18 
19  def __init__(self, hass: HomeAssistant, api: aiounifi.Controller) -> None:
20  """Initialize the UniFi entity loader."""
21  self.hasshass = hass
22  self.apiapi = api
23 
24  self._device_command_device_command = UnifiDeviceCommand(hass, api)
25  self._heartbeat_heartbeat = UnifiEntityHeartbeat(hass)
26 
27  @callback
28  def reset(self) -> None:
29  """Cancel timers."""
30  self._device_command_device_command.reset()
31  self._heartbeat_heartbeat.reset()
32 
33  @callback
34  def initialize(self) -> None:
35  """Initialize entity helper."""
36  self._heartbeat_heartbeat.initialize()
37 
38  @property
39  def signal_heartbeat(self) -> str:
40  """Event to signal new heartbeat missed."""
41  return self._heartbeat_heartbeat.signal
42 
43  @callback
44  def update_heartbeat(self, unique_id: str, heartbeat_expire_time: datetime) -> None:
45  """Update device time in heartbeat monitor."""
46  self._heartbeat_heartbeat.update(unique_id, heartbeat_expire_time)
47 
48  @callback
49  def remove_heartbeat(self, unique_id: str) -> None:
50  """Update device time in heartbeat monitor."""
51  self._heartbeat_heartbeat.remove(unique_id)
52 
53  @callback
55  self, device_id: str, port_idx: int, poe_mode: str
56  ) -> None:
57  """Queue commands to execute them together per device."""
58  self._device_command_device_command.queue_poe_command(device_id, port_idx, poe_mode)
59 
60 
62  """UniFi entity heartbeat monitor."""
63 
64  CHECK_HEARTBEAT_INTERVAL = timedelta(seconds=1)
65 
66  def __init__(self, hass: HomeAssistant) -> None:
67  """Initialize the heartbeat monitor."""
68  self.hasshass = hass
69 
70  self._cancel_heartbeat_check_cancel_heartbeat_check: CALLBACK_TYPE | None = None
71  self._heartbeat_time: dict[str, datetime] = {}
72 
73  @callback
74  def reset(self) -> None:
75  """Cancel timers."""
76  if self._cancel_heartbeat_check_cancel_heartbeat_check:
77  self._cancel_heartbeat_check_cancel_heartbeat_check()
78  self._cancel_heartbeat_check_cancel_heartbeat_check = None
79 
80  @callback
81  def initialize(self) -> None:
82  """Initialize heartbeat monitor."""
83  self._cancel_heartbeat_check_cancel_heartbeat_check = async_track_time_interval(
84  self.hasshass, self._check_for_stale_check_for_stale, self.CHECK_HEARTBEAT_INTERVALCHECK_HEARTBEAT_INTERVAL
85  )
86 
87  @property
88  def signal(self) -> str:
89  """Event to signal new heartbeat missed."""
90  return "unifi-heartbeat-missed"
91 
92  @callback
93  def update(self, unique_id: str, heartbeat_expire_time: datetime) -> None:
94  """Update device time in heartbeat monitor."""
95  self._heartbeat_time[unique_id] = heartbeat_expire_time
96 
97  @callback
98  def remove(self, unique_id: str) -> None:
99  """Remove device from heartbeat monitor."""
100  self._heartbeat_time.pop(unique_id, None)
101 
102  @callback
103  def _check_for_stale(self, *_: datetime) -> None:
104  """Check for any devices scheduled to be marked disconnected."""
105  now = dt_util.utcnow()
106 
107  unique_ids_to_remove = []
108  for unique_id, heartbeat_expire_time in self._heartbeat_time.items():
109  if now > heartbeat_expire_time:
110  async_dispatcher_send(self.hasshass, f"{self.signal}_{unique_id}")
111  unique_ids_to_remove.append(unique_id)
112 
113  for unique_id in unique_ids_to_remove:
114  del self._heartbeat_time[unique_id]
115 
116 
118  """UniFi Device command helper class."""
119 
120  COMMAND_DELAY = 5
121 
122  def __init__(self, hass: HomeAssistant, api: aiounifi.Controller) -> None:
123  """Initialize device command helper."""
124  self.hasshass = hass
125  self.apiapi = api
126 
127  self._command_queue: dict[str, dict[int, str]] = {}
128  self._cancel_command_cancel_command: CALLBACK_TYPE | None = None
129 
130  @callback
131  def reset(self) -> None:
132  """Cancel timers."""
133  if self._cancel_command_cancel_command:
134  self._cancel_command_cancel_command()
135  self._cancel_command_cancel_command = None
136 
137  @callback
138  def queue_poe_command(self, device_id: str, port_idx: int, poe_mode: str) -> None:
139  """Queue commands to execute them together per device."""
140  self.resetreset()
141 
142  device_queue = self._command_queue.setdefault(device_id, {})
143  device_queue[port_idx] = poe_mode
144 
145  async def _command(now: datetime) -> None:
146  """Execute previously queued commands."""
147  queue = self._command_queue.copy()
148  self._command_queue.clear()
149  for dev_id, device_commands in queue.items():
150  device = self.apiapi.devices[dev_id]
151  commands = list(device_commands.items())
152  await self.apiapi.request(
153  DeviceSetPoePortModeRequest.create(device, targets=commands)
154  )
155 
156  self._cancel_command_cancel_command = async_call_later(self.hasshass, self.COMMAND_DELAYCOMMAND_DELAY, _command)
None __init__(self, HomeAssistant hass, aiounifi.Controller api)
None queue_poe_command(self, str device_id, int port_idx, str poe_mode)
None update(self, str unique_id, datetime heartbeat_expire_time)
None __init__(self, HomeAssistant hass, aiounifi.Controller api)
None queue_poe_port_command(self, str device_id, int port_idx, str poe_mode)
None update_heartbeat(self, str unique_id, datetime heartbeat_expire_time)
bool remove(self, _T matcher)
Definition: match.py:214
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)
Definition: event.py:1597
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679