From a67a4873dcc2d7963337ca3b97c01279d2d2d91f Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 2 Dec 2021 19:26:10 +0100 Subject: [PATCH] Minor refactor of template cover (#59537) --- .../components/template/binary_sensor.py | 15 +-- homeassistant/components/template/const.py | 1 + homeassistant/components/template/cover.py | 108 ++++++------------ homeassistant/components/template/sensor.py | 25 ++-- .../components/template/template_entity.py | 59 +++++++++- 5 files changed, 104 insertions(+), 104 deletions(-) diff --git a/homeassistant/components/template/binary_sensor.py b/homeassistant/components/template/binary_sensor.py index cae751df170..06af6dca925 100644 --- a/homeassistant/components/template/binary_sensor.py +++ b/homeassistant/components/template/binary_sensor.py @@ -46,7 +46,11 @@ from .const import ( CONF_OBJECT_ID, CONF_PICTURE, ) -from .template_entity import TEMPLATE_ENTITY_COMMON_SCHEMA, TemplateEntity +from .template_entity import ( + TEMPLATE_ENTITY_COMMON_SCHEMA, + TemplateEntity, + rewrite_common_legacy_to_modern_conf, +) from .trigger_entity import TriggerEntity CONF_DELAY_ON = "delay_on" @@ -106,14 +110,7 @@ def rewrite_legacy_to_modern_conf(cfg: dict[str, dict]) -> list[dict]: for object_id, entity_cfg in cfg.items(): entity_cfg = {**entity_cfg, CONF_OBJECT_ID: object_id} - for from_key, to_key in LEGACY_FIELDS.items(): - if from_key not in entity_cfg or to_key in entity_cfg: - continue - - val = entity_cfg.pop(from_key) - if isinstance(val, str): - val = template.Template(val) - entity_cfg[to_key] = val + entity_cfg = rewrite_common_legacy_to_modern_conf(entity_cfg, LEGACY_FIELDS) if CONF_NAME not in entity_cfg: entity_cfg[CONF_NAME] = template.Template(object_id) diff --git a/homeassistant/components/template/const.py b/homeassistant/components/template/const.py index 54d213be0b1..9dfbe4a11d9 100644 --- a/homeassistant/components/template/const.py +++ b/homeassistant/components/template/const.py @@ -25,5 +25,6 @@ PLATFORMS = [ CONF_AVAILABILITY = "availability" CONF_ATTRIBUTES = "attributes" +CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" CONF_PICTURE = "picture" CONF_OBJECT_ID = "object_id" diff --git a/homeassistant/components/template/cover.py b/homeassistant/components/template/cover.py index d5cd04e94f2..dcfd8b41521 100644 --- a/homeassistant/components/template/cover.py +++ b/homeassistant/components/template/cover.py @@ -23,9 +23,7 @@ from homeassistant.const import ( CONF_COVERS, CONF_DEVICE_CLASS, CONF_ENTITY_ID, - CONF_ENTITY_PICTURE_TEMPLATE, CONF_FRIENDLY_NAME, - CONF_ICON_TEMPLATE, CONF_OPTIMISTIC, CONF_UNIQUE_ID, CONF_VALUE_TEMPLATE, @@ -40,8 +38,12 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from .const import CONF_AVAILABILITY_TEMPLATE, DOMAIN -from .template_entity import TemplateEntity +from .const import DOMAIN +from .template_entity import ( + TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY, + TemplateEntity, + rewrite_common_legacy_to_modern_conf, +) _LOGGER = logging.getLogger(__name__) _VALID_STATES = [ @@ -79,11 +81,8 @@ COVER_SCHEMA = vol.All( vol.Inclusive(CLOSE_ACTION, CONF_OPEN_AND_CLOSE): cv.SCRIPT_SCHEMA, vol.Optional(STOP_ACTION): cv.SCRIPT_SCHEMA, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template, vol.Optional(CONF_POSITION_TEMPLATE): cv.template, vol.Optional(CONF_TILT_TEMPLATE): cv.template, - vol.Optional(CONF_ICON_TEMPLATE): cv.template, - vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_OPTIMISTIC): cv.boolean, vol.Optional(CONF_TILT_OPTIMISTIC): cv.boolean, @@ -93,7 +92,7 @@ COVER_SCHEMA = vol.All( vol.Optional(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_UNIQUE_ID): cv.string, } - ), + ).extend(TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY.schema), cv.has_at_least_one_key(OPEN_ACTION, POSITION_ACTION), ) @@ -106,44 +105,17 @@ async def _async_create_entities(hass, config): """Create the Template cover.""" covers = [] - for device, device_config in config[CONF_COVERS].items(): - state_template = device_config.get(CONF_VALUE_TEMPLATE) - position_template = device_config.get(CONF_POSITION_TEMPLATE) - tilt_template = device_config.get(CONF_TILT_TEMPLATE) - icon_template = device_config.get(CONF_ICON_TEMPLATE) - availability_template = device_config.get(CONF_AVAILABILITY_TEMPLATE) - entity_picture_template = device_config.get(CONF_ENTITY_PICTURE_TEMPLATE) + for object_id, entity_config in config[CONF_COVERS].items(): - friendly_name = device_config.get(CONF_FRIENDLY_NAME, device) - device_class = device_config.get(CONF_DEVICE_CLASS) - open_action = device_config.get(OPEN_ACTION) - close_action = device_config.get(CLOSE_ACTION) - stop_action = device_config.get(STOP_ACTION) - position_action = device_config.get(POSITION_ACTION) - tilt_action = device_config.get(TILT_ACTION) - optimistic = device_config.get(CONF_OPTIMISTIC) - tilt_optimistic = device_config.get(CONF_TILT_OPTIMISTIC) - unique_id = device_config.get(CONF_UNIQUE_ID) + entity_config = rewrite_common_legacy_to_modern_conf(entity_config) + + unique_id = entity_config.get(CONF_UNIQUE_ID) covers.append( CoverTemplate( hass, - device, - friendly_name, - device_class, - state_template, - position_template, - tilt_template, - icon_template, - entity_picture_template, - availability_template, - open_action, - close_action, - stop_action, - position_action, - tilt_action, - optimistic, - tilt_optimistic, + object_id, + entity_config, unique_id, ) ) @@ -162,55 +134,41 @@ class CoverTemplate(TemplateEntity, CoverEntity): def __init__( self, hass, - device_id, - friendly_name, - device_class, - state_template, - position_template, - tilt_template, - icon_template, - entity_picture_template, - availability_template, - open_action, - close_action, - stop_action, - position_action, - tilt_action, - optimistic, - tilt_optimistic, + object_id, + config, unique_id, ): """Initialize the Template cover.""" - super().__init__( - availability_template=availability_template, - icon_template=icon_template, - entity_picture_template=entity_picture_template, - ) + super().__init__(config=config) self.entity_id = async_generate_entity_id( - ENTITY_ID_FORMAT, device_id, hass=hass + ENTITY_ID_FORMAT, object_id, hass=hass ) - self._name = friendly_name - self._template = state_template - self._position_template = position_template - self._tilt_template = tilt_template - self._device_class = device_class + self._name = friendly_name = config.get(CONF_FRIENDLY_NAME, object_id) + self._template = config.get(CONF_VALUE_TEMPLATE) + self._position_template = config.get(CONF_POSITION_TEMPLATE) + self._tilt_template = config.get(CONF_TILT_TEMPLATE) + self._device_class = config.get(CONF_DEVICE_CLASS) self._open_script = None - if open_action is not None: + if (open_action := config.get(OPEN_ACTION)) is not None: self._open_script = Script(hass, open_action, friendly_name, DOMAIN) self._close_script = None - if close_action is not None: + if (close_action := config.get(CLOSE_ACTION)) is not None: self._close_script = Script(hass, close_action, friendly_name, DOMAIN) self._stop_script = None - if stop_action is not None: + if (stop_action := config.get(STOP_ACTION)) is not None: self._stop_script = Script(hass, stop_action, friendly_name, DOMAIN) self._position_script = None - if position_action is not None: + if (position_action := config.get(POSITION_ACTION)) is not None: self._position_script = Script(hass, position_action, friendly_name, DOMAIN) self._tilt_script = None - if tilt_action is not None: + if (tilt_action := config.get(TILT_ACTION)) is not None: self._tilt_script = Script(hass, tilt_action, friendly_name, DOMAIN) - self._optimistic = optimistic or (not state_template and not position_template) - self._tilt_optimistic = tilt_optimistic or not tilt_template + optimistic = config.get(CONF_OPTIMISTIC) + self._optimistic = optimistic or ( + not self._template and not self._position_template + ) + tilt_optimistic = config.get(CONF_TILT_OPTIMISTIC) + self._tilt_optimistic = tilt_optimistic or not self._tilt_template self._position = None self._is_opening = False self._is_closing = False diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index a89a30af556..a31e49db570 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -20,7 +20,6 @@ from homeassistant.const import ( CONF_ENTITY_PICTURE_TEMPLATE, CONF_FRIENDLY_NAME, CONF_FRIENDLY_NAME_TEMPLATE, - CONF_ICON, CONF_ICON_TEMPLATE, CONF_NAME, CONF_SENSORS, @@ -36,21 +35,18 @@ from homeassistant.helpers.entity import async_generate_entity_id from .const import ( CONF_ATTRIBUTE_TEMPLATES, - CONF_ATTRIBUTES, - CONF_AVAILABILITY, CONF_AVAILABILITY_TEMPLATE, CONF_OBJECT_ID, - CONF_PICTURE, CONF_TRIGGER, ) -from .template_entity import TEMPLATE_ENTITY_COMMON_SCHEMA, TemplateEntity +from .template_entity import ( + TEMPLATE_ENTITY_COMMON_SCHEMA, + TemplateEntity, + rewrite_common_legacy_to_modern_conf, +) from .trigger_entity import TriggerEntity LEGACY_FIELDS = { - CONF_ICON_TEMPLATE: CONF_ICON, - CONF_ENTITY_PICTURE_TEMPLATE: CONF_PICTURE, - CONF_AVAILABILITY_TEMPLATE: CONF_AVAILABILITY, - CONF_ATTRIBUTE_TEMPLATES: CONF_ATTRIBUTES, CONF_FRIENDLY_NAME_TEMPLATE: CONF_NAME, CONF_FRIENDLY_NAME: CONF_NAME, CONF_VALUE_TEMPLATE: CONF_STATE, @@ -106,20 +102,13 @@ def extra_validation_checks(val): def rewrite_legacy_to_modern_conf(cfg: dict[str, dict]) -> list[dict]: - """Rewrite a legacy sensor definitions to modern ones.""" + """Rewrite legacy sensor definitions to modern ones.""" sensors = [] for object_id, entity_cfg in cfg.items(): entity_cfg = {**entity_cfg, CONF_OBJECT_ID: object_id} - for from_key, to_key in LEGACY_FIELDS.items(): - if from_key not in entity_cfg or to_key in entity_cfg: - continue - - val = entity_cfg.pop(from_key) - if isinstance(val, str): - val = template.Template(val) - entity_cfg[to_key] = val + entity_cfg = rewrite_common_legacy_to_modern_conf(entity_cfg, LEGACY_FIELDS) if CONF_NAME not in entity_cfg: entity_cfg[CONF_NAME] = template.Template(object_id) diff --git a/homeassistant/components/template/template_entity.py b/homeassistant/components/template/template_entity.py index 2e7799bd95b..55c9dbcf45b 100644 --- a/homeassistant/components/template/template_entity.py +++ b/homeassistant/components/template/template_entity.py @@ -2,12 +2,18 @@ from __future__ import annotations from collections.abc import Callable +import itertools import logging from typing import Any import voluptuous as vol -from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON +from homeassistant.const import ( + ATTR_ENTITY_ID, + CONF_ENTITY_PICTURE_TEMPLATE, + CONF_ICON, + CONF_ICON_TEMPLATE, +) from homeassistant.core import EVENT_HOMEASSISTANT_START, CoreState, callback from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv @@ -20,7 +26,13 @@ from homeassistant.helpers.event import ( ) from homeassistant.helpers.template import Template, result_as_boolean -from .const import CONF_ATTRIBUTES, CONF_AVAILABILITY, CONF_PICTURE +from .const import ( + CONF_ATTRIBUTE_TEMPLATES, + CONF_ATTRIBUTES, + CONF_AVAILABILITY, + CONF_AVAILABILITY_TEMPLATE, + CONF_PICTURE, +) _LOGGER = logging.getLogger(__name__) @@ -34,6 +46,49 @@ TEMPLATE_ENTITY_COMMON_SCHEMA = vol.Schema( } ) +TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY = vol.Schema( + { + vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template, + } +) + +TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY = vol.Schema( + { + vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template, + vol.Optional(CONF_ICON_TEMPLATE): cv.template, + } +).extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY.schema) + + +LEGACY_FIELDS = { + CONF_ICON_TEMPLATE: CONF_ICON, + CONF_ENTITY_PICTURE_TEMPLATE: CONF_PICTURE, + CONF_AVAILABILITY_TEMPLATE: CONF_AVAILABILITY, + CONF_ATTRIBUTE_TEMPLATES: CONF_ATTRIBUTES, +} + + +def rewrite_common_legacy_to_modern_conf( + entity_cfg: dict[str, Any], extra_legacy_fields: dict[str, str] = None +) -> list[dict]: + """Rewrite legacy config.""" + entity_cfg = {**entity_cfg} + if extra_legacy_fields is None: + extra_legacy_fields = {} + + for from_key, to_key in itertools.chain( + LEGACY_FIELDS.items(), extra_legacy_fields.items() + ): + if from_key not in entity_cfg or to_key in entity_cfg: + continue + + val = entity_cfg.pop(from_key) + if isinstance(val, str): + val = Template(val) + entity_cfg[to_key] = val + + return entity_cfg + class _TemplateAttribute: """Attribute value linked to template result."""