Teach TemplateEntity entity name (#62175)

* Teach TemplateEntity entity name

* Remove default name from number and select config schemas

* Re-add default name to number and select config schemas

* Set name to None if name template fails to render

* Update template button
This commit is contained in:
Erik Montnemery 2022-01-24 15:44:05 +01:00 committed by GitHub
parent 7b93226c6c
commit 321f54494e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 77 additions and 173 deletions

View File

@ -41,7 +41,7 @@ from homeassistant.helpers.script import Script
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import DOMAIN from .const import DOMAIN
from .template_entity import TemplateEntity from .template_entity import TemplateEntity, rewrite_common_legacy_to_modern_conf
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_VALID_STATES = [ _VALID_STATES = [
@ -102,6 +102,7 @@ async def _async_create_entities(hass, config):
alarm_control_panels = [] alarm_control_panels = []
for object_id, entity_config in config[CONF_ALARM_CONTROL_PANELS].items(): for object_id, entity_config in config[CONF_ALARM_CONTROL_PANELS].items():
entity_config = rewrite_common_legacy_to_modern_conf(entity_config)
unique_id = entity_config.get(CONF_UNIQUE_ID) unique_id = entity_config.get(CONF_UNIQUE_ID)
alarm_control_panels.append( alarm_control_panels.append(
@ -137,11 +138,11 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
unique_id, unique_id,
): ):
"""Initialize the panel.""" """Initialize the panel."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = name = config.get(CONF_NAME, object_id) name = self._attr_name
self._template = config.get(CONF_VALUE_TEMPLATE) self._template = config.get(CONF_VALUE_TEMPLATE)
self._disarm_script = None self._disarm_script = None
self._code_arm_required = config[CONF_CODE_ARM_REQUIRED] self._code_arm_required = config[CONF_CODE_ARM_REQUIRED]
@ -161,11 +162,6 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
self._state = None self._state = None
self._unique_id = unique_id self._unique_id = unique_id
@property
def name(self):
"""Return the display name of this alarm control panel."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this alarm control panel.""" """Return the unique id of this alarm control panel."""

View File

@ -196,25 +196,12 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
unique_id: str | None, unique_id: str | None,
) -> None: ) -> None:
"""Initialize the Template binary sensor.""" """Initialize the Template binary sensor."""
super().__init__(config=config) super().__init__(hass, config=config)
if (object_id := config.get(CONF_OBJECT_ID)) is not None: if (object_id := config.get(CONF_OBJECT_ID)) is not None:
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name: str | None = None
self._friendly_name_template = config.get(CONF_NAME)
# Try to render the name as it can influence the entity ID
if self._friendly_name_template:
self._friendly_name_template.hass = hass
try:
self._name = self._friendly_name_template.async_render(
parse_result=False
)
except template.TemplateError:
pass
self._device_class = config.get(CONF_DEVICE_CLASS) self._device_class = config.get(CONF_DEVICE_CLASS)
self._template = config[CONF_STATE] self._template = config[CONF_STATE]
self._state = None self._state = None
@ -228,11 +215,6 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
self.add_template_attribute("_state", self._template, None, self._update_state) self.add_template_attribute("_state", self._template, None, self._update_state)
if (
self._friendly_name_template is not None
and not self._friendly_name_template.is_static
):
self.add_template_attribute("_name", self._friendly_name_template)
if self._delay_on_raw is not None: if self._delay_on_raw is not None:
try: try:
@ -288,11 +270,6 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
# state with delay. Cancelled if template result changes. # state with delay. Cancelled if template result changes.
self._delay_cancel = async_call_later(self.hass, delay, _set_state) self._delay_cancel = async_call_later(self.hass, delay, _set_state)
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this binary sensor.""" """Return the unique id of this binary sensor."""

View File

@ -1,27 +1,25 @@
"""Support for buttons which integrates with other components.""" """Support for buttons which integrates with other components."""
from __future__ import annotations from __future__ import annotations
import contextlib
import logging import logging
from typing import Any from typing import Any
import voluptuous as vol import voluptuous as vol
from homeassistant.components.button import ( from homeassistant.components.button import DEVICE_CLASSES_SCHEMA, ButtonEntity
DEVICE_CLASSES_SCHEMA, from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME, CONF_UNIQUE_ID
ButtonDeviceClass,
ButtonEntity,
)
from homeassistant.const import CONF_DEVICE_CLASS, CONF_ICON, CONF_NAME, CONF_UNIQUE_ID
from homeassistant.core import Config, HomeAssistant from homeassistant.core import Config, HomeAssistant
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
from homeassistant.helpers.template import Template, TemplateError
from .const import CONF_AVAILABILITY, DOMAIN from .const import DOMAIN
from .template_entity import TemplateEntity from .template_entity import (
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
TEMPLATE_ENTITY_ICON_SCHEMA,
TemplateEntity,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -30,15 +28,17 @@ CONF_PRESS = "press"
DEFAULT_NAME = "Template Button" DEFAULT_NAME = "Template Button"
DEFAULT_OPTIMISTIC = False DEFAULT_OPTIMISTIC = False
BUTTON_SCHEMA = vol.Schema( BUTTON_SCHEMA = (
{ vol.Schema(
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template, {
vol.Required(CONF_PRESS): cv.SCRIPT_SCHEMA, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Required(CONF_PRESS): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_AVAILABILITY): cv.template, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_ICON): cv.template, }
} )
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema)
) )
@ -51,17 +51,7 @@ async def _async_create_entities(
unique_id = definition.get(CONF_UNIQUE_ID) unique_id = definition.get(CONF_UNIQUE_ID)
if unique_id and unique_id_prefix: if unique_id and unique_id_prefix:
unique_id = f"{unique_id_prefix}-{unique_id}" unique_id = f"{unique_id_prefix}-{unique_id}"
entities.append( entities.append(TemplateButtonEntity(hass, definition, unique_id))
TemplateButtonEntity(
hass,
definition[CONF_NAME],
definition.get(CONF_AVAILABILITY),
definition[CONF_PRESS],
definition.get(CONF_DEVICE_CLASS),
unique_id,
definition.get(CONF_ICON),
)
)
return entities return entities
@ -90,33 +80,16 @@ class TemplateButtonEntity(TemplateEntity, ButtonEntity):
def __init__( def __init__(
self, self,
hass: HomeAssistant, hass: HomeAssistant,
name_template: Template, config,
availability_template: Template | None,
command_press: dict[str, Any],
device_class: ButtonDeviceClass | None,
unique_id: str | None, unique_id: str | None,
icon_template: Template | None,
) -> None: ) -> None:
"""Initialize the button.""" """Initialize the button."""
super().__init__( super().__init__(hass, config=config)
availability_template=availability_template, icon_template=icon_template self._command_press = Script(hass, config[CONF_PRESS], self._attr_name, DOMAIN)
) self._attr_device_class = config.get(CONF_DEVICE_CLASS)
self._attr_name = DEFAULT_NAME
self._name_template = name_template
name_template.hass = hass
with contextlib.suppress(TemplateError):
self._attr_name = name_template.async_render(parse_result=False)
self._command_press = Script(hass, command_press, self._attr_name, DOMAIN)
self._attr_device_class = device_class
self._attr_unique_id = unique_id self._attr_unique_id = unique_id
self._attr_state = None self._attr_state = None
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
if self._name_template and not self._name_template.is_static:
self.add_template_attribute("_attr_name", self._name_template, cv.string)
await super().async_added_to_hass()
async def async_press(self) -> None: async def async_press(self) -> None:
"""Press the button.""" """Press the button."""
await self._command_press.async_run(context=self._context) await self._command_press.async_run(context=self._context)

View File

@ -148,11 +148,11 @@ class CoverTemplate(TemplateEntity, CoverEntity):
unique_id, unique_id,
): ):
"""Initialize the Template cover.""" """Initialize the Template cover."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = friendly_name = config.get(CONF_FRIENDLY_NAME, object_id) friendly_name = self._attr_name
self._template = config.get(CONF_VALUE_TEMPLATE) self._template = config.get(CONF_VALUE_TEMPLATE)
self._position_template = config.get(CONF_POSITION_TEMPLATE) self._position_template = config.get(CONF_POSITION_TEMPLATE)
self._tilt_template = config.get(CONF_TILT_TEMPLATE) self._tilt_template = config.get(CONF_TILT_TEMPLATE)
@ -271,11 +271,6 @@ class CoverTemplate(TemplateEntity, CoverEntity):
else: else:
self._tilt_value = state self._tilt_value = state
@property
def name(self):
"""Return the name of the cover."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this cover.""" """Return the unique id of this cover."""

View File

@ -138,12 +138,12 @@ class TemplateFan(TemplateEntity, FanEntity):
unique_id, unique_id,
): ):
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.hass = hass self.hass = hass
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = friendly_name = config.get(CONF_FRIENDLY_NAME, object_id) friendly_name = self._attr_name
self._template = config[CONF_VALUE_TEMPLATE] self._template = config[CONF_VALUE_TEMPLATE]
self._percentage_template = config.get(CONF_PERCENTAGE_TEMPLATE) self._percentage_template = config.get(CONF_PERCENTAGE_TEMPLATE)
@ -208,11 +208,6 @@ class TemplateFan(TemplateEntity, FanEntity):
self._unique_id = unique_id self._unique_id = unique_id
@property
def name(self):
"""Return the display name of this fan."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this fan.""" """Return the unique id of this fan."""

View File

@ -140,11 +140,11 @@ class LightTemplate(TemplateEntity, LightEntity):
unique_id, unique_id,
): ):
"""Initialize the light.""" """Initialize the light."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = friendly_name = config.get(CONF_FRIENDLY_NAME, object_id) friendly_name = self._attr_name
self._template = config.get(CONF_VALUE_TEMPLATE) self._template = config.get(CONF_VALUE_TEMPLATE)
self._on_script = Script(hass, config[CONF_ON_ACTION], friendly_name, DOMAIN) self._on_script = Script(hass, config[CONF_ON_ACTION], friendly_name, DOMAIN)
self._off_script = Script(hass, config[CONF_OFF_ACTION], friendly_name, DOMAIN) self._off_script = Script(hass, config[CONF_OFF_ACTION], friendly_name, DOMAIN)
@ -235,11 +235,6 @@ class LightTemplate(TemplateEntity, LightEntity):
"""Return the effect list.""" """Return the effect list."""
return self._effect_list return self._effect_list
@property
def name(self):
"""Return the display name of this light."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this light.""" """Return the unique id of this light."""

View File

@ -41,7 +41,7 @@ DEFAULT_OPTIMISTIC = False
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{ {
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA, vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA,
vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA, vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA,
vol.Required(CONF_VALUE_TEMPLATE): cv.template, vol.Required(CONF_VALUE_TEMPLATE): cv.template,
@ -77,9 +77,9 @@ class TemplateLock(TemplateEntity, LockEntity):
unique_id, unique_id,
): ):
"""Initialize the lock.""" """Initialize the lock."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=DEFAULT_NAME)
self._state = None self._state = None
self._name = name = config.get(CONF_NAME) name = self._attr_name
self._state_template = config.get(CONF_VALUE_TEMPLATE) self._state_template = config.get(CONF_VALUE_TEMPLATE)
self._command_lock = Script(hass, config[CONF_LOCK], name, DOMAIN) self._command_lock = Script(hass, config[CONF_LOCK], name, DOMAIN)
self._command_unlock = Script(hass, config[CONF_UNLOCK], name, DOMAIN) self._command_unlock = Script(hass, config[CONF_UNLOCK], name, DOMAIN)
@ -91,11 +91,6 @@ class TemplateLock(TemplateEntity, LockEntity):
"""Return true if we do optimistic updates.""" """Return true if we do optimistic updates."""
return self._optimistic return self._optimistic
@property
def name(self):
"""Return the name of the lock."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this lock.""" """Return the unique id of this lock."""

View File

@ -1,7 +1,6 @@
"""Support for numbers which integrates with other components.""" """Support for numbers which integrates with other components."""
from __future__ import annotations from __future__ import annotations
import contextlib
import logging import logging
from typing import Any from typing import Any
@ -22,7 +21,6 @@ from homeassistant.core import Config, HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
from homeassistant.helpers.template import TemplateError
from . import TriggerUpdateCoordinator from . import TriggerUpdateCoordinator
from .const import DOMAIN from .const import DOMAIN
@ -108,12 +106,7 @@ class TemplateNumber(TemplateEntity, NumberEntity):
unique_id: str | None, unique_id: str | None,
) -> None: ) -> None:
"""Initialize the number.""" """Initialize the number."""
super().__init__(config=config) super().__init__(hass, config=config)
self._attr_name = DEFAULT_NAME
self._name_template = name_template = config[CONF_NAME]
name_template.hass = hass
with contextlib.suppress(TemplateError):
self._attr_name = name_template.async_render(parse_result=False)
self._value_template = config[CONF_STATE] self._value_template = config[CONF_STATE]
self._command_set_value = Script( self._command_set_value = Script(
hass, config[CONF_SET_VALUE], self._attr_name, DOMAIN hass, config[CONF_SET_VALUE], self._attr_name, DOMAIN
@ -130,8 +123,6 @@ class TemplateNumber(TemplateEntity, NumberEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register callbacks.""" """Register callbacks."""
if self._name_template and not self._name_template.is_static:
self.add_template_attribute("_attr_name", self._name_template, cv.string)
self.add_template_attribute( self.add_template_attribute(
"_attr_value", "_attr_value",
self._value_template, self._value_template,

View File

@ -1,7 +1,6 @@
"""Support for selects which integrates with other components.""" """Support for selects which integrates with other components."""
from __future__ import annotations from __future__ import annotations
import contextlib
import logging import logging
from typing import Any from typing import Any
@ -18,7 +17,6 @@ from homeassistant.core import Config, HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
from homeassistant.helpers.template import TemplateError
from . import TriggerUpdateCoordinator from . import TriggerUpdateCoordinator
from .const import DOMAIN from .const import DOMAIN
@ -102,13 +100,7 @@ class TemplateSelect(TemplateEntity, SelectEntity):
unique_id: str | None, unique_id: str | None,
) -> None: ) -> None:
"""Initialize the select.""" """Initialize the select."""
super().__init__(config=config) super().__init__(hass, config=config)
self._attr_name = DEFAULT_NAME
name_template = config[CONF_NAME]
name_template.hass = hass
with contextlib.suppress(TemplateError):
self._attr_name = name_template.async_render(parse_result=False)
self._name_template = name_template
self._value_template = config[CONF_STATE] self._value_template = config[CONF_STATE]
self._command_select_option = Script( self._command_select_option = Script(
hass, config[CONF_SELECT_OPTION], self._attr_name, DOMAIN hass, config[CONF_SELECT_OPTION], self._attr_name, DOMAIN
@ -133,8 +125,6 @@ class TemplateSelect(TemplateEntity, SelectEntity):
validator=vol.All(cv.ensure_list, [cv.string]), validator=vol.All(cv.ensure_list, [cv.string]),
none_on_template_error=True, none_on_template_error=True,
) )
if self._name_template and not self._name_template.is_static:
self.add_template_attribute("_attr_name", self._name_template, cv.string)
await super().async_added_to_hass() await super().async_added_to_hass()
async def async_select_option(self, option: str) -> None: async def async_select_option(self, option: str) -> None:

View File

@ -199,25 +199,12 @@ class SensorTemplate(TemplateEntity, SensorEntity):
unique_id: str | None, unique_id: str | None,
) -> None: ) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(config=config) super().__init__(hass, config=config)
if (object_id := config.get(CONF_OBJECT_ID)) is not None: if (object_id := config.get(CONF_OBJECT_ID)) is not None:
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._friendly_name_template = config.get(CONF_NAME)
self._attr_name = None
# Try to render the name as it can influence the entity ID
if self._friendly_name_template:
self._friendly_name_template.hass = hass
try:
self._attr_name = self._friendly_name_template.async_render(
parse_result=False
)
except template.TemplateError:
pass
self._attr_native_unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT) self._attr_native_unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT)
self._template = config.get(CONF_STATE) self._template = config.get(CONF_STATE)
self._attr_device_class = config.get(CONF_DEVICE_CLASS) self._attr_device_class = config.get(CONF_DEVICE_CLASS)
@ -229,8 +216,6 @@ class SensorTemplate(TemplateEntity, SensorEntity):
self.add_template_attribute( self.add_template_attribute(
"_attr_native_value", self._template, None, self._update_state "_attr_native_value", self._template, None, self._update_state
) )
if self._friendly_name_template and not self._friendly_name_template.is_static:
self.add_template_attribute("_attr_name", self._friendly_name_template)
await super().async_added_to_hass() await super().async_added_to_hass()

View File

@ -98,11 +98,11 @@ class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity):
unique_id, unique_id,
): ):
"""Initialize the Template switch.""" """Initialize the Template switch."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = friendly_name = config.get(ATTR_FRIENDLY_NAME, object_id) friendly_name = self._attr_name
self._template = config.get(CONF_VALUE_TEMPLATE) self._template = config.get(CONF_VALUE_TEMPLATE)
self._on_script = Script(hass, config[ON_ACTION], friendly_name, DOMAIN) self._on_script = Script(hass, config[ON_ACTION], friendly_name, DOMAIN)
self._off_script = Script(hass, config[OFF_ACTION], friendly_name, DOMAIN) self._off_script = Script(hass, config[OFF_ACTION], friendly_name, DOMAIN)
@ -143,11 +143,6 @@ class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity):
await super().async_added_to_hass() await super().async_added_to_hass()
@property
def name(self):
"""Return the name of the switch."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this switch.""" """Return the unique id of this switch."""

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
import contextlib
import itertools import itertools
import logging import logging
from typing import Any from typing import Any
@ -11,8 +12,10 @@ import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
CONF_ENTITY_PICTURE_TEMPLATE, CONF_ENTITY_PICTURE_TEMPLATE,
CONF_FRIENDLY_NAME,
CONF_ICON, CONF_ICON,
CONF_ICON_TEMPLATE, CONF_ICON_TEMPLATE,
CONF_NAME,
) )
from homeassistant.core import EVENT_HOMEASSISTANT_START, CoreState, callback from homeassistant.core import EVENT_HOMEASSISTANT_START, CoreState, callback
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
@ -85,6 +88,7 @@ LEGACY_FIELDS = {
CONF_ENTITY_PICTURE_TEMPLATE: CONF_PICTURE, CONF_ENTITY_PICTURE_TEMPLATE: CONF_PICTURE,
CONF_AVAILABILITY_TEMPLATE: CONF_AVAILABILITY, CONF_AVAILABILITY_TEMPLATE: CONF_AVAILABILITY,
CONF_ATTRIBUTE_TEMPLATES: CONF_ATTRIBUTES, CONF_ATTRIBUTE_TEMPLATES: CONF_ATTRIBUTES,
CONF_FRIENDLY_NAME: CONF_NAME,
} }
@ -107,6 +111,9 @@ def rewrite_common_legacy_to_modern_conf(
val = Template(val) val = Template(val)
entity_cfg[to_key] = val entity_cfg[to_key] = val
if CONF_NAME in entity_cfg and isinstance(entity_cfg[CONF_NAME], str):
entity_cfg[CONF_NAME] = Template(entity_cfg[CONF_NAME])
return entity_cfg return entity_cfg
@ -207,12 +214,14 @@ class TemplateEntity(Entity):
def __init__( def __init__(
self, self,
hass,
*, *,
availability_template=None, availability_template=None,
icon_template=None, icon_template=None,
entity_picture_template=None, entity_picture_template=None,
attribute_templates=None, attribute_templates=None,
config=None, config=None,
fallback_name=None,
): ):
"""Template Entity.""" """Template Entity."""
self._template_attrs = {} self._template_attrs = {}
@ -224,11 +233,22 @@ class TemplateEntity(Entity):
self._availability_template = availability_template self._availability_template = availability_template
self._icon_template = icon_template self._icon_template = icon_template
self._entity_picture_template = entity_picture_template self._entity_picture_template = entity_picture_template
self._friendly_name_template = None
else: else:
self._attribute_templates = config.get(CONF_ATTRIBUTES) self._attribute_templates = config.get(CONF_ATTRIBUTES)
self._availability_template = config.get(CONF_AVAILABILITY) self._availability_template = config.get(CONF_AVAILABILITY)
self._icon_template = config.get(CONF_ICON) self._icon_template = config.get(CONF_ICON)
self._entity_picture_template = config.get(CONF_PICTURE) self._entity_picture_template = config.get(CONF_PICTURE)
self._friendly_name_template = config.get(CONF_NAME)
# Try to render the name as it can influence the entity ID
self._attr_name = fallback_name
if self._friendly_name_template:
self._friendly_name_template.hass = hass
with contextlib.suppress(TemplateError):
self._attr_name = self._friendly_name_template.async_render(
parse_result=False
)
@callback @callback
def _update_available(self, result): def _update_available(self, result):
@ -373,6 +393,12 @@ class TemplateEntity(Entity):
self.add_template_attribute( self.add_template_attribute(
"_attr_entity_picture", self._entity_picture_template "_attr_entity_picture", self._entity_picture_template
) )
if (
self._friendly_name_template is not None
and not self._friendly_name_template.is_static
):
self.add_template_attribute("_attr_name", self._friendly_name_template)
if self.hass.state == CoreState.running: if self.hass.state == CoreState.running:
await self._async_template_startup() await self._async_template_startup()
return return

View File

@ -142,11 +142,11 @@ class TemplateVacuum(TemplateEntity, StateVacuumEntity):
unique_id, unique_id,
): ):
"""Initialize the vacuum.""" """Initialize the vacuum."""
super().__init__(config=config) super().__init__(hass, config=config, fallback_name=object_id)
self.entity_id = async_generate_entity_id( self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, object_id, hass=hass ENTITY_ID_FORMAT, object_id, hass=hass
) )
self._name = friendly_name = config.get(CONF_FRIENDLY_NAME, object_id) friendly_name = self._attr_name
self._template = config.get(CONF_VALUE_TEMPLATE) self._template = config.get(CONF_VALUE_TEMPLATE)
self._battery_level_template = config.get(CONF_BATTERY_LEVEL_TEMPLATE) self._battery_level_template = config.get(CONF_BATTERY_LEVEL_TEMPLATE)
@ -205,11 +205,6 @@ class TemplateVacuum(TemplateEntity, StateVacuumEntity):
# List of valid fan speeds # List of valid fan speeds
self._fan_speed_list = config[CONF_FAN_SPEED_LIST] self._fan_speed_list = config[CONF_FAN_SPEED_LIST]
@property
def name(self):
"""Return the display name of this vacuum."""
return self._name
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id of this vacuum.""" """Return the unique id of this vacuum."""

View File

@ -30,7 +30,7 @@ from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .template_entity import TemplateEntity from .template_entity import TemplateEntity, rewrite_common_legacy_to_modern_conf
CONDITION_CLASSES = { CONDITION_CLASSES = {
ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLEAR_NIGHT,
@ -88,6 +88,7 @@ async def async_setup_platform(
) -> None: ) -> None:
"""Set up the Template weather.""" """Set up the Template weather."""
config = rewrite_common_legacy_to_modern_conf(config)
unique_id = config.get(CONF_UNIQUE_ID) unique_id = config.get(CONF_UNIQUE_ID)
async_add_entities( async_add_entities(
@ -111,9 +112,9 @@ class WeatherTemplate(TemplateEntity, WeatherEntity):
unique_id, unique_id,
): ):
"""Initialize the Template weather.""" """Initialize the Template weather."""
super().__init__(config=config) super().__init__(hass, config=config)
self._name = name = config[CONF_NAME] name = self._attr_name
self._condition_template = config[CONF_CONDITION_TEMPLATE] self._condition_template = config[CONF_CONDITION_TEMPLATE]
self._temperature_template = config[CONF_TEMPERATURE_TEMPLATE] self._temperature_template = config[CONF_TEMPERATURE_TEMPLATE]
self._humidity_template = config[CONF_HUMIDITY_TEMPLATE] self._humidity_template = config[CONF_HUMIDITY_TEMPLATE]
@ -139,11 +140,6 @@ class WeatherTemplate(TemplateEntity, WeatherEntity):
self._visibility = None self._visibility = None
self._forecast = [] self._forecast = []
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property @property
def condition(self): def condition(self):
"""Return the current condition.""" """Return the current condition."""

View File

@ -5,9 +5,9 @@ from homeassistant.components.template import template_entity
from homeassistant.helpers import template from homeassistant.helpers import template
async def test_template_entity_requires_hass_set(): async def test_template_entity_requires_hass_set(hass):
"""Test template entity requires hass to be set before accepting templates.""" """Test template entity requires hass to be set before accepting templates."""
entity = template_entity.TemplateEntity() entity = template_entity.TemplateEntity(hass)
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
entity.add_template_attribute("_hello", template.Template("Hello")) entity.add_template_attribute("_hello", template.Template("Hello"))