2016-03-09 09:25:50 +00:00
""" The test for the Template sensor platform. """
2024-03-08 13:44:56 +00:00
2020-08-09 02:34:14 +00:00
from asyncio import Event
2024-01-25 10:12:03 +00:00
from datetime import datetime , timedelta
2023-09-11 12:33:43 +00:00
from unittest . mock import ANY , patch
2020-08-09 02:34:14 +00:00
2021-02-11 16:36:19 +00:00
import pytest
2023-08-30 17:56:34 +00:00
from syrupy . assertion import SnapshotAssertion
2021-02-11 16:36:19 +00:00
2020-08-09 02:34:14 +00:00
from homeassistant . bootstrap import async_from_config_dict
2023-08-30 17:56:34 +00:00
from homeassistant . components import sensor , template
2024-01-25 10:12:03 +00:00
from homeassistant . components . template . sensor import TriggerSensorEntity
2019-12-08 20:05:08 +00:00
from homeassistant . const import (
2020-09-12 12:20:21 +00:00
ATTR_ENTITY_PICTURE ,
2024-11-06 03:36:26 +00:00
ATTR_FRIENDLY_NAME ,
2020-09-12 12:20:21 +00:00
ATTR_ICON ,
2020-08-09 02:34:14 +00:00
EVENT_COMPONENT_LOADED ,
2019-12-08 20:05:08 +00:00
EVENT_HOMEASSISTANT_START ,
STATE_OFF ,
STATE_ON ,
STATE_UNAVAILABLE ,
2021-03-29 16:57:51 +00:00
STATE_UNKNOWN ,
2019-12-08 20:05:08 +00:00
)
2023-02-08 18:10:53 +00:00
from homeassistant . core import Context , CoreState , HomeAssistant , State , callback
2024-06-22 10:45:06 +00:00
from homeassistant . helpers import device_registry as dr , entity_registry as er
2022-03-25 22:22:58 +00:00
from homeassistant . helpers . entity_component import async_update_entity
2024-08-20 10:55:39 +00:00
from homeassistant . helpers . entity_platform import AddEntitiesCallback
2020-08-25 22:20:04 +00:00
from homeassistant . helpers . template import Template
2024-08-20 10:55:39 +00:00
from homeassistant . helpers . typing import ConfigType , DiscoveryInfoType
2020-10-05 12:52:31 +00:00
from homeassistant . setup import ATTR_COMPONENT , async_setup_component
2020-08-25 22:20:04 +00:00
import homeassistant . util . dt as dt_util
2019-12-08 20:05:08 +00:00
2022-04-21 16:32:18 +00:00
from tests . common import (
2023-08-30 17:56:34 +00:00
MockConfigEntry ,
2022-04-21 16:32:18 +00:00
assert_setup_component ,
2024-03-16 22:37:24 +00:00
async_capture_events ,
2022-04-21 16:32:18 +00:00
async_fire_time_changed ,
mock_restore_cache_with_extra_data ,
)
2016-02-14 23:08:23 +00:00
2021-09-04 05:56:12 +00:00
TEST_NAME = " sensor.test_template_sensor "
2016-01-21 18:31:44 +00:00
2020-10-05 12:52:31 +00:00
2023-08-30 17:56:34 +00:00
@pytest.mark.parametrize (
" config_entry_extra_options " ,
[
{ } ,
{
" device_class " : " battery " ,
" state_class " : " measurement " ,
" unit_of_measurement " : " % " ,
} ,
] ,
)
async def test_setup_config_entry (
hass : HomeAssistant ,
snapshot : SnapshotAssertion ,
config_entry_extra_options : dict [ str , str ] ,
) - > None :
""" Test the config flow. """
state_template = " {{ float(states( ' sensor.one ' )) + float(states( ' sensor.two ' )) }} "
input_entities = [ " one " , " two " ]
input_states = { " one " : " 10 " , " two " : " 20 " }
template_type = sensor . DOMAIN
for input_entity in input_entities :
hass . states . async_set (
f " { template_type } . { input_entity } " ,
input_states [ input_entity ] ,
{ } ,
)
template_config_entry = MockConfigEntry (
data = { } ,
domain = template . DOMAIN ,
options = {
" name " : " My template " ,
" state " : state_template ,
" template_type " : template_type ,
}
| config_entry_extra_options ,
title = " My template " ,
)
template_config_entry . add_to_hass ( hass )
assert await hass . config_entries . async_setup ( template_config_entry . entry_id )
await hass . async_block_till_done ( )
state = hass . states . get ( f " { template_type } .my_template " )
assert state is not None
assert state == snapshot
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " It {{ states.sensor.test_state.state }}. "
}
} ,
} ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_template_legacy ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test template. """
assert hass . states . get ( TEST_NAME ) . state == " It . "
2020-10-05 12:52:31 +00:00
hass . states . async_set ( " sensor.test_state " , " Works " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
assert hass . states . get ( TEST_NAME ) . state == " It Works. "
2020-10-05 12:52:31 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" icon_template " : " { % i f states.sensor.test_state.state == "
" ' Works ' % } "
" mdi:check "
" { % e ndif % } " ,
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_icon_template ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test icon template. """
assert hass . states . get ( TEST_NAME ) . attributes . get ( " icon " ) == " "
2020-10-05 12:52:31 +00:00
hass . states . async_set ( " sensor.test_state " , " Works " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
assert hass . states . get ( TEST_NAME ) . attributes [ " icon " ] == " mdi:check "
2020-10-05 12:52:31 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" entity_picture_template " : " { % i f states.sensor.test_state.state == "
" ' Works ' % } "
" /local/sensor.png "
" { % e ndif % } " ,
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_entity_picture_template ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test entity_picture template. """
assert hass . states . get ( TEST_NAME ) . attributes . get ( " entity_picture " ) == " "
2020-10-05 12:52:31 +00:00
hass . states . async_set ( " sensor.test_state " , " Works " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
assert (
hass . states . get ( TEST_NAME ) . attributes [ " entity_picture " ] == " /local/sensor.png "
)
2020-10-05 12:52:31 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
2023-02-15 21:46:03 +00:00
( " attribute " , " config " , " expected " ) ,
2021-09-04 05:56:12 +00:00
[
(
" friendly_name " ,
2020-10-05 12:52:31 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" friendly_name_template " : " It {{ states.sensor.test_state.state }}. " ,
}
} ,
2021-09-04 05:56:12 +00:00
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-10-20 21:53:06 +00:00
( " It . " , " It Works. " ) ,
) ,
(
" friendly_name " ,
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" friendly_name_template " : " {{ ' It ' + states.sensor.test_state.state + ' . ' }} " ,
}
} ,
} ,
} ,
( None , " It Works. " ) ,
2021-09-04 05:56:12 +00:00
) ,
(
" friendly_name " ,
2020-10-05 12:52:31 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.fourohfour.state }} " ,
" friendly_name_template " : " It {{ states.sensor.test_state.state }}. " ,
}
} ,
2021-09-04 05:56:12 +00:00
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-10-20 21:53:06 +00:00
( " It . " , " It Works. " ) ,
2021-09-04 05:56:12 +00:00
) ,
(
" test_attribute " ,
2020-10-05 12:52:31 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" attribute_templates " : {
" test_attribute " : " It {{ states.sensor.test_state.state }}. "
2019-07-31 19:25:30 +00:00
} ,
2020-10-05 12:52:31 +00:00
}
} ,
2021-09-04 05:56:12 +00:00
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-10-20 21:53:06 +00:00
( " It . " , " It Works. " ) ,
2021-09-04 05:56:12 +00:00
) ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_friendly_name_template ( hass : HomeAssistant , attribute , expected ) - > None :
2021-09-04 05:56:12 +00:00
""" Test friendly_name template with an unknown value_template. """
2021-10-20 21:53:06 +00:00
assert hass . states . get ( TEST_NAME ) . attributes . get ( attribute ) == expected [ 0 ]
2020-10-05 12:52:31 +00:00
hass . states . async_set ( " sensor.test_state " , " Works " )
await hass . async_block_till_done ( )
2021-10-20 21:53:06 +00:00
assert hass . states . get ( TEST_NAME ) . attributes [ attribute ] == expected [ 1 ]
2020-10-05 12:52:31 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 0 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : { " value_template " : " { % i f rubbish % } " }
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test INVALID sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} "
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : { " invalid " } ,
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
{
" sensor " : {
" platform " : " template " ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" not_value_template " : " {{ states.sensor.test_state.state }} "
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
2020-10-05 12:52:31 +00:00
" test " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" device_class " : " foobarnotreal " ,
}
2021-09-04 05:56:12 +00:00
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_template_syntax_error ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test setup with invalid device_class. """
2021-10-07 10:58:00 +00:00
assert hass . states . async_all ( " sensor " ) == [ ]
2020-10-05 12:52:31 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " It {{ states.sensor.test_state "
" .attributes.missing }}. "
}
} ,
2020-10-05 12:52:31 +00:00
} ,
2021-09-04 05:56:12 +00:00
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_template_attribute_missing ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test missing attribute template. """
assert hass . states . get ( TEST_NAME ) . state == STATE_UNAVAILABLE
2020-10-05 12:52:31 +00:00
2021-09-04 05:56:12 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test1 " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
2022-12-21 21:47:59 +00:00
" unit_of_measurement " : " °C " ,
2021-09-04 05:56:12 +00:00
" device_class " : " temperature " ,
} ,
" test2 " : {
" value_template " : " {{ states.sensor.test_sensor.state }} "
} ,
} ,
} ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_setup_valid_device_class ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test setup with valid device_class. """
2023-01-16 13:42:47 +00:00
hass . states . async_set ( " sensor.test_sensor " , " 75 " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
assert hass . states . get ( " sensor.test1 " ) . attributes [ " device_class " ] == " temperature "
assert " device_class " not in hass . states . get ( " sensor.test2 " ) . attributes
2020-10-05 12:52:31 +00:00
2018-10-10 11:49:15 +00:00
2021-02-11 16:36:19 +00:00
@pytest.mark.parametrize ( " load_registries " , [ False ] )
2023-02-08 18:10:53 +00:00
async def test_creating_sensor_loads_group ( hass : HomeAssistant ) - > None :
2020-08-09 02:34:14 +00:00
""" Test setting up template sensor loads group component first. """
order = [ ]
after_dep_event = Event ( )
2024-08-20 10:55:39 +00:00
async def async_setup_group ( hass : HomeAssistant , config : ConfigType ) - > bool :
2020-08-09 02:34:14 +00:00
# Make sure group takes longer to load, so that it won't
# be loaded first by chance
await after_dep_event . wait ( )
order . append ( " group " )
return True
async def async_setup_template (
2024-08-20 10:55:39 +00:00
hass : HomeAssistant ,
config : ConfigType ,
async_add_entities : AddEntitiesCallback ,
discovery_info : DiscoveryInfoType | None = None ,
) - > bool :
2020-08-09 02:34:14 +00:00
order . append ( " sensor.template " )
return True
async def set_after_dep_event ( event ) :
if event . data [ ATTR_COMPONENT ] == " sensor " :
after_dep_event . set ( )
hass . bus . async_listen ( EVENT_COMPONENT_LOADED , set_after_dep_event )
2024-03-25 23:02:16 +00:00
with (
patch (
" homeassistant.components.group.async_setup " ,
new = async_setup_group ,
) ,
patch (
" homeassistant.components.template.sensor.async_setup_platform " ,
new = async_setup_template ,
) ,
2020-08-09 02:34:14 +00:00
) :
await async_from_config_dict (
{ " sensor " : { " platform " : " template " , " sensors " : { } } , " group " : { } } , hass
)
await hass . async_block_till_done ( )
assert order == [ " group " , " sensor.template " ]
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" availability_template " : " {{ is_state( ' sensor.availability_sensor ' , ' on ' ) }} " ,
}
} ,
} ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_available_template_with_entities ( hass : HomeAssistant ) - > None :
2019-09-24 14:05:19 +00:00
""" Test availability tempalates with values from other entities. """
hass . states . async_set ( " sensor.availability_sensor " , STATE_OFF )
# When template returns true..
hass . states . async_set ( " sensor.availability_sensor " , STATE_ON )
await hass . async_block_till_done ( )
# Device State should not be unavailable
2021-09-04 05:56:12 +00:00
assert hass . states . get ( TEST_NAME ) . state != STATE_UNAVAILABLE
2019-09-24 14:05:19 +00:00
# When Availability template returns false
hass . states . async_set ( " sensor.availability_sensor " , STATE_OFF )
await hass . async_block_till_done ( )
# device state should be unavailable
2021-09-04 05:56:12 +00:00
assert hass . states . get ( TEST_NAME ) . state == STATE_UNAVAILABLE
2019-09-24 14:05:19 +00:00
2019-09-01 16:12:55 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2019-09-01 16:12:55 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" invalid_template " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" attribute_templates " : {
" test_attribute " : " {{ states.sensor.unknown.attributes.picture }} "
} ,
}
} ,
2021-09-04 05:56:12 +00:00
} ,
2019-09-01 16:12:55 +00:00
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-02-16 13:08:03 +00:00
async def test_invalid_attribute_template (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog : pytest . LogCaptureFixture , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test that errors are logged if rendering template fails. """
hass . states . async_set ( " sensor.test_sensor " , " startup " )
2019-09-01 16:12:55 +00:00
await hass . async_block_till_done ( )
assert len ( hass . states . async_all ( ) ) == 2
2020-08-20 13:06:41 +00:00
hass . bus . async_fire ( EVENT_HOMEASSISTANT_START )
await hass . async_block_till_done ( )
2022-03-25 22:22:58 +00:00
await async_update_entity ( hass , " sensor.invalid_template " )
2021-09-04 14:09:55 +00:00
assert " TemplateError " in caplog_setup_text
2024-03-19 20:44:04 +00:00
assert (
" Template variable error: ' None ' has no attribute ' attributes ' when rendering "
in caplog . text
)
assert hass . states . get ( " sensor.invalid_template " ) . state == " startup "
2019-09-01 16:12:55 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2019-09-24 14:05:19 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" my_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" availability_template " : " {{ x - 12 }} " ,
}
} ,
2021-09-04 05:56:12 +00:00
} ,
2019-09-24 14:05:19 +00:00
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2021-09-04 05:56:12 +00:00
async def test_invalid_availability_template_keeps_component_available (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test that an invalid availability keeps the device available. """
2019-09-24 14:05:19 +00:00
assert hass . states . get ( " sensor.my_sensor " ) . state != STATE_UNAVAILABLE
2021-09-04 14:09:55 +00:00
assert " UndefinedError: ' x ' is undefined " in caplog_setup_text
2019-09-24 14:05:19 +00:00
2023-02-08 18:10:53 +00:00
async def test_no_template_match_all (
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
) - > None :
2020-08-20 13:06:41 +00:00
""" Test that we allow static templates. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test_sensor " , " startup " )
2024-01-18 18:41:32 +00:00
hass . set_state ( CoreState . not_running )
2020-08-21 23:31:48 +00:00
2019-07-31 19:25:30 +00:00
await async_setup_component (
hass ,
2020-10-05 12:52:31 +00:00
sensor . DOMAIN ,
2019-07-31 19:25:30 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" invalid_state " : { " value_template " : " {{ 1 + 1 }} " } ,
" invalid_icon " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" icon_template " : " {{ 1 + 1 }} " ,
} ,
" invalid_entity_picture " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" entity_picture_template " : " {{ 1 + 1 }} " ,
} ,
" invalid_friendly_name " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" friendly_name_template " : " {{ 1 + 1 }} " ,
} ,
2019-09-01 16:12:55 +00:00
" invalid_attribute " : {
" value_template " : " {{ states.sensor.test_sensor.state }} " ,
" attribute_templates " : { " test_attribute " : " {{ 1 + 1 }} " } ,
} ,
2018-10-10 11:49:15 +00:00
} ,
}
2019-07-31 19:25:30 +00:00
} ,
)
2020-06-01 05:18:30 +00:00
await hass . async_block_till_done ( )
2019-09-01 16:12:55 +00:00
assert hass . states . get ( " sensor.invalid_state " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_icon " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_entity_picture " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_friendly_name " ) . state == " unknown "
2018-10-10 11:49:15 +00:00
await hass . async_block_till_done ( )
2019-09-01 16:12:55 +00:00
assert len ( hass . states . async_all ( ) ) == 6
2019-07-31 19:25:30 +00:00
assert hass . states . get ( " sensor.invalid_state " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_icon " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_entity_picture " ) . state == " unknown "
assert hass . states . get ( " sensor.invalid_friendly_name " ) . state == " unknown "
2019-09-01 16:12:55 +00:00
assert hass . states . get ( " sensor.invalid_attribute " ) . state == " unknown "
2018-10-10 11:49:15 +00:00
2018-10-11 09:38:35 +00:00
hass . bus . async_fire ( EVENT_HOMEASSISTANT_START )
await hass . async_block_till_done ( )
2019-07-31 19:25:30 +00:00
assert hass . states . get ( " sensor.invalid_state " ) . state == " 2 "
assert hass . states . get ( " sensor.invalid_icon " ) . state == " startup "
assert hass . states . get ( " sensor.invalid_entity_picture " ) . state == " startup "
assert hass . states . get ( " sensor.invalid_friendly_name " ) . state == " startup "
2019-09-01 16:12:55 +00:00
assert hass . states . get ( " sensor.invalid_attribute " ) . state == " startup "
2018-10-11 09:38:35 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test_sensor " , " hello " )
2018-10-10 11:49:15 +00:00
await hass . async_block_till_done ( )
2019-07-31 19:25:30 +00:00
assert hass . states . get ( " sensor.invalid_state " ) . state == " 2 "
2020-07-15 05:34:35 +00:00
# Will now process because we have at least one valid template
assert hass . states . get ( " sensor.invalid_icon " ) . state == " hello "
assert hass . states . get ( " sensor.invalid_entity_picture " ) . state == " hello "
assert hass . states . get ( " sensor.invalid_friendly_name " ) . state == " hello "
assert hass . states . get ( " sensor.invalid_attribute " ) . state == " hello "
2018-10-10 11:49:15 +00:00
2022-03-25 22:22:58 +00:00
await async_update_entity ( hass , " sensor.invalid_state " )
await async_update_entity ( hass , " sensor.invalid_icon " )
await async_update_entity ( hass , " sensor.invalid_entity_picture " )
await async_update_entity ( hass , " sensor.invalid_friendly_name " )
await async_update_entity ( hass , " sensor.invalid_attribute " )
2018-10-10 11:49:15 +00:00
2019-07-31 19:25:30 +00:00
assert hass . states . get ( " sensor.invalid_state " ) . state == " 2 "
assert hass . states . get ( " sensor.invalid_icon " ) . state == " hello "
assert hass . states . get ( " sensor.invalid_entity_picture " ) . state == " hello "
assert hass . states . get ( " sensor.invalid_friendly_name " ) . state == " hello "
2019-09-01 16:12:55 +00:00
assert hass . states . get ( " sensor.invalid_attribute " ) . state == " hello "
2020-08-01 22:45:55 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-08-01 22:45:55 +00:00
{
2021-04-24 14:14:31 +00:00
" template " : {
" unique_id " : " group-id " ,
" sensor " : { " name " : " top-level " , " unique_id " : " sensor-id " , " state " : " 5 " } ,
} ,
2020-08-01 22:45:55 +00:00
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor_01 " : {
" unique_id " : " not-so-unique-anymore " ,
" value_template " : " {{ true }} " ,
} ,
" test_template_sensor_02 " : {
" unique_id " : " not-so-unique-anymore " ,
" value_template " : " {{ false }} " ,
} ,
} ,
2021-04-24 14:14:31 +00:00
} ,
2020-08-01 22:45:55 +00:00
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-03-01 15:04:40 +00:00
async def test_unique_id (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , entity_registry : er . EntityRegistry
2023-03-01 15:04:40 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test unique_id option only creates one sensor per id. """
2021-04-24 14:14:31 +00:00
assert len ( hass . states . async_all ( ) ) == 2
2023-03-01 15:04:40 +00:00
assert len ( entity_registry . entities ) == 2
assert entity_registry . async_get_entity_id (
" sensor " , " template " , " group-id-sensor-id "
2021-04-24 14:14:31 +00:00
)
2023-03-01 15:04:40 +00:00
assert entity_registry . async_get_entity_id (
" sensor " , " template " , " not-so-unique-anymore "
2021-04-24 14:14:31 +00:00
)
2020-08-25 22:20:04 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-08-25 22:20:04 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" solar_angle " : {
" friendly_name " : " Sun angle " ,
" unit_of_measurement " : " degrees " ,
" value_template " : " {{ state_attr( ' sun.sun ' , ' elevation ' ) }} " ,
} ,
" sunrise " : {
" value_template " : " {{ state_attr( ' sun.sun ' , ' next_rising ' ) }} "
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_sun_renders_once_per_sensor ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test sun change renders the template only once per sensor. """
2020-08-25 22:20:04 +00:00
2021-09-04 05:56:12 +00:00
now = dt_util . utcnow ( )
hass . states . async_set (
" sun.sun " , " above_horizon " , { " elevation " : 45.3 , " next_rising " : now }
)
2020-08-25 22:20:04 +00:00
await hass . async_block_till_done ( )
assert len ( hass . states . async_all ( ) ) == 3
assert hass . states . get ( " sensor.solar_angle " ) . state == " 45.3 "
assert hass . states . get ( " sensor.sunrise " ) . state == str ( now )
async_render_calls = [ ]
@callback
def _record_async_render ( self , * args , * * kwargs ) :
""" Catch async_render. """
async_render_calls . append ( self . template )
2023-01-16 13:42:47 +00:00
return " 75 "
2020-08-25 22:20:04 +00:00
later = dt_util . utcnow ( )
with patch . object ( Template , " async_render " , _record_async_render ) :
hass . states . async_set ( " sun.sun " , { " elevation " : 50 , " next_rising " : later } )
await hass . async_block_till_done ( )
2023-01-16 13:42:47 +00:00
assert hass . states . get ( " sensor.solar_angle " ) . state == " 75 "
assert hass . states . get ( " sensor.sunrise " ) . state == " 75 "
2020-08-25 22:20:04 +00:00
assert len ( async_render_calls ) == 2
assert set ( async_render_calls ) == {
" {{ state_attr( ' sun.sun ' , ' elevation ' ) }} " ,
" {{ state_attr( ' sun.sun ' , ' next_rising ' ) }} " ,
}
2020-09-10 18:50:11 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2022-04-20 13:30:17 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
2022-06-27 06:59:29 +00:00
" template " : {
" sensor " : {
" name " : " test_template_sensor " ,
" state " : " {{ this.attributes.test }}: {{ this.entity_id }} " ,
" attributes " : { " test " : " It {{ states.sensor.test_state.state }} " } ,
} ,
} ,
} ,
{
" template " : {
" trigger " : {
" platform " : " state " ,
" entity_id " : [
" sensor.test_state " ,
" sensor.test_template_sensor " ,
] ,
} ,
" sensor " : {
" name " : " test_template_sensor " ,
" state " : " {{ this.attributes.test }}: {{ this.entity_id }} " ,
" attributes " : { " test " : " It {{ states.sensor.test_state.state }} " } ,
2022-04-20 13:30:17 +00:00
} ,
} ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_this_variable ( hass : HomeAssistant ) - > None :
2022-04-20 13:30:17 +00:00
""" Test template. """
assert hass . states . get ( TEST_NAME ) . state == " It: " + TEST_NAME
hass . states . async_set ( " sensor.test_state " , " Works " )
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
assert hass . states . get ( TEST_NAME ) . state == " It Works: " + TEST_NAME
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2022-05-03 14:43:44 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" template " : {
" sensor " : {
" state " : " {{ this.attributes.get( ' test ' , ' no-test! ' ) }}: {{ this.entity_id }} " ,
" icon " : " mdi: { % i f this.entity_id in states and ' friendly_name ' in this.attributes % } {{ this.attributes[ ' friendly_name ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" name " : " { % i f this.entity_id in states and ' friendly_name ' in this.attributes % } {{ this.attributes[ ' friendly_name ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" picture " : " { % i f this.entity_id in states and ' entity_picture ' in this.attributes % } {{ this.attributes[ ' entity_picture ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" attributes " : { " test " : " {{ this.entity_id }} " } ,
} ,
} ,
} ,
] ,
)
2023-02-16 13:08:03 +00:00
async def test_this_variable_early_hass_not_running (
hass : HomeAssistant , config , count , domain
) - > None :
2022-05-03 14:43:44 +00:00
""" Test referencing ' this ' variable before the entity is in the state machine.
Hass is not yet started when the entity is added .
Icon , name and picture templates are rendered once in the constructor .
"""
entity_id = " sensor.none_false "
2024-01-18 18:41:32 +00:00
hass . set_state ( CoreState . not_running )
2022-05-03 14:43:44 +00:00
# Setup template
with assert_setup_component ( count , domain ) :
assert await async_setup_component (
hass ,
domain ,
config ,
)
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
# Sensor state not rendered, icon, name and picture
# templates rendered in constructor with entity_id set to None
state = hass . states . get ( entity_id )
assert state . state == " unknown "
assert state . attributes == {
" entity_picture " : " None:False " ,
" friendly_name " : " None:False " ,
" icon " : " mdi:None:False " ,
}
# Signal hass started
hass . bus . async_fire ( EVENT_HOMEASSISTANT_START )
await hass . async_block_till_done ( )
2023-08-30 14:22:52 +00:00
await hass . async_block_till_done ( )
2022-05-03 14:43:44 +00:00
2023-08-30 14:22:52 +00:00
# icon, name, picture + other templates now re-rendered
2022-05-03 14:43:44 +00:00
state = hass . states . get ( entity_id )
assert state . state == " sensor.none_false: sensor.none_false "
assert state . attributes == {
" entity_picture " : " sensor.none_false:False " ,
" friendly_name " : " sensor.none_false:False " ,
" icon " : " mdi:sensor.none_false:False " ,
" test " : " sensor.none_false " ,
}
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2022-05-03 14:43:44 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" template " : {
" sensor " : {
" state " : " {{ this.attributes.get( ' test ' , ' no-test! ' ) }}: {{ this.entity_id }} " ,
" icon " : " mdi: { % i f this.entity_id in states and ' friendly_name ' in this.attributes % } {{ this.attributes[ ' friendly_name ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" name " : " { % i f this.entity_id in states and ' friendly_name ' in this.attributes % } {{ this.attributes[ ' friendly_name ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" picture " : " { % i f this.entity_id in states and ' entity_picture ' in this.attributes % } {{ this.attributes[ ' entity_picture ' ]}} { % e lse % } {{ this.entity_id}}: {{ this.entity_id in states}} { % e ndif % } " ,
" attributes " : { " test " : " {{ this.entity_id }} " } ,
} ,
} ,
} ,
] ,
)
2023-02-16 13:08:03 +00:00
async def test_this_variable_early_hass_running (
hass : HomeAssistant , config , count , domain
) - > None :
2022-05-03 14:43:44 +00:00
""" Test referencing ' this ' variable before the entity is in the state machine.
Hass is already started when the entity is added .
Icon , name and picture templates are rendered in the constructor , and again
before the entity is added to hass .
"""
# Start hass
2024-01-12 09:21:26 +00:00
assert hass . state is CoreState . running
2022-05-03 14:43:44 +00:00
await hass . async_start ( )
await hass . async_block_till_done ( )
# Setup template
with assert_setup_component ( count , domain ) :
assert await async_setup_component (
hass ,
domain ,
config ,
)
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
entity_id = " sensor.none_false "
# All templated rendered
state = hass . states . get ( entity_id )
assert state . state == " sensor.none_false: sensor.none_false "
assert state . attributes == {
" entity_picture " : " sensor.none_false:False " ,
" friendly_name " : " sensor.none_false:False " ,
" icon " : " mdi:sensor.none_false:False " ,
" test " : " sensor.none_false " ,
}
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-09-12 12:20:21 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test " : {
" value_template " : " {{ ((states.sensor.test.state or 0) | int) + 1 }} " ,
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-02-16 13:08:03 +00:00
async def test_self_referencing_sensor_loop (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test a self referencing sensor does not loop forever. """
2020-09-12 12:20:21 +00:00
assert len ( hass . states . async_all ( ) ) == 1
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
2021-09-04 14:09:55 +00:00
assert " Template loop detected " in caplog_setup_text
2021-09-04 05:56:12 +00:00
assert int ( hass . states . get ( " sensor.test " ) . state ) == 2
2020-09-12 12:20:21 +00:00
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
assert int ( hass . states . get ( " sensor.test " ) . state ) == 2
2020-09-12 12:20:21 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-09-12 12:20:21 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test " : {
" value_template " : " {{ ((states.sensor.test.state or 0) | int) + 1 }} " ,
" icon_template " : " { % i f ((states.sensor.test.state or 0) | int) >= 1 % }mdi:greater { % e lse % }mdi:less { % e ndif % } " ,
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2021-09-04 14:09:55 +00:00
async def test_self_referencing_sensor_with_icon_loop (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test a self referencing sensor loops forever with a valid self referencing icon. """
2020-09-12 12:20:21 +00:00
assert len ( hass . states . async_all ( ) ) == 1
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
2021-09-04 14:09:55 +00:00
assert " Template loop detected " in caplog_setup_text
2020-09-12 12:20:21 +00:00
state = hass . states . get ( " sensor.test " )
2020-10-01 20:11:11 +00:00
assert int ( state . state ) == 3
2020-09-12 12:20:21 +00:00
assert state . attributes [ ATTR_ICON ] == " mdi:greater "
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
state = hass . states . get ( " sensor.test " )
2020-10-01 20:11:11 +00:00
assert int ( state . state ) == 3
2020-09-12 12:20:21 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-09-10 18:50:11 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test " : {
2020-09-12 12:20:21 +00:00
" value_template " : " {{ ((states.sensor.test.state or 0) | int) + 1 }} " ,
" icon_template " : " { % i f ((states.sensor.test.state or 0) | int) > 3 % }mdi:greater { % e lse % }mdi:less { % e ndif % } " ,
" entity_picture_template " : " { % i f ((states.sensor.test.state or 0) | int) >= 1 % }bigpic { % e lse % }smallpic { % e ndif % } " ,
2020-09-10 18:50:11 +00:00
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2021-09-04 05:56:12 +00:00
async def test_self_referencing_sensor_with_icon_and_picture_entity_loop (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test a self referencing sensor loop forevers with a valid self referencing icon. """
2020-09-10 18:50:11 +00:00
assert len ( hass . states . async_all ( ) ) == 1
await hass . async_block_till_done ( )
2020-09-12 12:20:21 +00:00
await hass . async_block_till_done ( )
2021-09-04 14:09:55 +00:00
assert " Template loop detected " in caplog_setup_text
2020-09-10 18:50:11 +00:00
2020-09-12 12:20:21 +00:00
state = hass . states . get ( " sensor.test " )
2020-10-01 20:11:11 +00:00
assert int ( state . state ) == 4
2020-09-12 12:20:21 +00:00
assert state . attributes [ ATTR_ICON ] == " mdi:less "
assert state . attributes [ ATTR_ENTITY_PICTURE ] == " bigpic "
2020-09-10 18:50:11 +00:00
await hass . async_block_till_done ( )
2020-10-01 20:11:11 +00:00
assert int ( state . state ) == 4
2020-09-10 18:50:11 +00:00
2020-09-12 12:20:21 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2020-09-12 12:20:21 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test " : {
" value_template " : " {{ 1 }} " ,
" entity_picture_template " : " {{ ((states.sensor.test.attributes[ ' entity_picture ' ] or 0) | int) + 1 }} " ,
2024-11-06 03:36:26 +00:00
" friendly_name_template " : " {{ ((states.sensor.test.attributes[ ' friendly_name ' ] or 0) | int) + 1 }} " ,
2020-09-12 12:20:21 +00:00
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-02-16 13:08:03 +00:00
async def test_self_referencing_entity_picture_loop (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test a self referencing sensor does not loop forever with a looping self referencing entity picture. """
2020-09-12 12:20:21 +00:00
assert len ( hass . states . async_all ( ) ) == 1
2020-10-01 19:39:44 +00:00
next_time = dt_util . utcnow ( ) + timedelta ( seconds = 1.2 )
with patch (
2024-03-20 23:49:37 +00:00
" homeassistant.helpers.ratelimit.time.time " , return_value = next_time . timestamp ( )
2020-10-01 19:39:44 +00:00
) :
async_fire_time_changed ( hass , next_time )
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
2020-09-10 18:50:11 +00:00
2021-09-04 14:09:55 +00:00
assert " Template loop detected " in caplog_setup_text
2020-09-12 12:20:21 +00:00
state = hass . states . get ( " sensor.test " )
assert int ( state . state ) == 1
2024-11-06 03:36:26 +00:00
assert state . attributes [ ATTR_ENTITY_PICTURE ] == " 3 "
assert state . attributes [ ATTR_FRIENDLY_NAME ] == " 3 "
2020-09-12 12:20:21 +00:00
await hass . async_block_till_done ( )
assert int ( state . state ) == 1
2023-02-08 18:10:53 +00:00
async def test_self_referencing_icon_with_no_loop (
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
) - > None :
2020-09-12 12:20:21 +00:00
""" Test a self referencing icon that does not loop. """
hass . states . async_set ( " sensor.heartworm_high_80 " , 10 )
hass . states . async_set ( " sensor.heartworm_low_57 " , 10 )
hass . states . async_set ( " sensor.heartworm_avg_64 " , 10 )
hass . states . async_set ( " sensor.heartworm_avg_57 " , 10 )
value_template_str = """ { % i f (states.sensor.heartworm_high_80.state|int >= 10) and (states.sensor.heartworm_low_57.state|int >= 10) % }
extreme
{ % elif ( states . sensor . heartworm_avg_64 . state | int > = 30 ) % }
high
{ % elif ( states . sensor . heartworm_avg_64 . state | int > = 14 ) % }
moderate
{ % elif ( states . sensor . heartworm_avg_64 . state | int > = 5 ) % }
slight
{ % elif ( states . sensor . heartworm_avg_57 . state | int > = 5 ) % }
marginal
{ % elif ( states . sensor . heartworm_avg_57 . state | int < 5 ) % }
none
{ % endif % } """
icon_template_str = """ { % i f is_state( ' sensor.heartworm_risk ' , " extreme " ) % }
mdi : hazard - lights
{ % elif is_state ( ' sensor.heartworm_risk ' , " high " ) % }
mdi : triangle - outline
{ % elif is_state ( ' sensor.heartworm_risk ' , " moderate " ) % }
mdi : alert - circle - outline
{ % elif is_state ( ' sensor.heartworm_risk ' , " slight " ) % }
mdi : exclamation
{ % elif is_state ( ' sensor.heartworm_risk ' , " marginal " ) % }
mdi : heart
{ % elif is_state ( ' sensor.heartworm_risk ' , " none " ) % }
mdi : snowflake
{ % endif % } """
await async_setup_component (
hass ,
2020-10-05 12:52:31 +00:00
sensor . DOMAIN ,
2020-09-12 12:20:21 +00:00
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" heartworm_risk " : {
" value_template " : value_template_str ,
" icon_template " : icon_template_str ,
} ,
} ,
}
} ,
)
await hass . async_block_till_done ( )
await hass . async_start ( )
await hass . async_block_till_done ( )
assert len ( hass . states . async_all ( ) ) == 5
hass . states . async_set ( " sensor.heartworm_high_80 " , 10 )
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
assert " Template loop detected " not in caplog . text
state = hass . states . get ( " sensor.heartworm_risk " )
assert state . state == " extreme "
assert state . attributes [ ATTR_ICON ] == " mdi:hazard-lights "
await hass . async_block_till_done ( )
assert state . state == " extreme "
assert state . attributes [ ATTR_ICON ] == " mdi:hazard-lights "
assert " Template loop detected " not in caplog . text
2020-10-26 15:08:57 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" friendly_name_template " : " {{ states.sensor.test_state.state }} " ,
}
} ,
}
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_duplicate_templates ( hass : HomeAssistant ) - > None :
2020-10-26 15:08:57 +00:00
""" Test template entity where the value and friendly name as the same template. """
hass . states . async_set ( " sensor.test_state " , " Abc " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
state = hass . states . get ( TEST_NAME )
2020-10-26 15:08:57 +00:00
assert state . attributes [ " friendly_name " ] == " Abc "
assert state . state == " Abc "
hass . states . async_set ( " sensor.test_state " , " Def " )
await hass . async_block_till_done ( )
2021-09-04 05:56:12 +00:00
state = hass . states . get ( TEST_NAME )
2020-10-26 15:08:57 +00:00
assert state . attributes [ " friendly_name " ] == " Def "
assert state . state == " Def "
2021-03-29 16:57:51 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 2 , " template " ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2021-03-29 16:57:51 +00:00
{
" template " : [
{ " invalid " : " config " } ,
2021-04-02 23:57:16 +00:00
# Config after invalid should still be set up
2021-03-29 16:57:51 +00:00
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensors " : {
" hello " : {
" friendly_name " : " Hello Name " ,
2021-04-02 23:57:16 +00:00
" unique_id " : " hello_name-id " ,
2021-03-29 16:57:51 +00:00
" device_class " : " battery " ,
" unit_of_measurement " : " % " ,
" value_template " : " {{ trigger.event.data.beer }} " ,
" entity_picture_template " : " {{ ' /local/dogs.png ' }} " ,
" icon_template " : " {{ ' mdi:pirate ' }} " ,
" attribute_templates " : {
" plus_one " : " {{ trigger.event.data.beer + 1 }} "
} ,
2021-04-02 17:24:38 +00:00
} ,
} ,
2021-04-02 23:57:16 +00:00
" sensor " : [
{
" name " : " via list " ,
" unique_id " : " via_list-id " ,
" device_class " : " battery " ,
" unit_of_measurement " : " % " ,
2021-09-03 07:02:45 +00:00
" availability " : " {{ True }} " ,
2021-04-02 23:57:16 +00:00
" state " : " {{ trigger.event.data.beer + 1 }} " ,
" picture " : " {{ ' /local/dogs.png ' }} " ,
" icon " : " {{ ' mdi:pirate ' }} " ,
" attributes " : {
" plus_one " : " {{ trigger.event.data.beer + 1 }} "
} ,
2021-06-23 21:37:04 +00:00
" state_class " : " measurement " ,
2021-04-02 23:57:16 +00:00
}
] ,
2021-04-02 17:24:38 +00:00
} ,
{
" trigger " : [ ] ,
" sensors " : {
" bare_minimum " : {
" value_template " : " {{ trigger.event.data.beer }} "
} ,
2021-03-29 16:57:51 +00:00
} ,
} ,
] ,
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-03-01 15:04:40 +00:00
async def test_trigger_entity (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , entity_registry : er . EntityRegistry
2023-03-01 15:04:40 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test trigger entity works. """
2021-04-02 23:57:16 +00:00
state = hass . states . get ( " sensor.hello_name " )
2021-03-29 16:57:51 +00:00
assert state is not None
assert state . state == STATE_UNKNOWN
2021-04-02 17:24:38 +00:00
state = hass . states . get ( " sensor.bare_minimum " )
assert state is not None
assert state . state == STATE_UNKNOWN
2021-03-29 16:57:51 +00:00
context = Context ( )
hass . bus . async_fire ( " test_event " , { " beer " : 2 } , context = context )
await hass . async_block_till_done ( )
2021-04-02 23:57:16 +00:00
state = hass . states . get ( " sensor.hello_name " )
2021-03-29 16:57:51 +00:00
assert state . state == " 2 "
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
2023-03-01 15:04:40 +00:00
assert len ( entity_registry . entities ) == 2
2021-04-02 23:57:16 +00:00
assert (
2023-03-01 15:04:40 +00:00
entity_registry . entities [ " sensor.hello_name " ] . unique_id
2021-04-02 23:57:16 +00:00
== " listening-test-event-hello_name-id "
)
2021-03-29 16:57:51 +00:00
assert (
2023-03-01 15:04:40 +00:00
entity_registry . entities [ " sensor.via_list " ] . unique_id
2021-04-02 23:57:16 +00:00
== " listening-test-event-via_list-id "
2021-03-29 16:57:51 +00:00
)
2021-04-02 23:57:16 +00:00
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 " ) == " % "
2021-06-23 21:37:04 +00:00
assert state . attributes . get ( " state_class " ) == " measurement "
2021-04-02 23:57:16 +00:00
assert state . context is context
2021-03-29 16:57:51 +00:00
2024-09-11 07:36:49 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , template . DOMAIN ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" condition " : [
{
" condition " : " template " ,
" value_template " : " {{ trigger.event.data.beer >= 42 }} " ,
}
] ,
" sensor " : [
{
" name " : " Enough Name " ,
" unique_id " : " enough-id " ,
" state " : " You had enough Beer. " ,
}
] ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_trigger_conditional_entity ( hass : HomeAssistant ) - > None :
2024-09-11 07:36:49 +00:00
""" Test conditional trigger entity works. """
state = hass . states . get ( " sensor.enough_name " )
assert state is not None
assert state . state == STATE_UNKNOWN
hass . bus . async_fire ( " test_event " , { " beer " : 2 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.enough_name " )
assert state . state == STATE_UNKNOWN
hass . bus . async_fire ( " test_event " , { " beer " : 42 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.enough_name " )
assert state . state == " You had enough Beer. "
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , template . DOMAIN ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" condition " : [
{
" condition " : " template " ,
" value_template " : " {{ trigger.event.data.beer / 0 == ' narf ' }} " ,
}
] ,
" sensor " : [
{
" name " : " Enough Name " ,
" unique_id " : " enough-id " ,
" state " : " You had enough Beer. " ,
}
] ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2024-09-11 07:36:49 +00:00
async def test_trigger_conditional_entity_evaluation_error (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
2024-09-11 07:36:49 +00:00
) - > None :
""" Test trigger entity is not updated when condition evaluation fails. """
hass . bus . async_fire ( " test_event " , { " beer " : 1 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.enough_name " )
assert state is not None
assert state . state == STATE_UNKNOWN
assert " Error evaluating condition in ' template entity ' " in caplog . text
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 0 , template . DOMAIN ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" condition " : [
{ " condition " : " template " , " value_template " : " {{ invalid " }
] ,
" sensor " : [
{
" name " : " Will Not Exist Name " ,
" state " : " Unimportant " ,
}
] ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2024-09-11 07:36:49 +00:00
async def test_trigger_conditional_entity_invalid_condition (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant ,
2024-09-11 07:36:49 +00:00
) - > None :
""" Test trigger entity is not created when condition is invalid. """
state = hass . states . get ( " sensor.will_not_exist_name " )
assert state is None
2023-09-11 12:33:43 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensors " : {
" hello " : {
" friendly_name " : " Hello Name " ,
" value_template " : " {{ trigger.event.data.beer }} " ,
" entity_picture_template " : " {{ ' /local/dogs.png ' }} " ,
" icon_template " : " {{ ' mdi:pirate ' }} " ,
" attribute_templates " : {
" last " : " {{ now().strftime( ' % D %X ' )}} " ,
" history_1 " : " {{ this.attributes.last|default( ' Not yet set ' )}} " ,
} ,
} ,
} ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_trigger_entity_runs_once ( hass : HomeAssistant ) - > None :
2023-09-11 12:33:43 +00:00
""" Test trigger entity handles a trigger once. """
state = hass . states . get ( " sensor.hello_name " )
assert state is not None
assert state . state == STATE_UNKNOWN
hass . bus . async_fire ( " test_event " , { " beer " : 2 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.hello_name " )
assert state . state == " 2 "
assert state . attributes . get ( " last " ) == ANY
assert state . attributes . get ( " history_1 " ) == " Not yet set "
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2021-03-29 16:57:51 +00:00
{
" template " : {
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensors " : {
" hello " : {
" unique_id " : " no-base-id " ,
" friendly_name " : " Hello " ,
" value_template " : " {{ non_existing + 1 }} " ,
}
} ,
} ,
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-03-01 15:04:40 +00:00
async def test_trigger_entity_render_error (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , entity_registry : er . EntityRegistry
2023-03-01 15:04:40 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test trigger entity handles render error. """
2021-03-29 16:57:51 +00:00
state = hass . states . get ( " sensor.hello " )
assert state is not None
assert state . state == STATE_UNKNOWN
context = Context ( )
hass . bus . async_fire ( " test_event " , { " beer " : 2 } , context = context )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.hello " )
assert state . state == STATE_UNAVAILABLE
2023-03-01 15:04:40 +00:00
assert len ( entity_registry . entities ) == 1
assert entity_registry . entities [ " sensor.hello " ] . unique_id == " no-base-id "
2021-03-29 16:57:51 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 0 , sensor . DOMAIN ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2021-03-29 16:57:51 +00:00
{
" sensor " : {
" platform " : " template " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " {{ states.sensor.test_state.state }} " ,
" friendly_name_template " : " {{ states.sensor.test_state.state }} " ,
}
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
2023-02-16 13:08:03 +00:00
async def test_trigger_not_allowed_platform_config (
2024-09-26 12:00:52 +00:00
hass : HomeAssistant , caplog_setup_text
2023-02-16 13:08:03 +00:00
) - > None :
2021-09-04 05:56:12 +00:00
""" Test we throw a helpful warning if a trigger is configured in platform config. """
state = hass . states . get ( TEST_NAME )
2021-03-29 16:57:51 +00:00
assert state is None
assert (
" You can only add triggers to template entities if they are defined under `template:`. "
2021-09-04 14:09:55 +00:00
in caplog_setup_text
2021-03-29 16:57:51 +00:00
)
2021-06-23 21:37:04 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize (
" config " ,
[
2021-06-23 21:37:04 +00:00
{
" template " : {
" sensor " : {
" name " : " top-level " ,
" device_class " : " battery " ,
" state_class " : " measurement " ,
" state " : " 5 " ,
" unit_of_measurement " : " % " ,
} ,
} ,
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_config_top_level ( hass : HomeAssistant ) - > None :
2021-09-04 05:56:12 +00:00
""" Test unique_id option only creates one sensor per id. """
2021-06-23 21:37:04 +00:00
assert len ( hass . states . async_all ( ) ) == 1
state = hass . states . get ( " sensor.top_level " )
assert state is not None
assert state . state == " 5 "
assert state . attributes [ " device_class " ] == " battery "
assert state . attributes [ " state_class " ] == " measurement "
2021-09-03 07:02:45 +00:00
2023-02-08 18:10:53 +00:00
async def test_trigger_entity_available ( hass : HomeAssistant ) - > None :
2021-09-03 07:02:45 +00:00
""" Test trigger entity availability works. """
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensor " : [
{
" name " : " Maybe Available " ,
" availability " : " {{ trigger and trigger.event.data.beer == 2 }} " ,
" state " : " {{ trigger.event.data.beer }} " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
# Sensors are unknown if never triggered
state = hass . states . get ( " sensor.maybe_available " )
assert state is not None
assert state . state == STATE_UNKNOWN
hass . bus . async_fire ( " test_event " , { " beer " : 2 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.maybe_available " )
assert state . state == " 2 "
hass . bus . async_fire ( " test_event " , { " beer " : 1 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.maybe_available " )
assert state . state == " unavailable "
2021-12-09 10:43:48 +00:00
2023-02-08 18:10:53 +00:00
async def test_trigger_entity_device_class_parsing_works ( hass : HomeAssistant ) - > None :
2021-12-09 10:43:48 +00:00
""" Test trigger entity device class parsing works. """
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensor " : [
{
" name " : " Date entity " ,
" state " : " {{ now().date() }} " ,
" device_class " : " date " ,
} ,
{
" name " : " Timestamp entity " ,
" state " : " {{ now() }} " ,
" device_class " : " timestamp " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
2022-03-20 09:25:15 +00:00
# State of timestamp sensors are always in UTC
now = dt_util . utcnow ( )
2021-12-09 10:43:48 +00:00
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
hass . bus . async_fire ( " test_event " )
await hass . async_block_till_done ( )
date_state = hass . states . get ( " sensor.date_entity " )
assert date_state is not None
assert date_state . state == now . date ( ) . isoformat ( )
ts_state = hass . states . get ( " sensor.timestamp_entity " )
assert ts_state is not None
assert ts_state . state == now . isoformat ( timespec = " seconds " )
2023-02-08 18:10:53 +00:00
async def test_trigger_entity_device_class_errors_works ( hass : HomeAssistant ) - > None :
2021-12-09 10:43:48 +00:00
""" Test trigger entity device class errors works. """
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensor " : [
{
" name " : " Date entity " ,
" state " : " invalid " ,
" device_class " : " date " ,
} ,
{
" name " : " Timestamp entity " ,
" state " : " invalid " ,
" device_class " : " timestamp " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
now = dt_util . now ( )
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
hass . bus . async_fire ( " test_event " )
await hass . async_block_till_done ( )
date_state = hass . states . get ( " sensor.date_entity " )
assert date_state is not None
assert date_state . state == STATE_UNKNOWN
ts_state = hass . states . get ( " sensor.timestamp_entity " )
assert ts_state is not None
assert ts_state . state == STATE_UNKNOWN
2024-01-25 10:12:03 +00:00
async def test_entity_last_reset_total_increasing (
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
) - > None :
""" Test last_reset is disallowed for total_increasing state_class. """
# State of timestamp sensors are always in UTC
now = dt_util . utcnow ( )
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" sensor " : [
{
" name " : " TotalIncreasing entity " ,
" state " : " {{ 0 }} " ,
" state_class " : " total_increasing " ,
" last_reset " : " {{ today_at( ' 00:00:00 ' )}} " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
totalincreasing_state = hass . states . get ( " sensor.totalincreasing_entity " )
assert totalincreasing_state is None
assert (
" last_reset is only valid for template sensors with state_class ' total ' "
in caplog . text
)
async def test_entity_last_reset_setup (
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
) - > None :
""" Test last_reset works for template sensors. """
# State of timestamp sensors are always in UTC
now = dt_util . utcnow ( )
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" sensor " : [
{
" name " : " Total entity " ,
" state " : " {{ states( ' sensor.test_state ' ) | int(0) + 1 }} " ,
" state_class " : " total " ,
" last_reset " : " {{ now() }} " ,
} ,
{
" name " : " Static last_reset entity " ,
" state " : " {{ states( ' sensor.test_state ' ) | int(0) }} " ,
" state_class " : " total " ,
" last_reset " : " 2023-01-01T00:00:00 " ,
} ,
] ,
} ,
{
" trigger " : {
" platform " : " state " ,
" entity_id " : [
" sensor.test_state " ,
] ,
} ,
" sensor " : {
" name " : " Total trigger entity " ,
" state " : " {{ states( ' sensor.test_state ' ) | int(0) + 2 }} " ,
" state_class " : " total " ,
" last_reset " : " {{ as_datetime( ' 2023-01-01 ' ) }} " ,
} ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
# Trigger update
hass . states . async_set ( " sensor.test_state " , " 0 " )
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
static_state = hass . states . get ( " sensor.static_last_reset_entity " )
assert static_state is not None
assert static_state . state == " 0 "
assert static_state . attributes . get ( " state_class " ) == " total "
assert (
static_state . attributes . get ( " last_reset " )
== datetime ( 2023 , 1 , 1 , 0 , 0 , 0 ) . isoformat ( )
)
total_state = hass . states . get ( " sensor.total_entity " )
assert total_state is not None
assert total_state . state == " 1 "
assert total_state . attributes . get ( " state_class " ) == " total "
assert total_state . attributes . get ( " last_reset " ) == now . isoformat ( )
total_trigger_state = hass . states . get ( " sensor.total_trigger_entity " )
assert total_trigger_state is not None
assert total_trigger_state . state == " 2 "
assert total_trigger_state . attributes . get ( " state_class " ) == " total "
assert (
total_trigger_state . attributes . get ( " last_reset " )
== datetime ( 2023 , 1 , 1 ) . isoformat ( )
)
async def test_entity_last_reset_static_value ( hass : HomeAssistant ) - > None :
""" Test static last_reset marked as static_rendered. """
tse = TriggerSensorEntity (
hass ,
None ,
{
" name " : Template ( " Static last_reset entity " , hass ) ,
" state " : Template ( " {{ states( ' sensor.test_state ' ) | int(0) }} " , hass ) ,
" state_class " : " total " ,
" last_reset " : Template ( " 2023-01-01T00:00:00 " , hass ) ,
} ,
)
assert " last_reset " in tse . _static_rendered
async def test_entity_last_reset_parsing (
hass : HomeAssistant , caplog : pytest . LogCaptureFixture
) - > None :
""" Test last_reset works for template sensors. """
# State of timestamp sensors are always in UTC
now = dt_util . utcnow ( )
2024-03-25 23:02:16 +00:00
with (
patch (
" homeassistant.components.template.sensor._LOGGER.warning "
) as mocked_warning ,
patch (
" homeassistant.components.template.template_entity._LOGGER.error "
) as mocked_error ,
patch ( " homeassistant.util.dt.now " , return_value = now ) ,
) :
2024-01-25 10:12:03 +00:00
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" sensor " : [
{
" name " : " Total entity " ,
" state " : " {{ states( ' sensor.test_state ' ) | int(0) + 1 }} " ,
" state_class " : " total " ,
" last_reset " : " {{ ' not a datetime ' }} " ,
} ,
] ,
} ,
{
" trigger " : {
" platform " : " state " ,
" entity_id " : [
" sensor.test_state " ,
] ,
} ,
" sensor " : {
" name " : " Total trigger entity " ,
" state " : " {{ states( ' sensor.test_state ' ) | int(0) + 2 }} " ,
" state_class " : " total " ,
" last_reset " : " {{ ' not a datetime ' }} " ,
} ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
# Trigger update
hass . states . async_set ( " sensor.test_state " , " 0 " )
await hass . async_block_till_done ( )
await hass . async_block_till_done ( )
# Trigger based datetime parsing warning:
mocked_warning . assert_called_once_with (
" %s rendered invalid timestamp for last_reset attribute: %s " ,
" sensor.total_trigger_entity " ,
" not a datetime " ,
)
# State based datetime parsing error
mocked_error . assert_called_once ( )
args , _ = mocked_error . call_args
assert len ( args ) == 6
assert args [ 0 ] == (
" Error validating template result ' %s ' "
" from template ' %s ' "
" for attribute ' %s ' in entity %s "
" validation message ' %s ' "
)
assert args [ 1 ] == " not a datetime "
assert args [ 3 ] == " _attr_last_reset "
assert args [ 4 ] == " sensor.total_entity "
assert args [ 5 ] == " Invalid datetime specified: not a datetime "
2023-02-08 18:10:53 +00:00
async def test_entity_device_class_parsing_works ( hass : HomeAssistant ) - > None :
2021-12-09 10:43:48 +00:00
""" Test entity device class parsing works. """
2022-03-20 09:25:15 +00:00
# State of timestamp sensors are always in UTC
now = dt_util . utcnow ( )
2021-12-09 10:43:48 +00:00
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" sensor " : [
{
" name " : " Date entity " ,
" state " : " {{ now().date() }} " ,
" device_class " : " date " ,
} ,
{
" name " : " Timestamp entity " ,
" state " : " {{ now() }} " ,
" device_class " : " timestamp " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
date_state = hass . states . get ( " sensor.date_entity " )
assert date_state is not None
assert date_state . state == now . date ( ) . isoformat ( )
ts_state = hass . states . get ( " sensor.timestamp_entity " )
assert ts_state is not None
assert ts_state . state == now . isoformat ( timespec = " seconds " )
2023-02-08 18:10:53 +00:00
async def test_entity_device_class_errors_works ( hass : HomeAssistant ) - > None :
2021-12-09 10:43:48 +00:00
""" Test entity device class errors works. """
assert await async_setup_component (
hass ,
" template " ,
{
" template " : [
{
" sensor " : [
{
" name " : " Date entity " ,
" state " : " invalid " ,
" device_class " : " date " ,
} ,
{
" name " : " Timestamp entity " ,
" state " : " invalid " ,
" device_class " : " timestamp " ,
} ,
] ,
} ,
] ,
} ,
)
await hass . async_block_till_done ( )
now = dt_util . now ( )
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
hass . bus . async_fire ( " test_event " )
await hass . async_block_till_done ( )
date_state = hass . states . get ( " sensor.date_entity " )
assert date_state is not None
assert date_state . state == STATE_UNKNOWN
ts_state = hass . states . get ( " sensor.timestamp_entity " )
assert ts_state is not None
assert ts_state . state == STATE_UNKNOWN
2022-04-21 16:32:18 +00:00
2023-02-15 13:09:50 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
2022-04-21 16:32:18 +00:00
@pytest.mark.parametrize (
" config " ,
[
{
" template " : {
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" sensor " : {
" name " : " test " ,
" state " : " {{ trigger.event.data.beer }} " ,
" picture " : " {{ ' /local/dogs.png ' }} " ,
" icon " : " {{ ' mdi:pirate ' }} " ,
" attributes " : {
" plus_one " : " {{ trigger.event.data.beer + 1 }} " ,
" another " : " {{ trigger.event.data.uno_mas or 1 }} " ,
} ,
} ,
} ,
} ,
] ,
)
@pytest.mark.parametrize (
2023-02-15 21:46:03 +00:00
( " restored_state " , " restored_native_value " , " initial_state " , " initial_attributes " ) ,
2022-04-21 16:32:18 +00:00
[
# the native value should be used, not the state
( " dog " , 10 , " 10 " , [ " entity_picture " , " icon " , " plus_one " ] ) ,
( STATE_UNAVAILABLE , 10 , STATE_UNKNOWN , [ ] ) ,
( STATE_UNKNOWN , 10 , STATE_UNKNOWN , [ ] ) ,
] ,
)
async def test_trigger_entity_restore_state (
2023-02-16 13:08:03 +00:00
hass : HomeAssistant ,
2022-04-21 16:32:18 +00:00
count ,
domain ,
config ,
restored_state ,
restored_native_value ,
initial_state ,
initial_attributes ,
2023-02-16 13:08:03 +00:00
) - > None :
2022-04-21 16:32:18 +00:00
""" Test restoring trigger template binary sensor. """
restored_attributes = {
" entity_picture " : " /local/cats.png " ,
" icon " : " mdi:ship " ,
" plus_one " : 55 ,
}
fake_state = State (
" sensor.test " ,
restored_state ,
restored_attributes ,
)
fake_extra_data = {
" native_value " : restored_native_value ,
" native_unit_of_measurement " : None ,
}
mock_restore_cache_with_extra_data ( hass , ( ( fake_state , fake_extra_data ) , ) )
with assert_setup_component ( count , domain ) :
assert await async_setup_component (
hass ,
domain ,
config ,
)
await hass . async_block_till_done ( )
await hass . async_start ( )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.test " )
assert state . state == initial_state
2024-06-12 14:44:29 +00:00
for attr , value in restored_attributes . items ( ) :
2022-04-21 16:32:18 +00:00
if attr in initial_attributes :
2024-06-12 14:44:29 +00:00
assert state . attributes [ attr ] == value
2022-04-21 16:32:18 +00:00
else :
assert attr not in state . attributes
assert " another " not in state . attributes
hass . bus . async_fire ( " test_event " , { " beer " : 2 } )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.test " )
assert state . state == " 2 "
assert state . attributes [ " icon " ] == " mdi:pirate "
assert state . attributes [ " entity_picture " ] == " /local/dogs.png "
assert state . attributes [ " plus_one " ] == 3
assert state . attributes [ " another " ] == 1
2023-09-02 23:19:45 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , " template " ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" action " : [
{
" variables " : {
" my_variable " : " {{ trigger.event.data.beer + 1 }} "
} ,
} ,
2024-03-16 22:37:24 +00:00
{ " event " : " test_event2 " , " event_data " : { " hello " : " world " } } ,
2023-09-02 23:19:45 +00:00
] ,
" sensor " : [
{
" name " : " Hello Name " ,
" state " : " {{ my_variable + 1 }} " ,
}
] ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_trigger_action ( hass : HomeAssistant ) - > None :
2023-09-02 23:19:45 +00:00
""" Test trigger entity with an action works. """
2024-03-16 22:37:24 +00:00
event = " test_event2 "
context = Context ( )
events = async_capture_events ( hass , event )
2023-09-02 23:19:45 +00:00
state = hass . states . get ( " sensor.hello_name " )
assert state is not None
assert state . state == STATE_UNKNOWN
context = Context ( )
hass . bus . async_fire ( " test_event " , { " beer " : 1 } , context = context )
await hass . async_block_till_done ( )
state = hass . states . get ( " sensor.hello_name " )
assert state . state == " 3 "
assert state . context is context
2024-03-16 22:37:24 +00:00
assert len ( events ) == 1
assert events [ 0 ] . context . parent_id == context . id
2024-06-22 10:45:06 +00:00
2024-09-11 07:36:49 +00:00
@pytest.mark.parametrize ( ( " count " , " domain " ) , [ ( 1 , template . DOMAIN ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" template " : [
{
" unique_id " : " listening-test-event " ,
" trigger " : { " platform " : " event " , " event_type " : " test_event " } ,
" condition " : [
{
" condition " : " template " ,
" value_template " : " {{ trigger.event.data.beer >= 42 }} " ,
}
] ,
" action " : [
{ " event " : " test_event_by_action " } ,
] ,
" sensor " : [
{
" name " : " Not That Important " ,
" state " : " Really not. " ,
}
] ,
} ,
] ,
} ,
] ,
)
2024-09-26 12:00:52 +00:00
@pytest.mark.usefixtures ( " start_ha " )
async def test_trigger_conditional_action ( hass : HomeAssistant ) - > None :
2024-09-11 07:36:49 +00:00
""" Test conditional trigger entity with an action works. """
event = " test_event_by_action "
events = async_capture_events ( hass , event )
hass . bus . async_fire ( " test_event " , { " beer " : 1 } )
await hass . async_block_till_done ( )
assert len ( events ) == 0
hass . bus . async_fire ( " test_event " , { " beer " : 42 } )
await hass . async_block_till_done ( )
assert len ( events ) == 1
2024-06-22 13:59:46 +00:00
async def test_device_id (
hass : HomeAssistant ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2024-06-22 10:45:06 +00:00
""" Test for device for Template. """
device_config_entry = MockConfigEntry ( )
device_config_entry . add_to_hass ( hass )
device_entry = device_registry . async_get_or_create (
config_entry_id = device_config_entry . entry_id ,
identifiers = { ( " sensor " , " identifier_test " ) } ,
connections = { ( " mac " , " 30:31:32:33:34:35 " ) } ,
)
await hass . async_block_till_done ( )
assert device_entry is not None
assert device_entry . id is not None
template_config_entry = MockConfigEntry (
data = { } ,
domain = template . DOMAIN ,
options = {
" name " : " My template " ,
" state " : " {{ 10}} " ,
" template_type " : " sensor " ,
" device_id " : device_entry . id ,
} ,
title = " My template " ,
)
template_config_entry . add_to_hass ( hass )
assert await hass . config_entries . async_setup ( template_config_entry . entry_id )
await hass . async_block_till_done ( )
template_entity = entity_registry . async_get ( " sensor.my_template " )
assert template_entity is not None
assert template_entity . device_id == device_entry . id