Add vacation mode to manual alarm_control_panel (#55340)

* Add vacation mode

* Add vacation to demo

* Deduplicate code in tests
This commit is contained in:
mbo18 2021-09-01 09:34:21 +02:00 committed by GitHub
parent 889aced3b6
commit a28593f133
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 171 additions and 518 deletions

View file

@ -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),

View file

@ -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(

View file

@ -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