mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 00:37:53 +00:00
Refactory of envisalink (#6160)
* Refactory of envisalink * remove event buss * init dispatcher from hass. * Move platform to new dispatcher * fix lint * add unittest & threadded functions * fix copy & past error
This commit is contained in:
parent
4f990ce488
commit
f2a2d6bfa1
@ -4,16 +4,20 @@ Support for Envisalink-based alarm control panels (Honeywell/DSC).
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/alarm_control_panel.envisalink/
|
||||
"""
|
||||
from os import path
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
import homeassistant.components.alarm_control_panel as alarm
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.components.envisalink import (
|
||||
EVL_CONTROLLER, EnvisalinkDevice, PARTITION_SCHEMA, CONF_CODE, CONF_PANIC,
|
||||
CONF_PARTITIONNAME, SIGNAL_PARTITION_UPDATE, SIGNAL_KEYPAD_UPDATE)
|
||||
DATA_EVL, EnvisalinkDevice, PARTITION_SCHEMA, CONF_CODE, CONF_PANIC,
|
||||
CONF_PARTITIONNAME, SIGNAL_KEYPAD_UPDATE, SIGNAL_PARTITION_UPDATE)
|
||||
from homeassistant.const import (
|
||||
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED,
|
||||
STATE_UNKNOWN, STATE_ALARM_TRIGGERED, STATE_ALARM_PENDING, ATTR_ENTITY_ID)
|
||||
@ -22,8 +26,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['envisalink']
|
||||
|
||||
DEVICES = []
|
||||
|
||||
SERVICE_ALARM_KEYPRESS = 'envisalink_alarm_keypress'
|
||||
ATTR_KEYPRESS = 'keypress'
|
||||
ALARM_KEYPRESS_SCHEMA = vol.Schema({
|
||||
@ -32,68 +34,72 @@ ALARM_KEYPRESS_SCHEMA = vol.Schema({
|
||||
})
|
||||
|
||||
|
||||
def alarm_keypress_handler(service):
|
||||
"""Map services to methods on Alarm."""
|
||||
entity_ids = service.data.get(ATTR_ENTITY_ID)
|
||||
keypress = service.data.get(ATTR_KEYPRESS)
|
||||
|
||||
_target_devices = [device for device in DEVICES
|
||||
if device.entity_id in entity_ids]
|
||||
|
||||
for device in _target_devices:
|
||||
EnvisalinkAlarm.alarm_keypress(device, keypress)
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Perform the setup for Envisalink alarm panels."""
|
||||
_configured_partitions = discovery_info['partitions']
|
||||
_code = discovery_info[CONF_CODE]
|
||||
_panic_type = discovery_info[CONF_PANIC]
|
||||
for part_num in _configured_partitions:
|
||||
_device_config_data = PARTITION_SCHEMA(
|
||||
_configured_partitions[part_num])
|
||||
_device = EnvisalinkAlarm(
|
||||
part_num,
|
||||
_device_config_data[CONF_PARTITIONNAME],
|
||||
_code,
|
||||
_panic_type,
|
||||
EVL_CONTROLLER.alarm_state['partition'][part_num],
|
||||
EVL_CONTROLLER)
|
||||
DEVICES.append(_device)
|
||||
configured_partitions = discovery_info['partitions']
|
||||
code = discovery_info[CONF_CODE]
|
||||
panic_type = discovery_info[CONF_PANIC]
|
||||
|
||||
add_devices(DEVICES)
|
||||
devices = []
|
||||
for part_num in configured_partitions:
|
||||
device_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
device = EnvisalinkAlarm(
|
||||
hass,
|
||||
part_num,
|
||||
device_config_data[CONF_PARTITIONNAME],
|
||||
code,
|
||||
panic_type,
|
||||
hass.data[DATA_EVL].alarm_state['partition'][part_num],
|
||||
hass.data[DATA_EVL]
|
||||
)
|
||||
devices.append(device)
|
||||
|
||||
yield from async_add_devices(devices)
|
||||
|
||||
@callback
|
||||
def alarm_keypress_handler(service):
|
||||
"""Map services to methods on Alarm."""
|
||||
entity_ids = service.data.get(ATTR_ENTITY_ID)
|
||||
keypress = service.data.get(ATTR_KEYPRESS)
|
||||
|
||||
target_devices = [device for device in devices
|
||||
if device.entity_id in entity_ids]
|
||||
|
||||
for device in target_devices:
|
||||
device.async_alarm_keypress(keypress)
|
||||
|
||||
# Register Envisalink specific services
|
||||
descriptions = load_yaml_config_file(
|
||||
path.join(path.dirname(__file__), 'services.yaml'))
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, load_yaml_config_file, os.path.join(
|
||||
os.path.dirname(__file__), 'services.yaml'))
|
||||
|
||||
hass.services.async_register(
|
||||
alarm.DOMAIN, SERVICE_ALARM_KEYPRESS, alarm_keypress_handler,
|
||||
descriptions.get(SERVICE_ALARM_KEYPRESS), schema=ALARM_KEYPRESS_SCHEMA)
|
||||
|
||||
hass.services.register(alarm.DOMAIN, SERVICE_ALARM_KEYPRESS,
|
||||
alarm_keypress_handler,
|
||||
descriptions.get(SERVICE_ALARM_KEYPRESS),
|
||||
schema=ALARM_KEYPRESS_SCHEMA)
|
||||
return True
|
||||
|
||||
|
||||
class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
|
||||
"""Representation of an Envisalink-based alarm panel."""
|
||||
|
||||
def __init__(self, partition_number, alarm_name, code, panic_type, info,
|
||||
controller):
|
||||
def __init__(self, hass, partition_number, alarm_name, code, panic_type,
|
||||
info, controller):
|
||||
"""Initialize the alarm panel."""
|
||||
from pydispatch import dispatcher
|
||||
self._partition_number = partition_number
|
||||
self._code = code
|
||||
self._panic_type = panic_type
|
||||
_LOGGER.debug("Setting up alarm: %s", alarm_name)
|
||||
EnvisalinkDevice.__init__(self, alarm_name, info, controller)
|
||||
dispatcher.connect(
|
||||
self._update_callback, signal=SIGNAL_PARTITION_UPDATE,
|
||||
sender=dispatcher.Any)
|
||||
dispatcher.connect(
|
||||
self._update_callback, signal=SIGNAL_KEYPAD_UPDATE,
|
||||
sender=dispatcher.Any)
|
||||
|
||||
_LOGGER.debug("Setting up alarm: %s", alarm_name)
|
||||
super().__init__(alarm_name, info, controller)
|
||||
|
||||
async_dispatcher_connect(
|
||||
hass, SIGNAL_KEYPAD_UPDATE, self._update_callback)
|
||||
async_dispatcher_connect(
|
||||
hass, SIGNAL_PARTITION_UPDATE, self._update_callback)
|
||||
|
||||
@callback
|
||||
def _update_callback(self, partition):
|
||||
"""Update HA state, if needed."""
|
||||
if partition is None or int(partition) == self._partition_number:
|
||||
@ -126,39 +132,44 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
|
||||
state = STATE_ALARM_DISARMED
|
||||
return state
|
||||
|
||||
def alarm_disarm(self, code=None):
|
||||
@asyncio.coroutine
|
||||
def async_alarm_disarm(self, code=None):
|
||||
"""Send disarm command."""
|
||||
if code:
|
||||
EVL_CONTROLLER.disarm_partition(str(code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].disarm_partition(
|
||||
str(code), self._partition_number)
|
||||
else:
|
||||
EVL_CONTROLLER.disarm_partition(str(self._code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].disarm_partition(
|
||||
str(self._code), self._partition_number)
|
||||
|
||||
def alarm_arm_home(self, code=None):
|
||||
@asyncio.coroutine
|
||||
def async_alarm_arm_home(self, code=None):
|
||||
"""Send arm home command."""
|
||||
if code:
|
||||
EVL_CONTROLLER.arm_stay_partition(str(code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].arm_stay_partition(
|
||||
str(code), self._partition_number)
|
||||
else:
|
||||
EVL_CONTROLLER.arm_stay_partition(str(self._code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].arm_stay_partition(
|
||||
str(self._code), self._partition_number)
|
||||
|
||||
def alarm_arm_away(self, code=None):
|
||||
@asyncio.coroutine
|
||||
def async_alarm_arm_away(self, code=None):
|
||||
"""Send arm away command."""
|
||||
if code:
|
||||
EVL_CONTROLLER.arm_away_partition(str(code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].arm_away_partition(
|
||||
str(code), self._partition_number)
|
||||
else:
|
||||
EVL_CONTROLLER.arm_away_partition(str(self._code),
|
||||
self._partition_number)
|
||||
self.hass.data[DATA_EVL].arm_away_partition(
|
||||
str(self._code), self._partition_number)
|
||||
|
||||
def alarm_trigger(self, code=None):
|
||||
@asyncio.coroutine
|
||||
def async_alarm_trigger(self, code=None):
|
||||
"""Alarm trigger command. Will be used to trigger a panic alarm."""
|
||||
EVL_CONTROLLER.panic_alarm(self._panic_type)
|
||||
self.hass.data[DATA_EVL].panic_alarm(self._panic_type)
|
||||
|
||||
def alarm_keypress(self, keypress=None):
|
||||
@callback
|
||||
def async_alarm_keypress(self, keypress=None):
|
||||
"""Send custom keypress."""
|
||||
if keypress:
|
||||
EVL_CONTROLLER.keypresses_to_partition(self._partition_number,
|
||||
keypress)
|
||||
self.hass.data[DATA_EVL].keypresses_to_partition(
|
||||
self._partition_number, keypress)
|
||||
|
@ -4,48 +4,56 @@ Support for Envisalink 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.envisalink/
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.components.envisalink import (EVL_CONTROLLER,
|
||||
ZONE_SCHEMA,
|
||||
CONF_ZONENAME,
|
||||
CONF_ZONETYPE,
|
||||
EnvisalinkDevice,
|
||||
SIGNAL_ZONE_UPDATE)
|
||||
from homeassistant.components.envisalink import (
|
||||
DATA_EVL, ZONE_SCHEMA, CONF_ZONENAME, CONF_ZONETYPE, EnvisalinkDevice,
|
||||
SIGNAL_ZONE_UPDATE)
|
||||
from homeassistant.const import ATTR_LAST_TRIP_TIME
|
||||
|
||||
DEPENDENCIES = ['envisalink']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Setup Envisalink binary sensor devices."""
|
||||
_configured_zones = discovery_info['zones']
|
||||
for zone_num in _configured_zones:
|
||||
_device_config_data = ZONE_SCHEMA(_configured_zones[zone_num])
|
||||
_device = EnvisalinkBinarySensor(
|
||||
configured_zones = discovery_info['zones']
|
||||
|
||||
devices = []
|
||||
for zone_num in configured_zones:
|
||||
device_config_data = ZONE_SCHEMA(configured_zones[zone_num])
|
||||
device = EnvisalinkBinarySensor(
|
||||
hass,
|
||||
zone_num,
|
||||
_device_config_data[CONF_ZONENAME],
|
||||
_device_config_data[CONF_ZONETYPE],
|
||||
EVL_CONTROLLER.alarm_state['zone'][zone_num],
|
||||
EVL_CONTROLLER)
|
||||
add_devices_callback([_device])
|
||||
device_config_data[CONF_ZONENAME],
|
||||
device_config_data[CONF_ZONETYPE],
|
||||
hass.data[DATA_EVL].alarm_state['zone'][zone_num],
|
||||
hass.data[DATA_EVL]
|
||||
)
|
||||
devices.append(device)
|
||||
|
||||
yield from async_add_devices(devices)
|
||||
|
||||
|
||||
class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice):
|
||||
"""Representation of an Envisalink binary sensor."""
|
||||
|
||||
def __init__(self, zone_number, zone_name, zone_type, info, controller):
|
||||
def __init__(self, hass, zone_number, zone_name, zone_type, info,
|
||||
controller):
|
||||
"""Initialize the binary_sensor."""
|
||||
from pydispatch import dispatcher
|
||||
self._zone_type = zone_type
|
||||
self._zone_number = zone_number
|
||||
|
||||
_LOGGER.debug('Setting up zone: ' + zone_name)
|
||||
EnvisalinkDevice.__init__(self, zone_name, info, controller)
|
||||
dispatcher.connect(self._update_callback,
|
||||
signal=SIGNAL_ZONE_UPDATE,
|
||||
sender=dispatcher.Any)
|
||||
super().__init__(zone_name, info, controller)
|
||||
|
||||
async_dispatcher_connect(
|
||||
hass, SIGNAL_ZONE_UPDATE, self._update_callback)
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
@ -64,7 +72,8 @@ class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice):
|
||||
"""Return the class of this sensor, from DEVICE_CLASSES."""
|
||||
return self._zone_type
|
||||
|
||||
@callback
|
||||
def _update_callback(self, zone):
|
||||
"""Update the zone's state, if needed."""
|
||||
if zone is None or int(zone) == self._zone_number:
|
||||
self.hass.schedule_update_ha_state()
|
||||
self.hass.async_add_job(self.async_update_ha_state())
|
||||
|
@ -4,20 +4,24 @@ Support for Envisalink devices.
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/envisalink/
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.components.discovery import load_platform
|
||||
from homeassistant.helpers.discovery import async_load_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
REQUIREMENTS = ['pyenvisalink==2.0', 'pydispatcher==2.0.5']
|
||||
REQUIREMENTS = ['pyenvisalink==2.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
DOMAIN = 'envisalink'
|
||||
|
||||
EVL_CONTROLLER = None
|
||||
DATA_EVL = 'envisalink'
|
||||
|
||||
CONF_EVL_HOST = 'host'
|
||||
CONF_EVL_PORT = 'port'
|
||||
@ -43,9 +47,9 @@ DEFAULT_ZONEDUMP_INTERVAL = 30
|
||||
DEFAULT_ZONETYPE = 'opening'
|
||||
DEFAULT_PANIC = 'Police'
|
||||
|
||||
SIGNAL_ZONE_UPDATE = 'zones_updated'
|
||||
SIGNAL_PARTITION_UPDATE = 'partition_updated'
|
||||
SIGNAL_KEYPAD_UPDATE = 'keypad_updated'
|
||||
SIGNAL_ZONE_UPDATE = 'envisalink.zones_updated'
|
||||
SIGNAL_PARTITION_UPDATE = 'envisalink.partition_updated'
|
||||
SIGNAL_KEYPAD_UPDATE = 'envisalink.keypad_updated'
|
||||
|
||||
ZONE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ZONENAME): cv.string,
|
||||
@ -77,119 +81,111 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup(hass, base_config):
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Common setup for Envisalink devices."""
|
||||
from pyenvisalink import EnvisalinkAlarmPanel
|
||||
from pydispatch import dispatcher
|
||||
|
||||
global EVL_CONTROLLER
|
||||
conf = config.get(DOMAIN)
|
||||
|
||||
config = base_config.get(DOMAIN)
|
||||
host = conf.get(CONF_EVL_HOST)
|
||||
port = conf.get(CONF_EVL_PORT)
|
||||
code = conf.get(CONF_CODE)
|
||||
panel_type = conf.get(CONF_PANEL_TYPE)
|
||||
panic_type = conf.get(CONF_PANIC)
|
||||
version = conf.get(CONF_EVL_VERSION)
|
||||
user = conf.get(CONF_USERNAME)
|
||||
password = conf.get(CONF_PASS)
|
||||
keep_alive = conf.get(CONF_EVL_KEEPALIVE)
|
||||
zone_dump = conf.get(CONF_ZONEDUMP_INTERVAL)
|
||||
zones = conf.get(CONF_ZONES)
|
||||
partitions = conf.get(CONF_PARTITIONS)
|
||||
sync_connect = asyncio.Future(loop=hass.loop)
|
||||
|
||||
_host = config.get(CONF_EVL_HOST)
|
||||
_port = config.get(CONF_EVL_PORT)
|
||||
_code = config.get(CONF_CODE)
|
||||
_panel_type = config.get(CONF_PANEL_TYPE)
|
||||
_panic_type = config.get(CONF_PANIC)
|
||||
_version = config.get(CONF_EVL_VERSION)
|
||||
_user = config.get(CONF_USERNAME)
|
||||
_pass = config.get(CONF_PASS)
|
||||
_keep_alive = config.get(CONF_EVL_KEEPALIVE)
|
||||
_zone_dump = config.get(CONF_ZONEDUMP_INTERVAL)
|
||||
_zones = config.get(CONF_ZONES)
|
||||
_partitions = config.get(CONF_PARTITIONS)
|
||||
_connect_status = {}
|
||||
EVL_CONTROLLER = EnvisalinkAlarmPanel(_host,
|
||||
_port,
|
||||
_panel_type,
|
||||
_version,
|
||||
_user,
|
||||
_pass,
|
||||
_zone_dump,
|
||||
_keep_alive,
|
||||
hass.loop)
|
||||
controller = EnvisalinkAlarmPanel(
|
||||
host, port, panel_type, version, user, password, zone_dump,
|
||||
keep_alive, hass.loop)
|
||||
hass.data[DATA_EVL] = controller
|
||||
|
||||
@callback
|
||||
def login_fail_callback(data):
|
||||
"""Callback for when the evl rejects our login."""
|
||||
_LOGGER.error("The envisalink rejected your credentials.")
|
||||
_connect_status['fail'] = 1
|
||||
sync_connect.set_result(False)
|
||||
|
||||
@callback
|
||||
def connection_fail_callback(data):
|
||||
"""Network failure callback."""
|
||||
_LOGGER.error("Could not establish a connection with the envisalink.")
|
||||
_connect_status['fail'] = 1
|
||||
sync_connect.set_result(False)
|
||||
|
||||
@callback
|
||||
def connection_success_callback(data):
|
||||
"""Callback for a successful connection."""
|
||||
_LOGGER.info("Established a connection with the envisalink.")
|
||||
_connect_status['success'] = 1
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_envisalink)
|
||||
sync_connect.set_result(True)
|
||||
|
||||
@callback
|
||||
def zones_updated_callback(data):
|
||||
"""Handle zone timer updates."""
|
||||
_LOGGER.info("Envisalink sent a zone update event. Updating zones...")
|
||||
dispatcher.send(signal=SIGNAL_ZONE_UPDATE,
|
||||
sender=None,
|
||||
zone=data)
|
||||
async_dispatcher_send(hass, SIGNAL_ZONE_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def alarm_data_updated_callback(data):
|
||||
"""Handle non-alarm based info updates."""
|
||||
_LOGGER.info("Envisalink sent new alarm info. Updating alarms...")
|
||||
dispatcher.send(signal=SIGNAL_KEYPAD_UPDATE,
|
||||
sender=None,
|
||||
partition=data)
|
||||
async_dispatcher_send(hass, SIGNAL_KEYPAD_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def partition_updated_callback(data):
|
||||
"""Handle partition changes thrown by evl (including alarms)."""
|
||||
_LOGGER.info("The envisalink sent a partition update event.")
|
||||
dispatcher.send(signal=SIGNAL_PARTITION_UPDATE,
|
||||
sender=None,
|
||||
partition=data)
|
||||
async_dispatcher_send(hass, SIGNAL_PARTITION_UPDATE, data)
|
||||
|
||||
@callback
|
||||
def stop_envisalink(event):
|
||||
"""Shutdown envisalink connection and thread on exit."""
|
||||
_LOGGER.info("Shutting down envisalink.")
|
||||
EVL_CONTROLLER.stop()
|
||||
controller.stop()
|
||||
|
||||
def start_envisalink(event):
|
||||
"""Startup process for the Envisalink."""
|
||||
hass.loop.call_soon_threadsafe(EVL_CONTROLLER.start)
|
||||
for _ in range(10):
|
||||
if 'success' in _connect_status:
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_envisalink)
|
||||
return True
|
||||
elif 'fail' in _connect_status:
|
||||
return False
|
||||
else:
|
||||
time.sleep(1)
|
||||
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
|
||||
|
||||
_LOGGER.error("Timeout occurred while establishing evl connection.")
|
||||
return False
|
||||
_LOGGER.info("Start envisalink.")
|
||||
controller.start()
|
||||
|
||||
EVL_CONTROLLER.callback_zone_timer_dump = zones_updated_callback
|
||||
EVL_CONTROLLER.callback_zone_state_change = zones_updated_callback
|
||||
EVL_CONTROLLER.callback_partition_state_change = partition_updated_callback
|
||||
EVL_CONTROLLER.callback_keypad_update = alarm_data_updated_callback
|
||||
EVL_CONTROLLER.callback_login_failure = login_fail_callback
|
||||
EVL_CONTROLLER.callback_login_timeout = connection_fail_callback
|
||||
EVL_CONTROLLER.callback_login_success = connection_success_callback
|
||||
|
||||
_result = start_envisalink(None)
|
||||
if not _result:
|
||||
result = yield from sync_connect
|
||||
if not result:
|
||||
return False
|
||||
|
||||
# Load sub-components for Envisalink
|
||||
if _partitions:
|
||||
load_platform(hass, 'alarm_control_panel', 'envisalink',
|
||||
{CONF_PARTITIONS: _partitions,
|
||||
CONF_CODE: _code,
|
||||
CONF_PANIC: _panic_type}, base_config)
|
||||
load_platform(hass, 'sensor', 'envisalink',
|
||||
{CONF_PARTITIONS: _partitions,
|
||||
CONF_CODE: _code}, base_config)
|
||||
if _zones:
|
||||
load_platform(hass, 'binary_sensor', 'envisalink',
|
||||
{CONF_ZONES: _zones}, base_config)
|
||||
if partitions:
|
||||
hass.async_add_job(async_load_platform(
|
||||
hass, 'alarm_control_panel', 'envisalink', {
|
||||
CONF_PARTITIONS: partitions,
|
||||
CONF_CODE: code,
|
||||
CONF_PANIC: panic_type
|
||||
}, config
|
||||
))
|
||||
hass.async_add_job(async_load_platform(
|
||||
hass, 'sensor', 'envisalink', {
|
||||
CONF_PARTITIONS: partitions,
|
||||
CONF_CODE: code
|
||||
}, config
|
||||
))
|
||||
if zones:
|
||||
hass.async_add_job(async_load_platform(
|
||||
hass, 'binary_sensor', 'envisalink', {
|
||||
CONF_ZONES: zones
|
||||
}, config
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
|
@ -4,51 +4,55 @@ Support for Envisalink sensors (shows panel info).
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/sensor.envisalink/
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
from homeassistant.components.envisalink import (EVL_CONTROLLER,
|
||||
PARTITION_SCHEMA,
|
||||
CONF_PARTITIONNAME,
|
||||
EnvisalinkDevice,
|
||||
SIGNAL_PARTITION_UPDATE,
|
||||
SIGNAL_KEYPAD_UPDATE)
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.components.envisalink import (
|
||||
DATA_EVL, PARTITION_SCHEMA, CONF_PARTITIONNAME, EnvisalinkDevice,
|
||||
SIGNAL_KEYPAD_UPDATE, SIGNAL_PARTITION_UPDATE)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
DEPENDENCIES = ['envisalink']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Perform the setup for Envisalink sensor devices."""
|
||||
_configured_partitions = discovery_info['partitions']
|
||||
for part_num in _configured_partitions:
|
||||
_device_config_data = PARTITION_SCHEMA(
|
||||
_configured_partitions[part_num])
|
||||
_device = EnvisalinkSensor(
|
||||
_device_config_data[CONF_PARTITIONNAME],
|
||||
configured_partitions = discovery_info['partitions']
|
||||
|
||||
devices = []
|
||||
for part_num in configured_partitions:
|
||||
device_config_data = PARTITION_SCHEMA(configured_partitions[part_num])
|
||||
device = EnvisalinkSensor(
|
||||
hass,
|
||||
device_config_data[CONF_PARTITIONNAME],
|
||||
part_num,
|
||||
EVL_CONTROLLER.alarm_state['partition'][part_num],
|
||||
EVL_CONTROLLER)
|
||||
add_devices_callback([_device])
|
||||
hass.data[DATA_EVL].alarm_state['partition'][part_num],
|
||||
hass.data[DATA_EVL])
|
||||
devices.append(device)
|
||||
|
||||
yield from async_add_devices(devices)
|
||||
|
||||
|
||||
class EnvisalinkSensor(EnvisalinkDevice):
|
||||
class EnvisalinkSensor(EnvisalinkDevice, Entity):
|
||||
"""Representation of an Envisalink keypad."""
|
||||
|
||||
def __init__(self, partition_name, partition_number, info, controller):
|
||||
def __init__(self, hass, partition_name, partition_number, info,
|
||||
controller):
|
||||
"""Initialize the sensor."""
|
||||
from pydispatch import dispatcher
|
||||
self._icon = 'mdi:alarm'
|
||||
self._partition_number = partition_number
|
||||
|
||||
_LOGGER.debug('Setting up sensor for partition: ' + partition_name)
|
||||
EnvisalinkDevice.__init__(self,
|
||||
partition_name + ' Keypad',
|
||||
info,
|
||||
controller)
|
||||
dispatcher.connect(self._update_callback,
|
||||
signal=SIGNAL_PARTITION_UPDATE,
|
||||
sender=dispatcher.Any)
|
||||
dispatcher.connect(self._update_callback,
|
||||
signal=SIGNAL_KEYPAD_UPDATE,
|
||||
sender=dispatcher.Any)
|
||||
super().__init__(partition_name + ' Keypad', info, controller)
|
||||
|
||||
async_dispatcher_connect(
|
||||
hass, SIGNAL_KEYPAD_UPDATE, self._update_callback)
|
||||
async_dispatcher_connect(
|
||||
hass, SIGNAL_PARTITION_UPDATE, self._update_callback)
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
@ -65,7 +69,8 @@ class EnvisalinkSensor(EnvisalinkDevice):
|
||||
"""Return the state attributes."""
|
||||
return self._info['status']
|
||||
|
||||
@callback
|
||||
def _update_callback(self, partition):
|
||||
"""Update the partition state in HA, if needed."""
|
||||
if partition is None or int(partition) == self._partition_number:
|
||||
self.hass.schedule_update_ha_state()
|
||||
self.hass.async_add_job(self.async_update_ha_state())
|
||||
|
42
homeassistant/helpers/dispatcher.py
Normal file
42
homeassistant/helpers/dispatcher.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""Helpers for hass dispatcher & internal component / platform."""
|
||||
|
||||
from homeassistant.core import callback
|
||||
|
||||
DATA_DISPATCHER = 'dispatcher'
|
||||
|
||||
|
||||
def dispatcher_connect(hass, signal, target):
|
||||
"""Connect a callable function to a singal."""
|
||||
hass.add_job(async_dispatcher_connect, hass, signal, target)
|
||||
|
||||
|
||||
@callback
|
||||
def async_dispatcher_connect(hass, signal, target):
|
||||
"""Connect a callable function to a singal.
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
if DATA_DISPATCHER not in hass.data:
|
||||
hass.data[DATA_DISPATCHER] = {}
|
||||
|
||||
if signal not in hass.data[DATA_DISPATCHER]:
|
||||
hass.data[DATA_DISPATCHER][signal] = []
|
||||
|
||||
hass.data[DATA_DISPATCHER][signal].append(target)
|
||||
|
||||
|
||||
def dispatcher_send(hass, signal, *args):
|
||||
"""Send signal and data."""
|
||||
hass.add_job(async_dispatcher_send, hass, signal, *args)
|
||||
|
||||
|
||||
@callback
|
||||
def async_dispatcher_send(hass, signal, *args):
|
||||
"""Send signal and data.
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
target_list = hass.data.get(DATA_DISPATCHER, {}).get(signal, [])
|
||||
|
||||
for target in target_list:
|
||||
hass.async_add_job(target, *args)
|
@ -457,7 +457,6 @@ pycmus==0.1.0
|
||||
# homeassistant.components.sensor.cups
|
||||
# pycups==1.9.73
|
||||
|
||||
# homeassistant.components.envisalink
|
||||
# homeassistant.components.zwave
|
||||
# homeassistant.components.binary_sensor.hikvision
|
||||
pydispatcher==2.0.5
|
||||
|
103
tests/helpers/test_dispatcher.py
Normal file
103
tests/helpers/test_dispatcher.py
Normal file
@ -0,0 +1,103 @@
|
||||
"""Test dispatcher helpers."""
|
||||
import asyncio
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
dispatcher_send, dispatcher_connect)
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class TestHelpersDispatcher(object):
|
||||
"""Tests for discovery helper methods."""
|
||||
|
||||
def setup_method(self, method):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
def teardown_method(self, method):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_simple_function(self):
|
||||
"""Test simple function (executor)."""
|
||||
calls = []
|
||||
|
||||
def test_funct(data):
|
||||
"""Test function."""
|
||||
calls.append(data)
|
||||
|
||||
dispatcher_connect(self.hass, 'test', test_funct)
|
||||
self.hass.block_till_done()
|
||||
|
||||
dispatcher_send(self.hass, 'test', 3)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3]
|
||||
|
||||
dispatcher_send(self.hass, 'test', 'bla')
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3, 'bla']
|
||||
|
||||
def test_simple_callback(self):
|
||||
"""Test simple callback (async)."""
|
||||
calls = []
|
||||
|
||||
@callback
|
||||
def test_funct(data):
|
||||
"""Test function."""
|
||||
calls.append(data)
|
||||
|
||||
dispatcher_connect(self.hass, 'test', test_funct)
|
||||
self.hass.block_till_done()
|
||||
|
||||
dispatcher_send(self.hass, 'test', 3)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3]
|
||||
|
||||
dispatcher_send(self.hass, 'test', 'bla')
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3, 'bla']
|
||||
|
||||
def test_simple_coro(self):
|
||||
"""Test simple coro (async)."""
|
||||
calls = []
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_funct(data):
|
||||
"""Test function."""
|
||||
calls.append(data)
|
||||
|
||||
dispatcher_connect(self.hass, 'test', test_funct)
|
||||
self.hass.block_till_done()
|
||||
|
||||
dispatcher_send(self.hass, 'test', 3)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3]
|
||||
|
||||
dispatcher_send(self.hass, 'test', 'bla')
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3, 'bla']
|
||||
|
||||
def test_simple_function_multiargs(self):
|
||||
"""Test simple function (executor)."""
|
||||
calls = []
|
||||
|
||||
def test_funct(data1, data2, data3):
|
||||
"""Test function."""
|
||||
calls.append(data1)
|
||||
calls.append(data2)
|
||||
calls.append(data3)
|
||||
|
||||
dispatcher_connect(self.hass, 'test', test_funct)
|
||||
self.hass.block_till_done()
|
||||
|
||||
dispatcher_send(self.hass, 'test', 3, 2, 'bla')
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert calls == [3, 2, 'bla']
|
Loading…
x
Reference in New Issue
Block a user