From 84667fd32dcfba52ce347d9e2c79f37aebcce495 Mon Sep 17 00:00:00 2001
From: Petro31 <35082313+Petro31@users.noreply.github.com>
Date: Fri, 14 Mar 2025 04:00:46 -0400
Subject: [PATCH] Migrate template light to new style (#140326)

* Migrate template light to new style

* add modern templates to tests

* fix comments
---
 homeassistant/components/template/config.py |    7 +-
 homeassistant/components/template/light.py  |  216 ++-
 tests/components/template/conftest.py       |    9 +
 tests/components/template/test_light.py     | 1597 ++++++++++++-------
 4 files changed, 1176 insertions(+), 653 deletions(-)

diff --git a/homeassistant/components/template/config.py b/homeassistant/components/template/config.py
index 9963731c784..07c3c1b437f 100644
--- a/homeassistant/components/template/config.py
+++ b/homeassistant/components/template/config.py
@@ -13,6 +13,7 @@ from homeassistant.components.blueprint import (
 )
 from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
 from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
+from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
 from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
 from homeassistant.components.select import DOMAIN as SELECT_DOMAIN
 from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
@@ -36,6 +37,7 @@ from . import (
     binary_sensor as binary_sensor_platform,
     button as button_platform,
     image as image_platform,
+    light as light_platform,
     number as number_platform,
     select as select_platform,
     sensor as sensor_platform,
@@ -104,11 +106,14 @@ CONFIG_SECTION_SCHEMA = vol.Schema(
             vol.Optional(IMAGE_DOMAIN): vol.All(
                 cv.ensure_list, [image_platform.IMAGE_SCHEMA]
             ),
+            vol.Optional(LIGHT_DOMAIN): vol.All(
+                cv.ensure_list, [light_platform.LIGHT_SCHEMA]
+            ),
             vol.Optional(WEATHER_DOMAIN): vol.All(
                 cv.ensure_list, [weather_platform.WEATHER_SCHEMA]
             ),
         },
-        ensure_domains_do_not_have_trigger_or_action(BUTTON_DOMAIN),
+        ensure_domains_do_not_have_trigger_or_action(BUTTON_DOMAIN, LIGHT_DOMAIN),
     )
 )
 
diff --git a/homeassistant/components/template/light.py b/homeassistant/components/template/light.py
index 352f571078a..1cc47c74aa0 100644
--- a/homeassistant/components/template/light.py
+++ b/homeassistant/components/template/light.py
@@ -26,9 +26,13 @@ from homeassistant.components.light import (
     filter_supported_color_modes,
 )
 from homeassistant.const import (
+    CONF_EFFECT,
     CONF_ENTITY_ID,
     CONF_FRIENDLY_NAME,
     CONF_LIGHTS,
+    CONF_NAME,
+    CONF_RGB,
+    CONF_STATE,
     CONF_UNIQUE_ID,
     CONF_VALUE_TEMPLATE,
     STATE_OFF,
@@ -36,15 +40,18 @@ from homeassistant.const import (
 )
 from homeassistant.core import HomeAssistant, callback
 from homeassistant.exceptions import TemplateError
-from homeassistant.helpers import config_validation as cv
+from homeassistant.helpers import config_validation as cv, template
 from homeassistant.helpers.entity import async_generate_entity_id
 from homeassistant.helpers.entity_platform import AddEntitiesCallback
 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
 from homeassistant.util import color as color_util
 
-from .const import DOMAIN
+from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
 from .template_entity import (
+    LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
+    TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
     TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
+    TEMPLATE_ENTITY_ICON_SCHEMA,
     TemplateEntity,
     rewrite_common_legacy_to_modern_conf,
 )
@@ -56,33 +63,96 @@ _VALID_STATES = [STATE_ON, STATE_OFF, "true", "false"]
 CONF_COLOR_ACTION = "set_color"
 CONF_COLOR_TEMPLATE = "color_template"
 
+CONF_HS = "hs"
 CONF_HS_ACTION = "set_hs"
 CONF_HS_TEMPLATE = "hs_template"
 CONF_RGB_ACTION = "set_rgb"
 CONF_RGB_TEMPLATE = "rgb_template"
+CONF_RGBW = "rgbw"
 CONF_RGBW_ACTION = "set_rgbw"
 CONF_RGBW_TEMPLATE = "rgbw_template"
+CONF_RGBWW = "rgbww"
 CONF_RGBWW_ACTION = "set_rgbww"
 CONF_RGBWW_TEMPLATE = "rgbww_template"
 CONF_EFFECT_ACTION = "set_effect"
+CONF_EFFECT_LIST = "effect_list"
 CONF_EFFECT_LIST_TEMPLATE = "effect_list_template"
 CONF_EFFECT_TEMPLATE = "effect_template"
+CONF_LEVEL = "level"
 CONF_LEVEL_ACTION = "set_level"
 CONF_LEVEL_TEMPLATE = "level_template"
+CONF_MAX_MIREDS = "max_mireds"
 CONF_MAX_MIREDS_TEMPLATE = "max_mireds_template"
+CONF_MIN_MIREDS = "min_mireds"
 CONF_MIN_MIREDS_TEMPLATE = "min_mireds_template"
 CONF_OFF_ACTION = "turn_off"
 CONF_ON_ACTION = "turn_on"
-CONF_SUPPORTS_TRANSITION = "supports_transition_template"
+CONF_SUPPORTS_TRANSITION = "supports_transition"
+CONF_SUPPORTS_TRANSITION_TEMPLATE = "supports_transition_template"
 CONF_TEMPERATURE_ACTION = "set_temperature"
+CONF_TEMPERATURE = "temperature"
 CONF_TEMPERATURE_TEMPLATE = "temperature_template"
 CONF_WHITE_VALUE_ACTION = "set_white_value"
+CONF_WHITE_VALUE = "white_value"
 CONF_WHITE_VALUE_TEMPLATE = "white_value_template"
 
 DEFAULT_MIN_MIREDS = 153
 DEFAULT_MAX_MIREDS = 500
 
-LIGHT_SCHEMA = vol.All(
+LEGACY_FIELDS = TEMPLATE_ENTITY_LEGACY_FIELDS | {
+    CONF_COLOR_ACTION: CONF_HS_ACTION,
+    CONF_COLOR_TEMPLATE: CONF_HS,
+    CONF_EFFECT_LIST_TEMPLATE: CONF_EFFECT_LIST,
+    CONF_EFFECT_TEMPLATE: CONF_EFFECT,
+    CONF_HS_TEMPLATE: CONF_HS,
+    CONF_LEVEL_TEMPLATE: CONF_LEVEL,
+    CONF_MAX_MIREDS_TEMPLATE: CONF_MAX_MIREDS,
+    CONF_MIN_MIREDS_TEMPLATE: CONF_MIN_MIREDS,
+    CONF_RGB_TEMPLATE: CONF_RGB,
+    CONF_RGBW_TEMPLATE: CONF_RGBW,
+    CONF_RGBWW_TEMPLATE: CONF_RGBWW,
+    CONF_SUPPORTS_TRANSITION_TEMPLATE: CONF_SUPPORTS_TRANSITION,
+    CONF_TEMPERATURE_TEMPLATE: CONF_TEMPERATURE,
+    CONF_VALUE_TEMPLATE: CONF_STATE,
+    CONF_WHITE_VALUE_TEMPLATE: CONF_WHITE_VALUE,
+}
+
+DEFAULT_NAME = "Template Light"
+
+LIGHT_SCHEMA = (
+    vol.Schema(
+        {
+            vol.Inclusive(CONF_EFFECT_ACTION, "effect"): cv.SCRIPT_SCHEMA,
+            vol.Inclusive(CONF_EFFECT_LIST, "effect"): cv.template,
+            vol.Inclusive(CONF_EFFECT, "effect"): cv.template,
+            vol.Optional(CONF_HS_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_HS): cv.template,
+            vol.Optional(CONF_LEVEL_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_LEVEL): cv.template,
+            vol.Optional(CONF_MAX_MIREDS): cv.template,
+            vol.Optional(CONF_MIN_MIREDS): cv.template,
+            vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
+            vol.Optional(CONF_PICTURE): cv.template,
+            vol.Optional(CONF_RGB_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_RGB): cv.template,
+            vol.Optional(CONF_RGBW_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_RGBW): cv.template,
+            vol.Optional(CONF_RGBWW_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_RGBWW): cv.template,
+            vol.Optional(CONF_STATE): cv.template,
+            vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
+            vol.Optional(CONF_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Optional(CONF_TEMPERATURE): cv.template,
+            vol.Optional(CONF_UNIQUE_ID): cv.string,
+            vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
+            vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
+        }
+    )
+    .extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
+    .extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
+)
+
+LEGACY_LIGHT_SCHEMA = vol.All(
     cv.deprecated(CONF_ENTITY_ID),
     vol.Schema(
         {
@@ -107,7 +177,7 @@ LIGHT_SCHEMA = vol.All(
             vol.Optional(CONF_MIN_MIREDS_TEMPLATE): cv.template,
             vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
             vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
-            vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
+            vol.Optional(CONF_SUPPORTS_TRANSITION_TEMPLATE): cv.template,
             vol.Optional(CONF_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
             vol.Optional(CONF_TEMPERATURE_TEMPLATE): cv.template,
             vol.Optional(CONF_UNIQUE_ID): cv.string,
@@ -121,31 +191,52 @@ PLATFORM_SCHEMA = vol.All(
     cv.removed(CONF_WHITE_VALUE_ACTION),
     cv.removed(CONF_WHITE_VALUE_TEMPLATE),
     LIGHT_PLATFORM_SCHEMA.extend(
-        {vol.Required(CONF_LIGHTS): cv.schema_with_slug_keys(LIGHT_SCHEMA)}
+        {vol.Required(CONF_LIGHTS): cv.schema_with_slug_keys(LEGACY_LIGHT_SCHEMA)}
     ),
 )
 
 
-async def _async_create_entities(hass: HomeAssistant, config):
-    """Create the Template Lights."""
+def rewrite_legacy_to_modern_conf(
+    hass: HomeAssistant, config: dict[str, dict]
+) -> list[dict]:
+    """Rewrite legacy switch configuration definitions to modern ones."""
     lights = []
+    for object_id, entity_conf in config.items():
+        entity_conf = {**entity_conf, CONF_OBJECT_ID: object_id}
 
-    for object_id, entity_config in config[CONF_LIGHTS].items():
-        entity_config = rewrite_common_legacy_to_modern_conf(hass, entity_config)
-        unique_id = entity_config.get(CONF_UNIQUE_ID)
-
-        lights.append(
-            LightTemplate(
-                hass,
-                object_id,
-                entity_config,
-                unique_id,
-            )
+        entity_conf = rewrite_common_legacy_to_modern_conf(
+            hass, entity_conf, LEGACY_FIELDS
         )
 
+        if CONF_NAME not in entity_conf:
+            entity_conf[CONF_NAME] = template.Template(object_id, hass)
+
+        lights.append(entity_conf)
+
     return lights
 
 
+@callback
+def _async_create_template_tracking_entities(
+    async_add_entities: AddEntitiesCallback,
+    hass: HomeAssistant,
+    definitions: list[dict],
+    unique_id_prefix: str | None,
+) -> None:
+    """Create the Template Lights."""
+    lights = []
+
+    for entity_conf in definitions:
+        unique_id = entity_conf.get(CONF_UNIQUE_ID)
+
+        if unique_id and unique_id_prefix:
+            unique_id = f"{unique_id_prefix}-{unique_id}"
+
+        lights.append(LightTemplate(hass, entity_conf, unique_id))
+
+    async_add_entities(lights)
+
+
 async def async_setup_platform(
     hass: HomeAssistant,
     config: ConfigType,
@@ -153,7 +244,21 @@ async def async_setup_platform(
     discovery_info: DiscoveryInfoType | None = None,
 ) -> None:
     """Set up the template lights."""
-    async_add_entities(await _async_create_entities(hass, config))
+    if discovery_info is None:
+        _async_create_template_tracking_entities(
+            async_add_entities,
+            hass,
+            rewrite_legacy_to_modern_conf(hass, config[CONF_LIGHTS]),
+            None,
+        )
+        return
+
+    _async_create_template_tracking_entities(
+        async_add_entities,
+        hass,
+        discovery_info["entities"],
+        discovery_info["unique_id"],
+    )
 
 
 class LightTemplate(TemplateEntity, LightEntity):
@@ -164,33 +269,30 @@ class LightTemplate(TemplateEntity, LightEntity):
     def __init__(
         self,
         hass: HomeAssistant,
-        object_id,
         config: dict[str, Any],
-        unique_id,
+        unique_id: str | None,
     ) -> None:
         """Initialize the light."""
-        super().__init__(
-            hass, config=config, fallback_name=object_id, unique_id=unique_id
-        )
-        self.entity_id = async_generate_entity_id(
-            ENTITY_ID_FORMAT, object_id, hass=hass
-        )
+        super().__init__(hass, config=config, fallback_name=None, unique_id=unique_id)
+        if (object_id := config.get(CONF_OBJECT_ID)) is not None:
+            self.entity_id = async_generate_entity_id(
+                ENTITY_ID_FORMAT, object_id, hass=hass
+            )
         name = self._attr_name
         if TYPE_CHECKING:
             assert name is not None
 
-        self._template = config.get(CONF_VALUE_TEMPLATE)
-        self._level_template = config.get(CONF_LEVEL_TEMPLATE)
-        self._temperature_template = config.get(CONF_TEMPERATURE_TEMPLATE)
-        self._color_template = config.get(CONF_COLOR_TEMPLATE)
-        self._hs_template = config.get(CONF_HS_TEMPLATE)
-        self._rgb_template = config.get(CONF_RGB_TEMPLATE)
-        self._rgbw_template = config.get(CONF_RGBW_TEMPLATE)
-        self._rgbww_template = config.get(CONF_RGBWW_TEMPLATE)
-        self._effect_list_template = config.get(CONF_EFFECT_LIST_TEMPLATE)
-        self._effect_template = config.get(CONF_EFFECT_TEMPLATE)
-        self._max_mireds_template = config.get(CONF_MAX_MIREDS_TEMPLATE)
-        self._min_mireds_template = config.get(CONF_MIN_MIREDS_TEMPLATE)
+        self._template = config.get(CONF_STATE)
+        self._level_template = config.get(CONF_LEVEL)
+        self._temperature_template = config.get(CONF_TEMPERATURE)
+        self._hs_template = config.get(CONF_HS)
+        self._rgb_template = config.get(CONF_RGB)
+        self._rgbw_template = config.get(CONF_RGBW)
+        self._rgbww_template = config.get(CONF_RGBWW)
+        self._effect_list_template = config.get(CONF_EFFECT_LIST)
+        self._effect_template = config.get(CONF_EFFECT)
+        self._max_mireds_template = config.get(CONF_MAX_MIREDS)
+        self._min_mireds_template = config.get(CONF_MIN_MIREDS)
         self._supports_transition_template = config.get(CONF_SUPPORTS_TRANSITION)
 
         for action_id in (CONF_ON_ACTION, CONF_OFF_ACTION, CONF_EFFECT_ACTION):
@@ -216,7 +318,6 @@ class LightTemplate(TemplateEntity, LightEntity):
         for action_id, color_mode in (
             (CONF_TEMPERATURE_ACTION, ColorMode.COLOR_TEMP),
             (CONF_LEVEL_ACTION, ColorMode.BRIGHTNESS),
-            (CONF_COLOR_ACTION, ColorMode.HS),
             (CONF_HS_ACTION, ColorMode.HS),
             (CONF_RGB_ACTION, ColorMode.RGB),
             (CONF_RGBW_ACTION, ColorMode.RGBW),
@@ -349,14 +450,6 @@ class LightTemplate(TemplateEntity, LightEntity):
                 self._update_temperature,
                 none_on_template_error=True,
             )
-        if self._color_template:
-            self.add_template_attribute(
-                "_hs_color",
-                self._color_template,
-                None,
-                self._update_hs,
-                none_on_template_error=True,
-            )
         if self._hs_template:
             self.add_template_attribute(
                 "_hs_color",
@@ -440,7 +533,7 @@ class LightTemplate(TemplateEntity, LightEntity):
             )
             self._color_mode = ColorMode.COLOR_TEMP
             self._temperature = color_temp
-            if self._hs_template is None and self._color_template is None:
+            if self._hs_template is None:
                 self._hs_color = None
             if self._rgb_template is None:
                 self._rgb_color = None
@@ -450,11 +543,7 @@ class LightTemplate(TemplateEntity, LightEntity):
                 self._rgbww_color = None
             optimistic_set = True
 
-        if (
-            self._hs_template is None
-            and self._color_template is None
-            and ATTR_HS_COLOR in kwargs
-        ):
+        if self._hs_template is None and ATTR_HS_COLOR in kwargs:
             _LOGGER.debug(
                 "Optimistically setting hs color to %s",
                 kwargs[ATTR_HS_COLOR],
@@ -480,7 +569,7 @@ class LightTemplate(TemplateEntity, LightEntity):
             self._rgb_color = kwargs[ATTR_RGB_COLOR]
             if self._temperature_template is None:
                 self._temperature = None
-            if self._hs_template is None and self._color_template is None:
+            if self._hs_template is None:
                 self._hs_color = None
             if self._rgbw_template is None:
                 self._rgbw_color = None
@@ -497,7 +586,7 @@ class LightTemplate(TemplateEntity, LightEntity):
             self._rgbw_color = kwargs[ATTR_RGBW_COLOR]
             if self._temperature_template is None:
                 self._temperature = None
-            if self._hs_template is None and self._color_template is None:
+            if self._hs_template is None:
                 self._hs_color = None
             if self._rgb_template is None:
                 self._rgb_color = None
@@ -514,7 +603,7 @@ class LightTemplate(TemplateEntity, LightEntity):
             self._rgbww_color = kwargs[ATTR_RGBWW_COLOR]
             if self._temperature_template is None:
                 self._temperature = None
-            if self._hs_template is None and self._color_template is None:
+            if self._hs_template is None:
                 self._hs_color = None
             if self._rgb_template is None:
                 self._rgb_color = None
@@ -561,17 +650,6 @@ class LightTemplate(TemplateEntity, LightEntity):
             await self.async_run_script(
                 effect_script, run_variables=common_params, context=self._context
             )
-        elif ATTR_HS_COLOR in kwargs and (
-            color_script := self._action_scripts.get(CONF_COLOR_ACTION)
-        ):
-            hs_value = kwargs[ATTR_HS_COLOR]
-            common_params["hs"] = hs_value
-            common_params["h"] = int(hs_value[0])
-            common_params["s"] = int(hs_value[1])
-
-            await self.async_run_script(
-                color_script, run_variables=common_params, context=self._context
-            )
         elif ATTR_HS_COLOR in kwargs and (
             hs_script := self._action_scripts.get(CONF_HS_ACTION)
         ):
diff --git a/tests/components/template/conftest.py b/tests/components/template/conftest.py
index bdca84ba071..86a30535e92 100644
--- a/tests/components/template/conftest.py
+++ b/tests/components/template/conftest.py
@@ -1,5 +1,7 @@
 """template conftest."""
 
+from enum import Enum
+
 import pytest
 
 from homeassistant.core import HomeAssistant, ServiceCall
@@ -9,6 +11,13 @@ from homeassistant.setup import async_setup_component
 from tests.common import assert_setup_component, async_mock_service
 
 
+class ConfigurationStyle(Enum):
+    """Configuration Styles for template testing."""
+
+    LEGACY = "Legacy"
+    MODERN = "Modern"
+
+
 @pytest.fixture
 def calls(hass: HomeAssistant) -> list[ServiceCall]:
     """Track calls to a mock service."""
diff --git a/tests/components/template/test_light.py b/tests/components/template/test_light.py
index a94ec233f81..1a739b4921e 100644
--- a/tests/components/template/test_light.py
+++ b/tests/components/template/test_light.py
@@ -4,7 +4,7 @@ from typing import Any
 
 import pytest
 
-from homeassistant.components import light
+from homeassistant.components import light, template
 from homeassistant.components.light import (
     ATTR_BRIGHTNESS,
     ATTR_COLOR_TEMP_KELVIN,
@@ -17,6 +17,7 @@ from homeassistant.components.light import (
     ColorMode,
     LightEntityFeature,
 )
+from homeassistant.components.template.light import rewrite_legacy_to_modern_conf
 from homeassistant.const import (
     ATTR_ENTITY_ID,
     SERVICE_TURN_OFF,
@@ -26,8 +27,12 @@ from homeassistant.const import (
     STATE_UNAVAILABLE,
 )
 from homeassistant.core import HomeAssistant, ServiceCall
+from homeassistant.helpers import entity_registry as er
+from homeassistant.helpers.template import Template
 from homeassistant.setup import async_setup_component
 
+from .conftest import ConfigurationStyle
+
 from tests.common import assert_setup_component
 
 # Represent for light's availability
@@ -154,10 +159,245 @@ OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG = {
 }
 
 
-async def async_setup_light(
+TEST_MISSING_KEY_CONFIG = {
+    "turn_on": {
+        "service": "light.turn_on",
+        "entity_id": "light.test_state",
+    },
+    "set_level": {
+        "service": "light.turn_on",
+        "data_template": {
+            "entity_id": "light.test_state",
+            "brightness": "{{brightness}}",
+        },
+    },
+}
+
+
+TEST_ON_ACTION_WITH_TRANSITION_CONFIG = {
+    "turn_on": {
+        "service": "test.automation",
+        "data_template": {
+            "transition": "{{transition}}",
+        },
+    },
+    "turn_off": {
+        "service": "light.turn_off",
+        "entity_id": "light.test_state",
+    },
+    "set_level": {
+        "service": "light.turn_on",
+        "data_template": {
+            "entity_id": "light.test_state",
+            "brightness": "{{brightness}}",
+            "transition": "{{transition}}",
+        },
+    },
+}
+
+
+TEST_OFF_ACTION_WITH_TRANSITION_CONFIG = {
+    "turn_on": {
+        "service": "light.turn_on",
+        "entity_id": "light.test_state",
+    },
+    "turn_off": {
+        "service": "test.automation",
+        "data_template": {
+            "transition": "{{transition}}",
+        },
+    },
+    "set_level": {
+        "service": "light.turn_on",
+        "data_template": {
+            "entity_id": "light.test_state",
+            "brightness": "{{brightness}}",
+            "transition": "{{transition}}",
+        },
+    },
+}
+
+
+TEST_ALL_COLORS_NO_TEMPLATE_CONFIG = {
+    "set_hs": {
+        "service": "test.automation",
+        "data_template": {
+            "entity_id": "test.test_state",
+            "h": "{{h}}",
+            "s": "{{s}}",
+        },
+    },
+    "set_temperature": {
+        "service": "test.automation",
+        "data_template": {
+            "entity_id": "test.test_state",
+            "color_temp": "{{color_temp}}",
+        },
+    },
+    "set_rgb": {
+        "service": "test.automation",
+        "data_template": {
+            "entity_id": "test.test_state",
+            "r": "{{r}}",
+            "g": "{{g}}",
+            "b": "{{b}}",
+        },
+    },
+    "set_rgbw": {
+        "service": "test.automation",
+        "data_template": {
+            "entity_id": "test.test_state",
+            "r": "{{r}}",
+            "g": "{{g}}",
+            "b": "{{b}}",
+            "w": "{{w}}",
+        },
+    },
+    "set_rgbww": {
+        "service": "test.automation",
+        "data_template": {
+            "entity_id": "test.test_state",
+            "r": "{{r}}",
+            "g": "{{g}}",
+            "b": "{{b}}",
+            "cw": "{{cw}}",
+            "ww": "{{ww}}",
+        },
+    },
+}
+
+
+TEST_UNIQUE_ID_CONFIG = {
+    **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+    "unique_id": "not-so-unique-anymore",
+}
+
+
+@pytest.mark.parametrize(
+    ("old_attr", "new_attr", "attr_template"),
+    [
+        (
+            "value_template",
+            "state",
+            "{{ 1 == 1 }}",
+        ),
+        (
+            "rgb_template",
+            "rgb",
+            "{{ (255,255,255) }}",
+        ),
+        (
+            "rgbw_template",
+            "rgbw",
+            "{{ (255,255,255,255) }}",
+        ),
+        (
+            "rgbww_template",
+            "rgbww",
+            "{{ (255,255,255,255,255) }}",
+        ),
+        (
+            "effect_list_template",
+            "effect_list",
+            "{{ ['a', 'b'] }}",
+        ),
+        (
+            "effect_template",
+            "effect",
+            "{{ 'a' }}",
+        ),
+        (
+            "level_template",
+            "level",
+            "{{ 255 }}",
+        ),
+        (
+            "max_mireds_template",
+            "max_mireds",
+            "{{ 255 }}",
+        ),
+        (
+            "min_mireds_template",
+            "min_mireds",
+            "{{ 255 }}",
+        ),
+        (
+            "supports_transition_template",
+            "supports_transition",
+            "{{ True }}",
+        ),
+        (
+            "temperature_template",
+            "temperature",
+            "{{ 255 }}",
+        ),
+        (
+            "white_value_template",
+            "white_value",
+            "{{ 255 }}",
+        ),
+        (
+            "hs_template",
+            "hs",
+            "{{ (255, 255) }}",
+        ),
+        (
+            "color_template",
+            "hs",
+            "{{ (255, 255) }}",
+        ),
+    ],
+)
+async def test_legacy_to_modern_config(
+    hass: HomeAssistant, old_attr: str, new_attr: str, attr_template: str
+) -> None:
+    """Test the conversion of legacy template to modern template."""
+    config = {
+        "foo": {
+            "friendly_name": "foo bar",
+            "unique_id": "foo-bar-light",
+            "icon_template": "{{ 'mdi.abc' }}",
+            "entity_picture_template": "{{ 'mypicture.jpg' }}",
+            "availability_template": "{{ 1 == 1 }}",
+            old_attr: attr_template,
+            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+        }
+    }
+    altered_configs = rewrite_legacy_to_modern_conf(hass, config)
+
+    assert len(altered_configs) == 1
+
+    assert [
+        {
+            "availability": Template("{{ 1 == 1 }}", hass),
+            "icon": Template("{{ 'mdi.abc' }}", hass),
+            "name": Template("foo bar", hass),
+            "object_id": "foo",
+            "picture": Template("{{ 'mypicture.jpg' }}", hass),
+            "turn_off": {
+                "data_template": {
+                    "action": "turn_off",
+                    "caller": "{{ this.entity_id }}",
+                },
+                "service": "test.automation",
+            },
+            "turn_on": {
+                "data_template": {
+                    "action": "turn_on",
+                    "caller": "{{ this.entity_id }}",
+                },
+                "service": "test.automation",
+            },
+            "unique_id": "foo-bar-light",
+            new_attr: Template(attr_template, hass),
+        }
+    ] == altered_configs
+
+
+async def async_setup_legacy_format(
     hass: HomeAssistant, count: int, light_config: dict[str, Any]
 ) -> None:
-    """Do setup of light integration."""
+    """Do setup of light integration via legacy format."""
     config = {"light": {"platform": "template", "lights": light_config}}
 
     with assert_setup_component(count, light.DOMAIN):
@@ -172,12 +412,291 @@ async def async_setup_light(
     await hass.async_block_till_done()
 
 
+async def async_setup_legacy_format_with_attribute(
+    hass: HomeAssistant,
+    count: int,
+    attribute: str,
+    attribute_template: str,
+    extra_config: dict,
+) -> None:
+    """Do setup of a legacy light that has a single templated attribute."""
+    extra = {attribute: attribute_template} if attribute and attribute_template else {}
+    await async_setup_legacy_format(
+        hass,
+        count,
+        {
+            "test_template_light": {
+                **extra_config,
+                "value_template": "{{ 1 == 1 }}",
+                **extra,
+            }
+        },
+    )
+
+
+async def async_setup_new_format(
+    hass: HomeAssistant, count: int, light_config: dict[str, Any]
+) -> None:
+    """Do setup of light integration via new format."""
+    config = {"template": {"light": light_config}}
+
+    with assert_setup_component(count, template.DOMAIN):
+        assert await async_setup_component(
+            hass,
+            template.DOMAIN,
+            config,
+        )
+
+    await hass.async_block_till_done()
+    await hass.async_start()
+    await hass.async_block_till_done()
+
+
+async def async_setup_modern_format_with_attribute(
+    hass: HomeAssistant,
+    count: int,
+    attribute: str,
+    attribute_template: str,
+    extra_config: dict,
+) -> None:
+    """Do setup of a legacy light that has a single templated attribute."""
+    extra = {attribute: attribute_template} if attribute and attribute_template else {}
+    await async_setup_new_format(
+        hass,
+        count,
+        {
+            "name": "test_template_light",
+            **extra_config,
+            "state": "{{ 1 == 1 }}",
+            **extra,
+        },
+    )
+
+
 @pytest.fixture
 async def setup_light(
-    hass: HomeAssistant, count: int, light_config: dict[str, Any]
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    light_config: dict[str, Any],
 ) -> None:
     """Do setup of light integration."""
-    await async_setup_light(hass, count, light_config)
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format(hass, count, light_config)
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_new_format(hass, count, light_config)
+
+
+@pytest.fixture
+async def setup_state_light(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    state_template: str,
+):
+    """Do setup of light integration."""
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format(
+            hass,
+            count,
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                    "value_template": state_template,
+                }
+            },
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_new_format(
+            hass,
+            count,
+            {
+                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                "name": "test_template_light",
+                "state": state_template,
+            },
+        )
+
+
+@pytest.fixture
+async def setup_single_attribute_light(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    attribute: str,
+    attribute_template: str,
+    extra_config: dict,
+) -> None:
+    """Do setup of light integration."""
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format_with_attribute(
+            hass, count, attribute, attribute_template, extra_config
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_modern_format_with_attribute(
+            hass, count, attribute, attribute_template, extra_config
+        )
+
+
+@pytest.fixture
+async def setup_single_action_light(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    extra_config: dict,
+) -> None:
+    """Do setup of light integration."""
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format_with_attribute(
+            hass, count, "", "", extra_config
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_modern_format_with_attribute(
+            hass, count, "", "", extra_config
+        )
+
+
+@pytest.fixture
+async def setup_light_with_effects(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    effect_list_template: str,
+    effect_template: str,
+) -> None:
+    """Do setup of light with effects."""
+    common = {
+        "set_effect": {
+            "service": "test.automation",
+            "data_template": {
+                "action": "set_effect",
+                "caller": "{{ this.entity_id }}",
+                "entity_id": "test.test_state",
+                "effect": "{{effect}}",
+            },
+        },
+    }
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format(
+            hass,
+            count,
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                    "value_template": "{{true}}",
+                    **common,
+                    "effect_list_template": effect_list_template,
+                    "effect_template": effect_template,
+                }
+            },
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_new_format(
+            hass,
+            count,
+            {
+                "name": "test_template_light",
+                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                "state": "{{true}}",
+                **common,
+                "effect_list": effect_list_template,
+                "effect": effect_template,
+            },
+        )
+
+
+@pytest.fixture
+async def setup_light_with_mireds(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    attribute: str,
+    attribute_template: str,
+) -> None:
+    """Do setup of light that uses mireds."""
+    common = {
+        "set_temperature": {
+            "service": "light.turn_on",
+            "data_template": {
+                "entity_id": "light.test_state",
+                "color_temp": "{{color_temp}}",
+            },
+        },
+        attribute: attribute_template,
+    }
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format(
+            hass,
+            count,
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+                    "value_template": "{{ 1 == 1 }}",
+                    **common,
+                    "temperature_template": "{{200}}",
+                }
+            },
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_new_format(
+            hass,
+            count,
+            {
+                "name": "test_template_light",
+                **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+                "state": "{{ 1 == 1 }}",
+                **common,
+                "temperature": "{{200}}",
+            },
+        )
+
+
+@pytest.fixture
+async def setup_light_with_transition_template(
+    hass: HomeAssistant,
+    count: int,
+    style: ConfigurationStyle,
+    transition_template: str,
+) -> None:
+    """Do setup of light that uses mireds."""
+    common = {
+        "set_effect": {
+            "service": "test.automation",
+            "data_template": {
+                "entity_id": "test.test_state",
+                "effect": "{{effect}}",
+            },
+        },
+    }
+    if style == ConfigurationStyle.LEGACY:
+        await async_setup_legacy_format(
+            hass,
+            count,
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG,
+                    "value_template": "{{ 1 == 1 }}",
+                    **common,
+                    "effect_list_template": "{{ ['Disco', 'Police'] }}",
+                    "effect_template": "{{ None }}",
+                    "supports_transition_template": transition_template,
+                }
+            },
+        )
+    elif style == ConfigurationStyle.MODERN:
+        await async_setup_new_format(
+            hass,
+            count,
+            {
+                "name": "test_template_light",
+                **OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG,
+                "state": "{{ 1 == 1 }}",
+                **common,
+                "effect_list": "{{ ['Disco', 'Police'] }}",
+                "effect": "{{ None }}",
+                "supports_transition": transition_template,
+            },
+        )
 
 
 @pytest.mark.parametrize("count", [1])
@@ -186,18 +705,15 @@ async def setup_light(
     [(0, [ColorMode.BRIGHTNESS])],
 )
 @pytest.mark.parametrize(
-    "light_config",
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{states.test['big.fat...']}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
+@pytest.mark.parametrize("state_template", ["{{states.test['big.fat...']}}"])
 async def test_template_state_invalid(
-    hass: HomeAssistant, supported_features, supported_color_modes, setup_light
+    hass: HomeAssistant, supported_features, supported_color_modes, setup_state_light
 ) -> None:
     """Test template state with render error."""
     state = hass.states.get("light.test_template_light")
@@ -209,17 +725,14 @@ async def test_template_state_invalid(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{ states.light.test_state.state }}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
-async def test_template_state_text(hass: HomeAssistant, setup_light) -> None:
+@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
+async def test_template_state_text(hass: HomeAssistant, setup_state_light) -> None:
     """Test the state text of a template."""
     set_state = STATE_ON
     hass.states.async_set("light.test_state", set_state)
@@ -242,7 +755,14 @@ async def test_template_state_text(hass: HomeAssistant, setup_light) -> None:
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("value_template", "expected_state", "expected_color_mode"),
+    "style",
+    [
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
+    ],
+)
+@pytest.mark.parametrize(
+    ("state_template", "expected_state", "expected_color_mode"),
     [
         (
             "{{ 1 == 1 }}",
@@ -256,21 +776,13 @@ async def test_template_state_text(hass: HomeAssistant, setup_light) -> None:
         ),
     ],
 )
-async def test_templatex_state_boolean(
+async def test_legacy_template_state_boolean(
     hass: HomeAssistant,
     expected_color_mode,
     expected_state,
-    count,
-    value_template,
+    setup_state_light,
 ) -> None:
     """Test the setting of the state with boolean on."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-            "value_template": value_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.state == expected_state
     assert state.attributes.get("color_mode") == expected_color_mode
@@ -280,48 +792,56 @@ async def test_templatex_state_boolean(
 
 @pytest.mark.parametrize("count", [0])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{%- if false -%}",
-            }
-        },
-        {
-            "bad name here": {
+        (
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                    "value_template": "{%- if false -%}",
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "bad name here": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                    "value_template": "{{ 1== 1}}",
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {"test_template_light": "Invalid"},
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
                 **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{ 1== 1}}",
-            }
-        },
-        {"test_template_light": "Invalid"},
+                "name": "test_template_light",
+                "state": "{%- if false -%}",
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
-async def test_template_syntax_error(hass: HomeAssistant, setup_light) -> None:
-    """Test templating syntax error."""
+async def test_template_config_errors(hass: HomeAssistant, setup_light) -> None:
+    """Test template light configuration errors."""
     assert hass.states.async_all("light") == []
 
 
 @pytest.mark.parametrize(
-    ("light_config", "count"),
+    ("light_config", "style", "count"),
     [
         (
-            {
-                "light_one": {
-                    "value_template": "{{ 1== 1}}",
-                    "turn_on": {
-                        "service": "light.turn_on",
-                        "entity_id": "light.test_state",
-                    },
-                    "set_level": {
-                        "service": "light.turn_on",
-                        "data_template": {
-                            "entity_id": "light.test_state",
-                            "brightness": "{{brightness}}",
-                        },
-                    },
-                }
-            },
+            {"light_one": {"value_template": "{{ 1== 1}}", **TEST_MISSING_KEY_CONFIG}},
+            ConfigurationStyle.LEGACY,
+            0,
+        ),
+        (
+            {"name": "light_one", "state": "{{ 1== 1}}", **TEST_MISSING_KEY_CONFIG},
+            ConfigurationStyle.MODERN,
             0,
         ),
     ],
@@ -336,18 +856,15 @@ async def test_missing_key(hass: HomeAssistant, count, setup_light) -> None:
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{states.light.test_state.state}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
+@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
 async def test_on_action(
-    hass: HomeAssistant, setup_light, calls: list[ServiceCall]
+    hass: HomeAssistant, setup_state_light, calls: list[ServiceCall]
 ) -> None:
     """Test on action."""
     hass.states.async_set("light.test_state", STATE_OFF)
@@ -378,32 +895,26 @@ async def test_on_action(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
-                "value_template": "{{states.light.test_state.state}}",
-                "turn_on": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "transition": "{{transition}}",
-                    },
-                },
-                "turn_off": {
-                    "service": "light.turn_off",
-                    "entity_id": "light.test_state",
-                },
-                "supports_transition_template": "{{true}}",
-                "set_level": {
-                    "service": "light.turn_on",
-                    "data_template": {
-                        "entity_id": "light.test_state",
-                        "brightness": "{{brightness}}",
-                        "transition": "{{transition}}",
-                    },
-                },
-            }
-        },
+        (
+            {
+                "test_template_light": {
+                    "value_template": "{{states.light.test_state.state}}",
+                    **TEST_ON_ACTION_WITH_TRANSITION_CONFIG,
+                    "supports_transition_template": "{{true}}",
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "name": "test_template_light",
+                **TEST_ON_ACTION_WITH_TRANSITION_CONFIG,
+                "supports_transition": "{{true}}",
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_on_action_with_transition(
@@ -437,13 +948,23 @@ async def test_on_action_with_transition(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
+        (
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "name": "test_template_light",
                 **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-            }
-        },
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_on_action_optimistic(
@@ -497,18 +1018,15 @@ async def test_on_action_optimistic(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{states.light.test_state.state}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
+@pytest.mark.parametrize("state_template", ["{{ states.light.test_state.state }}"])
 async def test_off_action(
-    hass: HomeAssistant, setup_light, calls: list[ServiceCall]
+    hass: HomeAssistant, setup_state_light, calls: list[ServiceCall]
 ) -> None:
     """Test off action."""
     hass.states.async_set("light.test_state", STATE_ON)
@@ -538,32 +1056,27 @@ async def test_off_action(
 
 @pytest.mark.parametrize("count", [(1)])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
-                "value_template": "{{states.light.test_state.state}}",
-                "turn_on": {
-                    "service": "light.turn_on",
-                    "entity_id": "light.test_state",
-                },
-                "turn_off": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "transition": "{{transition}}",
-                    },
-                },
-                "supports_transition_template": "{{true}}",
-                "set_level": {
-                    "service": "light.turn_on",
-                    "data_template": {
-                        "entity_id": "light.test_state",
-                        "brightness": "{{brightness}}",
-                        "transition": "{{transition}}",
-                    },
-                },
-            }
-        },
+        (
+            {
+                "test_template_light": {
+                    "value_template": "{{states.light.test_state.state}}",
+                    **TEST_OFF_ACTION_WITH_TRANSITION_CONFIG,
+                    "supports_transition_template": "{{true}}",
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "name": "test_template_light",
+                "state": "{{states.light.test_state.state}}",
+                **TEST_OFF_ACTION_WITH_TRANSITION_CONFIG,
+                "supports_transition": "{{true}}",
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_off_action_with_transition(
@@ -596,13 +1109,23 @@ async def test_off_action_with_transition(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
+        (
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "name": "test_template_light",
                 **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-            }
-        },
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_off_action_optimistic(
@@ -632,19 +1155,16 @@ async def test_off_action_optimistic(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
+@pytest.mark.parametrize("state_template", ["{{1 == 1}}"])
 async def test_level_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_state_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting brightness with optimistic template."""
@@ -671,9 +1191,18 @@ async def test_level_action_no_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_level", "level_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "level_template"),
+        (ConfigurationStyle.MODERN, "level"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_level", "attribute_template", "expected_color_mode"),
     [
         (255, "{{255}}", ColorMode.BRIGHTNESS),
         (None, "{{256}}", ColorMode.BRIGHTNESS),
@@ -690,20 +1219,11 @@ async def test_level_action_no_template(
 )
 async def test_level_template(
     hass: HomeAssistant,
-    expected_level,
-    expected_color_mode,
-    count,
-    level_template,
+    expected_level: Any,
+    expected_color_mode: ColorMode,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the level."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "level_template": level_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("brightness") == expected_level
     assert state.state == STATE_ON
@@ -712,9 +1232,18 @@ async def test_level_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_temp", "temperature_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "temperature_template"),
+        (ConfigurationStyle.MODERN, "temperature"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_temp", "attribute_template", "expected_color_mode"),
     [
         (500, "{{500}}", ColorMode.COLOR_TEMP),
         (None, "{{501}}", ColorMode.COLOR_TEMP),
@@ -727,20 +1256,11 @@ async def test_level_template(
 )
 async def test_temperature_template(
     hass: HomeAssistant,
-    expected_temp,
-    expected_color_mode,
-    count,
-    temperature_template,
+    expected_temp: Any,
+    expected_color_mode: ColorMode,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the temperature."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "temperature_template": temperature_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("color_temp") == expected_temp
     assert state.state == STATE_ON
@@ -749,21 +1269,19 @@ async def test_temperature_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"), [(1, OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
 async def test_temperature_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting temperature with optimistic template."""
@@ -793,43 +1311,53 @@ async def test_temperature_action_no_template(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style", "entity_id"),
     [
-        {
-            "test_template_light": {
+        (
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+                    "friendly_name": "Template light",
+                    "value_template": "{{ 1 == 1 }}",
+                }
+            },
+            ConfigurationStyle.LEGACY,
+            "light.test_template_light",
+        ),
+        (
+            {
                 **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "friendly_name": "Template light",
-                "value_template": "{{ 1 == 1 }}",
-            }
-        },
+                "name": "Template light",
+                "state": "{{ 1 == 1 }}",
+            },
+            ConfigurationStyle.MODERN,
+            "light.template_light",
+        ),
     ],
 )
-async def test_friendly_name(hass: HomeAssistant, setup_light) -> None:
+async def test_friendly_name(hass: HomeAssistant, entity_id: str, setup_light) -> None:
     """Test the accessibility of the friendly_name attribute."""
 
-    state = hass.states.get("light.test_template_light")
+    state = hass.states.get(entity_id)
     assert state is not None
 
     assert state.attributes.get("friendly_name") == "Template light"
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"), [(1, OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "friendly_name": "Template light",
-                "value_template": "{{ 1 == 1 }}",
-                "icon_template": (
-                    "{% if states.light.test_state.state %}mdi:check{% endif %}"
-                ),
-            }
-        },
+        (ConfigurationStyle.LEGACY, "icon_template"),
+        (ConfigurationStyle.MODERN, "icon"),
     ],
 )
-async def test_icon_template(hass: HomeAssistant, setup_light) -> None:
+@pytest.mark.parametrize(
+    "attribute_template", ["{% if states.light.test_state.state %}mdi:check{% endif %}"]
+)
+async def test_icon_template(hass: HomeAssistant, setup_single_attribute_light) -> None:
     """Test icon template."""
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("icon") == ""
@@ -842,23 +1370,23 @@ async def test_icon_template(hass: HomeAssistant, setup_light) -> None:
     assert state.attributes["icon"] == "mdi:check"
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"), [(1, OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "friendly_name": "Template light",
-                "value_template": "{{ 1 == 1 }}",
-                "entity_picture_template": (
-                    "{% if states.light.test_state.state %}/local/light.png{% endif %}"
-                ),
-            }
-        },
+        (ConfigurationStyle.LEGACY, "entity_picture_template"),
+        (ConfigurationStyle.MODERN, "picture"),
     ],
 )
-async def test_entity_picture_template(hass: HomeAssistant, setup_light) -> None:
+@pytest.mark.parametrize(
+    "attribute_template",
+    ["{% if states.light.test_state.state %}/local/light.png{% endif %}"],
+)
+async def test_entity_picture_template(
+    hass: HomeAssistant, setup_single_attribute_light
+) -> None:
     """Test entity_picture template."""
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("entity_picture") == ""
@@ -871,21 +1399,21 @@ async def test_entity_picture_template(hass: HomeAssistant, setup_light) -> None
     assert state.attributes["entity_picture"] == "/local/light.png"
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_LEGACY_COLOR_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        (1, OPTIMISTIC_LEGACY_COLOR_LIGHT_CONFIG),
+    ],
+)
+@pytest.mark.parametrize(
+    "style",
+    [
+        ConfigurationStyle.LEGACY,
     ],
 )
 async def test_legacy_color_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting color with optimistic template."""
@@ -913,24 +1441,25 @@ async def test_legacy_color_action_no_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        (1, OPTIMISTIC_HS_COLOR_LIGHT_CONFIG),
+    ],
+)
+@pytest.mark.parametrize(
+    "style",
+    [
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
 async def test_hs_color_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
-    """Test setting hs color with optimistic template."""
+    """Test setting color with optimistic template."""
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("hs_color") is None
 
@@ -955,21 +1484,20 @@ async def test_hs_color_action_no_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"),
+    [(1, OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG)],
+)
+@pytest.mark.parametrize(
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
 async def test_rgb_color_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting rgb color with optimistic template."""
@@ -998,21 +1526,20 @@ async def test_rgb_color_action_no_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"),
+    [(1, OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG)],
+)
+@pytest.mark.parametrize(
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
 async def test_rgbw_color_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting rgbw color with optimistic template."""
@@ -1045,21 +1572,20 @@ async def test_rgbw_color_action_no_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config"),
+    [(1, OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG)],
+)
+@pytest.mark.parametrize(
+    "style",
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-            }
-        },
+        ConfigurationStyle.LEGACY,
+        ConfigurationStyle.MODERN,
     ],
 )
 async def test_rgbww_color_action_no_template(
     hass: HomeAssistant,
-    setup_light,
+    setup_single_action_light,
     calls: list[ServiceCall],
 ) -> None:
     """Test setting rgbww color with optimistic template."""
@@ -1123,7 +1649,7 @@ async def test_legacy_color_template(
             "color_template": color_template,
         }
     }
-    await async_setup_light(hass, count, light_config)
+    await async_setup_legacy_format(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("hs_color") == expected_hs
     assert state.state == STATE_ON
@@ -1132,9 +1658,18 @@ async def test_legacy_color_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_hs", "hs_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_HS_COLOR_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "hs_template"),
+        (ConfigurationStyle.MODERN, "hs"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_hs", "attribute_template", "expected_color_mode"),
     [
         ((360, 100), "{{(360, 100)}}", ColorMode.HS),
         ((360, 100), "(360, 100)", ColorMode.HS),
@@ -1152,18 +1687,9 @@ async def test_hs_template(
     hass: HomeAssistant,
     expected_hs,
     expected_color_mode,
-    count,
-    hs_template,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the color."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_HS_COLOR_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "hs_template": hs_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("hs_color") == expected_hs
     assert state.state == STATE_ON
@@ -1172,9 +1698,18 @@ async def test_hs_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_rgb", "rgb_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "rgb_template"),
+        (ConfigurationStyle.MODERN, "rgb"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_rgb", "attribute_template", "expected_color_mode"),
     [
         ((160, 78, 192), "{{(160, 78, 192)}}", ColorMode.RGB),
         ((160, 78, 192), "{{[160, 78, 192]}}", ColorMode.RGB),
@@ -1193,18 +1728,9 @@ async def test_rgb_template(
     hass: HomeAssistant,
     expected_rgb,
     expected_color_mode,
-    count,
-    rgb_template,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the color."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_RGB_COLOR_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "rgb_template": rgb_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("rgb_color") == expected_rgb
     assert state.state == STATE_ON
@@ -1213,9 +1739,18 @@ async def test_rgb_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_rgbw", "rgbw_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "rgbw_template"),
+        (ConfigurationStyle.MODERN, "rgbw"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_rgbw", "attribute_template", "expected_color_mode"),
     [
         ((160, 78, 192, 25), "{{(160, 78, 192, 25)}}", ColorMode.RGBW),
         ((160, 78, 192, 25), "{{[160, 78, 192, 25]}}", ColorMode.RGBW),
@@ -1235,18 +1770,9 @@ async def test_rgbw_template(
     hass: HomeAssistant,
     expected_rgbw,
     expected_color_mode,
-    count,
-    rgbw_template,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the color."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_RGBW_COLOR_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "rgbw_template": rgbw_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("rgbw_color") == expected_rgbw
     assert state.state == STATE_ON
@@ -1255,9 +1781,18 @@ async def test_rgbw_template(
     assert state.attributes["supported_features"] == 0
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_rgbww", "rgbww_template", "expected_color_mode"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "rgbww_template"),
+        (ConfigurationStyle.MODERN, "rgbww"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_rgbww", "attribute_template", "expected_color_mode"),
     [
         ((160, 78, 192, 25, 55), "{{(160, 78, 192, 25, 55)}}", ColorMode.RGBWW),
         ((160, 78, 192, 25, 55), "(160, 78, 192, 25, 55)", ColorMode.RGBWW),
@@ -1282,18 +1817,9 @@ async def test_rgbww_template(
     hass: HomeAssistant,
     expected_rgbww,
     expected_color_mode,
-    count,
-    rgbww_template,
+    setup_single_attribute_light,
 ) -> None:
     """Test the template for the color."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_RGBWW_COLOR_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "rgbww_template": rgbww_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state.attributes.get("rgbww_color") == expected_rgbww
     assert state.state == STATE_ON
@@ -1304,59 +1830,27 @@ async def test_rgbww_template(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light": {
+        (
+            {
+                "test_template_light": {
+                    **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+                    "value_template": "{{1 == 1}}",
+                    **TEST_ALL_COLORS_NO_TEMPLATE_CONFIG,
+                }
+            },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            {
+                "name": "test_template_light",
                 **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-                "value_template": "{{1 == 1}}",
-                "set_hs": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "h": "{{h}}",
-                        "s": "{{s}}",
-                    },
-                },
-                "set_temperature": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "color_temp": "{{color_temp}}",
-                    },
-                },
-                "set_rgb": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "r": "{{r}}",
-                        "g": "{{g}}",
-                        "b": "{{b}}",
-                    },
-                },
-                "set_rgbw": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "r": "{{r}}",
-                        "g": "{{g}}",
-                        "b": "{{b}}",
-                        "w": "{{w}}",
-                    },
-                },
-                "set_rgbww": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "r": "{{r}}",
-                        "g": "{{g}}",
-                        "b": "{{b}}",
-                        "cw": "{{cw}}",
-                        "ww": "{{ww}}",
-                    },
-                },
-            }
-        },
+                "state": "{{1 == 1}}",
+                **TEST_ALL_COLORS_NO_TEMPLATE_CONFIG,
+            },
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_all_colors_mode_no_template(
@@ -1554,29 +2048,21 @@ async def test_all_colors_mode_no_template(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    "style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
+)
+@pytest.mark.parametrize(
+    ("effect_list_template", "effect_template", "effect", "expected"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{true}}",
-                "set_effect": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "action": "set_effect",
-                        "caller": "{{ this.entity_id }}",
-                        "entity_id": "test.test_state",
-                        "effect": "{{effect}}",
-                    },
-                },
-                "effect_list_template": "{{ ['Disco', 'Police'] }}",
-                "effect_template": "{{ 'Disco' }}",
-            }
-        },
+        ("{{ ['Disco', 'Police'] }}", "{{ 'Disco' }}", "Disco", "Disco"),
+        ("{{ ['Disco', 'Police'] }}", "{{ 'None' }}", "RGB", None),
     ],
 )
-async def test_effect_action_valid_effect(
-    hass: HomeAssistant, setup_light, calls: list[ServiceCall]
+async def test_effect_action(
+    hass: HomeAssistant,
+    effect: str,
+    expected: Any,
+    setup_light_with_effects,
+    calls: list[ServiceCall],
 ) -> None:
     """Test setting valid effect with template."""
     state = hass.states.get("light.test_template_light")
@@ -1585,64 +2071,24 @@ async def test_effect_action_valid_effect(
     await hass.services.async_call(
         light.DOMAIN,
         SERVICE_TURN_ON,
-        {ATTR_ENTITY_ID: "light.test_template_light", ATTR_EFFECT: "Disco"},
+        {ATTR_ENTITY_ID: "light.test_template_light", ATTR_EFFECT: effect},
         blocking=True,
     )
 
     assert len(calls) == 1
     assert calls[-1].data["action"] == "set_effect"
     assert calls[-1].data["caller"] == "light.test_template_light"
-    assert calls[-1].data["effect"] == "Disco"
+    assert calls[-1].data["effect"] == effect
 
     state = hass.states.get("light.test_template_light")
     assert state is not None
-    assert state.attributes.get("effect") == "Disco"
+    assert state.attributes.get("effect") == expected
 
 
-@pytest.mark.parametrize("count", [1])
+@pytest.mark.parametrize(("count", "effect_template"), [(1, "{{ None }}")])
 @pytest.mark.parametrize(
-    "light_config",
-    [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "value_template": "{{true}}",
-                "set_effect": {
-                    "service": "test.automation",
-                    "data_template": {
-                        "entity_id": "test.test_state",
-                        "effect": "{{effect}}",
-                    },
-                },
-                "effect_list_template": "{{ ['Disco', 'Police'] }}",
-                "effect_template": "{{ None }}",
-            }
-        },
-    ],
+    "style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
 )
-async def test_effect_action_invalid_effect(
-    hass: HomeAssistant, setup_light, calls: list[ServiceCall]
-) -> None:
-    """Test setting invalid effect with template."""
-    state = hass.states.get("light.test_template_light")
-    assert state is not None
-
-    await hass.services.async_call(
-        light.DOMAIN,
-        SERVICE_TURN_ON,
-        {ATTR_ENTITY_ID: "light.test_template_light", ATTR_EFFECT: "RGB"},
-        blocking=True,
-    )
-
-    assert len(calls) == 1
-    assert calls[0].data["effect"] == "RGB"
-
-    state = hass.states.get("light.test_template_light")
-    assert state is not None
-    assert state.attributes.get("effect") is None
-
-
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
     ("expected_effect_list", "effect_list_template"),
     [
@@ -1663,31 +2109,21 @@ async def test_effect_action_invalid_effect(
     ],
 )
 async def test_effect_list_template(
-    hass: HomeAssistant, expected_effect_list, count, effect_list_template
+    hass: HomeAssistant, expected_effect_list, setup_light_with_effects
 ) -> None:
     """Test the template for the effect list."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "set_effect": {
-                "service": "test.automation",
-                "data_template": {
-                    "entity_id": "test.test_state",
-                    "effect": "{{effect}}",
-                },
-            },
-            "effect_template": "{{ None }}",
-            "effect_list_template": effect_list_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state is not None
     assert state.attributes.get("effect_list") == expected_effect_list
 
 
-@pytest.mark.parametrize("count", [1])
+@pytest.mark.parametrize(
+    ("count", "effect_list_template"),
+    [(1, "{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}")],
+)
+@pytest.mark.parametrize(
+    "style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
+)
 @pytest.mark.parametrize(
     ("expected_effect", "effect_template"),
     [
@@ -1699,27 +2135,9 @@ async def test_effect_list_template(
     ],
 )
 async def test_effect_template(
-    hass: HomeAssistant, expected_effect, count, effect_template
+    hass: HomeAssistant, expected_effect, setup_light_with_effects
 ) -> None:
     """Test the template for the effect."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "set_effect": {
-                "service": "test.automation",
-                "data_template": {
-                    "entity_id": "test.test_state",
-                    "effect": "{{effect}}",
-                },
-            },
-            "effect_list_template": (
-                "{{ ['Strobe color', 'Police', 'Christmas', 'RGB', 'Random Loop'] }}"
-            ),
-            "effect_template": effect_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state is not None
     assert state.attributes.get("effect") == expected_effect
@@ -1727,7 +2145,14 @@ async def test_effect_template(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_min_mireds", "min_mireds_template"),
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "min_mireds_template"),
+        (ConfigurationStyle.MODERN, "min_mireds"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_min_mireds", "attribute_template"),
     [
         (118, "{{118}}"),
         (153, "{{x - 12}}"),
@@ -1738,25 +2163,9 @@ async def test_effect_template(
     ],
 )
 async def test_min_mireds_template(
-    hass: HomeAssistant, expected_min_mireds, count, min_mireds_template
+    hass: HomeAssistant, expected_min_mireds, setup_light_with_mireds
 ) -> None:
     """Test the template for the min mireds."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "set_temperature": {
-                "service": "light.turn_on",
-                "data_template": {
-                    "entity_id": "light.test_state",
-                    "color_temp": "{{color_temp}}",
-                },
-            },
-            "temperature_template": "{{200}}",
-            "min_mireds_template": min_mireds_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state is not None
     assert state.attributes.get("min_mireds") == expected_min_mireds
@@ -1764,7 +2173,14 @@ async def test_min_mireds_template(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_max_mireds", "max_mireds_template"),
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "max_mireds_template"),
+        (ConfigurationStyle.MODERN, "max_mireds"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_max_mireds", "attribute_template"),
     [
         (488, "{{488}}"),
         (500, "{{x - 12}}"),
@@ -1775,33 +2191,26 @@ async def test_min_mireds_template(
     ],
 )
 async def test_max_mireds_template(
-    hass: HomeAssistant, expected_max_mireds, count, max_mireds_template
+    hass: HomeAssistant, expected_max_mireds, setup_light_with_mireds
 ) -> None:
     """Test the template for the max mireds."""
-    light_config = {
-        "test_template_light": {
-            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-            "value_template": "{{ 1 == 1 }}",
-            "set_temperature": {
-                "service": "light.turn_on",
-                "data_template": {
-                    "entity_id": "light.test_state",
-                    "color_temp": "{{color_temp}}",
-                },
-            },
-            "temperature_template": "{{200}}",
-            "max_mireds_template": max_mireds_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state is not None
     assert state.attributes.get("max_mireds") == expected_max_mireds
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    ("expected_supports_transition", "supports_transition_template"),
+    ("count", "extra_config"), [(1, OPTIMISTIC_COLOR_TEMP_LIGHT_CONFIG)]
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "supports_transition_template"),
+        (ConfigurationStyle.MODERN, "supports_transition"),
+    ],
+)
+@pytest.mark.parametrize(
+    ("expected_supports_transition", "attribute_template"),
     [
         (True, "{{true}}"),
         (True, "{{1 == 1}}"),
@@ -1812,28 +2221,9 @@ async def test_max_mireds_template(
     ],
 )
 async def test_supports_transition_template(
-    hass: HomeAssistant,
-    expected_supports_transition,
-    count,
-    supports_transition_template,
+    hass: HomeAssistant, expected_supports_transition, setup_single_attribute_light
 ) -> None:
     """Test the template for the supports transition."""
-    light_config = {
-        "test_template_light": {
-            "value_template": "{{ 1 == 1 }}",
-            "turn_on": {"service": "light.turn_on", "entity_id": "light.test_state"},
-            "turn_off": {"service": "light.turn_off", "entity_id": "light.test_state"},
-            "set_temperature": {
-                "service": "light.turn_on",
-                "data_template": {
-                    "entity_id": "light.test_state",
-                    "color_temp": "{{color_temp}}",
-                },
-            },
-            "supports_transition_template": supports_transition_template,
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
 
     expected_value = 1
@@ -1847,36 +2237,16 @@ async def test_supports_transition_template(
     ) != expected_value
 
 
-@pytest.mark.parametrize("count", [1])
+@pytest.mark.parametrize(
+    ("count", "transition_template"), [(1, "{{ states('sensor.test') }}")]
+)
+@pytest.mark.parametrize(
+    "style", [ConfigurationStyle.LEGACY, ConfigurationStyle.MODERN]
+)
 async def test_supports_transition_template_updates(
-    hass: HomeAssistant, count: int
+    hass: HomeAssistant, setup_light_with_transition_template
 ) -> None:
     """Test the template for the supports transition dynamically."""
-    light_config = {
-        "test_template_light": {
-            "value_template": "{{ 1 == 1 }}",
-            "turn_on": {"service": "light.turn_on", "entity_id": "light.test_state"},
-            "turn_off": {"service": "light.turn_off", "entity_id": "light.test_state"},
-            "set_temperature": {
-                "service": "light.turn_on",
-                "data_template": {
-                    "entity_id": "light.test_state",
-                    "color_temp": "{{color_temp}}",
-                },
-            },
-            "set_effect": {
-                "service": "test.automation",
-                "data_template": {
-                    "entity_id": "test.test_state",
-                    "effect": "{{effect}}",
-                },
-            },
-            "effect_list_template": "{{ ['Disco', 'Police'] }}",
-            "effect_template": "{{ None }}",
-            "supports_transition_template": "{{ states('sensor.test') }}",
-        }
-    }
-    await async_setup_light(hass, count, light_config)
     state = hass.states.get("light.test_template_light")
     assert state is not None
 
@@ -1901,22 +2271,25 @@ async def test_supports_transition_template_updates(
     assert supported_features == LightEntityFeature.EFFECT
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config", "attribute_template"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "availability_template": (
-                    "{{ is_state('availability_boolean.state', 'on') }}"
-                ),
-            }
-        },
+        (
+            1,
+            OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+            "{{ is_state('availability_boolean.state', 'on') }}",
+        )
+    ],
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "availability_template"),
+        (ConfigurationStyle.MODERN, "availability"),
     ],
 )
 async def test_available_template_with_entities(
-    hass: HomeAssistant, setup_light
+    hass: HomeAssistant, setup_single_attribute_light
 ) -> None:
     """Test availability templates with values from other entities."""
     # When template returns true..
@@ -1934,20 +2307,25 @@ async def test_available_template_with_entities(
     assert hass.states.get("light.test_template_light").state == STATE_UNAVAILABLE
 
 
-@pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("count", "extra_config", "attribute_template"),
     [
-        {
-            "test_template_light": {
-                **OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
-                "availability_template": "{{ x - 12 }}",
-            }
-        },
+        (
+            1,
+            OPTIMISTIC_BRIGHTNESS_LIGHT_CONFIG,
+            "{{ x - 12 }}",
+        )
+    ],
+)
+@pytest.mark.parametrize(
+    ("style", "attribute"),
+    [
+        (ConfigurationStyle.LEGACY, "availability_template"),
+        (ConfigurationStyle.MODERN, "availability"),
     ],
 )
 async def test_invalid_availability_template_keeps_component_available(
-    hass: HomeAssistant, setup_light, caplog_setup_text
+    hass: HomeAssistant, setup_single_attribute_light, caplog_setup_text
 ) -> None:
     """Test that an invalid availability keeps the device available."""
     assert hass.states.get("light.test_template_light").state != STATE_UNAVAILABLE
@@ -1956,20 +2334,73 @@ async def test_invalid_availability_template_keeps_component_available(
 
 @pytest.mark.parametrize("count", [1])
 @pytest.mark.parametrize(
-    "light_config",
+    ("light_config", "style"),
     [
-        {
-            "test_template_light_01": {
-                **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-                "unique_id": "not-so-unique-anymore",
-            },
-            "test_template_light_02": {
-                **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
-                "unique_id": "not-so-unique-anymore",
+        (
+            {
+                "test_template_light_01": TEST_UNIQUE_ID_CONFIG,
+                "test_template_light_02": TEST_UNIQUE_ID_CONFIG,
             },
-        },
+            ConfigurationStyle.LEGACY,
+        ),
+        (
+            [
+                {
+                    "name": "test_template_light_01",
+                    **TEST_UNIQUE_ID_CONFIG,
+                },
+                {
+                    "name": "test_template_light_02",
+                    **TEST_UNIQUE_ID_CONFIG,
+                },
+            ],
+            ConfigurationStyle.MODERN,
+        ),
     ],
 )
 async def test_unique_id(hass: HomeAssistant, setup_light) -> None:
     """Test unique_id option only creates one light per id."""
     assert len(hass.states.async_all("light")) == 1
+
+
+async def test_nested_unique_id(
+    hass: HomeAssistant, entity_registry: er.EntityRegistry
+) -> None:
+    """Test unique_id option creates one light per nested id."""
+
+    with assert_setup_component(1, template.DOMAIN):
+        assert await async_setup_component(
+            hass,
+            template.DOMAIN,
+            {
+                "template": {
+                    "unique_id": "x",
+                    "light": [
+                        {
+                            "name": "test_a",
+                            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+                            "unique_id": "a",
+                        },
+                        {
+                            "name": "test_b",
+                            **OPTIMISTIC_ON_OFF_LIGHT_CONFIG,
+                            "unique_id": "b",
+                        },
+                    ],
+                }
+            },
+        )
+
+    await hass.async_block_till_done()
+    await hass.async_start()
+    await hass.async_block_till_done()
+
+    assert len(hass.states.async_all("light")) == 2
+
+    entry = entity_registry.async_get("light.test_a")
+    assert entry
+    assert entry.unique_id == "x-a"
+
+    entry = entity_registry.async_get("light.test_b")
+    assert entry
+    assert entry.unique_id == "x-b"
-- 
GitLab