From 3c87a3e892511d31da99e4c38d26c9bb9befbc34 Mon Sep 17 00:00:00 2001 From: Petro31 <35082313+Petro31@users.noreply.github.com> Date: Thu, 17 Jul 2025 17:19:45 -0400 Subject: [PATCH] Add a preview to template config flow for alarm control panel, image, and select platforms (#148441) --- .../template/alarm_control_panel.py | 12 ++++++++++++ .../components/template/config_flow.py | 19 ++++++++++++++----- homeassistant/components/template/select.py | 9 +++++++++ .../template/test_alarm_control_panel.py | 19 ++++++++++++++++++- tests/components/template/test_select.py | 19 ++++++++++++++++++- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/template/alarm_control_panel.py b/homeassistant/components/template/alarm_control_panel.py index 97896e08a68..cd70a7d44e0 100644 --- a/homeassistant/components/template/alarm_control_panel.py +++ b/homeassistant/components/template/alarm_control_panel.py @@ -206,6 +206,18 @@ async def async_setup_platform( ) +@callback +def async_create_preview_alarm_control_panel( + hass: HomeAssistant, name: str, config: dict[str, Any] +) -> StateAlarmControlPanelEntity: + """Create a preview alarm control panel.""" + updated_config = rewrite_options_to_modern_conf(config) + validated_config = ALARM_CONTROL_PANEL_CONFIG_SCHEMA( + updated_config | {CONF_NAME: name} + ) + return StateAlarmControlPanelEntity(hass, validated_config, None) + + class AbstractTemplateAlarmControlPanel( AbstractTemplateEntity, AlarmControlPanelEntity, RestoreEntity ): diff --git a/homeassistant/components/template/config_flow.py b/homeassistant/components/template/config_flow.py index e6cc377bc26..d6fc5768f81 100644 --- a/homeassistant/components/template/config_flow.py +++ b/homeassistant/components/template/config_flow.py @@ -50,6 +50,7 @@ from .alarm_control_panel import ( CONF_DISARM_ACTION, CONF_TRIGGER_ACTION, TemplateCodeFormat, + async_create_preview_alarm_control_panel, ) from .binary_sensor import async_create_preview_binary_sensor from .const import CONF_PRESS, CONF_TURN_OFF, CONF_TURN_ON, DOMAIN @@ -63,7 +64,7 @@ from .number import ( DEFAULT_STEP, async_create_preview_number, ) -from .select import CONF_OPTIONS, CONF_SELECT_OPTION +from .select import CONF_OPTIONS, CONF_SELECT_OPTION, async_create_preview_select from .sensor import async_create_preview_sensor from .switch import async_create_preview_switch from .template_entity import TemplateEntity @@ -319,6 +320,7 @@ CONFIG_FLOW = { "user": SchemaFlowMenuStep(TEMPLATE_TYPES), Platform.ALARM_CONTROL_PANEL: SchemaFlowFormStep( config_schema(Platform.ALARM_CONTROL_PANEL), + preview="template", validate_user_input=validate_user_input(Platform.ALARM_CONTROL_PANEL), ), Platform.BINARY_SENSOR: SchemaFlowFormStep( @@ -332,6 +334,7 @@ CONFIG_FLOW = { ), Platform.IMAGE: SchemaFlowFormStep( config_schema(Platform.IMAGE), + preview="template", validate_user_input=validate_user_input(Platform.IMAGE), ), Platform.NUMBER: SchemaFlowFormStep( @@ -341,6 +344,7 @@ CONFIG_FLOW = { ), Platform.SELECT: SchemaFlowFormStep( config_schema(Platform.SELECT), + preview="template", validate_user_input=validate_user_input(Platform.SELECT), ), Platform.SENSOR: SchemaFlowFormStep( @@ -360,6 +364,7 @@ OPTIONS_FLOW = { "init": SchemaFlowFormStep(next_step=choose_options_step), Platform.ALARM_CONTROL_PANEL: SchemaFlowFormStep( options_schema(Platform.ALARM_CONTROL_PANEL), + preview="template", validate_user_input=validate_user_input(Platform.ALARM_CONTROL_PANEL), ), Platform.BINARY_SENSOR: SchemaFlowFormStep( @@ -373,6 +378,7 @@ OPTIONS_FLOW = { ), Platform.IMAGE: SchemaFlowFormStep( options_schema(Platform.IMAGE), + preview="template", validate_user_input=validate_user_input(Platform.IMAGE), ), Platform.NUMBER: SchemaFlowFormStep( @@ -382,6 +388,7 @@ OPTIONS_FLOW = { ), Platform.SELECT: SchemaFlowFormStep( options_schema(Platform.SELECT), + preview="template", validate_user_input=validate_user_input(Platform.SELECT), ), Platform.SENSOR: SchemaFlowFormStep( @@ -400,10 +407,12 @@ CREATE_PREVIEW_ENTITY: dict[ str, Callable[[HomeAssistant, str, dict[str, Any]], TemplateEntity], ] = { - "binary_sensor": async_create_preview_binary_sensor, - "number": async_create_preview_number, - "sensor": async_create_preview_sensor, - "switch": async_create_preview_switch, + Platform.ALARM_CONTROL_PANEL: async_create_preview_alarm_control_panel, + Platform.BINARY_SENSOR: async_create_preview_binary_sensor, + Platform.NUMBER: async_create_preview_number, + Platform.SELECT: async_create_preview_select, + Platform.SENSOR: async_create_preview_sensor, + Platform.SWITCH: async_create_preview_switch, } diff --git a/homeassistant/components/template/select.py b/homeassistant/components/template/select.py index d5abf7033a9..4273af6db28 100644 --- a/homeassistant/components/template/select.py +++ b/homeassistant/components/template/select.py @@ -90,6 +90,15 @@ async def async_setup_entry( async_add_entities([TemplateSelect(hass, validated_config, config_entry.entry_id)]) +@callback +def async_create_preview_select( + hass: HomeAssistant, name: str, config: dict[str, Any] +) -> TemplateSelect: + """Create a preview select.""" + validated_config = SELECT_CONFIG_SCHEMA(config | {CONF_NAME: name}) + return TemplateSelect(hass, validated_config, None) + + class AbstractTemplateSelect(AbstractTemplateEntity, SelectEntity): """Representation of a template select features.""" diff --git a/tests/components/template/test_alarm_control_panel.py b/tests/components/template/test_alarm_control_panel.py index 1984b4ea2af..06d678edcab 100644 --- a/tests/components/template/test_alarm_control_panel.py +++ b/tests/components/template/test_alarm_control_panel.py @@ -23,9 +23,10 @@ from homeassistant.core import Event, HomeAssistant, State, callback from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component -from .conftest import ConfigurationStyle +from .conftest import ConfigurationStyle, async_get_flow_preview_state from tests.common import MockConfigEntry, assert_setup_component, mock_restore_cache +from tests.conftest import WebSocketGenerator TEST_OBJECT_ID = "test_template_panel" TEST_ENTITY_ID = f"alarm_control_panel.{TEST_OBJECT_ID}" @@ -915,3 +916,19 @@ async def test_device_id( template_entity = entity_registry.async_get("alarm_control_panel.my_template") assert template_entity is not None assert template_entity.device_id == device_entry.id + + +async def test_flow_preview( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, +) -> None: + """Test the config flow preview.""" + + state = await async_get_flow_preview_state( + hass, + hass_ws_client, + ALARM_DOMAIN, + {"name": "My template", "state": "{{ 'disarmed' }}"}, + ) + + assert state["state"] == AlarmControlPanelState.DISARMED diff --git a/tests/components/template/test_select.py b/tests/components/template/test_select.py index 6971d41750d..f613fa865a6 100644 --- a/tests/components/template/test_select.py +++ b/tests/components/template/test_select.py @@ -35,9 +35,10 @@ from homeassistant.core import Context, HomeAssistant, ServiceCall from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component -from .conftest import ConfigurationStyle +from .conftest import ConfigurationStyle, async_get_flow_preview_state from tests.common import MockConfigEntry, assert_setup_component, async_capture_events +from tests.conftest import WebSocketGenerator _TEST_OBJECT_ID = "template_select" _TEST_SELECT = f"select.{_TEST_OBJECT_ID}" @@ -645,3 +646,19 @@ async def test_availability(hass: HomeAssistant) -> None: state = hass.states.get(_TEST_SELECT) assert state.state == "yes" + + +async def test_flow_preview( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, +) -> None: + """Test the config flow preview.""" + + state = await async_get_flow_preview_state( + hass, + hass_ws_client, + select.DOMAIN, + {"name": "My template", **TEST_OPTIONS}, + ) + + assert state["state"] == "test"