Add instant arming for totalconnect (#60156)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Austin Mroczek 2021-12-11 17:58:12 -08:00 committed by GitHub
parent f75b325ab2
commit 3198211a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 0 deletions

View File

@ -21,12 +21,16 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED,
)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_platform
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
SERVICE_ALARM_ARM_AWAY_INSTANT = "arm_away_instant"
SERVICE_ALARM_ARM_HOME_INSTANT = "arm_home_instant"
async def async_setup_entry(hass, entry, async_add_entities) -> None:
"""Set up TotalConnect alarm panels based on a config entry."""
@ -48,6 +52,21 @@ async def async_setup_entry(hass, entry, async_add_entities) -> None:
async_add_entities(alarms, True)
# Set up services
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_ALARM_ARM_AWAY_INSTANT,
None,
"async_alarm_arm_away_instant",
)
platform.async_register_entity_service(
SERVICE_ALARM_ARM_HOME_INSTANT,
None,
"async_alarm_arm_home_instant",
)
class TotalConnectAlarm(CoordinatorEntity, alarm.AlarmControlPanelEntity):
"""Represent an TotalConnect status."""
@ -201,3 +220,31 @@ class TotalConnectAlarm(CoordinatorEntity, alarm.AlarmControlPanelEntity):
raise HomeAssistantError(
f"TotalConnect failed to arm night {self._name}."
) from error
async def async_alarm_arm_home_instant(self, code=None):
"""Send arm home instant command."""
await self.hass.async_add_executor_job(self._arm_home_instant)
await self.coordinator.async_request_refresh()
def _arm_home_instant(self):
"""Arm home instant synchronous."""
try:
ArmingHelper(self._partition).arm_stay_instant()
except BadResultCodeError as error:
raise HomeAssistantError(
f"TotalConnect failed to arm home instant {self._name}."
) from error
async def async_alarm_arm_away_instant(self, code=None):
"""Send arm away instant command."""
await self.hass.async_add_executor_job(self._arm_away_instant)
await self.coordinator.async_request_refresh()
def _arm_away_instant(self, code=None):
"""Arm away instant synchronous."""
try:
ArmingHelper(self._partition).arm_away_instant()
except BadResultCodeError as error:
raise HomeAssistantError(
f"TotalConnect failed to arm away instant {self._name}."
) from error

View File

@ -0,0 +1,15 @@
arm_away_instant:
name: Arm Away Instant
description: Arm Away with zero entry delay.
target:
entity:
integration: totalconnect
domain: alarm_control_panel
arm_home_instant:
name: Arm Home Instant
description: Arm Home with zero entry delay.
target:
entity:
integration: totalconnect
domain: alarm_control_panel

View File

@ -5,6 +5,11 @@ from unittest.mock import patch
import pytest
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.totalconnect import DOMAIN
from homeassistant.components.totalconnect.alarm_control_panel import (
SERVICE_ALARM_ARM_AWAY_INSTANT,
SERVICE_ALARM_ARM_HOME_INSTANT,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
@ -121,6 +126,82 @@ async def test_arm_home_failure(hass: HomeAssistant) -> None:
assert mock_request.call_count == 2
async def test_arm_home_instant_success(hass: HomeAssistant) -> None:
"""Test arm home instant method success."""
responses = [RESPONSE_DISARMED, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_STAY]
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await setup_platform(hass, ALARM_DOMAIN)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
DOMAIN, SERVICE_ALARM_ARM_HOME_INSTANT, DATA, blocking=True
)
assert mock_request.call_count == 2
async_fire_time_changed(hass, dt.utcnow() + DELAY)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_HOME
async def test_arm_home_instant_failure(hass: HomeAssistant) -> None:
"""Test arm home instant method failure."""
responses = [RESPONSE_DISARMED, RESPONSE_ARM_FAILURE]
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await setup_platform(hass, ALARM_DOMAIN)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
await hass.services.async_call(
DOMAIN, SERVICE_ALARM_ARM_HOME_INSTANT, DATA, blocking=True
)
await hass.async_block_till_done()
assert f"{err.value}" == "TotalConnect failed to arm home instant test."
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 2
async def test_arm_away_instant_success(hass: HomeAssistant) -> None:
"""Test arm home instant method success."""
responses = [RESPONSE_DISARMED, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_AWAY]
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await setup_platform(hass, ALARM_DOMAIN)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
DOMAIN, SERVICE_ALARM_ARM_AWAY_INSTANT, DATA, blocking=True
)
assert mock_request.call_count == 2
async_fire_time_changed(hass, dt.utcnow() + DELAY)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
async def test_arm_away_instant_failure(hass: HomeAssistant) -> None:
"""Test arm home instant method failure."""
responses = [RESPONSE_DISARMED, RESPONSE_ARM_FAILURE]
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await setup_platform(hass, ALARM_DOMAIN)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
await hass.services.async_call(
DOMAIN, SERVICE_ALARM_ARM_AWAY_INSTANT, DATA, blocking=True
)
await hass.async_block_till_done()
assert f"{err.value}" == "TotalConnect failed to arm away instant test."
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 2
async def test_arm_home_invalid_usercode(hass: HomeAssistant) -> None:
"""Test arm home method with invalid usercode."""
responses = [RESPONSE_DISARMED, RESPONSE_USER_CODE_INVALID]