* Enable alarmdecoder to see open/close state of bypassed zones when armed The alarmdecoder component already reported RF state bits as attributes. If the user knows which loop is set up for the zone in the alarm panel, they can use that information to tell whether the zone is open or closed even when the system is armed by monitoring the appropriate attribute. That’s awkward, so this commit enables the user to simply configure which loop is used and the component will update the state itself. * Simplify, also it's more correct to treat it as a state change rather than a permanent state, since it's possible the decoder might miss some events. * Remove relative import
145 lines
5.1 KiB
Python
145 lines
5.1 KiB
Python
"""
|
|
Support for AlarmDecoder zone states- represented as binary sensors.
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
https://home-assistant.io/components/binary_sensor.alarmdecoder/
|
|
"""
|
|
import logging
|
|
|
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
|
from homeassistant.components.alarmdecoder import (
|
|
ZONE_SCHEMA, CONF_ZONES, CONF_ZONE_NAME, CONF_ZONE_TYPE,
|
|
CONF_ZONE_RFID, CONF_ZONE_LOOP, SIGNAL_ZONE_FAULT, SIGNAL_ZONE_RESTORE,
|
|
SIGNAL_RFX_MESSAGE, SIGNAL_REL_MESSAGE, CONF_RELAY_ADDR,
|
|
CONF_RELAY_CHAN)
|
|
|
|
DEPENDENCIES = ['alarmdecoder']
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
ATTR_RF_BIT0 = 'rf_bit0'
|
|
ATTR_RF_LOW_BAT = 'rf_low_battery'
|
|
ATTR_RF_SUPERVISED = 'rf_supervised'
|
|
ATTR_RF_BIT3 = 'rf_bit3'
|
|
ATTR_RF_LOOP3 = 'rf_loop3'
|
|
ATTR_RF_LOOP2 = 'rf_loop2'
|
|
ATTR_RF_LOOP4 = 'rf_loop4'
|
|
ATTR_RF_LOOP1 = 'rf_loop1'
|
|
|
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
"""Set up the AlarmDecoder binary sensor devices."""
|
|
configured_zones = discovery_info[CONF_ZONES]
|
|
|
|
devices = []
|
|
for zone_num in configured_zones:
|
|
device_config_data = ZONE_SCHEMA(configured_zones[zone_num])
|
|
zone_type = device_config_data[CONF_ZONE_TYPE]
|
|
zone_name = device_config_data[CONF_ZONE_NAME]
|
|
zone_rfid = device_config_data.get(CONF_ZONE_RFID)
|
|
zone_loop = device_config_data.get(CONF_ZONE_LOOP)
|
|
relay_addr = device_config_data.get(CONF_RELAY_ADDR)
|
|
relay_chan = device_config_data.get(CONF_RELAY_CHAN)
|
|
device = AlarmDecoderBinarySensor(
|
|
zone_num, zone_name, zone_type, zone_rfid, zone_loop, relay_addr,
|
|
relay_chan)
|
|
devices.append(device)
|
|
|
|
add_entities(devices)
|
|
|
|
return True
|
|
|
|
|
|
class AlarmDecoderBinarySensor(BinarySensorDevice):
|
|
"""Representation of an AlarmDecoder binary sensor."""
|
|
|
|
def __init__(self, zone_number, zone_name, zone_type, zone_rfid, zone_loop,
|
|
relay_addr, relay_chan):
|
|
"""Initialize the binary_sensor."""
|
|
self._zone_number = zone_number
|
|
self._zone_type = zone_type
|
|
self._state = None
|
|
self._name = zone_name
|
|
self._rfid = zone_rfid
|
|
self._loop = zone_loop
|
|
self._rfstate = None
|
|
self._relay_addr = relay_addr
|
|
self._relay_chan = relay_chan
|
|
|
|
async def async_added_to_hass(self):
|
|
"""Register callbacks."""
|
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
SIGNAL_ZONE_FAULT, self._fault_callback)
|
|
|
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
SIGNAL_ZONE_RESTORE, self._restore_callback)
|
|
|
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
SIGNAL_RFX_MESSAGE, self._rfx_message_callback)
|
|
|
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
SIGNAL_REL_MESSAGE, self._rel_message_callback)
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the name of the entity."""
|
|
return self._name
|
|
|
|
@property
|
|
def should_poll(self):
|
|
"""No polling needed."""
|
|
return False
|
|
|
|
@property
|
|
def device_state_attributes(self):
|
|
"""Return the state attributes."""
|
|
attr = {}
|
|
if self._rfid and self._rfstate is not None:
|
|
attr[ATTR_RF_BIT0] = bool(self._rfstate & 0x01)
|
|
attr[ATTR_RF_LOW_BAT] = bool(self._rfstate & 0x02)
|
|
attr[ATTR_RF_SUPERVISED] = bool(self._rfstate & 0x04)
|
|
attr[ATTR_RF_BIT3] = bool(self._rfstate & 0x08)
|
|
attr[ATTR_RF_LOOP3] = bool(self._rfstate & 0x10)
|
|
attr[ATTR_RF_LOOP2] = bool(self._rfstate & 0x20)
|
|
attr[ATTR_RF_LOOP4] = bool(self._rfstate & 0x40)
|
|
attr[ATTR_RF_LOOP1] = bool(self._rfstate & 0x80)
|
|
return attr
|
|
|
|
@property
|
|
def is_on(self):
|
|
"""Return true if sensor is on."""
|
|
return self._state == 1
|
|
|
|
@property
|
|
def device_class(self):
|
|
"""Return the class of this sensor, from DEVICE_CLASSES."""
|
|
return self._zone_type
|
|
|
|
def _fault_callback(self, zone):
|
|
"""Update the zone's state, if needed."""
|
|
if zone is None or int(zone) == self._zone_number:
|
|
self._state = 1
|
|
self.schedule_update_ha_state()
|
|
|
|
def _restore_callback(self, zone):
|
|
"""Update the zone's state, if needed."""
|
|
if zone is None or int(zone) == self._zone_number:
|
|
self._state = 0
|
|
self.schedule_update_ha_state()
|
|
|
|
def _rfx_message_callback(self, message):
|
|
"""Update RF state."""
|
|
if self._rfid and message and message.serial_number == self._rfid:
|
|
self._rfstate = message.value
|
|
if self._loop:
|
|
self._state = 1 if message.loop[self._loop - 1] else 0
|
|
self.schedule_update_ha_state()
|
|
|
|
def _rel_message_callback(self, message):
|
|
"""Update relay state."""
|
|
if (self._relay_addr == message.address and
|
|
self._relay_chan == message.channel):
|
|
_LOGGER.debug("Relay %d:%d value:%d", message.address,
|
|
message.channel, message.value)
|
|
self._state = message.value
|
|
self.schedule_update_ha_state()
|