mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Add config flow to template alarm_control_panel (#125861)
* Add config flow to template alarm_control_panel * Remove commented code * Test import
This commit is contained in:
parent
cabaf37437
commit
2080b9a87c
@ -15,8 +15,10 @@ from homeassistant.components.alarm_control_panel import (
|
|||||||
AlarmControlPanelEntityFeature,
|
AlarmControlPanelEntityFeature,
|
||||||
CodeFormat,
|
CodeFormat,
|
||||||
)
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_CODE,
|
ATTR_CODE,
|
||||||
|
CONF_DEVICE_ID,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
@ -34,12 +36,14 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
|
from homeassistant.helpers import selector
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .template_entity import TemplateEntity, rewrite_common_legacy_to_modern_conf
|
from .template_entity import TemplateEntity, rewrite_common_legacy_to_modern_conf
|
||||||
@ -105,6 +109,25 @@ PLATFORM_SCHEMA = ALARM_CONTROL_PANEL_PLATFORM_SCHEMA.extend(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ALARM_CONTROL_PANEL_CONFIG_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_NAME): cv.template,
|
||||||
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
|
vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_ARM_AWAY_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_ARM_HOME_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_ARM_NIGHT_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_ARM_VACATION_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean,
|
||||||
|
vol.Optional(CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name): cv.enum(
|
||||||
|
TemplateCodeFormat
|
||||||
|
),
|
||||||
|
vol.Optional(CONF_DEVICE_ID): selector.DeviceSelector(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _async_create_entities(
|
async def _async_create_entities(
|
||||||
hass: HomeAssistant, config: dict[str, Any]
|
hass: HomeAssistant, config: dict[str, Any]
|
||||||
@ -128,6 +151,27 @@ async def _async_create_entities(
|
|||||||
return alarm_control_panels
|
return alarm_control_panels
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize config entry."""
|
||||||
|
_options = dict(config_entry.options)
|
||||||
|
_options.pop("template_type")
|
||||||
|
validated_config = ALARM_CONTROL_PANEL_CONFIG_SCHEMA(_options)
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
AlarmControlPanelTemplate(
|
||||||
|
hass,
|
||||||
|
slugify(_options[CONF_NAME]),
|
||||||
|
validated_config,
|
||||||
|
config_entry.entry_id,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config: ConfigType,
|
config: ConfigType,
|
||||||
|
@ -39,6 +39,18 @@ from homeassistant.helpers.schema_config_entry_flow import (
|
|||||||
SchemaFlowMenuStep,
|
SchemaFlowMenuStep,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .alarm_control_panel import (
|
||||||
|
CONF_ARM_AWAY_ACTION,
|
||||||
|
CONF_ARM_CUSTOM_BYPASS_ACTION,
|
||||||
|
CONF_ARM_HOME_ACTION,
|
||||||
|
CONF_ARM_NIGHT_ACTION,
|
||||||
|
CONF_ARM_VACATION_ACTION,
|
||||||
|
CONF_CODE_ARM_REQUIRED,
|
||||||
|
CONF_CODE_FORMAT,
|
||||||
|
CONF_DISARM_ACTION,
|
||||||
|
CONF_TRIGGER_ACTION,
|
||||||
|
TemplateCodeFormat,
|
||||||
|
)
|
||||||
from .binary_sensor import async_create_preview_binary_sensor
|
from .binary_sensor import async_create_preview_binary_sensor
|
||||||
from .const import CONF_PRESS, CONF_TURN_OFF, CONF_TURN_ON, DOMAIN
|
from .const import CONF_PRESS, CONF_TURN_OFF, CONF_TURN_ON, DOMAIN
|
||||||
from .number import (
|
from .number import (
|
||||||
@ -68,6 +80,30 @@ def generate_schema(domain: str, flow_type: str) -> vol.Schema:
|
|||||||
if flow_type == "config":
|
if flow_type == "config":
|
||||||
schema = {vol.Required(CONF_NAME): selector.TextSelector()}
|
schema = {vol.Required(CONF_NAME): selector.TextSelector()}
|
||||||
|
|
||||||
|
if domain == Platform.ALARM_CONTROL_PANEL:
|
||||||
|
schema |= {
|
||||||
|
vol.Optional(CONF_VALUE_TEMPLATE): selector.TemplateSelector(),
|
||||||
|
vol.Optional(CONF_DISARM_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_ARM_AWAY_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_ARM_CUSTOM_BYPASS_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_ARM_HOME_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_ARM_NIGHT_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_ARM_VACATION_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(CONF_TRIGGER_ACTION): selector.ActionSelector(),
|
||||||
|
vol.Optional(
|
||||||
|
CONF_CODE_ARM_REQUIRED, default=True
|
||||||
|
): selector.BooleanSelector(),
|
||||||
|
vol.Optional(
|
||||||
|
CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name
|
||||||
|
): selector.SelectSelector(
|
||||||
|
selector.SelectSelectorConfig(
|
||||||
|
options=[e.name for e in TemplateCodeFormat],
|
||||||
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||||
|
translation_key="alarm_control_panel_code_format",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
if domain == Platform.BINARY_SENSOR:
|
if domain == Platform.BINARY_SENSOR:
|
||||||
schema |= _SCHEMA_STATE
|
schema |= _SCHEMA_STATE
|
||||||
if flow_type == "config":
|
if flow_type == "config":
|
||||||
@ -265,6 +301,7 @@ def validate_user_input(
|
|||||||
|
|
||||||
|
|
||||||
TEMPLATE_TYPES = [
|
TEMPLATE_TYPES = [
|
||||||
|
"alarm_control_panel",
|
||||||
"binary_sensor",
|
"binary_sensor",
|
||||||
"button",
|
"button",
|
||||||
"image",
|
"image",
|
||||||
@ -276,6 +313,10 @@ TEMPLATE_TYPES = [
|
|||||||
|
|
||||||
CONFIG_FLOW = {
|
CONFIG_FLOW = {
|
||||||
"user": SchemaFlowMenuStep(TEMPLATE_TYPES),
|
"user": SchemaFlowMenuStep(TEMPLATE_TYPES),
|
||||||
|
Platform.ALARM_CONTROL_PANEL: SchemaFlowFormStep(
|
||||||
|
config_schema(Platform.ALARM_CONTROL_PANEL),
|
||||||
|
validate_user_input=validate_user_input(Platform.ALARM_CONTROL_PANEL),
|
||||||
|
),
|
||||||
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
||||||
config_schema(Platform.BINARY_SENSOR),
|
config_schema(Platform.BINARY_SENSOR),
|
||||||
preview="template",
|
preview="template",
|
||||||
@ -313,6 +354,10 @@ CONFIG_FLOW = {
|
|||||||
|
|
||||||
OPTIONS_FLOW = {
|
OPTIONS_FLOW = {
|
||||||
"init": SchemaFlowFormStep(next_step=choose_options_step),
|
"init": SchemaFlowFormStep(next_step=choose_options_step),
|
||||||
|
Platform.ALARM_CONTROL_PANEL: SchemaFlowFormStep(
|
||||||
|
options_schema(Platform.ALARM_CONTROL_PANEL),
|
||||||
|
validate_user_input=validate_user_input(Platform.ALARM_CONTROL_PANEL),
|
||||||
|
),
|
||||||
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
||||||
options_schema(Platform.BINARY_SENSOR),
|
options_schema(Platform.BINARY_SENSOR),
|
||||||
preview="template",
|
preview="template",
|
||||||
|
@ -1,6 +1,26 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"step": {
|
||||||
|
"alarm_control_panel": {
|
||||||
|
"data": {
|
||||||
|
"device_id": "[%key:common::config_flow::data::device%]",
|
||||||
|
"value_template": "[%key:component::template::config::step::switch::data::value_template%]",
|
||||||
|
"name": "[%key:common::config_flow::data::name%]",
|
||||||
|
"disarm": "Disarm action",
|
||||||
|
"arm_away": "Arm away action",
|
||||||
|
"arm_custom_bypass": "Arm custom bypass action",
|
||||||
|
"arm_home": "Arm home action",
|
||||||
|
"arm_night": "Arm night action",
|
||||||
|
"arm_vacation": "Arm vacation action",
|
||||||
|
"trigger": "Trigger action",
|
||||||
|
"code_arm_required": "Code arm required",
|
||||||
|
"code_format": "Code format"
|
||||||
|
},
|
||||||
|
"data_description": {
|
||||||
|
"device_id": "[%key:component::template::config::step::sensor::data_description::device_id%]"
|
||||||
|
},
|
||||||
|
"title": "Template alarm control panel"
|
||||||
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
"data": {
|
"data": {
|
||||||
"device_id": "[%key:common::config_flow::data::device%]",
|
"device_id": "[%key:common::config_flow::data::device%]",
|
||||||
@ -111,6 +131,25 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
|
"alarm_control_panel": {
|
||||||
|
"data": {
|
||||||
|
"device_id": "[%key:common::config_flow::data::device%]",
|
||||||
|
"value_template": "[%key:component::template::config::step::switch::data::value_template%]",
|
||||||
|
"disarm": "[%key:component::template::config::step::alarm_control_panel::data::disarm%]",
|
||||||
|
"arm_away": "[%key:component::template::config::step::alarm_control_panel::data::arm_away%]",
|
||||||
|
"arm_custom_bypass": "[%key:component::template::config::step::alarm_control_panel::data::arm_custom_bypass%]",
|
||||||
|
"arm_home": "[%key:component::template::config::step::alarm_control_panel::data::arm_home%]",
|
||||||
|
"arm_night": "[%key:component::template::config::step::alarm_control_panel::data::arm_night%]",
|
||||||
|
"arm_vacation": "[%key:component::template::config::step::alarm_control_panel::data::arm_vacation%]",
|
||||||
|
"trigger": "[%key:component::template::config::step::alarm_control_panel::data::trigger%]",
|
||||||
|
"code_arm_required": "[%key:component::template::config::step::alarm_control_panel::data::code_arm_required%]",
|
||||||
|
"code_format": "[%key:component::template::config::step::alarm_control_panel::data::code_format%]"
|
||||||
|
},
|
||||||
|
"data_description": {
|
||||||
|
"device_id": "[%key:component::template::config::step::sensor::data_description::device_id%]"
|
||||||
|
},
|
||||||
|
"title": "[%key:component::template::config::step::alarm_control_panel::title%]"
|
||||||
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
"data": {
|
"data": {
|
||||||
"device_id": "[%key:common::config_flow::data::device%]",
|
"device_id": "[%key:common::config_flow::data::device%]",
|
||||||
@ -200,6 +239,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"selector": {
|
"selector": {
|
||||||
|
"alarm_control_panel_code_format": {
|
||||||
|
"options": {
|
||||||
|
"no_code": "No code format",
|
||||||
|
"number": "Number",
|
||||||
|
"text": "Text"
|
||||||
|
}
|
||||||
|
},
|
||||||
"binary_sensor_device_class": {
|
"binary_sensor_device_class": {
|
||||||
"options": {
|
"options": {
|
||||||
"battery": "[%key:component::binary_sensor::entity_component::battery::name%]",
|
"battery": "[%key:component::binary_sensor::entity_component::battery::name%]",
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_setup_config_entry
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'changed_by': None,
|
||||||
|
'code_arm_required': True,
|
||||||
|
'code_format': <CodeFormat.NUMBER: 'number'>,
|
||||||
|
'friendly_name': 'My template',
|
||||||
|
'supported_features': <AlarmControlPanelEntityFeature: 0>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'alarm_control_panel.my_template',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'armed_away',
|
||||||
|
})
|
||||||
|
# ---
|
@ -1,7 +1,9 @@
|
|||||||
"""The tests for the Template alarm control panel platform."""
|
"""The tests for the Template alarm control panel platform."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components import template
|
||||||
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
|
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_DOMAIN,
|
ATTR_DOMAIN,
|
||||||
@ -23,7 +25,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import Event, HomeAssistant, State, callback
|
from homeassistant.core import Event, HomeAssistant, State, callback
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import assert_setup_component, mock_restore_cache
|
from tests.common import MockConfigEntry, assert_setup_component, mock_restore_cache
|
||||||
|
|
||||||
TEMPLATE_NAME = "alarm_control_panel.test_template_panel"
|
TEMPLATE_NAME = "alarm_control_panel.test_template_panel"
|
||||||
PANEL_NAME = "alarm_control_panel.test"
|
PANEL_NAME = "alarm_control_panel.test"
|
||||||
@ -130,6 +132,41 @@ async def test_template_state_text(hass: HomeAssistant, start_ha) -> None:
|
|||||||
assert state.state == "unknown"
|
assert state.state == "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_config_entry(
|
||||||
|
hass: HomeAssistant, snapshot: SnapshotAssertion
|
||||||
|
) -> None:
|
||||||
|
"""Test the config flow."""
|
||||||
|
value_template = "{{ states('alarm_control_panel.one') }}"
|
||||||
|
|
||||||
|
hass.states.async_set("alarm_control_panel.one", "armed_away", {})
|
||||||
|
|
||||||
|
template_config_entry = MockConfigEntry(
|
||||||
|
data={},
|
||||||
|
domain=template.DOMAIN,
|
||||||
|
options={
|
||||||
|
"name": "My template",
|
||||||
|
"value_template": value_template,
|
||||||
|
"template_type": "alarm_control_panel",
|
||||||
|
"code_arm_required": True,
|
||||||
|
"code_format": "number",
|
||||||
|
},
|
||||||
|
title="My template",
|
||||||
|
)
|
||||||
|
template_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert await hass.config_entries.async_setup(template_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("alarm_control_panel.my_template")
|
||||||
|
assert state is not None
|
||||||
|
assert state == snapshot
|
||||||
|
|
||||||
|
hass.states.async_set("alarm_control_panel.one", "disarmed", {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
state = hass.states.get("alarm_control_panel.my_template")
|
||||||
|
assert state.state == STATE_ALARM_DISARMED
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(("count", "domain"), [(1, "alarm_control_panel")])
|
@pytest.mark.parametrize(("count", "domain"), [(1, "alarm_control_panel")])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"config",
|
"config",
|
||||||
|
@ -29,6 +29,16 @@ from tests.typing import WebSocketGenerator
|
|||||||
"extra_attrs",
|
"extra_attrs",
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
|
(
|
||||||
|
"alarm_control_panel",
|
||||||
|
{"value_template": "{{ states('alarm_control_panel.one') }}"},
|
||||||
|
"armed_away",
|
||||||
|
{"one": "armed_away", "two": "disarmed"},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
{},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"binary_sensor",
|
"binary_sensor",
|
||||||
{
|
{
|
||||||
@ -270,6 +280,12 @@ async def test_config_flow(
|
|||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"alarm_control_panel",
|
||||||
|
{"value_template": "{{ states('alarm_control_panel.one') }}"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"select",
|
"select",
|
||||||
{"state": "{{ states('select.one') }}"},
|
{"state": "{{ states('select.one') }}"},
|
||||||
@ -476,6 +492,16 @@ def get_suggested(schema, key):
|
|||||||
},
|
},
|
||||||
"state",
|
"state",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"alarm_control_panel",
|
||||||
|
{"value_template": "{{ states('alarm_control_panel.one') }}"},
|
||||||
|
{"value_template": "{{ states('alarm_control_panel.two') }}"},
|
||||||
|
["armed_away", "disarmed"],
|
||||||
|
{"one": "armed_away", "two": "disarmed"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
"value_template",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"select",
|
"select",
|
||||||
{"state": "{{ states('select.one') }}"},
|
{"state": "{{ states('select.one') }}"},
|
||||||
@ -1244,6 +1270,12 @@ async def test_option_flow_sensor_preview_config_entry_removed(
|
|||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"alarm_control_panel",
|
||||||
|
{"value_template": "{{ states('alarm_control_panel.one') }}"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
{"code_arm_required": True, "code_format": "number"},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"select",
|
"select",
|
||||||
{"state": "{{ states('select.one') }}"},
|
{"state": "{{ states('select.one') }}"},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user