Add Arm Custom Bypass to alarm_control_panel (#10697)
parent
df37cb11fa
commit
e62ef067cc
|
@ -14,7 +14,7 @@ import voluptuous as vol
|
|||
from homeassistant.const import (
|
||||
ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
|
||||
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY,
|
||||
SERVICE_ALARM_ARM_NIGHT)
|
||||
SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_ARM_CUSTOM_BYPASS)
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
|
||||
|
@ -33,6 +33,7 @@ SERVICE_TO_METHOD = {
|
|||
SERVICE_ALARM_ARM_HOME: 'alarm_arm_home',
|
||||
SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away',
|
||||
SERVICE_ALARM_ARM_NIGHT: 'alarm_arm_night',
|
||||
SERVICE_ALARM_ARM_CUSTOM_BYPASS: 'alarm_arm_custom_bypass',
|
||||
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
|
||||
}
|
||||
|
||||
|
@ -107,6 +108,18 @@ def alarm_trigger(hass, code=None, entity_id=None):
|
|||
hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data)
|
||||
|
||||
|
||||
@bind_hass
|
||||
def alarm_arm_custom_bypass(hass, code=None, entity_id=None):
|
||||
"""Send the alarm the command for arm custom bypass."""
|
||||
data = {}
|
||||
if code:
|
||||
data[ATTR_CODE] = code
|
||||
if entity_id:
|
||||
data[ATTR_ENTITY_ID] = entity_id
|
||||
|
||||
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_CUSTOM_BYPASS, data)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Track states and offer events for sensors."""
|
||||
|
@ -216,6 +229,17 @@ class AlarmControlPanel(Entity):
|
|||
"""
|
||||
return self.hass.async_add_job(self.alarm_trigger, code)
|
||||
|
||||
def alarm_arm_custom_bypass(self, code=None):
|
||||
"""Send arm custom bypass command."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def async_alarm_arm_custom_bypass(self, code=None):
|
||||
"""Send arm custom bypass command.
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
return self.hass.async_add_job(self.alarm_arm_custom_bypass, code)
|
||||
|
||||
@property
|
||||
def state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
|
|
|
@ -14,9 +14,9 @@ import homeassistant.components.alarm_control_panel as alarm
|
|||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.const import (
|
||||
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT,
|
||||
STATE_ALARM_DISARMED, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED,
|
||||
CONF_PLATFORM, CONF_NAME, CONF_CODE, CONF_PENDING_TIME, CONF_TRIGGER_TIME,
|
||||
CONF_DISARM_AFTER_TRIGGER)
|
||||
STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_DISARMED, STATE_ALARM_PENDING,
|
||||
STATE_ALARM_TRIGGERED, CONF_PLATFORM, CONF_NAME, CONF_CODE,
|
||||
CONF_PENDING_TIME, CONF_TRIGGER_TIME, CONF_DISARM_AFTER_TRIGGER)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.event import track_point_in_time
|
||||
|
||||
|
@ -26,7 +26,8 @@ DEFAULT_TRIGGER_TIME = 120
|
|||
DEFAULT_DISARM_AFTER_TRIGGER = False
|
||||
|
||||
SUPPORTED_PENDING_STATES = [STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_TRIGGERED]
|
||||
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_TRIGGERED,
|
||||
STATE_ALARM_ARMED_CUSTOM_BYPASS]
|
||||
|
||||
ATTR_POST_PENDING_STATE = 'post_pending_state'
|
||||
|
||||
|
@ -59,6 +60,8 @@ PLATFORM_SCHEMA = vol.Schema(vol.All({
|
|||
vol.Optional(STATE_ALARM_ARMED_AWAY, default={}): STATE_SETTING_SCHEMA,
|
||||
vol.Optional(STATE_ALARM_ARMED_HOME, default={}): STATE_SETTING_SCHEMA,
|
||||
vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): STATE_SETTING_SCHEMA,
|
||||
vol.Optional(STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||
default={}): STATE_SETTING_SCHEMA,
|
||||
vol.Optional(STATE_ALARM_TRIGGERED, default={}): STATE_SETTING_SCHEMA,
|
||||
}, _state_validator))
|
||||
|
||||
|
@ -174,6 +177,13 @@ class ManualAlarm(alarm.AlarmControlPanel):
|
|||
|
||||
self._update_state(STATE_ALARM_ARMED_NIGHT)
|
||||
|
||||
def alarm_arm_custom_bypass(self, code=None):
|
||||
"""Send arm custom bypass command."""
|
||||
if not self._validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
|
||||
|
||||
def alarm_trigger(self, code=None):
|
||||
"""Send alarm trigger command. No code needed."""
|
||||
self._pre_trigger_state = self._state
|
||||
|
|
|
@ -181,6 +181,7 @@ STATE_ALARM_DISARMED = 'disarmed'
|
|||
STATE_ALARM_ARMED_HOME = 'armed_home'
|
||||
STATE_ALARM_ARMED_AWAY = 'armed_away'
|
||||
STATE_ALARM_ARMED_NIGHT = 'armed_night'
|
||||
STATE_ALARM_ARMED_CUSTOM_BYPASS = 'armed_custom_bypass'
|
||||
STATE_ALARM_PENDING = 'pending'
|
||||
STATE_ALARM_ARMING = 'arming'
|
||||
STATE_ALARM_DISARMING = 'disarming'
|
||||
|
@ -347,8 +348,10 @@ SERVICE_ALARM_DISARM = 'alarm_disarm'
|
|||
SERVICE_ALARM_ARM_HOME = 'alarm_arm_home'
|
||||
SERVICE_ALARM_ARM_AWAY = 'alarm_arm_away'
|
||||
SERVICE_ALARM_ARM_NIGHT = 'alarm_arm_night'
|
||||
SERVICE_ALARM_ARM_CUSTOM_BYPASS = 'alarm_arm_custom_bypass'
|
||||
SERVICE_ALARM_TRIGGER = 'alarm_trigger'
|
||||
|
||||
|
||||
SERVICE_LOCK = 'lock'
|
||||
SERVICE_UNLOCK = 'unlock'
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ from unittest.mock import patch
|
|||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import (
|
||||
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
|
||||
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED)
|
||||
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED)
|
||||
from homeassistant.components import alarm_control_panel
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
|
@ -673,3 +674,115 @@ class TestAlarmControlPanelManual(unittest.TestCase):
|
|||
|
||||
self.assertEqual(STATE_ALARM_TRIGGERED,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
def test_arm_custom_bypass_no_pending(self):
|
||||
"""Test arm custom bypass method."""
|
||||
self.assertTrue(setup_component(
|
||||
self.hass, alarm_control_panel.DOMAIN,
|
||||
{'alarm_control_panel': {
|
||||
'platform': 'manual',
|
||||
'name': 'test',
|
||||
'code': CODE,
|
||||
'pending_time': 0,
|
||||
'disarm_after_trigger': False
|
||||
}}))
|
||||
|
||||
entity_id = 'alarm_control_panel.test'
|
||||
|
||||
self.assertEqual(STATE_ALARM_DISARMED,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
alarm_control_panel.alarm_arm_custom_bypass(self.hass, CODE)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
def test_arm_custom_bypass_with_pending(self):
|
||||
"""Test arm custom bypass method."""
|
||||
self.assertTrue(setup_component(
|
||||
self.hass, alarm_control_panel.DOMAIN,
|
||||
{'alarm_control_panel': {
|
||||
'platform': 'manual',
|
||||
'name': 'test',
|
||||
'code': CODE,
|
||||
'pending_time': 1,
|
||||
'disarm_after_trigger': False
|
||||
}}))
|
||||
|
||||
entity_id = 'alarm_control_panel.test'
|
||||
|
||||
self.assertEqual(STATE_ALARM_DISARMED,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
alarm_control_panel.alarm_arm_custom_bypass(self.hass, CODE, entity_id)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(STATE_ALARM_PENDING,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.attributes['post_pending_state'] == \
|
||||
STATE_ALARM_ARMED_CUSTOM_BYPASS
|
||||
|
||||
future = dt_util.utcnow() + timedelta(seconds=1)
|
||||
with patch(('homeassistant.components.alarm_control_panel.manual.'
|
||||
'dt_util.utcnow'), return_value=future):
|
||||
fire_time_changed(self.hass, future)
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ALARM_ARMED_CUSTOM_BYPASS
|
||||
|
||||
def test_arm_custom_bypass_with_invalid_code(self):
|
||||
"""Attempt to custom bypass without a valid code."""
|
||||
self.assertTrue(setup_component(
|
||||
self.hass, alarm_control_panel.DOMAIN,
|
||||
{'alarm_control_panel': {
|
||||
'platform': 'manual',
|
||||
'name': 'test',
|
||||
'code': CODE,
|
||||
'pending_time': 1,
|
||||
'disarm_after_trigger': False
|
||||
}}))
|
||||
|
||||
entity_id = 'alarm_control_panel.test'
|
||||
|
||||
self.assertEqual(STATE_ALARM_DISARMED,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
alarm_control_panel.alarm_arm_custom_bypass(self.hass, CODE + '2')
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(STATE_ALARM_DISARMED,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
def test_armed_custom_bypass_with_specific_pending(self):
|
||||
"""Test arm custom bypass method."""
|
||||
self.assertTrue(setup_component(
|
||||
self.hass, alarm_control_panel.DOMAIN,
|
||||
{'alarm_control_panel': {
|
||||
'platform': 'manual',
|
||||
'name': 'test',
|
||||
'pending_time': 10,
|
||||
'armed_custom_bypass': {
|
||||
'pending_time': 2
|
||||
}
|
||||
}}))
|
||||
|
||||
entity_id = 'alarm_control_panel.test'
|
||||
|
||||
alarm_control_panel.alarm_arm_custom_bypass(self.hass)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(STATE_ALARM_PENDING,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
||||
future = dt_util.utcnow() + timedelta(seconds=2)
|
||||
with patch(('homeassistant.components.alarm_control_panel.manual.'
|
||||
'dt_util.utcnow'), return_value=future):
|
||||
fire_time_changed(self.hass, future)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||
self.hass.states.get(entity_id).state)
|
||||
|
|
Loading…
Reference in New Issue