From 8b0f362840d1f6e4880ead203c23620f6a8710a4 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sun, 8 Sep 2019 08:14:56 +0000 Subject: [PATCH 01/12] Added availability_template to Template Sensor platform --- homeassistant/components/template/sensor.py | 20 +++++++++ homeassistant/const.py | 1 + tests/components/template/test_sensor.py | 47 +++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index b77528e0c324a7..57217581665378 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -17,6 +17,7 @@ CONF_VALUE_TEMPLATE, CONF_ICON_TEMPLATE, CONF_ENTITY_PICTURE_TEMPLATE, + CONF_AVAILABILITY_TEMPLATE, ATTR_ENTITY_ID, CONF_SENSORS, EVENT_HOMEASSISTANT_START, @@ -39,6 +40,7 @@ vol.Optional(CONF_ICON_TEMPLATE): cv.template, vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template, vol.Optional(CONF_FRIENDLY_NAME_TEMPLATE): cv.template, + vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template, vol.Optional(CONF_ATTRIBUTE_TEMPLATES, default={}): vol.Schema( {cv.string: cv.template} ), @@ -62,6 +64,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= state_template = device_config[CONF_VALUE_TEMPLATE] icon_template = device_config.get(CONF_ICON_TEMPLATE) entity_picture_template = device_config.get(CONF_ENTITY_PICTURE_TEMPLATE) + availability_template = device_config.get(CONF_AVAILABILITY_TEMPLATE) friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device) friendly_name_template = device_config.get(CONF_FRIENDLY_NAME_TEMPLATE) unit_of_measurement = device_config.get(ATTR_UNIT_OF_MEASUREMENT) @@ -77,6 +80,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= CONF_ICON_TEMPLATE: icon_template, CONF_ENTITY_PICTURE_TEMPLATE: entity_picture_template, CONF_FRIENDLY_NAME_TEMPLATE: friendly_name_template, + CONF_AVAILABILITY_TEMPLATE: availability_template, } for tpl_name, template in chain(templates.items(), attribute_templates.items()): @@ -120,6 +124,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= state_template, icon_template, entity_picture_template, + availability_template, entity_ids, device_class, attribute_templates, @@ -146,6 +151,7 @@ def __init__( state_template, icon_template, entity_picture_template, + availability_template, entity_ids, device_class, attribute_templates, @@ -162,10 +168,12 @@ def __init__( self._state = None self._icon_template = icon_template self._entity_picture_template = entity_picture_template + self._availability_template = availability_template self._icon = None self._entity_picture = None self._entities = entity_ids self._device_class = device_class + self._available = True self._attribute_templates = attribute_templates self._attributes = {} @@ -222,6 +230,11 @@ def unit_of_measurement(self): """Return the unit_of_measurement of the device.""" return self._unit_of_measurement + @property + def available(self) -> bool: + """Return if the device is available.""" + return self._available + @property def device_state_attributes(self): """Return the state attributes.""" @@ -291,3 +304,10 @@ async def async_update(self): self._name, ex, ) + if self._availability_template is not None: + try: + result = self._availability_template.async_render() + self._available = result == "true" + except (TemplateError, ValueError) as err: + _LOGGER.error(err) + self._available = True diff --git a/homeassistant/const.py b/homeassistant/const.py index 4cfd16b8c9f0cc..5eb351916190ba 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -35,6 +35,7 @@ CONF_AUTHENTICATION = "authentication" CONF_AUTH_MFA_MODULES = "auth_mfa_modules" CONF_AUTH_PROVIDERS = "auth_providers" +CONF_AVAILABILITY_TEMPLATE = "availability_template" CONF_BASE = "base" CONF_BEFORE = "before" CONF_BELOW = "below" diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 9223399bee7af1..91e67e99e8a0b4 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -3,6 +3,7 @@ from homeassistant.setup import setup_component, async_setup_component from tests.common import get_test_home_assistant, assert_setup_component +from homeassistant.const import STATE_UNAVAILABLE class TestTemplateSensor: @@ -376,6 +377,52 @@ def test_setup_valid_device_class(self): state = self.hass.states.get("sensor.test2") assert "device_class" not in state.attributes + def test_available_template_with_entities(self): + """Test availability tempalates with values from other entities.""" + availability_template = """ + {% if is_state('availability_boolean.state', 'True') %} + {{ 'true' }} + {% else %} + {{ 'false' }} + {% endif %} + """ + + with assert_setup_component(1): + assert setup_component( + self.hass, + "sensor", + { + "sensor": { + "platform": "template", + "sensors": { + "test_template_sensor": { + "value_template": "{{ states.sensor.test_state.state }}", + "availability_template": availability_template, + } + }, + } + }, + ) + + self.hass.start() + self.hass.block_till_done() + + # When template returns true.. + self.hass.states.set("availability_boolean.state", True) + self.hass.block_till_done() + + # Device State should not be unavailable + state = self.hass.states.get("sensor.test_template_sensor") + assert state.state != STATE_UNAVAILABLE + + # When Availability template returns false + self.hass.states.set("availability_boolean.state", False) + self.hass.block_till_done() + + # device state should be unavailable + state = self.hass.states.get("sensor.test_template_sensor") + assert state.state == STATE_UNAVAILABLE + async def test_invalid_attribute_template(hass, caplog): """Test that errors are logged if rendering template fails.""" From aa547643ffecb4cbe9c7f6899955c598141cd624 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sun, 8 Sep 2019 14:11:14 +0000 Subject: [PATCH 02/12] Added to test for invalid values in availability_template --- tests/components/template/test_sensor.py | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 91e67e99e8a0b4..5678171fe3c333 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -452,6 +452,32 @@ async def test_invalid_attribute_template(hass, caplog): assert ("Error rendering attribute test_attribute") in caplog.text +async def test_invalid_availability_template_keeps_component_available(hass, caplog): + """Test that an invalid availability keeps the device available.""" + + await async_setup_component( + hass, + "sensor", + { + "sensor": { + "platform": "template", + "sensors": { + "my_sensor": { + "value_template": "{{ states.sensor.test_state.state }}", + "availability_template": "{{ x - 12 }}", + } + }, + } + }, + ) + + await hass.async_start() + await hass.async_block_till_done() + + assert hass.states.get("sensor.my_sensor") != STATE_UNAVAILABLE + assert ("UndefinedError: 'x' is undefined") in caplog.text + + async def test_no_template_match_all(hass, caplog): """Test that we do not allow sensors that match on all.""" hass.states.async_set("sensor.test_sensor", "startup") From 0b6552fd63d934c483f05df10b723a9d0fe1b7a2 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Thu, 12 Sep 2019 21:59:58 +0000 Subject: [PATCH 03/12] Updated AVAILABILITY_TEMPLATE Rendering error --- homeassistant/components/template/sensor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 57217581665378..f99a961064f544 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -308,6 +308,11 @@ async def async_update(self): try: result = self._availability_template.async_render() self._available = result == "true" - except (TemplateError, ValueError) as err: - _LOGGER.error(err) + except (TemplateError, ValueError) as ex: + _LOGGER.error( + "Could not render %s template %s: %s", + friendly_property_name, + self._name, + ex, + ) self._available = True From c074ba432324edcfaf8292aadd26394d6488428c Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sat, 14 Sep 2019 02:02:20 +0000 Subject: [PATCH 04/12] Moved const to package Const.py --- homeassistant/components/template/const.py | 3 +++ homeassistant/components/template/sensor.py | 11 ++++------- homeassistant/const.py | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 homeassistant/components/template/const.py diff --git a/homeassistant/components/template/const.py b/homeassistant/components/template/const.py new file mode 100644 index 00000000000000..e6cf69341f9de8 --- /dev/null +++ b/homeassistant/components/template/const.py @@ -0,0 +1,3 @@ +"""Constants for the Template Platform Components.""" + +CONF_AVAILABILITY_TEMPLATE = "availability_template" diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index f99a961064f544..862975e5860fa6 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -17,7 +17,6 @@ CONF_VALUE_TEMPLATE, CONF_ICON_TEMPLATE, CONF_ENTITY_PICTURE_TEMPLATE, - CONF_AVAILABILITY_TEMPLATE, ATTR_ENTITY_ID, CONF_SENSORS, EVENT_HOMEASSISTANT_START, @@ -25,6 +24,8 @@ MATCH_ALL, CONF_DEVICE_CLASS, ) + +from .const import CONF_AVAILABILITY_TEMPLATE from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity, async_generate_entity_id @@ -130,10 +131,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= attribute_templates, ) ) - if not sensors: - _LOGGER.error("No sensors added") - return False - async_add_entities(sensors) return True @@ -309,10 +306,10 @@ async def async_update(self): result = self._availability_template.async_render() self._available = result == "true" except (TemplateError, ValueError) as ex: + self._available = True _LOGGER.error( "Could not render %s template %s: %s", - friendly_property_name, + CONF_AVAILABILITY_TEMPLATE, self._name, ex, ) - self._available = True diff --git a/homeassistant/const.py b/homeassistant/const.py index 5eb351916190ba..4cfd16b8c9f0cc 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -35,7 +35,6 @@ CONF_AUTHENTICATION = "authentication" CONF_AUTH_MFA_MODULES = "auth_mfa_modules" CONF_AUTH_PROVIDERS = "auth_providers" -CONF_AVAILABILITY_TEMPLATE = "availability_template" CONF_BASE = "base" CONF_BEFORE = "before" CONF_BELOW = "below" From 8fb273f00c3b0a963d9e636d659665b81a96b265 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sat, 14 Sep 2019 03:16:17 +0000 Subject: [PATCH 05/12] Fix import order (pylint) --- homeassistant/components/template/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 862975e5860fa6..fe23c04b945bf4 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -25,11 +25,11 @@ CONF_DEVICE_CLASS, ) -from .const import CONF_AVAILABILITY_TEMPLATE from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.helpers.event import async_track_state_change +from .const import CONF_AVAILABILITY_TEMPLATE CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" From d0b6975bbd181f93abbc6d834615bbf3b45c0e56 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Tue, 17 Sep 2019 00:10:38 +0000 Subject: [PATCH 06/12] Moved availability_template rendering to common loop --- homeassistant/components/template/sensor.py | 29 +++++++-------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index fe23c04b945bf4..404490e38c96c4 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -170,7 +170,7 @@ def __init__( self._entity_picture = None self._entities = entity_ids self._device_class = device_class - self._available = True + self._available = "true" self._attribute_templates = attribute_templates self._attributes = {} @@ -230,7 +230,7 @@ def unit_of_measurement(self): @property def available(self) -> bool: """Return if the device is available.""" - return self._available + return self._available is not None and self._available == "true" @property def device_state_attributes(self): @@ -258,12 +258,6 @@ async def async_update(self): self._state = None _LOGGER.error("Could not render template %s: %s", self._name, ex) - templates = { - "_icon": self._icon_template, - "_entity_picture": self._entity_picture_template, - "_name": self._friendly_name_template, - } - attrs = {} for key, value in self._attribute_templates.items(): try: @@ -273,6 +267,13 @@ async def async_update(self): self._attributes = attrs + templates = { + "_icon": self._icon_template, + "_entity_picture": self._entity_picture_template, + "_name": self._friendly_name_template, + "_available": self._availability_template, + } + for property_name, template in templates.items(): if template is None: continue @@ -301,15 +302,3 @@ async def async_update(self): self._name, ex, ) - if self._availability_template is not None: - try: - result = self._availability_template.async_render() - self._available = result == "true" - except (TemplateError, ValueError) as ex: - self._available = True - _LOGGER.error( - "Could not render %s template %s: %s", - CONF_AVAILABILITY_TEMPLATE, - self._name, - ex, - ) From 14676d34849854ade7791119db4dd9e2113282b0 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Tue, 17 Sep 2019 02:47:30 +0000 Subject: [PATCH 07/12] Removed 'Magic' string --- homeassistant/components/template/sensor.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 404490e38c96c4..85d0efb27c75e3 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -32,6 +32,7 @@ from .const import CONF_AVAILABILITY_TEMPLATE CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" +EXPECTED_AVAILABILITY_RENDER_RESULT = "true" _LOGGER = logging.getLogger(__name__) @@ -170,7 +171,7 @@ def __init__( self._entity_picture = None self._entities = entity_ids self._device_class = device_class - self._available = "true" + self._available = EXPECTED_AVAILABILITY_RENDER_RESULT self._attribute_templates = attribute_templates self._attributes = {} @@ -230,7 +231,10 @@ def unit_of_measurement(self): @property def available(self) -> bool: """Return if the device is available.""" - return self._available is not None and self._available == "true" + return ( + self._available is not None + and self._available == EXPECTED_AVAILABILITY_RENDER_RESULT + ) @property def device_state_attributes(self): From 2c2c43f29f70ff3555c5b11ece9d5196e71d3865 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Tue, 17 Sep 2019 20:17:58 +1000 Subject: [PATCH 08/12] Cleaned up const and compare lowercase result to 'true' --- homeassistant/components/template/sensor.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 85d0efb27c75e3..32f59f57e5b390 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -32,7 +32,6 @@ from .const import CONF_AVAILABILITY_TEMPLATE CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" -EXPECTED_AVAILABILITY_RENDER_RESULT = "true" _LOGGER = logging.getLogger(__name__) @@ -171,7 +170,7 @@ def __init__( self._entity_picture = None self._entities = entity_ids self._device_class = device_class - self._available = EXPECTED_AVAILABILITY_RENDER_RESULT + self._available = "true" self._attribute_templates = attribute_templates self._attributes = {} @@ -231,10 +230,7 @@ def unit_of_measurement(self): @property def available(self) -> bool: """Return if the device is available.""" - return ( - self._available is not None - and self._available == EXPECTED_AVAILABILITY_RENDER_RESULT - ) + return self._available is not None and self._available.lower() == "true" @property def device_state_attributes(self): From 8155479e1987bfc395fd72efd9d8326fe5f48a2d Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Tue, 17 Sep 2019 21:14:36 +1000 Subject: [PATCH 09/12] Device is unavailbale if value template render fails --- homeassistant/components/template/sensor.py | 2 ++ tests/components/template/test_sensor.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 32f59f57e5b390..98f6864934c12a 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -246,7 +246,9 @@ async def async_update(self): """Update the state from the template.""" try: self._state = self._template.async_render() + self._available = "True" except TemplateError as ex: + self._available = "False" if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute" ): diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 5678171fe3c333..b214c3bfa373bd 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -252,7 +252,7 @@ def test_template_attribute_missing(self): self.hass.block_till_done() state = self.hass.states.get("sensor.test_template_sensor") - assert state.state == "unknown" + assert state.state == STATE_UNAVAILABLE def test_invalid_name_does_not_create(self): """Test invalid name.""" From c2b2ada880916e0ca0e8ae02a3cd30cd407146b6 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sat, 21 Sep 2019 23:40:28 +0000 Subject: [PATCH 10/12] Converted test ot Async and fixed states --- tests/components/template/test_sensor.py | 72 +++++++++++------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index b214c3bfa373bd..9db599f094c295 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -3,7 +3,7 @@ from homeassistant.setup import setup_component, async_setup_component from tests.common import get_test_home_assistant, assert_setup_component -from homeassistant.const import STATE_UNAVAILABLE +from homeassistant.const import STATE_UNAVAILABLE, STATE_ON, STATE_OFF class TestTemplateSensor: @@ -377,51 +377,43 @@ def test_setup_valid_device_class(self): state = self.hass.states.get("sensor.test2") assert "device_class" not in state.attributes - def test_available_template_with_entities(self): - """Test availability tempalates with values from other entities.""" - availability_template = """ - {% if is_state('availability_boolean.state', 'True') %} - {{ 'true' }} - {% else %} - {{ 'false' }} - {% endif %} - """ - with assert_setup_component(1): - assert setup_component( - self.hass, - "sensor", - { - "sensor": { - "platform": "template", - "sensors": { - "test_template_sensor": { - "value_template": "{{ states.sensor.test_state.state }}", - "availability_template": availability_template, - } - }, - } - }, - ) +async def test_available_template_with_entities(hass): + """Test availability tempalates with values from other entities.""" + hass.states.async_set("sensor.availability_sensor", STATE_OFF) + with assert_setup_component(1, "sensor"): + assert await async_setup_component( + hass, + "sensor", + { + "sensor": { + "platform": "template", + "sensors": { + "test_template_sensor": { + "value_template": "{{ states.sensor.test_sensor.state }}", + "availability_template": "{{ is_state('sensor.availability_sensor', 'on') }}", + } + }, + } + }, + ) - self.hass.start() - self.hass.block_till_done() + await hass.async_start() + await hass.async_block_till_done() - # When template returns true.. - self.hass.states.set("availability_boolean.state", True) - self.hass.block_till_done() + # 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 - state = self.hass.states.get("sensor.test_template_sensor") - assert state.state != STATE_UNAVAILABLE + # Device State should not be unavailable + assert hass.states.get("sensor.test_template_sensor").state != STATE_UNAVAILABLE - # When Availability template returns false - self.hass.states.set("availability_boolean.state", False) - self.hass.block_till_done() + # 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 - state = self.hass.states.get("sensor.test_template_sensor") - assert state.state == STATE_UNAVAILABLE + # device state should be unavailable + assert hass.states.get("sensor.test_template_sensor").state == STATE_UNAVAILABLE async def test_invalid_attribute_template(hass, caplog): From 703e2dda8774d8a8476da1f796c7fb76fece56cb Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sat, 21 Sep 2019 23:59:09 +0000 Subject: [PATCH 11/12] Comverted back to using boolean for _availability --- homeassistant/components/template/sensor.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 98f6864934c12a..a876819373652f 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -170,7 +170,7 @@ def __init__( self._entity_picture = None self._entities = entity_ids self._device_class = device_class - self._available = "true" + self._available = True self._attribute_templates = attribute_templates self._attributes = {} @@ -230,7 +230,7 @@ def unit_of_measurement(self): @property def available(self) -> bool: """Return if the device is available.""" - return self._available is not None and self._available.lower() == "true" + return self._available @property def device_state_attributes(self): @@ -246,9 +246,9 @@ async def async_update(self): """Update the state from the template.""" try: self._state = self._template.async_render() - self._available = "True" + self._available = True except TemplateError as ex: - self._available = "False" + self._available = False if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute" ): @@ -281,7 +281,10 @@ async def async_update(self): continue try: - setattr(self, property_name, template.async_render()) + value = template.async_render() + if property_name == "_available": + value = value.lower() == "true" + setattr(self, property_name, value) except TemplateError as ex: friendly_property_name = property_name[1:].replace("_", " ") if ex.args and ex.args[0].startswith( From 658611a4435e3e9bcae7a5a683747815a16e92b0 Mon Sep 17 00:00:00 2001 From: Gil Peeters Date: Sun, 22 Sep 2019 00:10:14 +0000 Subject: [PATCH 12/12] Fixed state check in test --- tests/components/template/test_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 9db599f094c295..b3813da176633c 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -466,7 +466,7 @@ async def test_invalid_availability_template_keeps_component_available(hass, cap await hass.async_start() await hass.async_block_till_done() - assert hass.states.get("sensor.my_sensor") != STATE_UNAVAILABLE + assert hass.states.get("sensor.my_sensor").state != STATE_UNAVAILABLE assert ("UndefinedError: 'x' is undefined") in caplog.text