Add optimistic option to alarm control panel yaml (#149334)

This commit is contained in:
Petro31 2025-07-28 11:44:43 -04:00 committed by GitHub
parent aa1314c1d5
commit 8339516fb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 10 deletions

View File

@ -49,6 +49,7 @@ from .helpers import (
)
from .template_entity import (
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA,
TEMPLATE_ENTITY_OPTIMISTIC_SCHEMA,
TemplateEntity,
make_template_entity_common_modern_schema,
)
@ -113,8 +114,8 @@ ALARM_CONTROL_PANEL_COMMON_SCHEMA = vol.Schema(
)
ALARM_CONTROL_PANEL_YAML_SCHEMA = ALARM_CONTROL_PANEL_COMMON_SCHEMA.extend(
make_template_entity_common_modern_schema(DEFAULT_NAME).schema
)
TEMPLATE_ENTITY_OPTIMISTIC_SCHEMA
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
ALARM_CONTROL_PANEL_LEGACY_YAML_SCHEMA = vol.Schema(
{
@ -205,13 +206,12 @@ class AbstractTemplateAlarmControlPanel(
"""Representation of a templated Alarm Control Panel features."""
_entity_id_format = ENTITY_ID_FORMAT
_optimistic_entity = True
# The super init is not called because TemplateEntity and TriggerEntity will call AbstractTemplateEntity.__init__.
# This ensures that the __init__ on AbstractTemplateEntity is not called twice.
def __init__(self, config: dict[str, Any]) -> None: # pylint: disable=super-init-not-called
"""Initialize the features."""
self._template = config.get(CONF_STATE)
self._attr_code_arm_required: bool = config[CONF_CODE_ARM_REQUIRED]
self._attr_code_format = config[CONF_CODE_FORMAT].value
@ -273,18 +273,14 @@ class AbstractTemplateAlarmControlPanel(
async def _async_alarm_arm(self, state: Any, script: Script | None, code: Any):
"""Arm the panel to specified state with supplied script."""
optimistic_set = False
if self._template is None:
self._state = state
optimistic_set = True
if script:
await self.async_run_script(
script, run_variables={ATTR_CODE: code}, context=self._context
)
if optimistic_set:
if self._attr_assumed_state:
self._state = state
self.async_write_ha_state()
async def async_alarm_arm_away(self, code: str | None = None) -> None:

View File

@ -932,3 +932,44 @@ async def test_flow_preview(
)
assert state["state"] == AlarmControlPanelState.DISARMED
@pytest.mark.parametrize(
("count", "panel_config"),
[
(
1,
{
"name": TEST_OBJECT_ID,
"state": "{{ states('alarm_control_panel.test') }}",
**OPTIMISTIC_TEMPLATE_ALARM_CONFIG,
"optimistic": True,
},
)
],
)
@pytest.mark.parametrize(
"style",
[ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER],
)
@pytest.mark.usefixtures("setup_panel")
async def test_optimistic(hass: HomeAssistant) -> None:
"""Test configuration with empty script."""
hass.states.async_set(TEST_STATE_ENTITY_ID, AlarmControlPanelState.DISARMED)
await hass.async_block_till_done()
await hass.services.async_call(
ALARM_DOMAIN,
"alarm_arm_away",
{"entity_id": TEST_ENTITY_ID, "code": "1234"},
blocking=True,
)
state = hass.states.get(TEST_ENTITY_ID)
assert state.state == AlarmControlPanelState.ARMED_AWAY
hass.states.async_set(TEST_STATE_ENTITY_ID, AlarmControlPanelState.ARMED_HOME)
await hass.async_block_till_done()
state = hass.states.get(TEST_ENTITY_ID)
assert state.state == AlarmControlPanelState.ARMED_HOME