mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Ease code before adding color and temperature to light template (#30455)
* Split async_update * Use pytest parameters to avoid duplicate code * Fix UnboundLocalError * Test error rendering for template state Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
e18426051b
commit
13e6479b6e
@ -329,7 +329,7 @@ homeassistant/components/tado/* @michaelarnauts
|
|||||||
homeassistant/components/tahoma/* @philklei
|
homeassistant/components/tahoma/* @philklei
|
||||||
homeassistant/components/tautulli/* @ludeeus
|
homeassistant/components/tautulli/* @ludeeus
|
||||||
homeassistant/components/tellduslive/* @fredrike
|
homeassistant/components/tellduslive/* @fredrike
|
||||||
homeassistant/components/template/* @PhracturedBlue
|
homeassistant/components/template/* @PhracturedBlue @tetienne
|
||||||
homeassistant/components/tesla/* @zabuldon @alandtse
|
homeassistant/components/tesla/* @zabuldon @alandtse
|
||||||
homeassistant/components/tfiac/* @fredrike @mellado
|
homeassistant/components/tfiac/* @fredrike @mellado
|
||||||
homeassistant/components/thethingsnetwork/* @fabaff
|
homeassistant/components/thethingsnetwork/* @fabaff
|
||||||
|
@ -267,38 +267,10 @@ class LightTemplate(Light):
|
|||||||
self.async_schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the state from the template."""
|
"""Update from templates."""
|
||||||
if self._template is not None:
|
self.update_state()
|
||||||
try:
|
|
||||||
state = self._template.async_render().lower()
|
|
||||||
except TemplateError as ex:
|
|
||||||
_LOGGER.error(ex)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
if state in _VALID_STATES:
|
self.update_brightness()
|
||||||
self._state = state in ("true", STATE_ON)
|
|
||||||
else:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Received invalid light is_on state: %s. Expected: %s",
|
|
||||||
state,
|
|
||||||
", ".join(_VALID_STATES),
|
|
||||||
)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
if self._level_template is not None:
|
|
||||||
try:
|
|
||||||
brightness = self._level_template.async_render()
|
|
||||||
except TemplateError as ex:
|
|
||||||
_LOGGER.error(ex)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
if 0 <= int(brightness) <= 255:
|
|
||||||
self._brightness = int(brightness)
|
|
||||||
else:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Received invalid brightness : %s. Expected: 0-255", brightness
|
|
||||||
)
|
|
||||||
self._brightness = None
|
|
||||||
|
|
||||||
for property_name, template in (
|
for property_name, template in (
|
||||||
("_icon", self._icon_template),
|
("_icon", self._icon_template),
|
||||||
@ -335,3 +307,39 @@ class LightTemplate(Light):
|
|||||||
self._name,
|
self._name,
|
||||||
ex,
|
ex,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def update_brightness(self):
|
||||||
|
"""Update the brightness from the template."""
|
||||||
|
if self._level_template is not None:
|
||||||
|
try:
|
||||||
|
brightness = self._level_template.async_render()
|
||||||
|
if 0 <= int(brightness) <= 255:
|
||||||
|
self._brightness = int(brightness)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Received invalid brightness : %s. Expected: 0-255", brightness
|
||||||
|
)
|
||||||
|
self._brightness = None
|
||||||
|
except TemplateError as ex:
|
||||||
|
_LOGGER.error(ex)
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def update_state(self):
|
||||||
|
"""Update the state from the template."""
|
||||||
|
if self._template is not None:
|
||||||
|
try:
|
||||||
|
state = self._template.async_render().lower()
|
||||||
|
if state in _VALID_STATES:
|
||||||
|
self._state = state in ("true", STATE_ON)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Received invalid light is_on state: %s. Expected: %s",
|
||||||
|
state,
|
||||||
|
", ".join(_VALID_STATES),
|
||||||
|
)
|
||||||
|
self._state = None
|
||||||
|
except TemplateError as ex:
|
||||||
|
_LOGGER.error(ex)
|
||||||
|
self._state = None
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/template",
|
"documentation": "https://www.home-assistant.io/integrations/template",
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@PhracturedBlue"]
|
"codeowners": ["@PhracturedBlue", "@tetienne"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
"""The tests for the Template light platform."""
|
"""The tests for the Template light platform."""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
from homeassistant.components.light import ATTR_BRIGHTNESS
|
||||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
|
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
|
||||||
@ -38,6 +40,45 @@ class TestTemplateLight:
|
|||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
|
def test_template_state_invalid(self):
|
||||||
|
"""Test template state with render error."""
|
||||||
|
with assert_setup_component(1, "light"):
|
||||||
|
assert setup.setup_component(
|
||||||
|
self.hass,
|
||||||
|
"light",
|
||||||
|
{
|
||||||
|
"light": {
|
||||||
|
"platform": "template",
|
||||||
|
"lights": {
|
||||||
|
"test_template_light": {
|
||||||
|
"value_template": "{{states.test['big.fat...']}}",
|
||||||
|
"turn_on": {
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"entity_id": "light.test_state",
|
||||||
|
},
|
||||||
|
"turn_off": {
|
||||||
|
"service": "light.turn_off",
|
||||||
|
"entity_id": "light.test_state",
|
||||||
|
},
|
||||||
|
"set_level": {
|
||||||
|
"service": "light.turn_on",
|
||||||
|
"data_template": {
|
||||||
|
"entity_id": "light.test_state",
|
||||||
|
"brightness": "{{brightness}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.hass.start()
|
||||||
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
state = self.hass.states.get("light.test_template_light")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
def test_template_state_text(self):
|
def test_template_state_text(self):
|
||||||
"""Test the state text of a template."""
|
"""Test the state text of a template."""
|
||||||
with assert_setup_component(1, "light"):
|
with assert_setup_component(1, "light"):
|
||||||
@ -86,7 +127,11 @@ class TestTemplateLight:
|
|||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
assert state.state == STATE_OFF
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
def test_template_state_boolean_on(self):
|
@pytest.mark.parametrize(
|
||||||
|
"expected_state,template",
|
||||||
|
[(STATE_ON, "{{ 1 == 1 }}"), (STATE_OFF, "{{ 1 == 2 }}")],
|
||||||
|
)
|
||||||
|
def test_template_state_boolean(self, expected_state, template):
|
||||||
"""Test the setting of the state with boolean on."""
|
"""Test the setting of the state with boolean on."""
|
||||||
with assert_setup_component(1, "light"):
|
with assert_setup_component(1, "light"):
|
||||||
assert setup.setup_component(
|
assert setup.setup_component(
|
||||||
@ -97,7 +142,7 @@ class TestTemplateLight:
|
|||||||
"platform": "template",
|
"platform": "template",
|
||||||
"lights": {
|
"lights": {
|
||||||
"test_template_light": {
|
"test_template_light": {
|
||||||
"value_template": "{{ 1 == 1 }}",
|
"value_template": template,
|
||||||
"turn_on": {
|
"turn_on": {
|
||||||
"service": "light.turn_on",
|
"service": "light.turn_on",
|
||||||
"entity_id": "light.test_state",
|
"entity_id": "light.test_state",
|
||||||
@ -123,46 +168,7 @@ class TestTemplateLight:
|
|||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
assert state.state == STATE_ON
|
assert state.state == expected_state
|
||||||
|
|
||||||
def test_template_state_boolean_off(self):
|
|
||||||
"""Test the setting of the state with off."""
|
|
||||||
with assert_setup_component(1, "light"):
|
|
||||||
assert setup.setup_component(
|
|
||||||
self.hass,
|
|
||||||
"light",
|
|
||||||
{
|
|
||||||
"light": {
|
|
||||||
"platform": "template",
|
|
||||||
"lights": {
|
|
||||||
"test_template_light": {
|
|
||||||
"value_template": "{{ 1 == 2 }}",
|
|
||||||
"turn_on": {
|
|
||||||
"service": "light.turn_on",
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
},
|
|
||||||
"turn_off": {
|
|
||||||
"service": "light.turn_off",
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
},
|
|
||||||
"set_level": {
|
|
||||||
"service": "light.turn_on",
|
|
||||||
"data_template": {
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
"brightness": "{{brightness}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.hass.start()
|
|
||||||
self.hass.block_till_done()
|
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
|
||||||
assert state.state == STATE_OFF
|
|
||||||
|
|
||||||
def test_template_syntax_error(self):
|
def test_template_syntax_error(self):
|
||||||
"""Test templating syntax error."""
|
"""Test templating syntax error."""
|
||||||
@ -271,110 +277,47 @@ class TestTemplateLight:
|
|||||||
|
|
||||||
assert self.hass.states.all() == []
|
assert self.hass.states.all() == []
|
||||||
|
|
||||||
def test_missing_template_does_create(self):
|
@pytest.mark.parametrize(
|
||||||
|
"missing_key, count", [("value_template", 1), ("turn_on", 0), ("turn_off", 0)]
|
||||||
|
)
|
||||||
|
def test_missing_key(self, missing_key, count):
|
||||||
"""Test missing template."""
|
"""Test missing template."""
|
||||||
with assert_setup_component(1, "light"):
|
light = {
|
||||||
assert setup.setup_component(
|
"light": {
|
||||||
self.hass,
|
"platform": "template",
|
||||||
"light",
|
"lights": {
|
||||||
{
|
"light_one": {
|
||||||
"light": {
|
"value_template": "{{ 1== 1}}",
|
||||||
"platform": "template",
|
"turn_on": {
|
||||||
"lights": {
|
"service": "light.turn_on",
|
||||||
"light_one": {
|
"entity_id": "light.test_state",
|
||||||
"turn_on": {
|
},
|
||||||
"service": "light.turn_on",
|
"turn_off": {
|
||||||
"entity_id": "light.test_state",
|
"service": "light.turn_off",
|
||||||
},
|
"entity_id": "light.test_state",
|
||||||
"turn_off": {
|
},
|
||||||
"service": "light.turn_off",
|
"set_level": {
|
||||||
"entity_id": "light.test_state",
|
"service": "light.turn_on",
|
||||||
},
|
"data_template": {
|
||||||
"set_level": {
|
"entity_id": "light.test_state",
|
||||||
"service": "light.turn_on",
|
"brightness": "{{brightness}}",
|
||||||
"data_template": {
|
},
|
||||||
"entity_id": "light.test_state",
|
|
||||||
"brightness": "{{brightness}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
del light["light"]["lights"]["light_one"][missing_key]
|
||||||
|
with assert_setup_component(count, "light"):
|
||||||
|
assert setup.setup_component(self.hass, "light", light)
|
||||||
self.hass.start()
|
self.hass.start()
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert self.hass.states.all() != []
|
if count:
|
||||||
|
assert self.hass.states.all() != []
|
||||||
def test_missing_on_does_not_create(self):
|
else:
|
||||||
"""Test missing on."""
|
assert self.hass.states.all() == []
|
||||||
with assert_setup_component(0, "light"):
|
|
||||||
assert setup.setup_component(
|
|
||||||
self.hass,
|
|
||||||
"light",
|
|
||||||
{
|
|
||||||
"light": {
|
|
||||||
"platform": "template",
|
|
||||||
"lights": {
|
|
||||||
"bad name here": {
|
|
||||||
"value_template": "{{ 1== 1}}",
|
|
||||||
"turn_off": {
|
|
||||||
"service": "light.turn_off",
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
},
|
|
||||||
"set_level": {
|
|
||||||
"service": "light.turn_on",
|
|
||||||
"data_template": {
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
"brightness": "{{brightness}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.hass.start()
|
|
||||||
self.hass.block_till_done()
|
|
||||||
|
|
||||||
assert self.hass.states.all() == []
|
|
||||||
|
|
||||||
def test_missing_off_does_not_create(self):
|
|
||||||
"""Test missing off."""
|
|
||||||
with assert_setup_component(0, "light"):
|
|
||||||
assert setup.setup_component(
|
|
||||||
self.hass,
|
|
||||||
"light",
|
|
||||||
{
|
|
||||||
"light": {
|
|
||||||
"platform": "template",
|
|
||||||
"lights": {
|
|
||||||
"bad name here": {
|
|
||||||
"value_template": "{{ 1== 1}}",
|
|
||||||
"turn_on": {
|
|
||||||
"service": "light.turn_on",
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
},
|
|
||||||
"set_level": {
|
|
||||||
"service": "light.turn_on",
|
|
||||||
"data_template": {
|
|
||||||
"entity_id": "light.test_state",
|
|
||||||
"brightness": "{{brightness}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.hass.start()
|
|
||||||
self.hass.block_till_done()
|
|
||||||
|
|
||||||
assert self.hass.states.all() == []
|
|
||||||
|
|
||||||
def test_on_action(self):
|
def test_on_action(self):
|
||||||
"""Test on action."""
|
"""Test on action."""
|
||||||
@ -594,7 +537,11 @@ class TestTemplateLight:
|
|||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get("brightness") == 124
|
assert state.attributes.get("brightness") == 124
|
||||||
|
|
||||||
def test_level_template(self):
|
@pytest.mark.parametrize(
|
||||||
|
"expected_level,template",
|
||||||
|
[(255, "{{255}}"), (None, "{{256}}"), (None, "{{x - 12}}")],
|
||||||
|
)
|
||||||
|
def test_level_template(self, expected_level, template):
|
||||||
"""Test the template for the level."""
|
"""Test the template for the level."""
|
||||||
with assert_setup_component(1, "light"):
|
with assert_setup_component(1, "light"):
|
||||||
assert setup.setup_component(
|
assert setup.setup_component(
|
||||||
@ -621,7 +568,7 @@ class TestTemplateLight:
|
|||||||
"brightness": "{{brightness}}",
|
"brightness": "{{brightness}}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"level_template": "{{42}}",
|
"level_template": template,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -633,8 +580,7 @@ class TestTemplateLight:
|
|||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
assert state.attributes.get("brightness") == expected_level
|
||||||
assert state.attributes.get("brightness") == 42
|
|
||||||
|
|
||||||
def test_friendly_name(self):
|
def test_friendly_name(self):
|
||||||
"""Test the accessibility of the friendly_name attribute."""
|
"""Test the accessibility of the friendly_name attribute."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user