mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Support modern config for the trigger based template entity (#48635)
This commit is contained in:
parent
cffdbfe13c
commit
e882460933
@ -2,7 +2,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from homeassistant.const import CONF_SENSORS, EVENT_HOMEASSISTANT_START
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
|
from homeassistant.const import EVENT_HOMEASSISTANT_START
|
||||||
from homeassistant.core import CoreState, callback
|
from homeassistant.core import CoreState, callback
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import (
|
||||||
discovery,
|
discovery,
|
||||||
@ -51,15 +52,16 @@ class TriggerUpdateCoordinator(update_coordinator.DataUpdateCoordinator):
|
|||||||
EVENT_HOMEASSISTANT_START, self._attach_triggers
|
EVENT_HOMEASSISTANT_START, self._attach_triggers
|
||||||
)
|
)
|
||||||
|
|
||||||
self.hass.async_create_task(
|
for platform_domain in (SENSOR_DOMAIN,):
|
||||||
discovery.async_load_platform(
|
self.hass.async_create_task(
|
||||||
self.hass,
|
discovery.async_load_platform(
|
||||||
"sensor",
|
self.hass,
|
||||||
DOMAIN,
|
platform_domain,
|
||||||
{"coordinator": self, "entities": self.config[CONF_SENSORS]},
|
DOMAIN,
|
||||||
hass_config,
|
{"coordinator": self, "entities": self.config[platform_domain]},
|
||||||
|
hass_config,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
async def _attach_triggers(self, start_event=None) -> None:
|
async def _attach_triggers(self, start_event=None) -> None:
|
||||||
"""Attach the triggers."""
|
"""Attach the triggers."""
|
||||||
|
@ -1,23 +1,72 @@
|
|||||||
"""Template config validator."""
|
"""Template config validator."""
|
||||||
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.sensor import (
|
||||||
|
DEVICE_CLASSES_SCHEMA as SENSOR_DEVICE_CLASSES_SCHEMA,
|
||||||
|
DOMAIN as SENSOR_DOMAIN,
|
||||||
|
)
|
||||||
from homeassistant.config import async_log_exception, config_without_domain
|
from homeassistant.config import async_log_exception, config_without_domain
|
||||||
from homeassistant.const import CONF_SENSORS, CONF_UNIQUE_ID
|
from homeassistant.const import (
|
||||||
from homeassistant.helpers import config_validation as cv
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_PICTURE_TEMPLATE,
|
||||||
|
CONF_FRIENDLY_NAME,
|
||||||
|
CONF_FRIENDLY_NAME_TEMPLATE,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ICON_TEMPLATE,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_SENSORS,
|
||||||
|
CONF_STATE,
|
||||||
|
CONF_UNIQUE_ID,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
|
CONF_VALUE_TEMPLATE,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers import config_validation as cv, template
|
||||||
from homeassistant.helpers.trigger import async_validate_trigger_config
|
from homeassistant.helpers.trigger import async_validate_trigger_config
|
||||||
|
|
||||||
from .const import CONF_TRIGGER, DOMAIN
|
from .const import (
|
||||||
from .sensor import SENSOR_SCHEMA
|
CONF_ATTRIBUTE_TEMPLATES,
|
||||||
|
CONF_ATTRIBUTES,
|
||||||
|
CONF_AVAILABILITY,
|
||||||
|
CONF_AVAILABILITY_TEMPLATE,
|
||||||
|
CONF_PICTURE,
|
||||||
|
CONF_TRIGGER,
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
|
from .sensor import SENSOR_SCHEMA as PLATFORM_SENSOR_SCHEMA
|
||||||
|
|
||||||
CONF_STATE = "state"
|
CONVERSION_PLATFORM = {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SENSOR_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(CONF_NAME): cv.template,
|
||||||
|
vol.Required(CONF_STATE): cv.template,
|
||||||
|
vol.Optional(CONF_ICON): cv.template,
|
||||||
|
vol.Optional(CONF_PICTURE): cv.template,
|
||||||
|
vol.Optional(CONF_AVAILABILITY): cv.template,
|
||||||
|
vol.Optional(CONF_ATTRIBUTES): vol.Schema({cv.string: cv.template}),
|
||||||
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||||
|
vol.Optional(CONF_DEVICE_CLASS): SENSOR_DEVICE_CLASSES_SCHEMA,
|
||||||
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
TRIGGER_ENTITY_SCHEMA = vol.Schema(
|
TRIGGER_ENTITY_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
vol.Required(CONF_TRIGGER): cv.TRIGGER_SCHEMA,
|
vol.Required(CONF_TRIGGER): cv.TRIGGER_SCHEMA,
|
||||||
vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
|
vol.Optional(SENSOR_DOMAIN): vol.All(cv.ensure_list, [SENSOR_SCHEMA]),
|
||||||
|
vol.Optional(CONF_SENSORS): cv.schema_with_slug_keys(PLATFORM_SENSOR_SCHEMA),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,9 +86,37 @@ async def async_validate_config(hass, config):
|
|||||||
)
|
)
|
||||||
except vol.Invalid as err:
|
except vol.Invalid as err:
|
||||||
async_log_exception(err, DOMAIN, cfg, hass)
|
async_log_exception(err, DOMAIN, cfg, hass)
|
||||||
|
continue
|
||||||
|
|
||||||
else:
|
if CONF_SENSORS not in cfg:
|
||||||
trigger_entity_configs.append(cfg)
|
trigger_entity_configs.append(cfg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
logging.getLogger(__name__).warning(
|
||||||
|
"The entity definition format under template: differs from the platform configuration format. See https://www.home-assistant.io/integrations/template#configuration-for-trigger-based-template-sensors"
|
||||||
|
)
|
||||||
|
sensor = list(cfg[SENSOR_DOMAIN]) if SENSOR_DOMAIN in cfg else []
|
||||||
|
|
||||||
|
for device_id, entity_cfg in cfg[CONF_SENSORS].items():
|
||||||
|
entity_cfg = {**entity_cfg}
|
||||||
|
|
||||||
|
for from_key, to_key in CONVERSION_PLATFORM.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
|
||||||
|
|
||||||
|
if CONF_NAME not in entity_cfg:
|
||||||
|
entity_cfg[CONF_NAME] = template.Template(device_id)
|
||||||
|
|
||||||
|
sensor.append(entity_cfg)
|
||||||
|
|
||||||
|
cfg = {**cfg, "sensor": sensor}
|
||||||
|
|
||||||
|
trigger_entity_configs.append(cfg)
|
||||||
|
|
||||||
# Create a copy of the configuration with all config for current
|
# Create a copy of the configuration with all config for current
|
||||||
# component removed and add validated config back in.
|
# component removed and add validated config back in.
|
||||||
|
@ -20,3 +20,7 @@ PLATFORMS = [
|
|||||||
"vacuum",
|
"vacuum",
|
||||||
"weather",
|
"weather",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CONF_AVAILABILITY = "availability"
|
||||||
|
CONF_ATTRIBUTES = "attributes"
|
||||||
|
CONF_PICTURE = "picture"
|
||||||
|
@ -18,6 +18,7 @@ from homeassistant.const import (
|
|||||||
CONF_FRIENDLY_NAME_TEMPLATE,
|
CONF_FRIENDLY_NAME_TEMPLATE,
|
||||||
CONF_ICON_TEMPLATE,
|
CONF_ICON_TEMPLATE,
|
||||||
CONF_SENSORS,
|
CONF_SENSORS,
|
||||||
|
CONF_STATE,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
@ -89,7 +90,7 @@ def _async_create_template_tracking_entities(hass, config):
|
|||||||
friendly_name_template = device_config.get(CONF_FRIENDLY_NAME_TEMPLATE)
|
friendly_name_template = device_config.get(CONF_FRIENDLY_NAME_TEMPLATE)
|
||||||
unit_of_measurement = device_config.get(CONF_UNIT_OF_MEASUREMENT)
|
unit_of_measurement = device_config.get(CONF_UNIT_OF_MEASUREMENT)
|
||||||
device_class = device_config.get(CONF_DEVICE_CLASS)
|
device_class = device_config.get(CONF_DEVICE_CLASS)
|
||||||
attribute_templates = device_config[CONF_ATTRIBUTE_TEMPLATES]
|
attribute_templates = device_config.get(CONF_ATTRIBUTE_TEMPLATES, {})
|
||||||
unique_id = device_config.get(CONF_UNIQUE_ID)
|
unique_id = device_config.get(CONF_UNIQUE_ID)
|
||||||
|
|
||||||
sensors.append(
|
sensors.append(
|
||||||
@ -118,8 +119,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
async_add_entities(_async_create_template_tracking_entities(hass, config))
|
async_add_entities(_async_create_template_tracking_entities(hass, config))
|
||||||
else:
|
else:
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
TriggerSensorEntity(hass, discovery_info["coordinator"], device_id, config)
|
TriggerSensorEntity(hass, discovery_info["coordinator"], config)
|
||||||
for device_id, config in discovery_info["entities"].items()
|
for config in discovery_info["entities"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -203,9 +204,9 @@ class TriggerSensorEntity(TriggerEntity, SensorEntity):
|
|||||||
"""Sensor entity based on trigger data."""
|
"""Sensor entity based on trigger data."""
|
||||||
|
|
||||||
domain = SENSOR_DOMAIN
|
domain = SENSOR_DOMAIN
|
||||||
extra_template_keys = (CONF_VALUE_TEMPLATE,)
|
extra_template_keys = (CONF_STATE,)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> str | None:
|
def state(self) -> str | None:
|
||||||
"""Return state of the sensor."""
|
"""Return state of the sensor."""
|
||||||
return self._rendered.get(CONF_VALUE_TEMPLATE)
|
return self._rendered.get(CONF_STATE)
|
||||||
|
@ -6,20 +6,16 @@ from typing import Any
|
|||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE_CLASS,
|
CONF_DEVICE_CLASS,
|
||||||
CONF_ENTITY_PICTURE_TEMPLATE,
|
CONF_ICON,
|
||||||
CONF_FRIENDLY_NAME,
|
CONF_NAME,
|
||||||
CONF_FRIENDLY_NAME_TEMPLATE,
|
|
||||||
CONF_ICON_TEMPLATE,
|
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
CONF_VALUE_TEMPLATE,
|
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import template, update_coordinator
|
from homeassistant.helpers import template, update_coordinator
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
|
||||||
|
|
||||||
from . import TriggerUpdateCoordinator
|
from . import TriggerUpdateCoordinator
|
||||||
from .const import CONF_ATTRIBUTE_TEMPLATES, CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_ATTRIBUTES, CONF_AVAILABILITY, CONF_PICTURE
|
||||||
|
|
||||||
|
|
||||||
class TriggerEntity(update_coordinator.CoordinatorEntity):
|
class TriggerEntity(update_coordinator.CoordinatorEntity):
|
||||||
@ -32,23 +28,13 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
|||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
coordinator: TriggerUpdateCoordinator,
|
coordinator: TriggerUpdateCoordinator,
|
||||||
device_id: str,
|
|
||||||
config: dict,
|
config: dict,
|
||||||
):
|
):
|
||||||
"""Initialize the entity."""
|
"""Initialize the entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
|
||||||
self.entity_id = async_generate_entity_id(
|
|
||||||
self.domain + ".{}", device_id, hass=hass
|
|
||||||
)
|
|
||||||
|
|
||||||
self._name = config.get(CONF_FRIENDLY_NAME, device_id)
|
|
||||||
|
|
||||||
entity_unique_id = config.get(CONF_UNIQUE_ID)
|
entity_unique_id = config.get(CONF_UNIQUE_ID)
|
||||||
|
|
||||||
if entity_unique_id is None and coordinator.unique_id:
|
|
||||||
entity_unique_id = device_id
|
|
||||||
|
|
||||||
if entity_unique_id and coordinator.unique_id:
|
if entity_unique_id and coordinator.unique_id:
|
||||||
self._unique_id = f"{coordinator.unique_id}-{entity_unique_id}"
|
self._unique_id = f"{coordinator.unique_id}-{entity_unique_id}"
|
||||||
else:
|
else:
|
||||||
@ -56,32 +42,33 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
|||||||
|
|
||||||
self._config = config
|
self._config = config
|
||||||
|
|
||||||
self._to_render = [
|
self._static_rendered = {}
|
||||||
itm
|
self._to_render = []
|
||||||
for itm in (
|
|
||||||
CONF_VALUE_TEMPLATE,
|
for itm in (
|
||||||
CONF_ICON_TEMPLATE,
|
CONF_NAME,
|
||||||
CONF_ENTITY_PICTURE_TEMPLATE,
|
CONF_ICON,
|
||||||
CONF_FRIENDLY_NAME_TEMPLATE,
|
CONF_PICTURE,
|
||||||
CONF_AVAILABILITY_TEMPLATE,
|
CONF_AVAILABILITY,
|
||||||
)
|
):
|
||||||
if itm in config
|
if itm not in config:
|
||||||
]
|
continue
|
||||||
|
|
||||||
|
if config[itm].is_static:
|
||||||
|
self._static_rendered[itm] = config[itm].template
|
||||||
|
else:
|
||||||
|
self._to_render.append(itm)
|
||||||
|
|
||||||
if self.extra_template_keys is not None:
|
if self.extra_template_keys is not None:
|
||||||
self._to_render.extend(self.extra_template_keys)
|
self._to_render.extend(self.extra_template_keys)
|
||||||
|
|
||||||
self._rendered = {}
|
# We make a copy so our initial render is 'unknown' and not 'unavailable'
|
||||||
|
self._rendered = dict(self._static_rendered)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Name of the entity."""
|
"""Name of the entity."""
|
||||||
if (
|
return self._rendered.get(CONF_NAME)
|
||||||
self._rendered is not None
|
|
||||||
and (name := self._rendered.get(CONF_FRIENDLY_NAME_TEMPLATE)) is not None
|
|
||||||
):
|
|
||||||
return name
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
@ -101,29 +88,27 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
|||||||
@property
|
@property
|
||||||
def icon(self) -> str | None:
|
def icon(self) -> str | None:
|
||||||
"""Return icon."""
|
"""Return icon."""
|
||||||
return self._rendered is not None and self._rendered.get(CONF_ICON_TEMPLATE)
|
return self._rendered.get(CONF_ICON)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entity_picture(self) -> str | None:
|
def entity_picture(self) -> str | None:
|
||||||
"""Return entity picture."""
|
"""Return entity picture."""
|
||||||
return self._rendered is not None and self._rendered.get(
|
return self._rendered.get(CONF_PICTURE)
|
||||||
CONF_ENTITY_PICTURE_TEMPLATE
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return availability of the entity."""
|
"""Return availability of the entity."""
|
||||||
return (
|
return (
|
||||||
self._rendered is not None
|
self._rendered is not self._static_rendered
|
||||||
and
|
and
|
||||||
# Check against False so `None` is ok
|
# Check against False so `None` is ok
|
||||||
self._rendered.get(CONF_AVAILABILITY_TEMPLATE) is not False
|
self._rendered.get(CONF_AVAILABILITY) is not False
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
def extra_state_attributes(self) -> dict[str, Any] | None:
|
||||||
"""Return extra attributes."""
|
"""Return extra attributes."""
|
||||||
return self._rendered.get(CONF_ATTRIBUTE_TEMPLATES)
|
return self._rendered.get(CONF_ATTRIBUTES)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Handle being added to Home Assistant."""
|
"""Handle being added to Home Assistant."""
|
||||||
@ -136,16 +121,16 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
|||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
"""Handle updated data from the coordinator."""
|
"""Handle updated data from the coordinator."""
|
||||||
try:
|
try:
|
||||||
rendered = {}
|
rendered = dict(self._static_rendered)
|
||||||
|
|
||||||
for key in self._to_render:
|
for key in self._to_render:
|
||||||
rendered[key] = self._config[key].async_render(
|
rendered[key] = self._config[key].async_render(
|
||||||
self.coordinator.data["run_variables"], parse_result=False
|
self.coordinator.data["run_variables"], parse_result=False
|
||||||
)
|
)
|
||||||
|
|
||||||
if CONF_ATTRIBUTE_TEMPLATES in self._config:
|
if CONF_ATTRIBUTES in self._config:
|
||||||
rendered[CONF_ATTRIBUTE_TEMPLATES] = template.render_complex(
|
rendered[CONF_ATTRIBUTES] = template.render_complex(
|
||||||
self._config[CONF_ATTRIBUTE_TEMPLATES],
|
self._config[CONF_ATTRIBUTES],
|
||||||
self.coordinator.data["run_variables"],
|
self.coordinator.data["run_variables"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -154,7 +139,7 @@ class TriggerEntity(update_coordinator.CoordinatorEntity):
|
|||||||
logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error(
|
logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error(
|
||||||
"Error rendering %s template for %s: %s", key, self.entity_id, err
|
"Error rendering %s template for %s: %s", key, self.entity_id, err
|
||||||
)
|
)
|
||||||
self._rendered = None
|
self._rendered = self._static_rendered
|
||||||
|
|
||||||
self.async_set_context(self.coordinator.data["context"])
|
self.async_set_context(self.coordinator.data["context"])
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -336,7 +336,7 @@ class Template:
|
|||||||
If limited is True, the template is not allowed to access any function or filter depending on hass or the state machine.
|
If limited is True, the template is not allowed to access any function or filter depending on hass or the state machine.
|
||||||
"""
|
"""
|
||||||
if self.is_static:
|
if self.is_static:
|
||||||
if self.hass.config.legacy_templates or not parse_result:
|
if not parse_result or self.hass.config.legacy_templates:
|
||||||
return self.template
|
return self.template
|
||||||
return self._parse_result(self.template)
|
return self._parse_result(self.template)
|
||||||
|
|
||||||
@ -360,7 +360,7 @@ class Template:
|
|||||||
If limited is True, the template is not allowed to access any function or filter depending on hass or the state machine.
|
If limited is True, the template is not allowed to access any function or filter depending on hass or the state machine.
|
||||||
"""
|
"""
|
||||||
if self.is_static:
|
if self.is_static:
|
||||||
if self.hass.config.legacy_templates or not parse_result:
|
if not parse_result or self.hass.config.legacy_templates:
|
||||||
return self.template
|
return self.template
|
||||||
return self._parse_result(self.template)
|
return self._parse_result(self.template)
|
||||||
|
|
||||||
|
@ -998,14 +998,14 @@ async def test_trigger_entity(hass):
|
|||||||
{
|
{
|
||||||
"template": [
|
"template": [
|
||||||
{"invalid": "config"},
|
{"invalid": "config"},
|
||||||
# This one should still be set up
|
# Config after invalid should still be set up
|
||||||
{
|
{
|
||||||
"unique_id": "listening-test-event",
|
"unique_id": "listening-test-event",
|
||||||
"trigger": {"platform": "event", "event_type": "test_event"},
|
"trigger": {"platform": "event", "event_type": "test_event"},
|
||||||
"sensors": {
|
"sensors": {
|
||||||
"hello": {
|
"hello": {
|
||||||
"friendly_name": "Hello Name",
|
"friendly_name": "Hello Name",
|
||||||
"unique_id": "just_a_test",
|
"unique_id": "hello_name-id",
|
||||||
"device_class": "battery",
|
"device_class": "battery",
|
||||||
"unit_of_measurement": "%",
|
"unit_of_measurement": "%",
|
||||||
"value_template": "{{ trigger.event.data.beer }}",
|
"value_template": "{{ trigger.event.data.beer }}",
|
||||||
@ -1016,6 +1016,20 @@ async def test_trigger_entity(hass):
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
"name": "via list",
|
||||||
|
"unique_id": "via_list-id",
|
||||||
|
"device_class": "battery",
|
||||||
|
"unit_of_measurement": "%",
|
||||||
|
"state": "{{ trigger.event.data.beer + 1 }}",
|
||||||
|
"picture": "{{ '/local/dogs.png' }}",
|
||||||
|
"icon": "{{ 'mdi:pirate' }}",
|
||||||
|
"attributes": {
|
||||||
|
"plus_one": "{{ trigger.event.data.beer + 1 }}"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"trigger": [],
|
"trigger": [],
|
||||||
@ -1031,7 +1045,7 @@ async def test_trigger_entity(hass):
|
|||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.hello")
|
state = hass.states.get("sensor.hello_name")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
@ -1043,7 +1057,7 @@ async def test_trigger_entity(hass):
|
|||||||
hass.bus.async_fire("test_event", {"beer": 2}, context=context)
|
hass.bus.async_fire("test_event", {"beer": 2}, context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.hello")
|
state = hass.states.get("sensor.hello_name")
|
||||||
assert state.state == "2"
|
assert state.state == "2"
|
||||||
assert state.attributes.get("device_class") == "battery"
|
assert state.attributes.get("device_class") == "battery"
|
||||||
assert state.attributes.get("icon") == "mdi:pirate"
|
assert state.attributes.get("icon") == "mdi:pirate"
|
||||||
@ -1053,10 +1067,24 @@ async def test_trigger_entity(hass):
|
|||||||
assert state.context is context
|
assert state.context is context
|
||||||
|
|
||||||
ent_reg = entity_registry.async_get(hass)
|
ent_reg = entity_registry.async_get(hass)
|
||||||
assert len(ent_reg.entities) == 1
|
assert len(ent_reg.entities) == 2
|
||||||
assert (
|
assert (
|
||||||
ent_reg.entities["sensor.hello"].unique_id == "listening-test-event-just_a_test"
|
ent_reg.entities["sensor.hello_name"].unique_id
|
||||||
|
== "listening-test-event-hello_name-id"
|
||||||
)
|
)
|
||||||
|
assert (
|
||||||
|
ent_reg.entities["sensor.via_list"].unique_id
|
||||||
|
== "listening-test-event-via_list-id"
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.via_list")
|
||||||
|
assert state.state == "3"
|
||||||
|
assert state.attributes.get("device_class") == "battery"
|
||||||
|
assert state.attributes.get("icon") == "mdi:pirate"
|
||||||
|
assert state.attributes.get("entity_picture") == "/local/dogs.png"
|
||||||
|
assert state.attributes.get("plus_one") == 3
|
||||||
|
assert state.attributes.get("unit_of_measurement") == "%"
|
||||||
|
assert state.context is context
|
||||||
|
|
||||||
|
|
||||||
async def test_trigger_entity_render_error(hass):
|
async def test_trigger_entity_render_error(hass):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user