diff --git a/homeassistant/exceptions.py b/homeassistant/exceptions.py index 0ac231fd314..84ba2cfa348 100644 --- a/homeassistant/exceptions.py +++ b/homeassistant/exceptions.py @@ -85,7 +85,7 @@ class ConditionErrorIndex(ConditionError): @attr.s class ConditionErrorContainer(ConditionError): - """Condition error with index.""" + """Condition error with subconditions.""" # List of ConditionErrors that this error wraps errors: Sequence[ConditionError] = attr.ib() diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index c20755a1780..40087650141 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -342,12 +342,25 @@ def async_numeric_state_from_config( if value_template is not None: value_template.hass = hass - return all( - async_numeric_state( - hass, entity_id, below, above, value_template, variables, attribute - ) - for entity_id in entity_ids - ) + errors = [] + for index, entity_id in enumerate(entity_ids): + try: + if not async_numeric_state( + hass, entity_id, below, above, value_template, variables, attribute + ): + return False + except ConditionError as ex: + errors.append( + ConditionErrorIndex( + "numeric_state", index=index, total=len(entity_ids), error=ex + ) + ) + + # Raise the errors if no check was false + if errors: + raise ConditionErrorContainer("numeric_state", errors=errors) + + return True return if_numeric_state @@ -429,10 +442,23 @@ def state_from_config( def if_state(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Test if condition.""" - return all( - state(hass, entity_id, req_states, for_period, attribute) - for entity_id in entity_ids - ) + errors = [] + for index, entity_id in enumerate(entity_ids): + try: + if not state(hass, entity_id, req_states, for_period, attribute): + return False + except ConditionError as ex: + errors.append( + ConditionErrorIndex( + "state", index=index, total=len(entity_ids), error=ex + ) + ) + + # Raise the errors if no check was false + if errors: + raise ConditionErrorContainer("state", errors=errors) + + return True return if_state diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index 2c35a3c8b15..5074b6e70c4 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -390,17 +390,18 @@ async def test_state_raises(hass): with pytest.raises(ConditionError, match="no entity"): condition.state(hass, entity=None, req_state="missing") - # Unknown entity_id - with pytest.raises(ConditionError, match="unknown entity"): - test = await condition.async_from_config( - hass, - { - "condition": "state", - "entity_id": "sensor.door_unknown", - "state": "open", - }, - ) - + # Unknown entities + test = await condition.async_from_config( + hass, + { + "condition": "state", + "entity_id": ["sensor.door_unknown", "sensor.window_unknown"], + "state": "open", + }, + ) + with pytest.raises(ConditionError, match="unknown entity.*door"): + test(hass) + with pytest.raises(ConditionError, match="unknown entity.*window"): test(hass) # Unknown attribute @@ -632,17 +633,18 @@ async def test_state_using_input_entities(hass): async def test_numeric_state_raises(hass): """Test that numeric_state raises ConditionError on errors.""" - # Unknown entity_id - with pytest.raises(ConditionError, match="unknown entity"): - test = await condition.async_from_config( - hass, - { - "condition": "numeric_state", - "entity_id": "sensor.temperature_unknown", - "above": 0, - }, - ) - + # Unknown entities + test = await condition.async_from_config( + hass, + { + "condition": "numeric_state", + "entity_id": ["sensor.temperature_unknown", "sensor.humidity_unknown"], + "above": 0, + }, + ) + with pytest.raises(ConditionError, match="unknown entity.*temperature"): + test(hass) + with pytest.raises(ConditionError, match="unknown entity.*humidity"): test(hass) # Unknown attribute