Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for control of ElkM1 sensors."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from elkm1_lib.const import SettingFormat, ZoneType
8 from elkm1_lib.counters import Counter
9 from elkm1_lib.elements import Element
10 from elkm1_lib.keypads import Keypad
11 from elkm1_lib.panel import Panel
12 from elkm1_lib.settings import Setting
13 from elkm1_lib.util import pretty_const
14 from elkm1_lib.zones import Zone
15 import voluptuous as vol
16 
17 from homeassistant.components.sensor import SensorEntity
18 from homeassistant.const import EntityCategory, UnitOfElectricPotential
19 from homeassistant.core import HomeAssistant
20 from homeassistant.exceptions import HomeAssistantError
21 from homeassistant.helpers import entity_platform
22 from homeassistant.helpers.entity_platform import AddEntitiesCallback
23 from homeassistant.helpers.typing import VolDictType
24 
25 from . import ElkM1ConfigEntry
26 from .const import ATTR_VALUE, ELK_USER_CODE_SERVICE_SCHEMA
27 from .entity import ElkAttachedEntity, ElkEntity, create_elk_entities
28 
29 SERVICE_SENSOR_COUNTER_REFRESH = "sensor_counter_refresh"
30 SERVICE_SENSOR_COUNTER_SET = "sensor_counter_set"
31 SERVICE_SENSOR_ZONE_BYPASS = "sensor_zone_bypass"
32 SERVICE_SENSOR_ZONE_TRIGGER = "sensor_zone_trigger"
33 UNDEFINED_TEMPERATURE = -40
34 
35 ELK_SET_COUNTER_SERVICE_SCHEMA: VolDictType = {
36  vol.Required(ATTR_VALUE): vol.All(vol.Coerce(int), vol.Range(0, 65535))
37 }
38 
39 
41  hass: HomeAssistant,
42  config_entry: ElkM1ConfigEntry,
43  async_add_entities: AddEntitiesCallback,
44 ) -> None:
45  """Create the Elk-M1 sensor platform."""
46  elk_data = config_entry.runtime_data
47  elk = elk_data.elk
48  entities: list[ElkEntity] = []
49  create_elk_entities(elk_data, elk.counters, "counter", ElkCounter, entities)
50  create_elk_entities(elk_data, elk.keypads, "keypad", ElkKeypad, entities)
51  create_elk_entities(elk_data, [elk.panel], "panel", ElkPanel, entities)
52  create_elk_entities(elk_data, elk.settings, "setting", ElkSetting, entities)
53  create_elk_entities(elk_data, elk.zones, "zone", ElkZone, entities)
54  async_add_entities(entities)
55 
56  platform = entity_platform.async_get_current_platform()
57 
58  platform.async_register_entity_service(
59  SERVICE_SENSOR_COUNTER_REFRESH,
60  None,
61  "async_counter_refresh",
62  )
63  platform.async_register_entity_service(
64  SERVICE_SENSOR_COUNTER_SET,
65  ELK_SET_COUNTER_SERVICE_SCHEMA,
66  "async_counter_set",
67  )
68  platform.async_register_entity_service(
69  SERVICE_SENSOR_ZONE_BYPASS,
70  ELK_USER_CODE_SERVICE_SCHEMA,
71  "async_zone_bypass",
72  )
73  platform.async_register_entity_service(
74  SERVICE_SENSOR_ZONE_TRIGGER,
75  None,
76  "async_zone_trigger",
77  )
78 
79 
80 def temperature_to_state(temperature: int, undefined_temperature: int) -> str | None:
81  """Convert temperature to a state."""
82  return f"{temperature}" if temperature > undefined_temperature else None
83 
84 
86  """Base representation of Elk-M1 sensor."""
87 
88  _attr_native_value: str | None = None
89 
90  async def async_counter_refresh(self) -> None:
91  """Refresh the value of a counter from the panel."""
92  if not isinstance(self, ElkCounter):
93  raise HomeAssistantError("supported only on ElkM1 Counter sensors")
94  self._element_element.get()
95 
96  async def async_counter_set(self, value: int | None = None) -> None:
97  """Set the value of a counter on the panel."""
98  if not isinstance(self, ElkCounter):
99  raise HomeAssistantError("supported only on ElkM1 Counter sensors")
100  if value is not None:
101  self._element_element.set(value)
102 
103  async def async_zone_bypass(self, code: int | None = None) -> None:
104  """Bypass zone."""
105  if not isinstance(self, ElkZone):
106  raise HomeAssistantError("supported only on ElkM1 Zone sensors")
107  if code is not None:
108  self._element_element.bypass(code)
109 
110  async def async_zone_trigger(self) -> None:
111  """Trigger zone."""
112  if not isinstance(self, ElkZone):
113  raise HomeAssistantError("supported only on ElkM1 Zone sensors")
114  self._element_element.trigger()
115 
116 
118  """Representation of an Elk-M1 Counter."""
119 
120  _attr_icon = "mdi:numeric"
121  _element: Counter
122 
123  def _element_changed(self, _: Element, changeset: Any) -> None:
124  self._attr_native_value_attr_native_value = self._element_element.value
125 
126 
128  """Representation of an Elk-M1 Keypad."""
129 
130  _attr_icon = "mdi:thermometer-lines"
131  _element: Keypad
132 
133  @property
134  def temperature_unit(self) -> str:
135  """Return the temperature unit."""
136  return self._temperature_unit
137 
138  @property
139  def native_unit_of_measurement(self) -> str:
140  """Return the unit of measurement."""
141  return self._temperature_unit
142 
143  @property
144  def extra_state_attributes(self) -> dict[str, Any]:
145  """Attributes of the sensor."""
146  attrs: dict[str, Any] = self.initial_attrsinitial_attrs()
147  attrs["area"] = self._element_element.area + 1
148  attrs["temperature"] = self._attr_native_value_attr_native_value
149  attrs["last_user_time"] = self._element_element.last_user_time.isoformat()
150  attrs["last_user"] = self._element_element.last_user + 1
151  attrs["code"] = self._element_element.code
152  attrs["last_user_name"] = self._elk_elk.users.username(self._element_element.last_user)
153  attrs["last_keypress"] = self._element_element.last_keypress
154  return attrs
155 
156  def _element_changed(self, _: Element, changeset: Any) -> None:
157  self._attr_native_value_attr_native_value = temperature_to_state(
158  self._element_element.temperature, UNDEFINED_TEMPERATURE
159  )
160 
161 
163  """Representation of an Elk-M1 Panel."""
164 
165  _attr_translation_key = "panel"
166  _attr_entity_category = EntityCategory.DIAGNOSTIC
167  _element: Panel
168 
169  @property
170  def extra_state_attributes(self) -> dict[str, Any]:
171  """Attributes of the sensor."""
172  attrs = self.initial_attrsinitial_attrs()
173  attrs["system_trouble_status"] = self._element_element.system_trouble_status
174  return attrs
175 
176  def _element_changed(self, _: Element, changeset: Any) -> None:
177  if self._elk_elk.is_connected():
178  self._attr_native_value_attr_native_value = (
179  "Paused" if self._element_element.remote_programming_status else "Connected"
180  )
181  else:
182  self._attr_native_value_attr_native_value = "Disconnected"
183 
184 
186  """Representation of an Elk-M1 Setting."""
187 
188  _attr_translation_key = "setting"
189  _element: Setting
190 
191  def _element_changed(self, _: Element, changeset: Any) -> None:
192  self._attr_native_value_attr_native_value = self._element_element.value
193 
194  @property
195  def extra_state_attributes(self) -> dict[str, Any]:
196  """Attributes of the sensor."""
197  attrs: dict[str, Any] = self.initial_attrsinitial_attrs()
198  attrs["value_format"] = SettingFormat(self._element_element.value_format).name.lower()
199  return attrs
200 
201 
203  """Representation of an Elk-M1 Zone."""
204 
205  _element: Zone
206 
207  @property
208  def icon(self) -> str:
209  """Icon to use in the frontend."""
210  zone_icons = {
211  ZoneType.FIRE_ALARM: "fire",
212  ZoneType.FIRE_VERIFIED: "fire",
213  ZoneType.FIRE_SUPERVISORY: "fire",
214  ZoneType.KEYFOB: "key",
215  ZoneType.NON_ALARM: "alarm-off",
216  ZoneType.MEDICAL_ALARM: "medical-bag",
217  ZoneType.POLICE_ALARM: "alarm-light",
218  ZoneType.POLICE_NO_INDICATION: "alarm-light",
219  ZoneType.KEY_MOMENTARY_ARM_DISARM: "power",
220  ZoneType.KEY_MOMENTARY_ARM_AWAY: "power",
221  ZoneType.KEY_MOMENTARY_ARM_STAY: "power",
222  ZoneType.KEY_MOMENTARY_DISARM: "power",
223  ZoneType.KEY_ON_OFF: "toggle-switch",
224  ZoneType.MUTE_AUDIBLES: "volume-mute",
225  ZoneType.POWER_SUPERVISORY: "power-plug",
226  ZoneType.TEMPERATURE: "thermometer-lines",
227  ZoneType.ANALOG_ZONE: "speedometer",
228  ZoneType.PHONE_KEY: "phone-classic",
229  ZoneType.INTERCOM_KEY: "deskphone",
230  }
231  return f"mdi:{zone_icons.get(self._element.definition, 'alarm-bell')}"
232 
233  @property
234  def extra_state_attributes(self) -> dict[str, Any]:
235  """Attributes of the sensor."""
236  attrs: dict[str, Any] = self.initial_attrsinitial_attrs()
237  attrs["physical_status"] = self._element_element.physical_status.name.lower()
238  attrs["logical_status"] = self._element_element.logical_status.name.lower()
239  attrs["definition"] = self._element_element.definition.name.lower()
240  attrs["area"] = self._element_element.area + 1
241  attrs["triggered_alarm"] = self._element_element.triggered_alarm
242  return attrs
243 
244  @property
245  def temperature_unit(self) -> str | None:
246  """Return the temperature unit."""
247  if self._element_element.definition == ZoneType.TEMPERATURE:
248  return self._temperature_unit
249  return None
250 
251  @property
252  def native_unit_of_measurement(self) -> str | None:
253  """Return the unit of measurement."""
254  if self._element_element.definition == ZoneType.TEMPERATURE:
255  return self._temperature_unit
256  if self._element_element.definition == ZoneType.ANALOG_ZONE:
257  return UnitOfElectricPotential.VOLT
258  return None
259 
260  def _element_changed(self, _: Element, changeset: Any) -> None:
261  if self._element_element.definition == ZoneType.TEMPERATURE:
262  self._attr_native_value_attr_native_value = temperature_to_state(
263  self._element_element.temperature, UNDEFINED_TEMPERATURE
264  )
265  elif self._element_element.definition == ZoneType.ANALOG_ZONE:
266  self._attr_native_value_attr_native_value = f"{self._element.voltage}"
267  else:
268  self._attr_native_value_attr_native_value = pretty_const(self._element_element.logical_status.name)
None _element_changed(self, Element _, Any changeset)
Definition: sensor.py:123
None _element_changed(self, Element _, Any changeset)
Definition: sensor.py:156
dict[str, Any] extra_state_attributes(self)
Definition: sensor.py:170
None _element_changed(self, Element _, Any changeset)
Definition: sensor.py:176
None _element_changed(self, Element _, Any changeset)
Definition: sensor.py:191
dict[str, Any] extra_state_attributes(self)
Definition: sensor.py:234
None _element_changed(self, Element _, Any changeset)
Definition: sensor.py:260
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
list[ElkEntity]|None create_elk_entities(ELKM1Data elk_data, Iterable[Element] elk_elements, str element_type, Any class_, list[ElkEntity] entities)
Definition: entity.py:30
str|None temperature_to_state(int temperature, int undefined_temperature)
Definition: sensor.py:80
None async_setup_entry(HomeAssistant hass, ElkM1ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:44