Raise on invalid (dis)arm code in manual alarm (#90579)

This commit is contained in:
Franck Nijhof 2023-03-31 16:08:16 +02:00 committed by Paulus Schoutsen
parent 89dc6db5a7
commit 88a407361c
2 changed files with 32 additions and 42 deletions

View File

@ -29,6 +29,7 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED, STATE_ALARM_TRIGGERED,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_time from homeassistant.helpers.event import async_track_point_in_time
@ -285,56 +286,34 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None: async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command.""" """Send disarm command."""
if not self._async_validate_code(code, STATE_ALARM_DISARMED): self._async_validate_code(code, STATE_ALARM_DISARMED)
return
self._state = STATE_ALARM_DISARMED self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow() self._state_ts = dt_util.utcnow()
self.async_write_ha_state() self.async_write_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None: async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command.""" """Send arm home command."""
if self.code_arm_required and not self._async_validate_code( self._async_validate_code(code, STATE_ALARM_ARMED_HOME)
code, STATE_ALARM_ARMED_HOME
):
return
self._async_update_state(STATE_ALARM_ARMED_HOME) self._async_update_state(STATE_ALARM_ARMED_HOME)
async def async_alarm_arm_away(self, code: str | None = None) -> None: async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command.""" """Send arm away command."""
if self.code_arm_required and not self._async_validate_code( self._async_validate_code(code, STATE_ALARM_ARMED_AWAY)
code, STATE_ALARM_ARMED_AWAY
):
return
self._async_update_state(STATE_ALARM_ARMED_AWAY) self._async_update_state(STATE_ALARM_ARMED_AWAY)
async def async_alarm_arm_night(self, code: str | None = None) -> None: async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command.""" """Send arm night command."""
if self.code_arm_required and not self._async_validate_code( self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT)
code, STATE_ALARM_ARMED_NIGHT
):
return
self._async_update_state(STATE_ALARM_ARMED_NIGHT) self._async_update_state(STATE_ALARM_ARMED_NIGHT)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None: async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm vacation command.""" """Send arm vacation command."""
if self.code_arm_required and not self._async_validate_code( self._async_validate_code(code, STATE_ALARM_ARMED_VACATION)
code, STATE_ALARM_ARMED_VACATION
):
return
self._async_update_state(STATE_ALARM_ARMED_VACATION) self._async_update_state(STATE_ALARM_ARMED_VACATION)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None: async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command.""" """Send arm custom bypass command."""
if self.code_arm_required and not self._async_validate_code( self._async_validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS)
code, STATE_ALARM_ARMED_CUSTOM_BYPASS
):
return
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS) self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
async def async_alarm_trigger(self, code: str | None = None) -> None: async def async_alarm_trigger(self, code: str | None = None) -> None:
@ -383,18 +362,22 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
def _async_validate_code(self, code, state): def _async_validate_code(self, code, state):
"""Validate given code.""" """Validate given code."""
if self._code is None: if (
return True state != STATE_ALARM_DISARMED and not self.code_arm_required
) or self._code is None:
return
if isinstance(self._code, str): if isinstance(self._code, str):
alarm_code = self._code alarm_code = self._code
else: else:
alarm_code = self._code.async_render( alarm_code = self._code.async_render(
parse_result=False, from_state=self._state, to_state=state parse_result=False, from_state=self._state, to_state=state
) )
check = not alarm_code or code == alarm_code
if not check: if not alarm_code or code == alarm_code:
_LOGGER.warning("Invalid code given for %s", state) return
return check
raise HomeAssistantError("Invalid alarm code provided")
@property @property
def extra_state_attributes(self) -> dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any]:

View File

@ -26,6 +26,7 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED, STATE_ALARM_TRIGGERED,
) )
from homeassistant.core import CoreState, HomeAssistant, State from homeassistant.core import CoreState, HomeAssistant, State
from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -224,12 +225,16 @@ async def test_with_invalid_code(hass: HomeAssistant, service, expected_state) -
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
await hass.services.async_call( with pytest.raises(HomeAssistantError, match=r"^Invalid alarm code provided$"):
alarm_control_panel.DOMAIN, await hass.services.async_call(
service, alarm_control_panel.DOMAIN,
{ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE + "2"}, service,
blocking=True, {
) ATTR_ENTITY_ID: "alarm_control_panel.test",
ATTR_CODE: f"{CODE}2",
},
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
@ -1082,7 +1087,8 @@ async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> N
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
await common.async_alarm_disarm(hass, entity_id=entity_id) with pytest.raises(HomeAssistantError, match=r"^Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
@ -1125,7 +1131,8 @@ async def test_disarm_with_template_code(hass: HomeAssistant) -> None:
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME assert state.state == STATE_ALARM_ARMED_HOME
await common.async_alarm_disarm(hass, "def") with pytest.raises(HomeAssistantError, match=r"^Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, "def")
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME assert state.state == STATE_ALARM_ARMED_HOME