diff --git a/homeassistant/components/manual/alarm_control_panel.py b/homeassistant/components/manual/alarm_control_panel.py index f0436ba1d69..da77aea6c4a 100644 --- a/homeassistant/components/manual/alarm_control_panel.py +++ b/homeassistant/components/manual/alarm_control_panel.py @@ -29,6 +29,7 @@ from homeassistant.const import ( STATE_ALARM_TRIGGERED, ) from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback 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: """Send disarm command.""" - if not self._async_validate_code(code, STATE_ALARM_DISARMED): - return - + self._async_validate_code(code, STATE_ALARM_DISARMED) self._state = STATE_ALARM_DISARMED self._state_ts = dt_util.utcnow() self.async_write_ha_state() async def async_alarm_arm_home(self, code: str | None = None) -> None: """Send arm home command.""" - if self.code_arm_required and not self._async_validate_code( - code, STATE_ALARM_ARMED_HOME - ): - return - + self._async_validate_code(code, STATE_ALARM_ARMED_HOME) self._async_update_state(STATE_ALARM_ARMED_HOME) async def async_alarm_arm_away(self, code: str | None = None) -> None: """Send arm away command.""" - if self.code_arm_required and not self._async_validate_code( - code, STATE_ALARM_ARMED_AWAY - ): - return - + self._async_validate_code(code, STATE_ALARM_ARMED_AWAY) self._async_update_state(STATE_ALARM_ARMED_AWAY) async def async_alarm_arm_night(self, code: str | None = None) -> None: """Send arm night command.""" - if self.code_arm_required and not self._async_validate_code( - code, STATE_ALARM_ARMED_NIGHT - ): - return - + self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT) self._async_update_state(STATE_ALARM_ARMED_NIGHT) async def async_alarm_arm_vacation(self, code: str | None = None) -> None: """Send arm vacation command.""" - if self.code_arm_required and not self._async_validate_code( - code, STATE_ALARM_ARMED_VACATION - ): - return - + self._async_validate_code(code, 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: """Send arm custom bypass command.""" - if self.code_arm_required and not self._async_validate_code( - code, STATE_ALARM_ARMED_CUSTOM_BYPASS - ): - return - + self._async_validate_code(code, 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: @@ -383,18 +362,22 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity): def _async_validate_code(self, code, state): """Validate given code.""" - if self._code is None: - return True + if ( + state != STATE_ALARM_DISARMED and not self.code_arm_required + ) or self._code is None: + return + if isinstance(self._code, str): alarm_code = self._code else: alarm_code = self._code.async_render( parse_result=False, from_state=self._state, to_state=state ) - check = not alarm_code or code == alarm_code - if not check: - _LOGGER.warning("Invalid code given for %s", state) - return check + + if not alarm_code or code == alarm_code: + return + + raise HomeAssistantError("Invalid alarm code provided") @property def extra_state_attributes(self) -> dict[str, Any]: diff --git a/tests/components/manual/test_alarm_control_panel.py b/tests/components/manual/test_alarm_control_panel.py index 21cbc95d4e6..f1a4b2da2ef 100644 --- a/tests/components/manual/test_alarm_control_panel.py +++ b/tests/components/manual/test_alarm_control_panel.py @@ -26,6 +26,7 @@ from homeassistant.const import ( STATE_ALARM_TRIGGERED, ) from homeassistant.core import CoreState, HomeAssistant, State +from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component 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 - await hass.services.async_call( - alarm_control_panel.DOMAIN, - service, - {ATTR_ENTITY_ID: "alarm_control_panel.test", ATTR_CODE: CODE + "2"}, - blocking=True, - ) + with pytest.raises(HomeAssistantError, match=r"^Invalid alarm code provided$"): + await hass.services.async_call( + alarm_control_panel.DOMAIN, + service, + { + ATTR_ENTITY_ID: "alarm_control_panel.test", + ATTR_CODE: f"{CODE}2", + }, + blocking=True, + ) 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 - 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 @@ -1125,7 +1131,8 @@ async def test_disarm_with_template_code(hass: HomeAssistant) -> None: state = hass.states.get(entity_id) 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) assert state.state == STATE_ALARM_ARMED_HOME