Subscribe to state change events only if the template has entities (#39188)
parent
68c0f770fe
commit
20398cc0a6
|
@ -484,12 +484,6 @@ class _TrackTemplateResultInfo:
|
|||
if self._info.exception:
|
||||
return True
|
||||
|
||||
# There are no entities in the template
|
||||
# to track so this template will
|
||||
# re-render on EVERY state change
|
||||
if not self._info.domains and not self._info.entities:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@callback
|
||||
|
|
|
@ -10,8 +10,10 @@ from homeassistant.const import (
|
|||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.core import CoreState
|
||||
from homeassistant.core import CoreState, callback
|
||||
from homeassistant.helpers.template import Template
|
||||
from homeassistant.setup import ATTR_COMPONENT, async_setup_component, setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import assert_setup_component, get_test_home_assistant
|
||||
|
||||
|
@ -694,3 +696,64 @@ async def test_unique_id(hass):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 1
|
||||
|
||||
|
||||
async def test_sun_renders_once_per_sensor(hass):
|
||||
"""Test sun change renders the template only once per sensor."""
|
||||
|
||||
now = dt_util.utcnow()
|
||||
hass.states.async_set(
|
||||
"sun.sun", "above_horizon", {"elevation": 45.3, "next_rising": now}
|
||||
)
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
"sensor",
|
||||
{
|
||||
"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') }}"
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
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') }}",
|
||||
}
|
||||
|
|
|
@ -39,7 +39,10 @@ async def test_if_fires_on_change_bool(hass, calls):
|
|||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {"platform": "template", "value_template": "{{ true }}"},
|
||||
"trigger": {
|
||||
"platform": "template",
|
||||
"value_template": "{{ states.test.entity.state and true }}",
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
|
@ -64,7 +67,10 @@ async def test_if_fires_on_change_str(hass, calls):
|
|||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {"platform": "template", "value_template": '{{ "true" }}'},
|
||||
"trigger": {
|
||||
"platform": "template",
|
||||
"value_template": '{{ states.test.entity.state and "true" }}',
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
|
@ -82,7 +88,10 @@ async def test_if_fires_on_change_str_crazy(hass, calls):
|
|||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {"platform": "template", "value_template": '{{ "TrUE" }}'},
|
||||
"trigger": {
|
||||
"platform": "template",
|
||||
"value_template": '{{ states.test.entity.state and "TrUE" }}',
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
|
@ -100,7 +109,10 @@ async def test_if_not_fires_on_change_bool(hass, calls):
|
|||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {"platform": "template", "value_template": "{{ false }}"},
|
||||
"trigger": {
|
||||
"platform": "template",
|
||||
"value_template": "{{ states.test.entity.state and false }}",
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
|
@ -178,7 +190,10 @@ async def test_if_fires_on_two_change(hass, calls):
|
|||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {"platform": "template", "value_template": "{{ true }}"},
|
||||
"trigger": {
|
||||
"platform": "template",
|
||||
"value_template": "{{ states.test.entity.state and true }}",
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
|
|
|
@ -542,12 +542,6 @@ async def test_track_template_error(hass, caplog):
|
|||
assert "lunch" not in caplog.text
|
||||
assert "TemplateAssertionError" not in caplog.text
|
||||
|
||||
hass.states.async_set("switch.not_exist", "on")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert "lunch" in caplog.text
|
||||
assert "TemplateAssertionError" in caplog.text
|
||||
|
||||
|
||||
async def test_track_template_result(hass):
|
||||
"""Test tracking template."""
|
||||
|
|
Loading…
Reference in New Issue