2016-03-09 09:25:50 +00:00
""" The test for the Template sensor platform. """
2020-08-09 02:34:14 +00:00
from asyncio import Event
2020-10-01 19:39:44 +00:00
from datetime import timedelta
2021-01-01 21:31:56 +00:00
from unittest . mock import patch
2020-08-09 02:34:14 +00:00
2021-02-11 16:36:19 +00:00
import pytest
2020-08-09 02:34:14 +00:00
from homeassistant . bootstrap import async_from_config_dict
2020-10-05 12:52:31 +00:00
from homeassistant . components import sensor
2019-12-08 20:05:08 +00:00
from homeassistant . const import (
2020-09-12 12:20:21 +00:00
ATTR_ENTITY_PICTURE ,
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
)
2022-04-21 16:32:18 +00:00
from homeassistant . core import Context , CoreState , State , callback
2021-03-29 16:57:51 +00:00
from homeassistant . helpers import entity_registry
2022-03-25 22:22:58 +00:00
from homeassistant . helpers . entity_component import async_update_entity
2020-08-25 22:20:04 +00:00
from homeassistant . helpers . template import Template
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 (
assert_setup_component ,
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@pytest.mark.parametrize (
" config " ,
[
{
" sensor " : {
" platform " : " template " ,
" sensors " : {
" test_template_sensor " : {
" value_template " : " It {{ states.sensor.test_state.state }}. "
}
} ,
} ,
} ,
] ,
)
async def test_template_legacy ( hass , start_ha ) :
""" 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
} ,
] ,
)
async def test_icon_template ( hass , start_ha ) :
""" 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
} ,
] ,
)
async def test_entity_picture_template ( hass , start_ha ) :
""" 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@pytest.mark.parametrize (
2021-10-20 21:53:06 +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
) ,
] ,
)
2021-10-20 21:53:06 +00:00
async def test_friendly_name_template ( hass , attribute , expected , start_ha ) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 0 , sensor . DOMAIN ) ] )
@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
} ,
] ,
)
async def test_template_syntax_error ( hass , start_ha ) :
""" 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
} ,
] ,
)
async def test_template_attribute_missing ( hass , start_ha ) :
""" 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
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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 }} "
} ,
} ,
} ,
} ,
] ,
)
async def test_setup_valid_device_class ( hass , start_ha ) :
""" Test setup with valid device_class. """
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 ] )
2020-08-09 02:34:14 +00:00
async def test_creating_sensor_loads_group ( hass ) :
""" Test setting up template sensor loads group component first. """
order = [ ]
after_dep_event = Event ( )
async def async_setup_group ( hass , config ) :
# 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 (
hass , config , async_add_entities , discovery_info = None
) :
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 )
with patch (
2020-08-27 11:56:20 +00:00
" homeassistant.components.group.async_setup " ,
new = async_setup_group ,
2020-08-09 02:34:14 +00:00
) , patch (
" homeassistant.components.template.sensor.async_setup_platform " ,
new = async_setup_template ,
) :
await async_from_config_dict (
{ " sensor " : { " platform " : " template " , " sensors " : { } } , " group " : { } } , hass
)
await hass . async_block_till_done ( )
assert order == [ " group " , " sensor.template " ]
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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 ' ) }} " ,
}
} ,
} ,
} ,
] ,
)
async def test_available_template_with_entities ( hass , start_ha ) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
2021-09-04 14:09:55 +00:00
async def test_invalid_attribute_template ( hass , caplog , start_ha , caplog_setup_text ) :
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
2020-08-20 13:06:41 +00:00
assert " test_attribute " in caplog . text
2019-09-01 16:12:55 +00:00
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
async def test_invalid_availability_template_keeps_component_available (
2021-09-04 14:09:55 +00:00
hass , start_ha , caplog_setup_text
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
2018-10-10 11:49:15 +00:00
async def test_no_template_match_all ( hass , caplog ) :
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 " )
2020-08-21 23:31:48 +00:00
hass . state = CoreState . not_running
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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
] ,
)
async def test_unique_id ( hass , start_ha ) :
""" 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
ent_reg = entity_registry . async_get ( hass )
assert len ( ent_reg . entities ) == 2
assert (
ent_reg . async_get_entity_id ( " sensor " , " template " , " group-id-sensor-id " )
is not None
)
assert (
ent_reg . async_get_entity_id ( " sensor " , " template " , " not-so-unique-anymore " )
is not None
)
2020-08-25 22:20:04 +00:00
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
async def test_sun_renders_once_per_sensor ( hass , start_ha ) :
""" 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 )
return " mocked "
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 ( )
assert hass . states . get ( " sensor.solar_angle " ) . state == " mocked "
assert hass . states . get ( " sensor.sunrise " ) . state == " mocked "
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
2022-06-27 06:59:29 +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
} ,
} ,
} ,
] ,
)
async def test_this_variable ( hass , start_ha ) :
""" 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
2022-05-03 14:43:44 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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 }} " } ,
} ,
} ,
} ,
] ,
)
async def test_this_variable_early_hass_not_running ( hass , config , count , domain ) :
""" 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 "
hass . state = CoreState . not_running
# 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 ( )
# Re-render icon, name, pciture + other templates now 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 " ,
}
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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 }} " } ,
} ,
} ,
} ,
] ,
)
async def test_this_variable_early_hass_running ( hass , config , count , domain ) :
""" 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
assert hass . state == CoreState . running
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 " ,
}
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
2021-09-04 14:09:55 +00:00
async def test_self_referencing_sensor_loop ( hass , start_ha , caplog_setup_text ) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
2021-09-04 14:09:55 +00:00
async def test_self_referencing_sensor_with_icon_loop (
hass , start_ha , caplog_setup_text
) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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
] ,
)
async def test_self_referencing_sensor_with_icon_and_picture_entity_loop (
2021-09-04 14:09:55 +00:00
hass , start_ha , caplog_setup_text
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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 }} " ,
} ,
} ,
}
} ,
2021-09-04 05:56:12 +00:00
] ,
)
2021-09-04 14:09:55 +00:00
async def test_self_referencing_entity_picture_loop ( hass , start_ha , caplog_setup_text ) :
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 (
" homeassistant.helpers.ratelimit.dt_util.utcnow " , return_value = next_time
) :
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
2020-10-06 22:05:52 +00:00
assert state . attributes [ ATTR_ENTITY_PICTURE ] == 2
2020-09-12 12:20:21 +00:00
await hass . async_block_till_done ( )
assert int ( state . state ) == 1
async def test_self_referencing_icon_with_no_loop ( hass , caplog ) :
""" 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , sensor . DOMAIN ) ] )
@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 }} " ,
}
} ,
}
} ,
] ,
)
async def test_duplicate_templates ( hass , start_ha ) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 2 , " template " ) ] )
@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
] ,
)
async def test_trigger_entity ( hass , start_ha ) :
""" 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
ent_reg = entity_registry . async_get ( hass )
2021-04-02 23:57:16 +00:00
assert len ( ent_reg . entities ) == 2
assert (
ent_reg . entities [ " sensor.hello_name " ] . unique_id
== " listening-test-event-hello_name-id "
)
2021-03-29 16:57:51 +00:00
assert (
2021-04-02 23:57:16 +00:00
ent_reg . entities [ " sensor.via_list " ] . unique_id
== " 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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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
] ,
)
async def test_trigger_entity_render_error ( hass , start_ha ) :
""" 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
ent_reg = entity_registry . async_get ( hass )
assert len ( ent_reg . entities ) == 1
assert ent_reg . entities [ " sensor.hello " ] . unique_id == " no-base-id "
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 0 , sensor . DOMAIN ) ] )
@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
] ,
)
2021-09-04 14:09:55 +00:00
async def test_trigger_not_allowed_platform_config ( hass , start_ha , caplog_setup_text ) :
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
2021-09-04 05:56:12 +00:00
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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
] ,
)
async def test_config_top_level ( hass , start_ha ) :
""" 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
async def test_trigger_entity_available ( hass ) :
""" 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
async def test_trigger_entity_device_class_parsing_works ( hass ) :
""" 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 " )
async def test_trigger_entity_device_class_errors_works ( hass ) :
""" 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
async def test_entity_device_class_parsing_works ( hass ) :
""" 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 " )
async def test_entity_device_class_errors_works ( hass ) :
""" 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
@pytest.mark.parametrize ( " count,domain " , [ ( 1 , " template " ) ] )
@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 (
" restored_state, restored_native_value, initial_state, initial_attributes " ,
[
# 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 (
hass ,
count ,
domain ,
config ,
restored_state ,
restored_native_value ,
initial_state ,
initial_attributes ,
) :
""" 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
for attr in restored_attributes :
if attr in initial_attributes :
assert state . attributes [ attr ] == restored_attributes [ attr ]
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