From e57b3ae847a6d12c571b4f1eae1bbd49550a6479 Mon Sep 17 00:00:00 2001 From: sfam Date: Mon, 28 Sep 2015 23:36:46 +0000 Subject: [PATCH] add manual alarm --- .../alarm_control_panel/__init__.py | 23 ++- .../components/alarm_control_panel/manual.py | 142 ++++++++++++++++++ .../components/alarm_control_panel/mqtt.py | 4 + .../alarm_control_panel/verisure.py | 4 + homeassistant/const.py | 3 + 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/alarm_control_panel/manual.py diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 49eb5eafba7..f922ecdacc0 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -8,7 +8,7 @@ import os from homeassistant.components import verisure from homeassistant.const import ( - ATTR_ENTITY_ID, + ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER, SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY) from homeassistant.config import load_yaml_config_file from homeassistant.helpers.entity import Entity @@ -29,6 +29,7 @@ SERVICE_TO_METHOD = { SERVICE_ALARM_DISARM: 'alarm_disarm', SERVICE_ALARM_ARM_HOME: 'alarm_arm_home', SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away', + SERVICE_ALARM_TRIGGER: 'alarm_trigger' } ATTR_CODE = 'code' @@ -53,9 +54,9 @@ def setup(hass, config): target_alarms = component.extract_from_service(service) if ATTR_CODE not in service.data: - return - - code = service.data[ATTR_CODE] + code = None + else: + code = service.data[ATTR_CODE] method = SERVICE_TO_METHOD[service.service] @@ -102,6 +103,16 @@ def alarm_arm_away(hass, code, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data) +def alarm_trigger(hass, code, entity_id=None): + """ Send the alarm the command for trigger. """ + data = {ATTR_CODE: code} + + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) + + # pylint: disable=no-self-use class AlarmControlPanel(Entity): """ ABC for alarm control devices. """ @@ -123,6 +134,10 @@ class AlarmControlPanel(Entity): """ Send arm away command. """ raise NotImplementedError() + def alarm_trigger(self, code=None): + """ Send alarm trigger command. """ + raise NotImplementedError() + @property def state_attributes(self): """ Return the state attributes. """ diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py new file mode 100644 index 00000000000..e83a2e9da2f --- /dev/null +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -0,0 +1,142 @@ +""" +homeassistant.components.alarm_control_panel.manual + +Configuration: + +alarm_control_panel: + platform: manual + name: "HA Alarm" + code: "mySecretCode" + pending_time: 60 + trigger_time: 120 + +Variables: + +name +*Optional +The name of the alarm. Default is 'HA Alarm'. + +code +*Optional +If defined, specifies a code to arm or disarm the alarm in the frontend. + +pending_time +*Optional +The time in seconds of the pending time before arming the alarm. +Default is 60 seconds. + +trigger_time +*Optional +The time in seconds of the trigger time in which the alarm is firing. +Default is 120 seconds. + +""" + +import logging +import time +import homeassistant.components.alarm_control_panel as alarm + +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = [] + +DEFAULT_ALARM_NAME = 'HA Alarm' +DEFAULT_PENDING_TIME = 60 +DEFAULT_TRIGGER_TIME = 120 + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the manual alarm platform. """ + + add_devices([ManualAlarm( + hass, + config.get('name', DEFAULT_ALARM_NAME), + config.get('code'), + config.get('pending_time', DEFAULT_PENDING_TIME), + config.get('trigger_time', DEFAULT_TRIGGER_TIME), + )]) + + +# pylint: disable=too-many-arguments, too-many-instance-attributes +class ManualAlarm(alarm.AlarmControlPanel): + """ represents an alarm status within home assistant. """ + + def __init__(self, hass, name, code, pending_time, trigger_time): + self._state = STATE_ALARM_DISARMED + self._hass = hass + self._name = name + self._code = code + self._pending_time = pending_time + self._trigger_time = trigger_time + self._pending_to = None + + @property + def should_poll(self): + """ No polling needed """ + return False + + @property + def name(self): + """ Returns the name of the device. """ + return self._name + + @property + def state(self): + """ Returns the state of the device. """ + return self._state + + @property + def code_format(self): + """ One or more characters """ + return None if self._code is None else '.+' + + def change_alarm_state(self, begin, end, delay=0): + """ changes between state with delay """ + self._state = begin + self._pending_to = end + self.update_ha_state() + time.sleep(delay) + if self._pending_to == end and begin != end: + self._state = end + self._pending_to = None + self.update_ha_state() + + def alarm_disarm(self, code=None): + """ Send disarm command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_DISARMED, STATE_ALARM_DISARMED) + else: + _LOGGER.warning("Wrong code entered while disarming!") + + def alarm_arm_home(self, code=None): + """ Send arm home command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME, + self._pending_time) + else: + _LOGGER.warning("Wrong code entered while arming home!") + + def alarm_arm_away(self, code=None): + """ Send arm away command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY, + self._pending_time) + else: + _LOGGER.warning("Wrong code entered while arming away!") + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, + self._pending_time) + if self._state == STATE_ALARM_TRIGGERED: + self.change_alarm_state( + STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED, + self._trigger_time) diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index f4d89e5a847..27e78cb38fe 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -166,3 +166,7 @@ class MqttAlarm(alarm.AlarmControlPanel): self._payload_arm_away, self._qos) else: _LOGGER.warning("Wrong code entered while arming away!") + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + return diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 7923f7c97e7..f590d462e9b 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -91,3 +91,7 @@ class VerisureAlarm(alarm.AlarmControlPanel): code, verisure.MY_PAGES.ALARM_ARMED_AWAY) _LOGGER.warning('arming away') + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + return diff --git a/homeassistant/const.py b/homeassistant/const.py index 5fc3ad4f4a9..7df5e27fbe7 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -51,6 +51,8 @@ STATE_STANDBY = 'standby' STATE_ALARM_DISARMED = 'disarmed' STATE_ALARM_ARMED_HOME = 'armed_home' STATE_ALARM_ARMED_AWAY = 'armed_away' +STATE_ALARM_PENDING = 'pending' +STATE_ALARM_TRIGGERED = 'triggered' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event @@ -121,6 +123,7 @@ SERVICE_MEDIA_SEEK = "media_seek" SERVICE_ALARM_DISARM = "alarm_disarm" SERVICE_ALARM_ARM_HOME = "alarm_arm_home" SERVICE_ALARM_ARM_AWAY = "alarm_arm_away" +SERVICE_ALARM_TRIGGER = "alarm_trigger" # #### API / REMOTE #### SERVER_PORT = 8123