From a28593f1335b9dc59d9d5fe6bb68566717a150c8 Mon Sep 17 00:00:00 2001 From: mbo18 Date: Wed, 1 Sep 2021 09:34:21 +0200 Subject: [PATCH] Add vacation mode to manual alarm_control_panel (#55340) * Add vacation mode * Add vacation to demo * Deduplicate code in tests --- .../components/demo/alarm_control_panel.py | 6 + .../components/manual/alarm_control_panel.py | 16 + .../manual/test_alarm_control_panel.py | 667 ++++-------------- 3 files changed, 171 insertions(+), 518 deletions(-) diff --git a/homeassistant/components/demo/alarm_control_panel.py b/homeassistant/components/demo/alarm_control_panel.py index d5bb71da67b..5a4485c7365 100644 --- a/homeassistant/components/demo/alarm_control_panel.py +++ b/homeassistant/components/demo/alarm_control_panel.py @@ -10,6 +10,7 @@ from homeassistant.const import ( STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMED_VACATION, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, ) @@ -42,6 +43,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= CONF_DELAY_TIME: datetime.timedelta(seconds=0), CONF_TRIGGER_TIME: datetime.timedelta(seconds=10), }, + STATE_ALARM_ARMED_VACATION: { + CONF_ARMING_TIME: datetime.timedelta(seconds=5), + CONF_DELAY_TIME: datetime.timedelta(seconds=0), + CONF_TRIGGER_TIME: datetime.timedelta(seconds=10), + }, STATE_ALARM_DISARMED: { CONF_DELAY_TIME: datetime.timedelta(seconds=0), CONF_TRIGGER_TIME: datetime.timedelta(seconds=10), diff --git a/homeassistant/components/manual/alarm_control_panel.py b/homeassistant/components/manual/alarm_control_panel.py index 00c155615ee..a78476cf5d3 100644 --- a/homeassistant/components/manual/alarm_control_panel.py +++ b/homeassistant/components/manual/alarm_control_panel.py @@ -12,6 +12,7 @@ from homeassistant.components.alarm_control_panel.const import ( SUPPORT_ALARM_ARM_CUSTOM_BYPASS, SUPPORT_ALARM_ARM_HOME, SUPPORT_ALARM_ARM_NIGHT, + SUPPORT_ALARM_ARM_VACATION, SUPPORT_ALARM_TRIGGER, ) from homeassistant.const import ( @@ -26,6 +27,7 @@ from homeassistant.const import ( STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMING, STATE_ALARM_DISARMED, STATE_ALARM_PENDING, @@ -53,6 +55,7 @@ SUPPORTED_STATES = [ STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_TRIGGERED, ] @@ -132,6 +135,9 @@ PLATFORM_SCHEMA = vol.Schema( vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): _state_schema( STATE_ALARM_ARMED_NIGHT ), + vol.Optional(STATE_ALARM_ARMED_VACATION, default={}): _state_schema( + STATE_ALARM_ARMED_VACATION + ), vol.Optional(STATE_ALARM_ARMED_CUSTOM_BYPASS, default={}): _state_schema( STATE_ALARM_ARMED_CUSTOM_BYPASS ), @@ -250,6 +256,7 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity): SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT + | SUPPORT_ALARM_ARM_VACATION | SUPPORT_ALARM_TRIGGER | SUPPORT_ALARM_ARM_CUSTOM_BYPASS ) @@ -327,6 +334,15 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity): self._update_state(STATE_ALARM_ARMED_NIGHT) + def alarm_arm_vacation(self, code=None): + """Send arm vacation command.""" + if self._code_arm_required and not self._validate_code( + code, STATE_ALARM_ARMED_VACATION + ): + return + + self._update_state(STATE_ALARM_ARMED_VACATION) + def alarm_arm_custom_bypass(self, code=None): """Send arm custom bypass command.""" if self._code_arm_required and not self._validate_code( diff --git a/tests/components/manual/test_alarm_control_panel.py b/tests/components/manual/test_alarm_control_panel.py index f3cf3ccce39..2db5b827838 100644 --- a/tests/components/manual/test_alarm_control_panel.py +++ b/tests/components/manual/test_alarm_control_panel.py @@ -2,13 +2,23 @@ from datetime import timedelta from unittest.mock import MagicMock, patch +import pytest + from homeassistant.components import alarm_control_panel from homeassistant.components.demo import alarm_control_panel as demo from homeassistant.const import ( + ATTR_CODE, + ATTR_ENTITY_ID, + SERVICE_ALARM_ARM_AWAY, + SERVICE_ALARM_ARM_CUSTOM_BYPASS, + SERVICE_ALARM_ARM_HOME, + SERVICE_ALARM_ARM_NIGHT, + SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMING, STATE_ALARM_DISARMED, STATE_ALARM_PENDING, @@ -32,8 +42,18 @@ async def test_setup_demo_platform(hass): assert add_entities.call_count == 1 -async def test_arm_home_no_pending(hass): - """Test arm home method.""" +@pytest.mark.parametrize( + "service,expected_state", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_no_pending(hass, service, expected_state): + """Test no pending after arming.""" assert await async_setup_component( hass, alarm_control_panel.DOMAIN, @@ -53,13 +73,28 @@ async def test_arm_home_no_pending(hass): assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_home(hass, CODE) + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE}, + blocking=True, + ) - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME + assert hass.states.get(entity_id).state == expected_state -async def test_arm_home_no_pending_when_code_not_req(hass): - """Test arm home method.""" +@pytest.mark.parametrize( + "service,expected_state", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_no_pending_when_code_not_req(hass, service, expected_state): + """Test no pending when code not required.""" assert await async_setup_component( hass, alarm_control_panel.DOMAIN, @@ -80,13 +115,28 @@ async def test_arm_home_no_pending_when_code_not_req(hass): assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_home(hass, 0) + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE}, + blocking=True, + ) - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME + assert hass.states.get(entity_id).state == expected_state -async def test_arm_home_with_pending(hass): - """Test arm home method.""" +@pytest.mark.parametrize( + "service,expected_state", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_with_pending(hass, service, expected_state): + """Test with pending after arming.""" assert await async_setup_component( hass, alarm_control_panel.DOMAIN, @@ -106,12 +156,17 @@ async def test_arm_home_with_pending(hass): assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_home(hass, CODE, entity_id) + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE}, + blocking=True, + ) assert hass.states.get(entity_id).state == STATE_ALARM_ARMING state = hass.states.get(entity_id) - assert state.attributes["next_state"] == STATE_ALARM_ARMED_HOME + assert state.attributes["next_state"] == expected_state future = dt_util.utcnow() + timedelta(seconds=1) with patch( @@ -122,11 +177,31 @@ async def test_arm_home_with_pending(hass): await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == STATE_ALARM_ARMED_HOME + assert state.state == expected_state + + # Do not go to the pending state when updating to the same state + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE}, + blocking=True, + ) + + assert hass.states.get(entity_id).state == expected_state -async def test_arm_home_with_invalid_code(hass): - """Attempt to arm home without a valid code.""" +@pytest.mark.parametrize( + "service,expected_state", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_with_invalid_code(hass, service, expected_state): + """Attempt to arm without a valid code.""" assert await async_setup_component( hass, alarm_control_panel.DOMAIN, @@ -146,65 +221,27 @@ async def test_arm_home_with_invalid_code(hass): assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_home(hass, CODE + "2") - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - -async def test_arm_away_no_pending(hass): - """Test arm home method.""" - assert await async_setup_component( - hass, + await hass.services.async_call( alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE + "2"}, + blocking=True, ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_away(hass, CODE, entity_id) - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY - - -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, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_away(hass, 0, entity_id) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY - - -async def test_arm_home_with_template_code(hass): +@pytest.mark.parametrize( + "service,expected_state", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_with_template_code(hass, service, expected_state): """Attempt to arm with a template-based code.""" assert await async_setup_component( hass, @@ -225,14 +262,29 @@ async def test_arm_home_with_template_code(hass): assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - await common.async_alarm_arm_home(hass, "abc") + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: "abc"}, + blocking=True, + ) state = hass.states.get(entity_id) - assert state.state == STATE_ALARM_ARMED_HOME + assert state.state == expected_state -async def test_arm_away_with_pending(hass): - """Test arm home method.""" +@pytest.mark.parametrize( + "service,expected_state,", + [ + (SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY), + (SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS), + (SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME), + (SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT), + (SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION), + ], +) +async def test_with_specific_pending(hass, service, expected_state): + """Test arming with specific pending.""" assert await async_setup_component( hass, alarm_control_panel.DOMAIN, @@ -240,9 +292,8 @@ async def test_arm_away_with_pending(hass): "alarm_control_panel": { "platform": "manual", "name": "test", - "code": CODE, - "arming_time": 1, - "disarm_after_trigger": False, + "arming_time": 10, + expected_state: {"arming_time": 2}, } }, ) @@ -250,16 +301,16 @@ async def test_arm_away_with_pending(hass): entity_id = "alarm_control_panel.test" - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_away(hass, CODE) + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + {ATTR_ENTITY_ID: "alarm_control_panel.test"}, + blocking=True, + ) assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - state = hass.states.get(entity_id) - assert state.attributes["next_state"] == STATE_ALARM_ARMED_AWAY - - future = dt_util.utcnow() + timedelta(seconds=1) + future = dt_util.utcnow() + timedelta(seconds=2) with patch( ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), return_value=future, @@ -267,158 +318,7 @@ async def test_arm_away_with_pending(hass): async_fire_time_changed(hass, future) await hass.async_block_till_done() - state = hass.states.get(entity_id) - assert state.state == STATE_ALARM_ARMED_AWAY - - -async def test_arm_away_with_invalid_code(hass): - """Attempt to arm away without a valid code.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 1, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_away(hass, CODE + "2") - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - -async def test_arm_night_no_pending(hass): - """Test arm night method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_night(hass, CODE) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT - - -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, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_night(hass, 0) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT - - -async def test_arm_night_with_pending(hass): - """Test arm night method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 1, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_night(hass, CODE, entity_id) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - state = hass.states.get(entity_id) - assert state.attributes["next_state"] == STATE_ALARM_ARMED_NIGHT - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - assert state.state == STATE_ALARM_ARMED_NIGHT - - # Do not go to the pending state when updating to the same state - await common.async_alarm_arm_night(hass, CODE, entity_id) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT - - -async def test_arm_night_with_invalid_code(hass): - """Attempt to night home without a valid code.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 1, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_night(hass, CODE + "2") - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED + assert hass.states.get(entity_id).state == expected_state async def test_trigger_no_pending(hass): @@ -806,105 +706,6 @@ async def test_trigger_with_pending_and_specific_delay(hass): assert state.state == STATE_ALARM_TRIGGERED -async def test_armed_home_with_specific_pending(hass): - """Test arm home method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "arming_time": 10, - "armed_home": {"arming_time": 2}, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - await common.async_alarm_arm_home(hass) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - future = dt_util.utcnow() + timedelta(seconds=2) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME - - -async def test_armed_away_with_specific_pending(hass): - """Test arm home method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "arming_time": 10, - "armed_away": {"arming_time": 2}, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - await common.async_alarm_arm_away(hass) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - future = dt_util.utcnow() + timedelta(seconds=2) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY - - -async def test_armed_night_with_specific_pending(hass): - """Test arm home method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "arming_time": 10, - "armed_night": {"arming_time": 2}, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - await common.async_alarm_arm_night(hass) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - future = dt_util.utcnow() + timedelta(seconds=2) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT - - async def test_trigger_with_specific_pending(hass): """Test arm home method.""" assert await async_setup_component( @@ -1298,158 +1099,6 @@ async def test_disarm_with_template_code(hass): assert state.state == STATE_ALARM_DISARMED -async def test_arm_custom_bypass_no_pending(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, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_custom_bypass(hass, CODE) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_CUSTOM_BYPASS - - -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, - "arming_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_custom_bypass(hass, 0) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_CUSTOM_BYPASS - - -async def test_arm_custom_bypass_with_pending(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, - "arming_time": 1, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_custom_bypass(hass, CODE, entity_id) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - state = hass.states.get(entity_id) - assert state.attributes["next_state"] == STATE_ALARM_ARMED_CUSTOM_BYPASS - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - assert state.state == STATE_ALARM_ARMED_CUSTOM_BYPASS - - -async def test_arm_custom_bypass_with_invalid_code(hass): - """Attempt to custom bypass without a valid code.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "code": CODE, - "arming_time": 1, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - await common.async_alarm_arm_custom_bypass(hass, CODE + "2") - - assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED - - -async def test_armed_custom_bypass_with_specific_pending(hass): - """Test arm custom bypass method.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "arming_time": 10, - "armed_custom_bypass": {"arming_time": 2}, - } - }, - ) - await hass.async_block_till_done() - - entity_id = "alarm_control_panel.test" - - await common.async_alarm_arm_custom_bypass(hass) - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMING - - future = dt_util.utcnow() + timedelta(seconds=2) - with patch( - ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"), - return_value=future, - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_CUSTOM_BYPASS - - async def test_arm_away_after_disabled_disarmed(hass, legacy_patchable_time): """Test pending state with and without zero trigger time.""" assert await async_setup_component( @@ -1518,11 +1167,20 @@ async def test_arm_away_after_disabled_disarmed(hass, legacy_patchable_time): assert state.state == STATE_ALARM_TRIGGERED -async def test_restore_armed_state(hass): - """Ensure armed state is restored on startup.""" - mock_restore_cache( - hass, (State("alarm_control_panel.test", STATE_ALARM_ARMED_AWAY),) - ) +@pytest.mark.parametrize( + "expected_state", + [ + (STATE_ALARM_ARMED_AWAY), + (STATE_ALARM_ARMED_CUSTOM_BYPASS), + (STATE_ALARM_ARMED_HOME), + (STATE_ALARM_ARMED_NIGHT), + (STATE_ALARM_ARMED_VACATION), + (STATE_ALARM_DISARMED), + ], +) +async def test_restore_state(hass, expected_state): + """Ensure state is restored on startup.""" + mock_restore_cache(hass, (State("alarm_control_panel.test", expected_state),)) hass.state = CoreState.starting mock_component(hass, "recorder") @@ -1544,31 +1202,4 @@ async def test_restore_armed_state(hass): state = hass.states.get("alarm_control_panel.test") assert state - assert state.state == STATE_ALARM_ARMED_AWAY - - -async def test_restore_disarmed_state(hass): - """Ensure disarmed state is restored on startup.""" - mock_restore_cache(hass, (State("alarm_control_panel.test", STATE_ALARM_DISARMED),)) - - hass.state = CoreState.starting - mock_component(hass, "recorder") - - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - "alarm_control_panel": { - "platform": "manual", - "name": "test", - "arming_time": 0, - "trigger_time": 0, - "disarm_after_trigger": False, - } - }, - ) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.test") - assert state - assert state.state == STATE_ALARM_DISARMED + assert state.state == expected_state