From f4a9ad0b2ebc3369da3ae6b5c62c1f9eae0bb193 Mon Sep 17 00:00:00 2001 From: c-soft Date: Thu, 7 Mar 2019 04:47:47 +0100 Subject: [PATCH] Fix initialization and add "pending" status of Satel integra (#21194) * Added updating alarm state after start of the HA. Still rough and dirty. * Fixed initialization of the panel and binary sensor. Before cleanup. * Added alarm clearing, linting fixes. * Removed dead code, added style changes. * Updated requirements * Fixed linting errors. * Fixed linting errors * Fixed linter errors. * Fixed hopefully last linter errors. * Fixes after code review, imports sorted. * Removed init debugging --- .../components/satel_integra/__init__.py | 42 ++------- .../satel_integra/alarm_control_panel.py | 90 ++++++++++++++++--- .../components/satel_integra/binary_sensor.py | 22 +++-- requirements_all.txt | 2 +- 4 files changed, 102 insertions(+), 54 deletions(-) diff --git a/homeassistant/components/satel_integra/__init__.py b/homeassistant/components/satel_integra/__init__.py index bff365a079f..93f157cd5ec 100644 --- a/homeassistant/components/satel_integra/__init__.py +++ b/homeassistant/components/satel_integra/__init__.py @@ -1,19 +1,15 @@ """Support for Satel Integra devices.""" -import asyncio import logging - import voluptuous as vol +from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import callback -from homeassistant.const import ( - STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, - STATE_ALARM_TRIGGERED, EVENT_HOMEASSISTANT_STOP) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send -REQUIREMENTS = ['satel_integra==0.2.0'] +REQUIREMENTS = ['satel_integra==0.3.2'] DEFAULT_ALARM_NAME = 'satel_integra' DEFAULT_PORT = 7094 @@ -76,7 +72,7 @@ async def async_setup(hass, config): port = conf.get(CONF_DEVICE_PORT) partition = conf.get(CONF_DEVICE_PARTITION) - from satel_integra.satel_integra import AsyncSatel, AlarmState + from satel_integra.satel_integra import AsyncSatel controller = AsyncSatel(host, port, hass.loop, zones, outputs, partition) @@ -96,41 +92,19 @@ async def async_setup(hass, config): conf, conf.get(CONF_ARM_HOME_MODE)) - task_control_panel = hass.async_create_task( + hass.async_create_task( async_load_platform(hass, 'alarm_control_panel', DOMAIN, conf, config)) - task_zones = hass.async_create_task( + hass.async_create_task( async_load_platform(hass, 'binary_sensor', DOMAIN, {CONF_ZONES: zones, CONF_OUTPUTS: outputs}, config) ) - await asyncio.wait([task_control_panel, task_zones], loop=hass.loop) - @callback - def alarm_status_update_callback(status): + def alarm_status_update_callback(): """Send status update received from alarm to home assistant.""" - _LOGGER.debug("Alarm status callback, status: %s", status) - hass_alarm_status = STATE_ALARM_DISARMED - - if status == AlarmState.ARMED_MODE0: - hass_alarm_status = STATE_ALARM_ARMED_AWAY - - elif status in [ - AlarmState.ARMED_MODE0, - AlarmState.ARMED_MODE1, - AlarmState.ARMED_MODE2, - AlarmState.ARMED_MODE3 - ]: - hass_alarm_status = STATE_ALARM_ARMED_HOME - - elif status in [AlarmState.TRIGGERED, AlarmState.TRIGGERED_FIRE]: - hass_alarm_status = STATE_ALARM_TRIGGERED - - elif status == AlarmState.DISARMED: - hass_alarm_status = STATE_ALARM_DISARMED - - _LOGGER.debug("Sending hass_alarm_status: %s...", hass_alarm_status) - async_dispatcher_send(hass, SIGNAL_PANEL_MESSAGE, hass_alarm_status) + _LOGGER.debug("Sending request to update panel state") + async_dispatcher_send(hass, SIGNAL_PANEL_MESSAGE) @callback def zones_update_callback(status): diff --git a/homeassistant/components/satel_integra/alarm_control_panel.py b/homeassistant/components/satel_integra/alarm_control_panel.py index 360acdb2497..d2d9f473051 100644 --- a/homeassistant/components/satel_integra/alarm_control_panel.py +++ b/homeassistant/components/satel_integra/alarm_control_panel.py @@ -1,12 +1,19 @@ """Support for Satel Integra alarm, using ETHM module.""" +import asyncio import logging +from collections import OrderedDict import homeassistant.components.alarm_control_panel as alarm -from homeassistant.components.satel_integra import ( - CONF_ARM_HOME_MODE, DATA_SATEL, SIGNAL_PANEL_MESSAGE) +from homeassistant.const import ( + STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect +from . import ( + CONF_ARM_HOME_MODE, CONF_DEVICE_PARTITION, DATA_SATEL, + SIGNAL_PANEL_MESSAGE) + _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['satel_integra'] @@ -19,32 +26,73 @@ async def async_setup_platform( return device = SatelIntegraAlarmPanel( - "Alarm Panel", discovery_info.get(CONF_ARM_HOME_MODE)) + "Alarm Panel", + discovery_info.get(CONF_ARM_HOME_MODE), + discovery_info.get(CONF_DEVICE_PARTITION)) + async_add_entities([device]) class SatelIntegraAlarmPanel(alarm.AlarmControlPanel): """Representation of an AlarmDecoder-based alarm panel.""" - def __init__(self, name, arm_home_mode): + def __init__(self, name, arm_home_mode, partition_id): """Initialize the alarm panel.""" self._name = name self._state = None self._arm_home_mode = arm_home_mode + self._partition_id = partition_id async def async_added_to_hass(self): - """Register callbacks.""" + """Update alarm status and register callbacks for future updates.""" + _LOGGER.debug("Starts listening for panel messages") + self._update_alarm_status() async_dispatcher_connect( - self.hass, SIGNAL_PANEL_MESSAGE, self._message_callback) + self.hass, SIGNAL_PANEL_MESSAGE, self._update_alarm_status) @callback - def _message_callback(self, message): - """Handle received messages.""" - if message != self._state: - self._state = message + def _update_alarm_status(self): + """Handle alarm status update.""" + state = self._read_alarm_state() + _LOGGER.debug("Got status update, current status: %s", state) + if state != self._state: + self._state = state self.async_schedule_update_ha_state() else: - _LOGGER.warning("Ignoring alarm status message, same state") + _LOGGER.debug("Ignoring alarm status message, same state") + + def _read_alarm_state(self): + """Read current status of the alarm and translate it into HA status.""" + from satel_integra.satel_integra import AlarmState + + # Default - disarmed: + hass_alarm_status = STATE_ALARM_DISARMED + + satel_controller = self.hass.data[DATA_SATEL] + if not satel_controller.connected: + return None + + state_map = OrderedDict([ + (AlarmState.TRIGGERED, STATE_ALARM_TRIGGERED), + (AlarmState.TRIGGERED_FIRE, STATE_ALARM_TRIGGERED), + (AlarmState.ARMED_MODE3, STATE_ALARM_ARMED_HOME), + (AlarmState.ARMED_MODE2, STATE_ALARM_ARMED_HOME), + (AlarmState.ARMED_MODE1, STATE_ALARM_ARMED_HOME), + (AlarmState.ARMED_MODE0, STATE_ALARM_ARMED_AWAY), + (AlarmState.EXIT_COUNTDOWN_OVER_10, STATE_ALARM_PENDING), + (AlarmState.EXIT_COUNTDOWN_UNDER_10, STATE_ALARM_PENDING) + ]) + _LOGGER.debug("State map of Satel: %s", + satel_controller.partition_states) + + for satel_state, ha_state in state_map.items(): + if satel_state in satel_controller.partition_states and\ + self._partition_id in\ + satel_controller.partition_states[satel_state]: + hass_alarm_status = ha_state + break + + return hass_alarm_status @property def name(self): @@ -68,16 +116,32 @@ class SatelIntegraAlarmPanel(alarm.AlarmControlPanel): async def async_alarm_disarm(self, code=None): """Send disarm command.""" - if code: - await self.hass.data[DATA_SATEL].disarm(code) + if not code: + _LOGGER.debug("Code was empty or None") + return + + clear_alarm_necessary = self._state == STATE_ALARM_TRIGGERED + + _LOGGER.debug("Disarming, self._state: %s", self._state) + + await self.hass.data[DATA_SATEL].disarm(code) + + if clear_alarm_necessary: + # Wait 1s before clearing the alarm + await asyncio.sleep(1) + await self.hass.data[DATA_SATEL].clear_alarm(code) async def async_alarm_arm_away(self, code=None): """Send arm away command.""" + _LOGGER.debug("Arming away") + if code: await self.hass.data[DATA_SATEL].arm(code) async def async_alarm_arm_home(self, code=None): """Send arm home command.""" + _LOGGER.debug("Arming home") + if code: await self.hass.data[DATA_SATEL].arm( code, self._arm_home_mode) diff --git a/homeassistant/components/satel_integra/binary_sensor.py b/homeassistant/components/satel_integra/binary_sensor.py index 34ced628712..0384ff37f14 100644 --- a/homeassistant/components/satel_integra/binary_sensor.py +++ b/homeassistant/components/satel_integra/binary_sensor.py @@ -2,15 +2,13 @@ import logging from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.satel_integra import (CONF_ZONES, - CONF_OUTPUTS, - CONF_ZONE_NAME, - CONF_ZONE_TYPE, - SIGNAL_ZONES_UPDATED, - SIGNAL_OUTPUTS_UPDATED) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect +from . import ( + CONF_OUTPUTS, CONF_ZONE_NAME, CONF_ZONE_TYPE, CONF_ZONES, DATA_SATEL, + SIGNAL_OUTPUTS_UPDATED, SIGNAL_ZONES_UPDATED) + DEPENDENCIES = ['satel_integra'] _LOGGER = logging.getLogger(__name__) @@ -58,6 +56,18 @@ class SatelIntegraBinarySensor(BinarySensorDevice): async def async_added_to_hass(self): """Register callbacks.""" + if self._react_to_signal == SIGNAL_OUTPUTS_UPDATED: + if self._device_number in\ + self.hass.data[DATA_SATEL].violated_outputs: + self._state = 1 + else: + self._state = 0 + else: + if self._device_number in\ + self.hass.data[DATA_SATEL].violated_zones: + self._state = 1 + else: + self._state = 0 async_dispatcher_connect( self.hass, self._react_to_signal, self._devices_updated) diff --git a/requirements_all.txt b/requirements_all.txt index 207097b2bdc..c03af9f9cc1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1532,7 +1532,7 @@ rxv==0.6.0 samsungctl[websocket]==0.7.1 # homeassistant.components.satel_integra -satel_integra==0.2.0 +satel_integra==0.3.2 # homeassistant.components.sensor.deutsche_bahn schiene==0.22