From 722b9912347441c204e3adfa667a5fc3e1676f7e Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Wed, 12 Apr 2023 21:23:24 +0200 Subject: [PATCH] Support unknown state, position or tilt for template cover (#91172) * Support unknown state for template cover * Remove not related changes --- homeassistant/components/template/cover.py | 9 ++ tests/components/template/test_cover.py | 124 ++++++++++++++++++--- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/template/cover.py b/homeassistant/components/template/cover.py index 1e0fdfacc8e..256773b714b 100644 --- a/homeassistant/components/template/cover.py +++ b/homeassistant/components/template/cover.py @@ -52,6 +52,7 @@ _VALID_STATES = [ STATE_CLOSING, "true", "false", + "none", ] CONF_POSITION_TEMPLATE = "position_template" @@ -238,6 +239,10 @@ class CoverTemplate(TemplateEntity, CoverEntity): @callback def _update_position(self, result): + if result is None: + self._position = None + return + try: state = float(result) except ValueError as err: @@ -256,6 +261,10 @@ class CoverTemplate(TemplateEntity, CoverEntity): @callback def _update_tilt(self, result): + if result is None: + self._tilt_value = None + return + try: state = float(result) except ValueError as err: diff --git a/tests/components/template/test_cover.py b/tests/components/template/test_cover.py index adc41fe717b..fefad59aa08 100644 --- a/tests/components/template/test_cover.py +++ b/tests/components/template/test_cover.py @@ -1,4 +1,6 @@ """The tests for the Template cover platform.""" +from typing import Any + import pytest from homeassistant import setup @@ -149,6 +151,72 @@ async def test_template_state_text( assert text in caplog.text +@pytest.mark.parametrize(("count", "domain"), [(1, DOMAIN)]) +@pytest.mark.parametrize( + ("config", "entity", "set_state", "test_state", "attr"), + [ + ( + { + DOMAIN: { + "platform": "template", + "covers": { + "test_template_cover": { + **OPEN_CLOSE_COVER_CONFIG, + "position_template": ( + "{{ states.cover.test.attributes.position }}" + ), + "value_template": "{{ states.cover.test_state.state }}", + } + }, + } + }, + "cover.test_state", + "", + STATE_UNKNOWN, + {}, + ), + ( + { + DOMAIN: { + "platform": "template", + "covers": { + "test_template_cover": { + **OPEN_CLOSE_COVER_CONFIG, + "position_template": ( + "{{ states.cover.test.attributes.position }}" + ), + "value_template": "{{ states.cover.test_state.state }}", + } + }, + } + }, + "cover.test_state", + None, + STATE_UNKNOWN, + {}, + ), + ], +) +async def test_template_state_text_ignored_if_none_or_empty( + hass: HomeAssistant, + entity: str, + set_state: str, + test_state: str, + attr: dict[str, Any], + start_ha, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test ignoring an empty state text of a template.""" + state = hass.states.get("cover.test_template_cover") + assert state.state == STATE_UNKNOWN + + hass.states.async_set(entity, set_state, attributes=attr) + await hass.async_block_till_done() + state = hass.states.get("cover.test_template_cover") + assert state.state == test_state + assert "ERROR" not in caplog.text + + @pytest.mark.parametrize(("count", "domain"), [(1, DOMAIN)]) @pytest.mark.parametrize( "config", @@ -191,7 +259,9 @@ async def test_template_state_boolean(hass: HomeAssistant, start_ha) -> None: }, ], ) -async def test_template_position(hass: HomeAssistant, start_ha) -> None: +async def test_template_position( + hass: HomeAssistant, start_ha, caplog: pytest.LogCaptureFixture +) -> None: """Test the position_template attribute.""" hass.states.async_set("cover.test", STATE_OPEN) attrs = {} @@ -199,6 +269,7 @@ async def test_template_position(hass: HomeAssistant, start_ha) -> None: for set_state, pos, test_state in [ (STATE_CLOSED, 42, STATE_OPEN), (STATE_OPEN, 0.0, STATE_CLOSED), + (STATE_CLOSED, None, STATE_UNKNOWN), ]: attrs["position"] = pos hass.states.async_set("cover.test", set_state, attributes=attrs) @@ -206,6 +277,7 @@ async def test_template_position(hass: HomeAssistant, start_ha) -> None: state = hass.states.get("cover.test_template_cover") assert state.attributes.get("current_position") == pos assert state.state == test_state + assert "ValueError" not in caplog.text @pytest.mark.parametrize(("count", "domain"), [(1, DOMAIN)]) @@ -233,26 +305,46 @@ async def test_template_not_optimistic(hass: HomeAssistant, start_ha) -> None: @pytest.mark.parametrize(("count", "domain"), [(1, DOMAIN)]) @pytest.mark.parametrize( - "config", + ("config", "tilt_position"), [ - { - DOMAIN: { - "platform": "template", - "covers": { - "test_template_cover": { - **OPEN_CLOSE_COVER_CONFIG, - "value_template": "{{ 1 == 1 }}", - "tilt_template": "{{ 42 }}", - } - }, - } - }, + ( + { + DOMAIN: { + "platform": "template", + "covers": { + "test_template_cover": { + **OPEN_CLOSE_COVER_CONFIG, + "value_template": "{{ 1 == 1 }}", + "tilt_template": "{{ 42 }}", + } + }, + } + }, + 42.0, + ), + ( + { + DOMAIN: { + "platform": "template", + "covers": { + "test_template_cover": { + **OPEN_CLOSE_COVER_CONFIG, + "value_template": "{{ 1 == 1 }}", + "tilt_template": "{{ None }}", + } + }, + } + }, + None, + ), ], ) -async def test_template_tilt(hass: HomeAssistant, start_ha) -> None: +async def test_template_tilt( + hass: HomeAssistant, tilt_position: float | None, start_ha +) -> None: """Test the tilt_template attribute.""" state = hass.states.get("cover.test_template_cover") - assert state.attributes.get("current_tilt_position") == 42.0 + assert state.attributes.get("current_tilt_position") == tilt_position @pytest.mark.parametrize(("count", "domain"), [(1, DOMAIN)])