Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new arm_custom_bypass state #10697

Merged
merged 1 commit into from
Nov 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion homeassistant/components/alarm_control_panel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
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
Expand All @@ -33,6 +33,7 @@
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'
}

Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -216,6 +229,17 @@ def async_alarm_trigger(self, code=None):
"""
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."""
Expand Down
18 changes: 14 additions & 4 deletions homeassistant/components/alarm_control_panel/manual.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
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

Expand All @@ -26,7 +26,8 @@
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'

Expand Down Expand Up @@ -59,6 +60,8 @@ def _state_validator(config):
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))

Expand Down Expand Up @@ -174,6 +177,13 @@ def alarm_arm_night(self, code=None):

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
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
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'
Expand Down Expand Up @@ -347,8 +348,10 @@
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'

Expand Down
115 changes: 114 additions & 1 deletion tests/components/alarm_control_panel/test_manual.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
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

Expand Down Expand Up @@ -673,3 +674,115 @@ def test_disarm_during_trigger_with_invalid_code(self):

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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no newline at end of file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think this comment is valid anymore