From 1460f7bd80933c45b87cc2e6c39a819d859b54b9 Mon Sep 17 00:00:00 2001 From: Kevin Cooper Date: Mon, 17 Jun 2019 22:59:20 +0100 Subject: [PATCH] Add code_arm_required to manual alarm (#22618) * Add code_arm_required to manual alarm * Add fix for alarm front end more-info-alarm_control_panel --- .../components/demo/alarm_control_panel.py | 2 +- .../components/manual/alarm_control_panel.py | 23 +++- .../manual/test_alarm_control_panel.py | 100 ++++++++++++++++++ 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/demo/alarm_control_panel.py b/homeassistant/components/demo/alarm_control_panel.py index 3cf5aaca57e..a960848eee7 100644 --- a/homeassistant/components/demo/alarm_control_panel.py +++ b/homeassistant/components/demo/alarm_control_panel.py @@ -12,7 +12,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Demo alarm control panel platform.""" async_add_entities([ - ManualAlarm(hass, 'Alarm', '1234', None, False, { + ManualAlarm(hass, 'Alarm', '1234', None, True, False, { STATE_ALARM_ARMED_AWAY: { CONF_DELAY_TIME: datetime.timedelta(seconds=0), CONF_PENDING_TIME: datetime.timedelta(seconds=5), diff --git a/homeassistant/components/manual/alarm_control_panel.py b/homeassistant/components/manual/alarm_control_panel.py index 14934db41c2..da0f7035d5c 100644 --- a/homeassistant/components/manual/alarm_control_panel.py +++ b/homeassistant/components/manual/alarm_control_panel.py @@ -21,6 +21,7 @@ from homeassistant.helpers.restore_state import RestoreEntity _LOGGER = logging.getLogger(__name__) CONF_CODE_TEMPLATE = 'code_template' +CONF_CODE_ARM_REQUIRED = 'code_arm_required' DEFAULT_ALARM_NAME = 'HA Alarm' DEFAULT_DELAY_TIME = datetime.timedelta(seconds=0) @@ -76,6 +77,7 @@ PLATFORM_SCHEMA = vol.Schema(vol.All({ vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string, vol.Exclusive(CONF_CODE, 'code validation'): cv.string, vol.Exclusive(CONF_CODE_TEMPLATE, 'code validation'): cv.template, + vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean, vol.Optional(CONF_DELAY_TIME, default=DEFAULT_DELAY_TIME): vol.All(cv.time_period, cv.positive_timedelta), vol.Optional(CONF_PENDING_TIME, default=DEFAULT_PENDING_TIME): @@ -106,6 +108,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): config[CONF_NAME], config.get(CONF_CODE), config.get(CONF_CODE_TEMPLATE), + config.get(CONF_CODE_ARM_REQUIRED), config.get(CONF_DISARM_AFTER_TRIGGER, DEFAULT_DISARM_AFTER_TRIGGER), config )]) @@ -124,7 +127,7 @@ class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity): """ def __init__(self, hass, name, code, code_template, - disarm_after_trigger, config): + code_arm_required, disarm_after_trigger, config): """Init the manual alarm panel.""" self._state = STATE_ALARM_DISARMED self._hass = hass @@ -134,6 +137,7 @@ class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity): self._code.hass = hass else: self._code = code or None + self._code_arm_required = code_arm_required self._disarm_after_trigger = disarm_after_trigger self._previous_state = self._state self._state_ts = None @@ -205,6 +209,11 @@ class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity): return alarm.FORMAT_NUMBER return alarm.FORMAT_TEXT + @property + def code_arm_required(self): + """Whether the code is required for arm actions.""" + return self._code_arm_required + def alarm_disarm(self, code=None): """Send disarm command.""" if not self._validate_code(code, STATE_ALARM_DISARMED): @@ -216,28 +225,32 @@ class ManualAlarm(alarm.AlarmControlPanel, RestoreEntity): def alarm_arm_home(self, code=None): """Send arm home command.""" - if not self._validate_code(code, STATE_ALARM_ARMED_HOME): + if self._code_arm_required and not \ + self._validate_code(code, STATE_ALARM_ARMED_HOME): return self._update_state(STATE_ALARM_ARMED_HOME) def alarm_arm_away(self, code=None): """Send arm away command.""" - if not self._validate_code(code, STATE_ALARM_ARMED_AWAY): + if self._code_arm_required and not \ + self._validate_code(code, STATE_ALARM_ARMED_AWAY): return self._update_state(STATE_ALARM_ARMED_AWAY) def alarm_arm_night(self, code=None): """Send arm night command.""" - if not self._validate_code(code, STATE_ALARM_ARMED_NIGHT): + if self._code_arm_required and not \ + self._validate_code(code, STATE_ALARM_ARMED_NIGHT): return 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): + if self._code_arm_required and not \ + self._validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS): return self._update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS) diff --git a/tests/components/manual/test_alarm_control_panel.py b/tests/components/manual/test_alarm_control_panel.py index f0f10720853..2cb7e3f1428 100644 --- a/tests/components/manual/test_alarm_control_panel.py +++ b/tests/components/manual/test_alarm_control_panel.py @@ -48,6 +48,31 @@ async def test_arm_home_no_pending(hass): hass.states.get(entity_id).state +async def test_arm_home_no_pending_when_code_not_req(hass): + """Test arm home method.""" + assert await async_setup_component( + hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'code_arm_required': False, + 'pending_time': 0, + 'disarm_after_trigger': False + }}) + + entity_id = 'alarm_control_panel.test' + + assert STATE_ALARM_DISARMED == \ + hass.states.get(entity_id).state + + common.async_alarm_arm_home(hass, 0) + await hass.async_block_till_done() + + assert STATE_ALARM_ARMED_HOME == \ + hass.states.get(entity_id).state + + async def test_arm_home_with_pending(hass): """Test arm home method.""" assert await async_setup_component( @@ -129,6 +154,31 @@ async def test_arm_away_no_pending(hass): hass.states.get(entity_id).state +async def test_arm_away_no_pending_when_code_not_req(hass): + """Test arm home method.""" + assert await async_setup_component( + hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'code_arm_required': False, + 'pending_time': 0, + 'disarm_after_trigger': False + }}) + + entity_id = 'alarm_control_panel.test' + + assert STATE_ALARM_DISARMED == \ + hass.states.get(entity_id).state + + common.async_alarm_arm_away(hass, 0, entity_id) + await hass.async_block_till_done() + + assert STATE_ALARM_ARMED_AWAY == \ + hass.states.get(entity_id).state + + async def test_arm_home_with_template_code(hass): """Attempt to arm with a template-based code.""" assert await async_setup_component( @@ -233,6 +283,31 @@ async def test_arm_night_no_pending(hass): hass.states.get(entity_id).state +async def test_arm_night_no_pending_when_code_not_req(hass): + """Test arm night method.""" + assert await async_setup_component( + hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'code_arm_required': False, + 'pending_time': 0, + 'disarm_after_trigger': False + }}) + + entity_id = 'alarm_control_panel.test' + + assert STATE_ALARM_DISARMED == \ + hass.states.get(entity_id).state + + common.async_alarm_arm_night(hass, 0) + await hass.async_block_till_done() + + assert STATE_ALARM_ARMED_NIGHT == \ + hass.states.get(entity_id).state + + async def test_arm_night_with_pending(hass): """Test arm night method.""" assert await async_setup_component( @@ -1128,6 +1203,31 @@ async def test_arm_custom_bypass_no_pending(hass): hass.states.get(entity_id).state +async def test_arm_custom_bypass_no_pending_when_code_not_req(hass): + """Test arm custom bypass method.""" + assert await async_setup_component( + hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'code_arm_required': False, + 'pending_time': 0, + 'disarm_after_trigger': False + }}) + + entity_id = 'alarm_control_panel.test' + + assert STATE_ALARM_DISARMED == \ + hass.states.get(entity_id).state + + common.async_alarm_arm_custom_bypass(hass, 0) + await hass.async_block_till_done() + + assert STATE_ALARM_ARMED_CUSTOM_BYPASS == \ + hass.states.get(entity_id).state + + async def test_arm_custom_bypass_with_pending(hass): """Test arm custom bypass method.""" assert await async_setup_component(