Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for AlarmDecoder zone states- represented as binary sensors."""
2 
3 import logging
4 
5 from homeassistant.components.binary_sensor import BinarySensorEntity
6 from homeassistant.core import HomeAssistant
7 from homeassistant.helpers.dispatcher import async_dispatcher_connect
8 from homeassistant.helpers.entity_platform import AddEntitiesCallback
9 
10 from . import AlarmDecoderConfigEntry
11 from .const import (
12  CONF_RELAY_ADDR,
13  CONF_RELAY_CHAN,
14  CONF_ZONE_LOOP,
15  CONF_ZONE_NAME,
16  CONF_ZONE_NUMBER,
17  CONF_ZONE_RFID,
18  CONF_ZONE_TYPE,
19  DEFAULT_ZONE_OPTIONS,
20  OPTIONS_ZONES,
21  SIGNAL_REL_MESSAGE,
22  SIGNAL_RFX_MESSAGE,
23  SIGNAL_ZONE_FAULT,
24  SIGNAL_ZONE_RESTORE,
25 )
26 from .entity import AlarmDecoderEntity
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 ATTR_RF_BIT0 = "rf_bit0"
31 ATTR_RF_LOW_BAT = "rf_low_battery"
32 ATTR_RF_SUPERVISED = "rf_supervised"
33 ATTR_RF_BIT3 = "rf_bit3"
34 ATTR_RF_LOOP3 = "rf_loop3"
35 ATTR_RF_LOOP2 = "rf_loop2"
36 ATTR_RF_LOOP4 = "rf_loop4"
37 ATTR_RF_LOOP1 = "rf_loop1"
38 
39 
41  hass: HomeAssistant,
42  entry: AlarmDecoderConfigEntry,
43  async_add_entities: AddEntitiesCallback,
44 ) -> None:
45  """Set up for AlarmDecoder sensor."""
46 
47  client = entry.runtime_data.client
48  zones = entry.options.get(OPTIONS_ZONES, DEFAULT_ZONE_OPTIONS)
49 
50  entities = []
51  for zone_num in zones:
52  zone_info = zones[zone_num]
53  zone_type = zone_info[CONF_ZONE_TYPE]
54  zone_name = zone_info[CONF_ZONE_NAME]
55  zone_rfid = zone_info.get(CONF_ZONE_RFID)
56  zone_loop = zone_info.get(CONF_ZONE_LOOP)
57  relay_addr = zone_info.get(CONF_RELAY_ADDR)
58  relay_chan = zone_info.get(CONF_RELAY_CHAN)
59  entity = AlarmDecoderBinarySensor(
60  client,
61  zone_num,
62  zone_name,
63  zone_type,
64  zone_rfid,
65  zone_loop,
66  relay_addr,
67  relay_chan,
68  )
69  entities.append(entity)
70 
71  async_add_entities(entities)
72 
73 
75  """Representation of an AlarmDecoder binary sensor."""
76 
77  _attr_should_poll = False
78 
79  def __init__(
80  self,
81  client,
82  zone_number,
83  zone_name,
84  zone_type,
85  zone_rfid,
86  zone_loop,
87  relay_addr,
88  relay_chan,
89  ):
90  """Initialize the binary_sensor."""
91  super().__init__(client)
92  self._attr_unique_id_attr_unique_id = f"{client.serial_number}-zone-{zone_number}"
93  self._zone_number_zone_number = int(zone_number)
94  self._zone_type_zone_type = zone_type
95  self._attr_name_attr_name = zone_name
96  self._attr_is_on_attr_is_on = False
97  self._rfid_rfid = zone_rfid
98  self._loop_loop = zone_loop
99  self._relay_addr_relay_addr = relay_addr
100  self._relay_chan_relay_chan = relay_chan
101  self._attr_device_class_attr_device_class = zone_type
102  self._attr_extra_state_attributes_attr_extra_state_attributes = {
103  CONF_ZONE_NUMBER: self._zone_number_zone_number,
104  }
105 
106  async def async_added_to_hass(self) -> None:
107  """Register callbacks."""
108  self.async_on_removeasync_on_remove(
109  async_dispatcher_connect(self.hasshass, SIGNAL_ZONE_FAULT, self._fault_callback_fault_callback)
110  )
111 
112  self.async_on_removeasync_on_remove(
114  self.hasshass, SIGNAL_ZONE_RESTORE, self._restore_callback_restore_callback
115  )
116  )
117 
118  self.async_on_removeasync_on_remove(
120  self.hasshass, SIGNAL_RFX_MESSAGE, self._rfx_message_callback_rfx_message_callback
121  )
122  )
123 
124  self.async_on_removeasync_on_remove(
126  self.hasshass, SIGNAL_REL_MESSAGE, self._rel_message_callback_rel_message_callback
127  )
128  )
129 
130  def _fault_callback(self, zone):
131  """Update the zone's state, if needed."""
132  if zone is None or int(zone) == self._zone_number_zone_number:
133  self._attr_is_on_attr_is_on = True
134  self.schedule_update_ha_stateschedule_update_ha_state()
135 
136  def _restore_callback(self, zone):
137  """Update the zone's state, if needed."""
138  if zone is None or (int(zone) == self._zone_number_zone_number and not self._loop_loop):
139  self._attr_is_on_attr_is_on = False
140  self.schedule_update_ha_stateschedule_update_ha_state()
141 
142  def _rfx_message_callback(self, message):
143  """Update RF state."""
144  if self._rfid_rfid and message and message.serial_number == self._rfid_rfid:
145  rfstate = message.value
146  if self._loop_loop:
147  self._attr_is_on_attr_is_on = bool(message.loop[self._loop_loop - 1])
148  attr = {CONF_ZONE_NUMBER: self._zone_number_zone_number}
149  if self._rfid_rfid and rfstate is not None:
150  attr[ATTR_RF_BIT0] = bool(rfstate & 0x01)
151  attr[ATTR_RF_LOW_BAT] = bool(rfstate & 0x02)
152  attr[ATTR_RF_SUPERVISED] = bool(rfstate & 0x04)
153  attr[ATTR_RF_BIT3] = bool(rfstate & 0x08)
154  attr[ATTR_RF_LOOP3] = bool(rfstate & 0x10)
155  attr[ATTR_RF_LOOP2] = bool(rfstate & 0x20)
156  attr[ATTR_RF_LOOP4] = bool(rfstate & 0x40)
157  attr[ATTR_RF_LOOP1] = bool(rfstate & 0x80)
158  self._attr_extra_state_attributes_attr_extra_state_attributes = attr
159  self.schedule_update_ha_stateschedule_update_ha_state()
160 
161  def _rel_message_callback(self, message):
162  """Update relay / expander state."""
163 
164  if self._relay_addr_relay_addr == message.address and self._relay_chan_relay_chan == message.channel:
165  _LOGGER.debug(
166  "%s %d:%d value:%d",
167  "Relay" if message.type == message.RELAY else "ZoneExpander",
168  message.address,
169  message.channel,
170  message.value,
171  )
172  self._attr_is_on_attr_is_on = bool(message.value)
173  self.schedule_update_ha_stateschedule_update_ha_state()
def __init__(self, client, zone_number, zone_name, zone_type, zone_rfid, zone_loop, relay_addr, relay_chan)
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None schedule_update_ha_state(self, bool force_refresh=False)
Definition: entity.py:1244
None async_setup_entry(HomeAssistant hass, AlarmDecoderConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103