mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Create zone bypass switches for DSC panels (#63200)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
3c1d1bd060
commit
10efeb2935
@ -39,6 +39,9 @@ CONF_ZONENAME = "name"
|
||||
CONF_ZONES = "zones"
|
||||
CONF_ZONETYPE = "type"
|
||||
|
||||
PANEL_TYPE_HONEYWELL = "HONEYWELL"
|
||||
PANEL_TYPE_DSC = "DSC"
|
||||
|
||||
DEFAULT_PORT = 4025
|
||||
DEFAULT_EVL_VERSION = 3
|
||||
DEFAULT_KEEPALIVE = 60
|
||||
@ -50,6 +53,7 @@ DEFAULT_TIMEOUT = 10
|
||||
SIGNAL_ZONE_UPDATE = "envisalink.zones_updated"
|
||||
SIGNAL_PARTITION_UPDATE = "envisalink.partition_updated"
|
||||
SIGNAL_KEYPAD_UPDATE = "envisalink.keypad_updated"
|
||||
SIGNAL_ZONE_BYPASS_UPDATE = "envisalink.zone_bypass_updated"
|
||||
|
||||
ZONE_SCHEMA = vol.Schema(
|
||||
{
|
||||
@ -66,7 +70,7 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_PANEL_TYPE): vol.All(
|
||||
cv.string, vol.In(["HONEYWELL", "DSC"])
|
||||
cv.string, vol.In([PANEL_TYPE_HONEYWELL, PANEL_TYPE_DSC])
|
||||
),
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASS): cv.string,
|
||||
@ -137,14 +141,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
hass.data[DATA_EVL] = controller
|
||||
|
||||
@callback
|
||||
def login_fail_callback(data):
|
||||
def async_login_fail_callback(data):
|
||||
"""Handle when the evl rejects our login."""
|
||||
_LOGGER.error("The Envisalink rejected your credentials")
|
||||
if not sync_connect.done():
|
||||
sync_connect.set_result(False)
|
||||
|
||||
@callback
|
||||
def connection_fail_callback(data):
|
||||
def async_connection_fail_callback(data):
|
||||
"""Network failure callback."""
|
||||
_LOGGER.error("Could not establish a connection with the Envisalink- retrying")
|
||||
if not sync_connect.done():
|
||||
@ -152,7 +156,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
sync_connect.set_result(True)
|
||||
|
||||
@callback
|
||||
def connection_success_callback(data):
|
||||
def async_connection_success_callback(data):
|
||||
"""Handle a successful connection."""
|
||||
_LOGGER.info("Established a connection with the Envisalink")
|
||||
if not sync_connect.done():
|
||||
@ -160,23 +164,29 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
sync_connect.set_result(True)
|
||||
|
||||
@callback
|
||||
def zones_updated_callback(data):
|
||||
def async_zones_updated_callback(data):
|
||||
"""Handle zone timer updates."""
|
||||
_LOGGER.debug("Envisalink sent a zone update event. Updating zones")
|
||||
async_dispatcher_send(hass, SIGNAL_ZONE_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def alarm_data_updated_callback(data):
|
||||
def async_alarm_data_updated_callback(data):
|
||||
"""Handle non-alarm based info updates."""
|
||||
_LOGGER.debug("Envisalink sent new alarm info. Updating alarms")
|
||||
async_dispatcher_send(hass, SIGNAL_KEYPAD_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def partition_updated_callback(data):
|
||||
def async_partition_updated_callback(data):
|
||||
"""Handle partition changes thrown by evl (including alarms)."""
|
||||
_LOGGER.debug("The envisalink sent a partition update event")
|
||||
async_dispatcher_send(hass, SIGNAL_PARTITION_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def async_zone_bypass_update(data):
|
||||
"""Handle zone bypass status updates."""
|
||||
_LOGGER.debug("Envisalink sent a zone bypass update event. Updating zones")
|
||||
async_dispatcher_send(hass, SIGNAL_ZONE_BYPASS_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def stop_envisalink(event):
|
||||
"""Shutdown envisalink connection and thread on exit."""
|
||||
@ -189,13 +199,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
partition = call.data.get(ATTR_PARTITION)
|
||||
controller.command_output(code, partition, custom_function)
|
||||
|
||||
controller.callback_zone_timer_dump = zones_updated_callback
|
||||
controller.callback_zone_state_change = zones_updated_callback
|
||||
controller.callback_partition_state_change = partition_updated_callback
|
||||
controller.callback_keypad_update = alarm_data_updated_callback
|
||||
controller.callback_login_failure = login_fail_callback
|
||||
controller.callback_login_timeout = connection_fail_callback
|
||||
controller.callback_login_success = connection_success_callback
|
||||
controller.callback_zone_timer_dump = async_zones_updated_callback
|
||||
controller.callback_zone_state_change = async_zones_updated_callback
|
||||
controller.callback_partition_state_change = async_partition_updated_callback
|
||||
controller.callback_keypad_update = async_alarm_data_updated_callback
|
||||
controller.callback_login_failure = async_login_fail_callback
|
||||
controller.callback_login_timeout = async_connection_fail_callback
|
||||
controller.callback_login_success = async_connection_success_callback
|
||||
controller.callback_zone_bypass_update = async_zone_bypass_update
|
||||
|
||||
_LOGGER.info("Start envisalink")
|
||||
controller.start()
|
||||
@ -229,6 +240,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
hass, Platform.BINARY_SENSOR, "envisalink", {CONF_ZONES: zones}, config
|
||||
)
|
||||
)
|
||||
# Only DSC panels support getting zone bypass status
|
||||
if panel_type == PANEL_TYPE_DSC:
|
||||
hass.async_create_task(
|
||||
async_load_platform(
|
||||
hass, "switch", "envisalink", {CONF_ZONES: zones}, config
|
||||
)
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_CUSTOM_FUNCTION, handle_custom_function, schema=SERVICE_SCHEMA
|
||||
|
@ -68,39 +68,39 @@ async def async_setup_platform(
|
||||
code = discovery_info[CONF_CODE]
|
||||
panic_type = discovery_info[CONF_PANIC]
|
||||
|
||||
devices = []
|
||||
entities = []
|
||||
for part_num in configured_partitions:
|
||||
device_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
device = EnvisalinkAlarm(
|
||||
entity_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
entity = EnvisalinkAlarm(
|
||||
hass,
|
||||
part_num,
|
||||
device_config_data[CONF_PARTITIONNAME],
|
||||
entity_config_data[CONF_PARTITIONNAME],
|
||||
code,
|
||||
panic_type,
|
||||
hass.data[DATA_EVL].alarm_state["partition"][part_num],
|
||||
hass.data[DATA_EVL],
|
||||
)
|
||||
devices.append(device)
|
||||
entities.append(entity)
|
||||
|
||||
async_add_entities(devices)
|
||||
async_add_entities(entities)
|
||||
|
||||
@callback
|
||||
def alarm_keypress_handler(service: ServiceCall) -> None:
|
||||
def async_alarm_keypress_handler(service: ServiceCall) -> None:
|
||||
"""Map services to methods on Alarm."""
|
||||
entity_ids = service.data[ATTR_ENTITY_ID]
|
||||
keypress = service.data[ATTR_KEYPRESS]
|
||||
|
||||
target_devices = [
|
||||
device for device in devices if device.entity_id in entity_ids
|
||||
target_entities = [
|
||||
entity for entity in entities if entity.entity_id in entity_ids
|
||||
]
|
||||
|
||||
for device in target_devices:
|
||||
device.async_alarm_keypress(keypress)
|
||||
for entity in target_entities:
|
||||
entity.async_alarm_keypress(keypress)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_ALARM_KEYPRESS,
|
||||
alarm_keypress_handler,
|
||||
async_alarm_keypress_handler,
|
||||
schema=ALARM_KEYPRESS_SCHEMA,
|
||||
)
|
||||
|
||||
@ -123,17 +123,17 @@ class EnvisalinkAlarm(EnvisalinkDevice, AlarmControlPanelEntity):
|
||||
"""Register callbacks."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_KEYPAD_UPDATE, self._update_callback
|
||||
self.hass, SIGNAL_KEYPAD_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_PARTITION_UPDATE, self._update_callback
|
||||
self.hass, SIGNAL_PARTITION_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def _update_callback(self, partition):
|
||||
def async_update_callback(self, partition):
|
||||
"""Update Home Assistant state, if needed."""
|
||||
if partition is None or int(partition) == self._partition_number:
|
||||
self.async_write_ha_state()
|
||||
|
@ -30,25 +30,25 @@ async def async_setup_platform(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Envisalink binary sensor devices."""
|
||||
"""Set up the Envisalink binary sensor entities."""
|
||||
if not discovery_info:
|
||||
return
|
||||
configured_zones = discovery_info["zones"]
|
||||
|
||||
devices = []
|
||||
entities = []
|
||||
for zone_num in configured_zones:
|
||||
device_config_data = ZONE_SCHEMA(configured_zones[zone_num])
|
||||
device = EnvisalinkBinarySensor(
|
||||
entity_config_data = ZONE_SCHEMA(configured_zones[zone_num])
|
||||
entity = EnvisalinkBinarySensor(
|
||||
hass,
|
||||
zone_num,
|
||||
device_config_data[CONF_ZONENAME],
|
||||
device_config_data[CONF_ZONETYPE],
|
||||
entity_config_data[CONF_ZONENAME],
|
||||
entity_config_data[CONF_ZONETYPE],
|
||||
hass.data[DATA_EVL].alarm_state["zone"][zone_num],
|
||||
hass.data[DATA_EVL],
|
||||
)
|
||||
devices.append(device)
|
||||
entities.append(entity)
|
||||
|
||||
async_add_entities(devices)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorEntity):
|
||||
@ -64,7 +64,11 @@ class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorEntity):
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
async_dispatcher_connect(self.hass, SIGNAL_ZONE_UPDATE, self._update_callback)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_ZONE_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
@ -102,7 +106,7 @@ class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorEntity):
|
||||
return self._zone_type
|
||||
|
||||
@callback
|
||||
def _update_callback(self, zone):
|
||||
def async_update_callback(self, zone):
|
||||
"""Update the zone's state, if needed."""
|
||||
if zone is None or int(zone) == self._zone_number:
|
||||
self.async_write_ha_state()
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "envisalink",
|
||||
"name": "Envisalink",
|
||||
"documentation": "https://www.home-assistant.io/integrations/envisalink",
|
||||
"requirements": ["pyenvisalink==4.0"],
|
||||
"requirements": ["pyenvisalink==4.3"],
|
||||
"codeowners": [],
|
||||
"iot_class": "local_push"
|
||||
}
|
||||
|
@ -27,25 +27,25 @@ async def async_setup_platform(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Perform the setup for Envisalink sensor devices."""
|
||||
"""Perform the setup for Envisalink sensor entities."""
|
||||
if not discovery_info:
|
||||
return
|
||||
configured_partitions = discovery_info["partitions"]
|
||||
|
||||
devices = []
|
||||
entities = []
|
||||
for part_num in configured_partitions:
|
||||
device_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
device = EnvisalinkSensor(
|
||||
entity_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
entity = EnvisalinkSensor(
|
||||
hass,
|
||||
device_config_data[CONF_PARTITIONNAME],
|
||||
entity_config_data[CONF_PARTITIONNAME],
|
||||
part_num,
|
||||
hass.data[DATA_EVL].alarm_state["partition"][part_num],
|
||||
hass.data[DATA_EVL],
|
||||
)
|
||||
|
||||
devices.append(device)
|
||||
entities.append(entity)
|
||||
|
||||
async_add_entities(devices)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class EnvisalinkSensor(EnvisalinkDevice, SensorEntity):
|
||||
@ -61,9 +61,15 @@ class EnvisalinkSensor(EnvisalinkDevice, SensorEntity):
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
async_dispatcher_connect(self.hass, SIGNAL_KEYPAD_UPDATE, self._update_callback)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_PARTITION_UPDATE, self._update_callback
|
||||
self.hass, SIGNAL_KEYPAD_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_PARTITION_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
@ -82,7 +88,7 @@ class EnvisalinkSensor(EnvisalinkDevice, SensorEntity):
|
||||
return self._info["status"]
|
||||
|
||||
@callback
|
||||
def _update_callback(self, partition):
|
||||
def async_update_callback(self, partition):
|
||||
"""Update the partition state in HA, if needed."""
|
||||
if partition is None or int(partition) == self._partition_number:
|
||||
self.async_write_ha_state()
|
||||
|
87
homeassistant/components/envisalink/switch.py
Normal file
87
homeassistant/components/envisalink/switch.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""Support for Envisalink zone bypass switches."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from . import (
|
||||
CONF_ZONENAME,
|
||||
DATA_EVL,
|
||||
SIGNAL_ZONE_BYPASS_UPDATE,
|
||||
ZONE_SCHEMA,
|
||||
EnvisalinkDevice,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Envisalink switch entities."""
|
||||
if not discovery_info:
|
||||
return
|
||||
configured_zones = discovery_info["zones"]
|
||||
|
||||
entities = []
|
||||
for zone_num in configured_zones:
|
||||
entity_config_data = ZONE_SCHEMA(configured_zones[zone_num])
|
||||
zone_name = f"{entity_config_data[CONF_ZONENAME]}_bypass"
|
||||
_LOGGER.debug("Setting up zone_bypass switch: %s", zone_name)
|
||||
|
||||
entity = EnvisalinkSwitch(
|
||||
hass,
|
||||
zone_num,
|
||||
zone_name,
|
||||
hass.data[DATA_EVL].alarm_state["zone"][zone_num],
|
||||
hass.data[DATA_EVL],
|
||||
)
|
||||
entities.append(entity)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class EnvisalinkSwitch(EnvisalinkDevice, SwitchEntity):
|
||||
"""Representation of an Envisalink switch."""
|
||||
|
||||
def __init__(self, hass, zone_number, zone_name, info, controller):
|
||||
"""Initialize the switch."""
|
||||
self._zone_number = zone_number
|
||||
|
||||
super().__init__(zone_name, info, controller)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_ZONE_BYPASS_UPDATE, self.async_update_callback
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return the boolean response if the zone is bypassed."""
|
||||
return self._info["bypassed"]
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Send the bypass keypress sequence to toggle the zone bypass."""
|
||||
self._controller.toggle_zone_bypass(self._zone_number)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Send the bypass keypress sequence to toggle the zone bypass."""
|
||||
self._controller.toggle_zone_bypass(self._zone_number)
|
||||
|
||||
@callback
|
||||
def async_update_callback(self, bypass_map):
|
||||
"""Update the zone bypass state in HA, if needed."""
|
||||
if bypass_map is None or self._zone_number in bypass_map:
|
||||
_LOGGER.debug("Bypass state changed for zone %d", self._zone_number)
|
||||
self.async_write_ha_state()
|
@ -1500,7 +1500,7 @@ pyeight==0.2.0
|
||||
pyemby==1.8
|
||||
|
||||
# homeassistant.components.envisalink
|
||||
pyenvisalink==4.0
|
||||
pyenvisalink==4.3
|
||||
|
||||
# homeassistant.components.ephember
|
||||
pyephember==0.3.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user