mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Adapt template sensors to use the same plural trigger/condition/action definitions as automations (#127875)
* Add plurals to template entities * Ruff * Ruffy ruff * Fix linters * Fix bug introduced after merging dev * Fix merge mistake * Revert adding automation helper * Revert "Fix bug introduced after merging dev" This reverts commit 098d478f150a06546fb9ec3668865fa5d763c6b2. * Fix blueprint validation * Apply suggestions from code review --------- Co-authored-by: Erik <erik@montnemery.com>
This commit is contained in:
parent
f2838e493b
commit
8ff4d5dcbf
@ -18,6 +18,7 @@ from homeassistant.const import (
|
|||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_MODE,
|
ATTR_MODE,
|
||||||
ATTR_NAME,
|
ATTR_NAME,
|
||||||
|
CONF_ACTIONS,
|
||||||
CONF_ALIAS,
|
CONF_ALIAS,
|
||||||
CONF_CONDITIONS,
|
CONF_CONDITIONS,
|
||||||
CONF_DEVICE_ID,
|
CONF_DEVICE_ID,
|
||||||
@ -27,6 +28,7 @@ from homeassistant.const import (
|
|||||||
CONF_MODE,
|
CONF_MODE,
|
||||||
CONF_PATH,
|
CONF_PATH,
|
||||||
CONF_PLATFORM,
|
CONF_PLATFORM,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_VARIABLES,
|
CONF_VARIABLES,
|
||||||
CONF_ZONE,
|
CONF_ZONE,
|
||||||
EVENT_HOMEASSISTANT_STARTED,
|
EVENT_HOMEASSISTANT_STARTED,
|
||||||
@ -86,11 +88,9 @@ from homeassistant.util.hass_dict import HassKey
|
|||||||
|
|
||||||
from .config import AutomationConfig, ValidationStatus
|
from .config import AutomationConfig, ValidationStatus
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_ACTIONS,
|
|
||||||
CONF_INITIAL_STATE,
|
CONF_INITIAL_STATE,
|
||||||
CONF_TRACE,
|
CONF_TRACE,
|
||||||
CONF_TRIGGER_VARIABLES,
|
CONF_TRIGGER_VARIABLES,
|
||||||
CONF_TRIGGERS,
|
|
||||||
DEFAULT_INITIAL_STATE,
|
DEFAULT_INITIAL_STATE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
|
@ -14,11 +14,15 @@ from homeassistant.components import blueprint
|
|||||||
from homeassistant.components.trace import TRACE_CONFIG_SCHEMA
|
from homeassistant.components.trace import TRACE_CONFIG_SCHEMA
|
||||||
from homeassistant.config import config_per_platform, config_without_domain
|
from homeassistant.config import config_per_platform, config_without_domain
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
CONF_ACTION,
|
||||||
|
CONF_ACTIONS,
|
||||||
CONF_ALIAS,
|
CONF_ALIAS,
|
||||||
CONF_CONDITION,
|
CONF_CONDITION,
|
||||||
CONF_CONDITIONS,
|
CONF_CONDITIONS,
|
||||||
CONF_DESCRIPTION,
|
CONF_DESCRIPTION,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_TRIGGER,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_VARIABLES,
|
CONF_VARIABLES,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -30,14 +34,10 @@ from homeassistant.helpers.typing import ConfigType
|
|||||||
from homeassistant.util.yaml.input import UndefinedSubstitution
|
from homeassistant.util.yaml.input import UndefinedSubstitution
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_ACTION,
|
|
||||||
CONF_ACTIONS,
|
|
||||||
CONF_HIDE_ENTITY,
|
CONF_HIDE_ENTITY,
|
||||||
CONF_INITIAL_STATE,
|
CONF_INITIAL_STATE,
|
||||||
CONF_TRACE,
|
CONF_TRACE,
|
||||||
CONF_TRIGGER,
|
|
||||||
CONF_TRIGGER_VARIABLES,
|
CONF_TRIGGER_VARIABLES,
|
||||||
CONF_TRIGGERS,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
)
|
)
|
||||||
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
CONF_ACTION = "action"
|
|
||||||
CONF_ACTIONS = "actions"
|
|
||||||
CONF_TRIGGER = "trigger"
|
|
||||||
CONF_TRIGGERS = "triggers"
|
|
||||||
CONF_TRIGGER_VARIABLES = "trigger_variables"
|
CONF_TRIGGER_VARIABLES = "trigger_variables"
|
||||||
DOMAIN = "automation"
|
DOMAIN = "automation"
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE_ID,
|
CONF_DEVICE_ID,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
SERVICE_RELOAD,
|
SERVICE_RELOAD,
|
||||||
)
|
)
|
||||||
@ -27,7 +28,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||||||
from homeassistant.loader import async_get_integration
|
from homeassistant.loader import async_get_integration
|
||||||
from homeassistant.util.hass_dict import HassKey
|
from homeassistant.util.hass_dict import HassKey
|
||||||
|
|
||||||
from .const import CONF_MAX, CONF_MIN, CONF_STEP, CONF_TRIGGER, DOMAIN, PLATFORMS
|
from .const import CONF_MAX, CONF_MIN, CONF_STEP, DOMAIN, PLATFORMS
|
||||||
from .coordinator import TriggerUpdateCoordinator
|
from .coordinator import TriggerUpdateCoordinator
|
||||||
from .helpers import async_get_blueprints
|
from .helpers import async_get_blueprints
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ async def _process_config(hass: HomeAssistant, hass_config: ConfigType) -> None:
|
|||||||
coordinator_tasks: list[Coroutine[Any, Any, TriggerUpdateCoordinator]] = []
|
coordinator_tasks: list[Coroutine[Any, Any, TriggerUpdateCoordinator]] = []
|
||||||
|
|
||||||
for conf_section in hass_config[DOMAIN]:
|
for conf_section in hass_config[DOMAIN]:
|
||||||
if CONF_TRIGGER in conf_section:
|
if CONF_TRIGGERS in conf_section:
|
||||||
coordinator_tasks.append(init_coordinator(hass, conf_section))
|
coordinator_tasks.append(init_coordinator(hass, conf_section))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAI
|
|||||||
from homeassistant.components.blueprint import (
|
from homeassistant.components.blueprint import (
|
||||||
BLUEPRINT_INSTANCE_FIELDS,
|
BLUEPRINT_INSTANCE_FIELDS,
|
||||||
is_blueprint_instance_config,
|
is_blueprint_instance_config,
|
||||||
|
schemas as blueprint_schemas,
|
||||||
)
|
)
|
||||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
||||||
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
|
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
|
||||||
@ -22,9 +24,15 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
|||||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||||
from homeassistant.config import async_log_schema_error, config_without_domain
|
from homeassistant.config import async_log_schema_error, config_without_domain
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
CONF_ACTION,
|
||||||
|
CONF_ACTIONS,
|
||||||
CONF_BINARY_SENSORS,
|
CONF_BINARY_SENSORS,
|
||||||
|
CONF_CONDITION,
|
||||||
|
CONF_CONDITIONS,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_SENSORS,
|
CONF_SENSORS,
|
||||||
|
CONF_TRIGGER,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_VARIABLES,
|
CONF_VARIABLES,
|
||||||
)
|
)
|
||||||
@ -47,14 +55,7 @@ from . import (
|
|||||||
switch as switch_platform,
|
switch as switch_platform,
|
||||||
weather as weather_platform,
|
weather as weather_platform,
|
||||||
)
|
)
|
||||||
from .const import (
|
from .const import DOMAIN, PLATFORMS, TemplateConfig
|
||||||
CONF_ACTION,
|
|
||||||
CONF_CONDITION,
|
|
||||||
CONF_TRIGGER,
|
|
||||||
DOMAIN,
|
|
||||||
PLATFORMS,
|
|
||||||
TemplateConfig,
|
|
||||||
)
|
|
||||||
from .helpers import async_get_blueprints
|
from .helpers import async_get_blueprints
|
||||||
|
|
||||||
PACKAGE_MERGE_HINT = "list"
|
PACKAGE_MERGE_HINT = "list"
|
||||||
@ -67,7 +68,7 @@ def ensure_domains_do_not_have_trigger_or_action(*keys: str) -> Callable[[dict],
|
|||||||
def validate(obj: dict):
|
def validate(obj: dict):
|
||||||
options = set(obj.keys())
|
options = set(obj.keys())
|
||||||
if found_domains := domains.intersection(options):
|
if found_domains := domains.intersection(options):
|
||||||
invalid = {CONF_TRIGGER, CONF_ACTION}
|
invalid = {CONF_TRIGGERS, CONF_ACTIONS}
|
||||||
if found_invalid := invalid.intersection(set(obj.keys())):
|
if found_invalid := invalid.intersection(set(obj.keys())):
|
||||||
raise vol.Invalid(
|
raise vol.Invalid(
|
||||||
f"Unsupported option(s) found for domain {found_domains.pop()}, please remove ({', '.join(found_invalid)}) from your configuration",
|
f"Unsupported option(s) found for domain {found_domains.pop()}, please remove ({', '.join(found_invalid)}) from your configuration",
|
||||||
@ -78,13 +79,22 @@ def ensure_domains_do_not_have_trigger_or_action(*keys: str) -> Callable[[dict],
|
|||||||
return validate
|
return validate
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SECTION_SCHEMA = vol.Schema(
|
def _backward_compat_schema(value: Any | None) -> Any:
|
||||||
vol.All(
|
"""Backward compatibility for automations."""
|
||||||
|
|
||||||
|
value = cv.renamed(CONF_TRIGGER, CONF_TRIGGERS)(value)
|
||||||
|
value = cv.renamed(CONF_ACTION, CONF_ACTIONS)(value)
|
||||||
|
return cv.renamed(CONF_CONDITION, CONF_CONDITIONS)(value)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SECTION_SCHEMA = vol.All(
|
||||||
|
_backward_compat_schema,
|
||||||
|
vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
vol.Optional(CONF_TRIGGER): cv.TRIGGER_SCHEMA,
|
vol.Optional(CONF_TRIGGERS): cv.TRIGGER_SCHEMA,
|
||||||
vol.Optional(CONF_CONDITION): cv.CONDITIONS_SCHEMA,
|
vol.Optional(CONF_CONDITIONS): cv.CONDITIONS_SCHEMA,
|
||||||
vol.Optional(CONF_ACTION): cv.SCRIPT_SCHEMA,
|
vol.Optional(CONF_ACTIONS): cv.SCRIPT_SCHEMA,
|
||||||
vol.Optional(CONF_VARIABLES): cv.SCRIPT_VARIABLES_SCHEMA,
|
vol.Optional(CONF_VARIABLES): cv.SCRIPT_VARIABLES_SCHEMA,
|
||||||
vol.Optional(NUMBER_DOMAIN): vol.All(
|
vol.Optional(NUMBER_DOMAIN): vol.All(
|
||||||
cv.ensure_list, [number_platform.NUMBER_SCHEMA]
|
cv.ensure_list, [number_platform.NUMBER_SCHEMA]
|
||||||
@ -123,10 +133,14 @@ CONFIG_SECTION_SCHEMA = vol.Schema(
|
|||||||
cv.ensure_list, [cover_platform.COVER_SCHEMA]
|
cv.ensure_list, [cover_platform.COVER_SCHEMA]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
ensure_domains_do_not_have_trigger_or_action(
|
),
|
||||||
BUTTON_DOMAIN, COVER_DOMAIN, LIGHT_DOMAIN
|
ensure_domains_do_not_have_trigger_or_action(
|
||||||
),
|
BUTTON_DOMAIN, COVER_DOMAIN, LIGHT_DOMAIN
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
TEMPLATE_BLUEPRINT_SCHEMA = vol.All(
|
||||||
|
_backward_compat_schema, blueprint_schemas.BLUEPRINT_SCHEMA
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_BLUEPRINT_INSTANCE_SCHEMA = vol.Schema(
|
TEMPLATE_BLUEPRINT_INSTANCE_SCHEMA = vol.Schema(
|
||||||
@ -169,7 +183,7 @@ async def _async_resolve_blueprints(
|
|||||||
# house input results for template entities. For Trigger based template entities
|
# house input results for template entities. For Trigger based template entities
|
||||||
# CONF_VARIABLES should not be removed because the variables are always
|
# CONF_VARIABLES should not be removed because the variables are always
|
||||||
# executed between the trigger and action.
|
# executed between the trigger and action.
|
||||||
if CONF_TRIGGER not in config and CONF_VARIABLES in config:
|
if CONF_TRIGGERS not in config and CONF_VARIABLES in config:
|
||||||
config[platform][CONF_VARIABLES] = config.pop(CONF_VARIABLES)
|
config[platform][CONF_VARIABLES] = config.pop(CONF_VARIABLES)
|
||||||
raw_config = dict(config)
|
raw_config = dict(config)
|
||||||
|
|
||||||
@ -187,14 +201,14 @@ async def async_validate_config_section(
|
|||||||
|
|
||||||
validated_config = await _async_resolve_blueprints(hass, config)
|
validated_config = await _async_resolve_blueprints(hass, config)
|
||||||
|
|
||||||
if CONF_TRIGGER in validated_config:
|
if CONF_TRIGGERS in validated_config:
|
||||||
validated_config[CONF_TRIGGER] = await async_validate_trigger_config(
|
validated_config[CONF_TRIGGERS] = await async_validate_trigger_config(
|
||||||
hass, validated_config[CONF_TRIGGER]
|
hass, validated_config[CONF_TRIGGERS]
|
||||||
)
|
)
|
||||||
|
|
||||||
if CONF_CONDITION in validated_config:
|
if CONF_CONDITIONS in validated_config:
|
||||||
validated_config[CONF_CONDITION] = await async_validate_conditions_config(
|
validated_config[CONF_CONDITIONS] = await async_validate_conditions_config(
|
||||||
hass, validated_config[CONF_CONDITION]
|
hass, validated_config[CONF_CONDITIONS]
|
||||||
)
|
)
|
||||||
|
|
||||||
return validated_config
|
return validated_config
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
"""Constants for the Template Platform Components."""
|
"""Constants for the Template Platform Components."""
|
||||||
|
|
||||||
from homeassistant.components.blueprint import BLUEPRINT_SCHEMA
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
CONF_ACTION = "action"
|
|
||||||
CONF_ATTRIBUTE_TEMPLATES = "attribute_templates"
|
CONF_ATTRIBUTE_TEMPLATES = "attribute_templates"
|
||||||
CONF_ATTRIBUTES = "attributes"
|
CONF_ATTRIBUTES = "attributes"
|
||||||
CONF_AVAILABILITY = "availability"
|
CONF_AVAILABILITY = "availability"
|
||||||
CONF_AVAILABILITY_TEMPLATE = "availability_template"
|
CONF_AVAILABILITY_TEMPLATE = "availability_template"
|
||||||
CONF_CONDITION = "condition"
|
|
||||||
CONF_MAX = "max"
|
CONF_MAX = "max"
|
||||||
CONF_MIN = "min"
|
CONF_MIN = "min"
|
||||||
CONF_OBJECT_ID = "object_id"
|
CONF_OBJECT_ID = "object_id"
|
||||||
CONF_PICTURE = "picture"
|
CONF_PICTURE = "picture"
|
||||||
CONF_PRESS = "press"
|
CONF_PRESS = "press"
|
||||||
CONF_STEP = "step"
|
CONF_STEP = "step"
|
||||||
CONF_TRIGGER = "trigger"
|
|
||||||
CONF_TURN_OFF = "turn_off"
|
CONF_TURN_OFF = "turn_off"
|
||||||
CONF_TURN_ON = "turn_on"
|
CONF_TURN_ON = "turn_on"
|
||||||
|
|
||||||
@ -41,8 +37,6 @@ PLATFORMS = [
|
|||||||
Platform.WEATHER,
|
Platform.WEATHER,
|
||||||
]
|
]
|
||||||
|
|
||||||
TEMPLATE_BLUEPRINT_SCHEMA = BLUEPRINT_SCHEMA
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateConfig(dict):
|
class TemplateConfig(dict):
|
||||||
"""Dummy class to allow adding attributes."""
|
"""Dummy class to allow adding attributes."""
|
||||||
|
@ -5,7 +5,14 @@ import logging
|
|||||||
from typing import TYPE_CHECKING, Any, cast
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
from homeassistant.components.blueprint import CONF_USE_BLUEPRINT
|
from homeassistant.components.blueprint import CONF_USE_BLUEPRINT
|
||||||
from homeassistant.const import CONF_PATH, CONF_VARIABLES, EVENT_HOMEASSISTANT_START
|
from homeassistant.const import (
|
||||||
|
CONF_ACTIONS,
|
||||||
|
CONF_CONDITIONS,
|
||||||
|
CONF_PATH,
|
||||||
|
CONF_TRIGGERS,
|
||||||
|
CONF_VARIABLES,
|
||||||
|
EVENT_HOMEASSISTANT_START,
|
||||||
|
)
|
||||||
from homeassistant.core import Context, CoreState, Event, HomeAssistant, callback
|
from homeassistant.core import Context, CoreState, Event, HomeAssistant, callback
|
||||||
from homeassistant.helpers import condition, discovery, trigger as trigger_helper
|
from homeassistant.helpers import condition, discovery, trigger as trigger_helper
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
@ -14,7 +21,7 @@ from homeassistant.helpers.trace import trace_get
|
|||||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
from .const import CONF_ACTION, CONF_CONDITION, CONF_TRIGGER, DOMAIN, PLATFORMS
|
from .const import DOMAIN, PLATFORMS
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -84,17 +91,17 @@ class TriggerUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
|
|
||||||
async def _attach_triggers(self, start_event: Event | None = None) -> None:
|
async def _attach_triggers(self, start_event: Event | None = None) -> None:
|
||||||
"""Attach the triggers."""
|
"""Attach the triggers."""
|
||||||
if CONF_ACTION in self.config:
|
if CONF_ACTIONS in self.config:
|
||||||
self._script = Script(
|
self._script = Script(
|
||||||
self.hass,
|
self.hass,
|
||||||
self.config[CONF_ACTION],
|
self.config[CONF_ACTIONS],
|
||||||
self.name,
|
self.name,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
if CONF_CONDITION in self.config:
|
if CONF_CONDITIONS in self.config:
|
||||||
self._cond_func = await condition.async_conditions_from_config(
|
self._cond_func = await condition.async_conditions_from_config(
|
||||||
self.hass, self.config[CONF_CONDITION], _LOGGER, "template entity"
|
self.hass, self.config[CONF_CONDITIONS], _LOGGER, "template entity"
|
||||||
)
|
)
|
||||||
|
|
||||||
if start_event is not None:
|
if start_event is not None:
|
||||||
@ -107,7 +114,7 @@ class TriggerUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
|
|
||||||
self._unsub_trigger = await trigger_helper.async_initialize_triggers(
|
self._unsub_trigger = await trigger_helper.async_initialize_triggers(
|
||||||
self.hass,
|
self.hass,
|
||||||
self.config[CONF_TRIGGER],
|
self.config[CONF_TRIGGERS],
|
||||||
action,
|
action,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
self.name,
|
self.name,
|
||||||
|
@ -8,7 +8,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||||||
from homeassistant.helpers.entity_platform import async_get_platforms
|
from homeassistant.helpers.entity_platform import async_get_platforms
|
||||||
from homeassistant.helpers.singleton import singleton
|
from homeassistant.helpers.singleton import singleton
|
||||||
|
|
||||||
from .const import DOMAIN, TEMPLATE_BLUEPRINT_SCHEMA
|
from .const import DOMAIN
|
||||||
from .entity import AbstractTemplateEntity
|
from .entity import AbstractTemplateEntity
|
||||||
|
|
||||||
DATA_BLUEPRINTS = "template_blueprints"
|
DATA_BLUEPRINTS = "template_blueprints"
|
||||||
@ -54,6 +54,9 @@ async def _reload_blueprint_templates(hass: HomeAssistant, blueprint_path: str)
|
|||||||
@callback
|
@callback
|
||||||
def async_get_blueprints(hass: HomeAssistant) -> blueprint.DomainBlueprints:
|
def async_get_blueprints(hass: HomeAssistant) -> blueprint.DomainBlueprints:
|
||||||
"""Get template blueprints."""
|
"""Get template blueprints."""
|
||||||
|
# pylint: disable-next=import-outside-toplevel
|
||||||
|
from .config import TEMPLATE_BLUEPRINT_SCHEMA
|
||||||
|
|
||||||
return blueprint.DomainBlueprints(
|
return blueprint.DomainBlueprints(
|
||||||
hass,
|
hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -33,6 +33,8 @@ from homeassistant.const import (
|
|||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_SENSORS,
|
CONF_SENSORS,
|
||||||
CONF_STATE,
|
CONF_STATE,
|
||||||
|
CONF_TRIGGER,
|
||||||
|
CONF_TRIGGERS,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
@ -53,12 +55,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from . import TriggerUpdateCoordinator
|
from . import TriggerUpdateCoordinator
|
||||||
from .const import (
|
from .const import CONF_ATTRIBUTE_TEMPLATES, CONF_AVAILABILITY_TEMPLATE, CONF_OBJECT_ID
|
||||||
CONF_ATTRIBUTE_TEMPLATES,
|
|
||||||
CONF_AVAILABILITY_TEMPLATE,
|
|
||||||
CONF_OBJECT_ID,
|
|
||||||
CONF_TRIGGER,
|
|
||||||
)
|
|
||||||
from .template_entity import (
|
from .template_entity import (
|
||||||
TEMPLATE_ENTITY_COMMON_SCHEMA,
|
TEMPLATE_ENTITY_COMMON_SCHEMA,
|
||||||
TemplateEntity,
|
TemplateEntity,
|
||||||
@ -132,7 +129,7 @@ LEGACY_SENSOR_SCHEMA = vol.All(
|
|||||||
|
|
||||||
def extra_validation_checks(val):
|
def extra_validation_checks(val):
|
||||||
"""Run extra validation checks."""
|
"""Run extra validation checks."""
|
||||||
if CONF_TRIGGER in val:
|
if CONF_TRIGGERS in val or CONF_TRIGGER in val:
|
||||||
raise vol.Invalid(
|
raise vol.Invalid(
|
||||||
"You can only add triggers to template entities if they are defined under"
|
"You can only add triggers to template entities if they are defined under"
|
||||||
" `template:`. See the template documentation for more information:"
|
" `template:`. See the template documentation for more information:"
|
||||||
@ -170,6 +167,7 @@ PLATFORM_SCHEMA = vol.All(
|
|||||||
SENSOR_PLATFORM_SCHEMA.extend(
|
SENSOR_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_TRIGGER): cv.match_all, # to raise custom warning
|
vol.Optional(CONF_TRIGGER): cv.match_all, # to raise custom warning
|
||||||
|
vol.Optional(CONF_TRIGGERS): cv.match_all, # to raise custom warning
|
||||||
vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(LEGACY_SENSOR_SCHEMA),
|
vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(LEGACY_SENSOR_SCHEMA),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
@ -115,6 +115,7 @@ SUN_EVENT_SUNRISE: Final = "sunrise"
|
|||||||
CONF_ABOVE: Final = "above"
|
CONF_ABOVE: Final = "above"
|
||||||
CONF_ACCESS_TOKEN: Final = "access_token"
|
CONF_ACCESS_TOKEN: Final = "access_token"
|
||||||
CONF_ACTION: Final = "action"
|
CONF_ACTION: Final = "action"
|
||||||
|
CONF_ACTIONS: Final = "actions"
|
||||||
CONF_ADDRESS: Final = "address"
|
CONF_ADDRESS: Final = "address"
|
||||||
CONF_AFTER: Final = "after"
|
CONF_AFTER: Final = "after"
|
||||||
CONF_ALIAS: Final = "alias"
|
CONF_ALIAS: Final = "alias"
|
||||||
|
@ -212,11 +212,16 @@ async def test_reload_template_when_blueprint_changes(hass: HomeAssistant) -> No
|
|||||||
assert not_inverted.state == "on"
|
assert not_inverted.state == "on"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("blueprint"),
|
||||||
|
["test_event_sensor.yaml", "test_event_sensor_legacy_schema.yaml"],
|
||||||
|
)
|
||||||
async def test_trigger_event_sensor(
|
async def test_trigger_event_sensor(
|
||||||
hass: HomeAssistant, device_registry: dr.DeviceRegistry
|
hass: HomeAssistant,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
blueprint: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test event sensor blueprint."""
|
"""Test event sensor blueprint."""
|
||||||
blueprint = "test_event_sensor.yaml"
|
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
"template",
|
"template",
|
||||||
|
@ -2303,6 +2303,61 @@ async def test_trigger_conditional_action(hass: HomeAssistant) -> None:
|
|||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("trigger_field", ["trigger", "triggers"])
|
||||||
|
@pytest.mark.parametrize("condition_field", ["condition", "conditions"])
|
||||||
|
@pytest.mark.parametrize("action_field", ["action", "actions"])
|
||||||
|
async def test_legacy_and_new_config_schema(
|
||||||
|
hass: HomeAssistant, trigger_field: str, condition_field: str, action_field: str
|
||||||
|
) -> None:
|
||||||
|
"""Tests that both old and new config schema (singular -> plural) work."""
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"template",
|
||||||
|
{
|
||||||
|
"template": [
|
||||||
|
{
|
||||||
|
"unique_id": "listening-test-event",
|
||||||
|
f"{trigger_field}": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "beer_event",
|
||||||
|
},
|
||||||
|
f"{condition_field}": [
|
||||||
|
{
|
||||||
|
"condition": "template",
|
||||||
|
"value_template": "{{ trigger.event.data.beer >= 42 }}",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
f"{action_field}": [
|
||||||
|
{"event": "test_event_by_action"},
|
||||||
|
],
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
"name": "Unimportant",
|
||||||
|
"state": "Uninteresting",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
event = "test_event_by_action"
|
||||||
|
events = async_capture_events(hass, event)
|
||||||
|
|
||||||
|
hass.bus.async_fire("beer_event", {"beer": 1})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(events) == 0
|
||||||
|
|
||||||
|
hass.bus.async_fire("beer_event", {"beer": 42})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(events) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_device_id(
|
async def test_device_id(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
device_registry: dr.DeviceRegistry,
|
device_registry: dr.DeviceRegistry,
|
||||||
|
@ -14,7 +14,7 @@ blueprint:
|
|||||||
description: The event_data for the event trigger
|
description: The event_data for the event trigger
|
||||||
selector:
|
selector:
|
||||||
object:
|
object:
|
||||||
trigger:
|
triggers:
|
||||||
- trigger: event
|
- trigger: event
|
||||||
event_type: !input event_type
|
event_type: !input event_type
|
||||||
event_data: !input event_data
|
event_data: !input event_data
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
blueprint:
|
||||||
|
name: Create Sensor from Event
|
||||||
|
description: Creates a timestamp sensor from an event
|
||||||
|
domain: template
|
||||||
|
source_url: https://github.com/home-assistant/core/blob/dev/homeassistant/components/template/blueprints/event_sensor.yaml
|
||||||
|
input:
|
||||||
|
event_type:
|
||||||
|
name: Name of the event_type
|
||||||
|
description: The event_type for the event trigger
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
event_data:
|
||||||
|
name: The data for the event
|
||||||
|
description: The event_data for the event trigger
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
trigger:
|
||||||
|
- trigger: event
|
||||||
|
event_type: !input event_type
|
||||||
|
event_data: !input event_data
|
||||||
|
variables:
|
||||||
|
event_data: "{{ trigger.event.data }}"
|
||||||
|
sensor:
|
||||||
|
state: "{{ now() }}"
|
||||||
|
device_class: timestamp
|
||||||
|
attributes:
|
||||||
|
data: "{{ event_data }}"
|
Loading…
x
Reference in New Issue
Block a user