Add RestoreEntity to template alarm_control_panel (#125844)

This commit is contained in:
G Johansson 2024-09-13 16:44:48 +02:00 committed by GitHub
parent a2a049c5cc
commit d855f70e3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 93 additions and 8 deletions

View file

@ -4,6 +4,7 @@ from __future__ import annotations
from enum import Enum
import logging
from typing import Any
import voluptuous as vol
@ -29,12 +30,14 @@ from homeassistant.const import (
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import TemplateError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.script import Script
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@ -103,7 +106,9 @@ PLATFORM_SCHEMA = ALARM_CONTROL_PANEL_PLATFORM_SCHEMA.extend(
)
async def _async_create_entities(hass, config):
async def _async_create_entities(
hass: HomeAssistant, config: dict[str, Any]
) -> list[AlarmControlPanelTemplate]:
"""Create Template Alarm Control Panels."""
alarm_control_panels = []
@ -133,18 +138,18 @@ async def async_setup_platform(
async_add_entities(await _async_create_entities(hass, config))
class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity, RestoreEntity):
"""Representation of a templated Alarm Control Panel."""
_attr_should_poll = False
def __init__(
self,
hass,
object_id,
config,
unique_id,
):
hass: HomeAssistant,
object_id: str,
config: dict,
unique_id: str | None,
) -> None:
"""Initialize the panel."""
super().__init__(
hass, config=config, fallback_name=object_id, unique_id=unique_id
@ -153,6 +158,7 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
ENTITY_ID_FORMAT, object_id, hass=hass
)
name = self._attr_name
assert name is not None
self._template = config.get(CONF_VALUE_TEMPLATE)
self._disarm_script = None
self._attr_code_arm_required: bool = config[CONF_CODE_ARM_REQUIRED]
@ -216,6 +222,19 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
)
self._attr_supported_features = supported_features
async def async_added_to_hass(self) -> None:
"""Restore last state."""
await super().async_added_to_hass()
if (
(last_state := await self.async_get_last_state()) is not None
and last_state.state not in (STATE_UNKNOWN, STATE_UNAVAILABLE)
and last_state.state in _VALID_STATES
# The trigger might have fired already while we waited for stored data,
# then we should not restore state
and self._state is None
):
self._state = last_state.state
@property
def state(self) -> str | None:
"""Return the state of the device."""

View file

@ -17,8 +17,13 @@ from homeassistant.const import (
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.core import Event, HomeAssistant, State, callback
from homeassistant.setup import async_setup_component
from tests.common import assert_setup_component, mock_restore_cache
TEMPLATE_NAME = "alarm_control_panel.test_template_panel"
PANEL_NAME = "alarm_control_panel.test"
@ -400,3 +405,64 @@ async def test_code_config(
state = hass.states.get(TEMPLATE_NAME)
assert state.attributes.get("code_format") == code_format
assert state.attributes.get("code_arm_required") == code_arm_required
@pytest.mark.parametrize(("count", "domain"), [(1, "alarm_control_panel")])
@pytest.mark.parametrize(
"config",
[
{
"alarm_control_panel": {
"platform": "template",
"panels": {"test_template_panel": TEMPLATE_ALARM_CONFIG},
}
},
],
)
@pytest.mark.parametrize(
("restored_state", "initial_state"),
[
(STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMED_VACATION),
(STATE_ALARM_ARMING, STATE_ALARM_ARMING),
(STATE_ALARM_DISARMED, STATE_ALARM_DISARMED),
(STATE_ALARM_PENDING, STATE_ALARM_PENDING),
(STATE_ALARM_TRIGGERED, STATE_ALARM_TRIGGERED),
(STATE_UNAVAILABLE, STATE_UNKNOWN),
(STATE_UNKNOWN, STATE_UNKNOWN),
("faulty_state", STATE_UNKNOWN),
],
)
async def test_restore_state(
hass: HomeAssistant,
count,
domain,
config,
restored_state,
initial_state,
) -> None:
"""Test restoring template alarm control panel."""
fake_state = State(
"alarm_control_panel.test_template_panel",
restored_state,
{},
)
mock_restore_cache(hass, (fake_state,))
with assert_setup_component(count, domain):
assert await async_setup_component(
hass,
domain,
config,
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
state = hass.states.get("alarm_control_panel.test_template_panel")
assert state.state == initial_state