Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Base entity for Geniushub."""
2 
3 from datetime import datetime, timedelta
4 from typing import Any
5 
6 from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
7 from homeassistant.helpers.dispatcher import async_dispatcher_connect
8 from homeassistant.helpers.entity import Entity
9 import homeassistant.util.dt as dt_util
10 
11 from . import ATTR_DURATION, ATTR_ZONE_MODE, DOMAIN, SVC_SET_ZONE_OVERRIDE
12 
13 # temperature is repeated here, as it gives access to high-precision temps
14 GH_ZONE_ATTRS = ["mode", "temperature", "type", "occupied", "override"]
15 GH_DEVICE_ATTRS = {
16  "luminance": "luminance",
17  "measuredTemperature": "measured_temperature",
18  "occupancyTrigger": "occupancy_trigger",
19  "setback": "setback",
20  "setTemperature": "set_temperature",
21  "wakeupInterval": "wakeup_interval",
22 }
23 
24 
26  """Base for all Genius Hub entities."""
27 
28  _attr_should_poll = False
29 
30  def __init__(self) -> None:
31  """Initialize the entity."""
32  self._unique_id: str | None = None
33 
34  async def async_added_to_hass(self) -> None:
35  """Set up a listener when this entity is added to HA."""
36  self.async_on_removeasync_on_remove(async_dispatcher_connect(self.hasshass, DOMAIN, self._refresh_refresh))
37 
38  async def _refresh(self, payload: dict | None = None) -> None:
39  """Process any signals."""
40  self.async_schedule_update_ha_stateasync_schedule_update_ha_state(force_refresh=True)
41 
42  @property
43  def unique_id(self) -> str | None:
44  """Return a unique ID."""
45  return self._unique_id
46 
47 
49  """Base for all Genius Hub devices."""
50 
51  def __init__(self, broker, device) -> None:
52  """Initialize the Device."""
53  super().__init__()
54 
55  self._device_device = device
56  self._unique_id_unique_id = f"{broker.hub_uid}_device_{device.id}"
57  self._last_comms_last_comms: datetime | None = None
58  self._state_attr_state_attr = None
59 
60  @property
61  def extra_state_attributes(self) -> dict[str, Any]:
62  """Return the device state attributes."""
63  attrs = {}
64  attrs["assigned_zone"] = self._device_device.data["assignedZones"][0]["name"]
65  if self._last_comms_last_comms:
66  attrs["last_comms"] = self._last_comms_last_comms.isoformat()
67 
68  state = dict(self._device_device.data["state"])
69  if "_state" in self._device_device.data: # only via v3 API
70  state.update(self._device_device.data["_state"])
71 
72  attrs["state"] = {
73  GH_DEVICE_ATTRS[k]: v for k, v in state.items() if k in GH_DEVICE_ATTRS
74  }
75 
76  return attrs
77 
78  async def async_update(self) -> None:
79  """Update an entity's state data."""
80  if "_state" in self._device_device.data: # only via v3 API
81  self._last_comms_last_comms = dt_util.utc_from_timestamp(
82  self._device_device.data["_state"]["lastComms"]
83  )
84 
85 
87  """Base for all Genius Hub zones."""
88 
89  def __init__(self, broker, zone) -> None:
90  """Initialize the Zone."""
91  super().__init__()
92 
93  self._zone_zone = zone
94  self._unique_id_unique_id = f"{broker.hub_uid}_zone_{zone.id}"
95 
96  async def _refresh(self, payload: dict | None = None) -> None:
97  """Process any signals."""
98  if payload is None:
99  self.async_schedule_update_ha_stateasync_schedule_update_ha_state(force_refresh=True)
100  return
101 
102  if payload["unique_id"] != self._unique_id_unique_id:
103  return
104 
105  if payload["service"] == SVC_SET_ZONE_OVERRIDE:
106  temperature = round(payload["data"][ATTR_TEMPERATURE] * 10) / 10
107  duration = payload["data"].get(ATTR_DURATION, timedelta(hours=1))
108 
109  await self._zone_zone.set_override(temperature, int(duration.total_seconds()))
110  return
111 
112  mode = payload["data"][ATTR_ZONE_MODE]
113 
114  if mode == "footprint" and not self._zone_zone._has_pir: # noqa: SLF001
115  raise TypeError(
116  f"'{self.entity_id}' cannot support footprint mode (it has no PIR)"
117  )
118 
119  await self._zone_zone.set_mode(mode)
120 
121  @property
122  def name(self) -> str:
123  """Return the name of the climate device."""
124  return self._zone_zone.name
125 
126  @property
127  def extra_state_attributes(self) -> dict[str, Any]:
128  """Return the device state attributes."""
129  status = {k: v for k, v in self._zone_zone.data.items() if k in GH_ZONE_ATTRS}
130  return {"status": status}
131 
132 
134  """Base for Genius Heating Zones."""
135 
136  _max_temp: float
137  _min_temp: float
138 
139  @property
140  def current_temperature(self) -> float | None:
141  """Return the current temperature."""
142  return self._zone_zone.data.get("temperature")
143 
144  @property
145  def target_temperature(self) -> float:
146  """Return the temperature we try to reach."""
147  return self._zone_zone.data["setpoint"]
148 
149  @property
150  def min_temp(self) -> float:
151  """Return max valid temperature that can be set."""
152  return self._min_temp
153 
154  @property
155  def max_temp(self) -> float:
156  """Return max valid temperature that can be set."""
157  return self._max_temp
158 
159  @property
160  def temperature_unit(self) -> str:
161  """Return the unit of measurement."""
162  return UnitOfTemperature.CELSIUS
163 
164  async def async_set_temperature(self, **kwargs) -> None:
165  """Set a new target temperature for this zone."""
166  await self._zone_zone.set_override(
167  kwargs[ATTR_TEMPERATURE], kwargs.get(ATTR_DURATION, 3600)
168  )
None _refresh(self, dict|None payload=None)
Definition: entity.py:38
None _refresh(self, dict|None payload=None)
Definition: entity.py:96
None async_schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1265
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103