Skip to content

Commit bcb87cf

Browse files
authored
Support variables, icon, and picture for all compatible template platforms (home-assistant#145893)
* Fix template entity variables in blueprints * add picture and icon tests * add variable test for all platforms * apply comments * Update all test names
1 parent d01758c commit bcb87cf

31 files changed

+751
-432
lines changed

homeassistant/components/template/alarm_control_panel.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,12 @@
4141
from homeassistant.helpers.script import Script
4242
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
4343

44-
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
44+
from .const import CONF_OBJECT_ID, DOMAIN
4545
from .entity import AbstractTemplateEntity
4646
from .template_entity import (
4747
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
48-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
49-
TEMPLATE_ENTITY_ICON_SCHEMA,
5048
TemplateEntity,
49+
make_template_entity_common_modern_schema,
5150
rewrite_common_legacy_to_modern_conf,
5251
)
5352

@@ -105,15 +104,10 @@ class TemplateCodeFormat(Enum):
105104
CONF_CODE_FORMAT, default=TemplateCodeFormat.number.name
106105
): cv.enum(TemplateCodeFormat),
107106
vol.Optional(CONF_DISARM_ACTION): cv.SCRIPT_SCHEMA,
108-
vol.Optional(CONF_NAME): cv.template,
109-
vol.Optional(CONF_PICTURE): cv.template,
110107
vol.Optional(CONF_STATE): cv.template,
111108
vol.Optional(CONF_TRIGGER_ACTION): cv.SCRIPT_SCHEMA,
112-
vol.Optional(CONF_UNIQUE_ID): cv.string,
113109
}
114-
)
115-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
116-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema),
110+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
117111
)
118112

119113

@@ -419,9 +413,7 @@ def __init__(
419413
unique_id: str | None,
420414
) -> None:
421415
"""Initialize the panel."""
422-
TemplateEntity.__init__(
423-
self, hass, config=config, fallback_name=None, unique_id=unique_id
424-
)
416+
TemplateEntity.__init__(self, hass, config=config, unique_id=unique_id)
425417
AbstractTemplateAlarmControlPanel.__init__(self, config)
426418
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
427419
self.entity_id = async_generate_entity_id(

homeassistant/components/template/button.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,19 @@
2626
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
2727

2828
from .const import CONF_PRESS, DOMAIN
29-
from .template_entity import (
30-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
31-
TEMPLATE_ENTITY_ICON_SCHEMA,
32-
TemplateEntity,
33-
)
29+
from .template_entity import TemplateEntity, make_template_entity_common_modern_schema
3430

3531
_LOGGER = logging.getLogger(__name__)
3632

3733
DEFAULT_NAME = "Template Button"
3834
DEFAULT_OPTIMISTIC = False
3935

40-
BUTTON_SCHEMA = (
41-
vol.Schema(
42-
{
43-
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
44-
vol.Required(CONF_PRESS): cv.SCRIPT_SCHEMA,
45-
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
46-
vol.Optional(CONF_UNIQUE_ID): cv.string,
47-
}
48-
)
49-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
50-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
51-
)
36+
BUTTON_SCHEMA = vol.Schema(
37+
{
38+
vol.Required(CONF_PRESS): cv.SCRIPT_SCHEMA,
39+
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
40+
}
41+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
5242

5343
CONFIG_BUTTON_SCHEMA = vol.Schema(
5444
{

homeassistant/components/template/cover.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@
3737
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
3838

3939
from . import TriggerUpdateCoordinator
40-
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
40+
from .const import CONF_OBJECT_ID, DOMAIN
4141
from .entity import AbstractTemplateEntity
4242
from .template_entity import (
4343
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
44-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
4544
TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
46-
TEMPLATE_ENTITY_ICON_SCHEMA,
4745
TemplateEntity,
46+
make_template_entity_common_modern_schema,
4847
rewrite_common_legacy_to_modern_conf,
4948
)
5049
from .trigger_entity import TriggerEntity
@@ -100,21 +99,16 @@
10099
vol.Inclusive(CLOSE_ACTION, CONF_OPEN_AND_CLOSE): cv.SCRIPT_SCHEMA,
101100
vol.Inclusive(OPEN_ACTION, CONF_OPEN_AND_CLOSE): cv.SCRIPT_SCHEMA,
102101
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
103-
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
104102
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
105-
vol.Optional(CONF_PICTURE): cv.template,
106103
vol.Optional(CONF_POSITION): cv.template,
107104
vol.Optional(CONF_STATE): cv.template,
108105
vol.Optional(CONF_TILT_OPTIMISTIC): cv.boolean,
109106
vol.Optional(CONF_TILT): cv.template,
110-
vol.Optional(CONF_UNIQUE_ID): cv.string,
111107
vol.Optional(POSITION_ACTION): cv.SCRIPT_SCHEMA,
112108
vol.Optional(STOP_ACTION): cv.SCRIPT_SCHEMA,
113109
vol.Optional(TILT_ACTION): cv.SCRIPT_SCHEMA,
114110
}
115-
)
116-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
117-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema),
111+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema),
118112
cv.has_at_least_one_key(OPEN_ACTION, POSITION_ACTION),
119113
)
120114

@@ -463,9 +457,7 @@ def __init__(
463457
unique_id,
464458
) -> None:
465459
"""Initialize the Template cover."""
466-
TemplateEntity.__init__(
467-
self, hass, config=config, fallback_name=None, unique_id=unique_id
468-
)
460+
TemplateEntity.__init__(self, hass, config=config, unique_id=unique_id)
469461
AbstractTemplateCover.__init__(self, config)
470462
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
471463
self.entity_id = async_generate_entity_id(

homeassistant/components/template/fan.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@
3737
from homeassistant.helpers.entity_platform import AddEntitiesCallback
3838
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
3939

40-
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
40+
from .const import CONF_OBJECT_ID, DOMAIN
4141
from .entity import AbstractTemplateEntity
4242
from .template_entity import (
4343
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
44-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
4544
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY,
46-
TEMPLATE_ENTITY_ICON_SCHEMA,
4745
TemplateEntity,
46+
make_template_entity_common_modern_schema,
4847
rewrite_common_legacy_to_modern_conf,
4948
)
5049

@@ -85,12 +84,10 @@
8584
vol.Schema(
8685
{
8786
vol.Optional(CONF_DIRECTION): cv.template,
88-
vol.Optional(CONF_NAME): cv.template,
8987
vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
9088
vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
9189
vol.Optional(CONF_OSCILLATING): cv.template,
9290
vol.Optional(CONF_PERCENTAGE): cv.template,
93-
vol.Optional(CONF_PICTURE): cv.template,
9491
vol.Optional(CONF_PRESET_MODE): cv.template,
9592
vol.Optional(CONF_PRESET_MODES): cv.ensure_list,
9693
vol.Optional(CONF_SET_DIRECTION_ACTION): cv.SCRIPT_SCHEMA,
@@ -99,11 +96,8 @@
9996
vol.Optional(CONF_SET_PRESET_MODE_ACTION): cv.SCRIPT_SCHEMA,
10097
vol.Optional(CONF_SPEED_COUNT): vol.Coerce(int),
10198
vol.Optional(CONF_STATE): cv.template,
102-
vol.Optional(CONF_UNIQUE_ID): cv.string,
10399
}
104-
)
105-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
106-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema),
100+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
107101
)
108102

109103
LEGACY_FAN_SCHEMA = vol.All(
@@ -488,9 +482,7 @@ def __init__(
488482
unique_id,
489483
) -> None:
490484
"""Initialize the fan."""
491-
TemplateEntity.__init__(
492-
self, hass, config=config, fallback_name=None, unique_id=unique_id
493-
)
485+
TemplateEntity.__init__(self, hass, config=config, unique_id=unique_id)
494486
AbstractTemplateFan.__init__(self, config)
495487
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
496488
self.entity_id = async_generate_entity_id(

homeassistant/components/template/image.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@
2929

3030
from . import TriggerUpdateCoordinator
3131
from .const import CONF_PICTURE
32-
from .template_entity import TemplateEntity, make_template_entity_common_schema
32+
from .template_entity import (
33+
TemplateEntity,
34+
make_template_entity_common_modern_attributes_schema,
35+
)
3336
from .trigger_entity import TriggerEntity
3437

3538
_LOGGER = logging.getLogger(__name__)
@@ -43,7 +46,7 @@
4346
vol.Required(CONF_URL): cv.template,
4447
vol.Optional(CONF_VERIFY_SSL, default=True): bool,
4548
}
46-
).extend(make_template_entity_common_schema(DEFAULT_NAME).schema)
49+
).extend(make_template_entity_common_modern_attributes_schema(DEFAULT_NAME).schema)
4750

4851

4952
IMAGE_CONFIG_SCHEMA = vol.Schema(

homeassistant/components/template/light.py

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,13 @@
4949
from homeassistant.util import color as color_util
5050

5151
from . import TriggerUpdateCoordinator
52-
from .const import CONF_OBJECT_ID, CONF_PICTURE, DOMAIN
52+
from .const import CONF_OBJECT_ID, DOMAIN
5353
from .entity import AbstractTemplateEntity
5454
from .template_entity import (
5555
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
56-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
5756
TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
58-
TEMPLATE_ENTITY_ICON_SCHEMA,
5957
TemplateEntity,
58+
make_template_entity_common_modern_schema,
6059
rewrite_common_legacy_to_modern_conf,
6160
)
6261
from .trigger_entity import TriggerEntity
@@ -124,38 +123,31 @@
124123

125124
DEFAULT_NAME = "Template Light"
126125

127-
LIGHT_SCHEMA = (
128-
vol.Schema(
129-
{
130-
vol.Inclusive(CONF_EFFECT_ACTION, "effect"): cv.SCRIPT_SCHEMA,
131-
vol.Inclusive(CONF_EFFECT_LIST, "effect"): cv.template,
132-
vol.Inclusive(CONF_EFFECT, "effect"): cv.template,
133-
vol.Optional(CONF_HS_ACTION): cv.SCRIPT_SCHEMA,
134-
vol.Optional(CONF_HS): cv.template,
135-
vol.Optional(CONF_LEVEL_ACTION): cv.SCRIPT_SCHEMA,
136-
vol.Optional(CONF_LEVEL): cv.template,
137-
vol.Optional(CONF_MAX_MIREDS): cv.template,
138-
vol.Optional(CONF_MIN_MIREDS): cv.template,
139-
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
140-
vol.Optional(CONF_PICTURE): cv.template,
141-
vol.Optional(CONF_RGB_ACTION): cv.SCRIPT_SCHEMA,
142-
vol.Optional(CONF_RGB): cv.template,
143-
vol.Optional(CONF_RGBW_ACTION): cv.SCRIPT_SCHEMA,
144-
vol.Optional(CONF_RGBW): cv.template,
145-
vol.Optional(CONF_RGBWW_ACTION): cv.SCRIPT_SCHEMA,
146-
vol.Optional(CONF_RGBWW): cv.template,
147-
vol.Optional(CONF_STATE): cv.template,
148-
vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
149-
vol.Optional(CONF_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
150-
vol.Optional(CONF_TEMPERATURE): cv.template,
151-
vol.Optional(CONF_UNIQUE_ID): cv.string,
152-
vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
153-
vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
154-
}
155-
)
156-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
157-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
158-
)
126+
LIGHT_SCHEMA = vol.Schema(
127+
{
128+
vol.Inclusive(CONF_EFFECT_ACTION, "effect"): cv.SCRIPT_SCHEMA,
129+
vol.Inclusive(CONF_EFFECT_LIST, "effect"): cv.template,
130+
vol.Inclusive(CONF_EFFECT, "effect"): cv.template,
131+
vol.Optional(CONF_HS_ACTION): cv.SCRIPT_SCHEMA,
132+
vol.Optional(CONF_HS): cv.template,
133+
vol.Optional(CONF_LEVEL_ACTION): cv.SCRIPT_SCHEMA,
134+
vol.Optional(CONF_LEVEL): cv.template,
135+
vol.Optional(CONF_MAX_MIREDS): cv.template,
136+
vol.Optional(CONF_MIN_MIREDS): cv.template,
137+
vol.Optional(CONF_RGB_ACTION): cv.SCRIPT_SCHEMA,
138+
vol.Optional(CONF_RGB): cv.template,
139+
vol.Optional(CONF_RGBW_ACTION): cv.SCRIPT_SCHEMA,
140+
vol.Optional(CONF_RGBW): cv.template,
141+
vol.Optional(CONF_RGBWW_ACTION): cv.SCRIPT_SCHEMA,
142+
vol.Optional(CONF_RGBWW): cv.template,
143+
vol.Optional(CONF_STATE): cv.template,
144+
vol.Optional(CONF_SUPPORTS_TRANSITION): cv.template,
145+
vol.Optional(CONF_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
146+
vol.Optional(CONF_TEMPERATURE): cv.template,
147+
vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
148+
vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
149+
}
150+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
159151

160152
LEGACY_LIGHT_SCHEMA = vol.All(
161153
cv.deprecated(CONF_ENTITY_ID),
@@ -955,9 +947,7 @@ def __init__(
955947
unique_id: str | None,
956948
) -> None:
957949
"""Initialize the light."""
958-
TemplateEntity.__init__(
959-
self, hass, config=config, fallback_name=None, unique_id=unique_id
960-
)
950+
TemplateEntity.__init__(self, hass, config=config, unique_id=unique_id)
961951
AbstractTemplateLight.__init__(self, config)
962952
if (object_id := config.get(CONF_OBJECT_ID)) is not None:
963953
self.entity_id = async_generate_entity_id(

homeassistant/components/template/lock.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@
3131
from .entity import AbstractTemplateEntity
3232
from .template_entity import (
3333
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
34-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
3534
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY,
36-
TEMPLATE_ENTITY_ICON_SCHEMA,
3735
TemplateEntity,
36+
make_template_entity_common_modern_schema,
3837
rewrite_common_legacy_to_modern_conf,
3938
)
4039

@@ -57,17 +56,13 @@
5756
{
5857
vol.Optional(CONF_CODE_FORMAT): cv.template,
5958
vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA,
60-
vol.Optional(CONF_NAME): cv.template,
6159
vol.Optional(CONF_OPEN): cv.SCRIPT_SCHEMA,
6260
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
6361
vol.Optional(CONF_PICTURE): cv.template,
6462
vol.Required(CONF_STATE): cv.template,
65-
vol.Optional(CONF_UNIQUE_ID): cv.string,
6663
vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA,
6764
}
68-
)
69-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
70-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema),
65+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
7166
)
7267

7368

@@ -313,9 +308,7 @@ def __init__(
313308
unique_id: str | None,
314309
) -> None:
315310
"""Initialize the lock."""
316-
TemplateEntity.__init__(
317-
self, hass, config=config, fallback_name=DEFAULT_NAME, unique_id=unique_id
318-
)
311+
TemplateEntity.__init__(self, hass, config=config, unique_id=unique_id)
319312
AbstractTemplateLock.__init__(self, config)
320313
name = self._attr_name
321314
if TYPE_CHECKING:

homeassistant/components/template/number.py

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,7 @@
3535

3636
from . import TriggerUpdateCoordinator
3737
from .const import CONF_MAX, CONF_MIN, CONF_STEP, DOMAIN
38-
from .template_entity import (
39-
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
40-
TEMPLATE_ENTITY_ICON_SCHEMA,
41-
TemplateEntity,
42-
)
38+
from .template_entity import TemplateEntity, make_template_entity_common_modern_schema
4339
from .trigger_entity import TriggerEntity
4440

4541
_LOGGER = logging.getLogger(__name__)
@@ -49,23 +45,17 @@
4945
DEFAULT_NAME = "Template Number"
5046
DEFAULT_OPTIMISTIC = False
5147

52-
NUMBER_SCHEMA = (
53-
vol.Schema(
54-
{
55-
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
56-
vol.Required(CONF_STATE): cv.template,
57-
vol.Required(CONF_SET_VALUE): cv.SCRIPT_SCHEMA,
58-
vol.Required(CONF_STEP): cv.template,
59-
vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): cv.template,
60-
vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): cv.template,
61-
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
62-
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
63-
vol.Optional(CONF_UNIQUE_ID): cv.string,
64-
}
65-
)
66-
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
67-
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
68-
)
48+
NUMBER_SCHEMA = vol.Schema(
49+
{
50+
vol.Required(CONF_STATE): cv.template,
51+
vol.Required(CONF_SET_VALUE): cv.SCRIPT_SCHEMA,
52+
vol.Required(CONF_STEP): cv.template,
53+
vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): cv.template,
54+
vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): cv.template,
55+
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
56+
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
57+
}
58+
).extend(make_template_entity_common_modern_schema(DEFAULT_NAME).schema)
6959
NUMBER_CONFIG_SCHEMA = vol.Schema(
7060
{
7161
vol.Required(CONF_NAME): cv.template,

0 commit comments

Comments
 (0)