diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 82839d1e0f8..473641b10a4 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -171,8 +171,8 @@ async def async_not_from_config( def numeric_state( hass: HomeAssistant, entity: Union[None, str, State], - below: Optional[float] = None, - above: Optional[float] = None, + below: Optional[Union[float, str]] = None, + above: Optional[Union[float, str]] = None, value_template: Optional[Template] = None, variables: TemplateVarsType = None, ) -> bool: @@ -192,8 +192,8 @@ def numeric_state( def async_numeric_state( hass: HomeAssistant, entity: Union[None, str, State], - below: Optional[float] = None, - above: Optional[float] = None, + below: Optional[Union[float, str]] = None, + above: Optional[Union[float, str]] = None, value_template: Optional[Template] = None, variables: TemplateVarsType = None, attribute: Optional[str] = None, @@ -233,11 +233,29 @@ def async_numeric_state( ) return False - if below is not None and fvalue >= below: - return False + if below is not None: + if isinstance(below, str): + below_entity = hass.states.get(below) + if ( + not below_entity + or below_entity.state in (STATE_UNAVAILABLE, STATE_UNKNOWN) + or fvalue >= float(below_entity.state) + ): + return False + elif fvalue >= below: + return False - if above is not None and fvalue <= above: - return False + if above is not None: + if isinstance(above, str): + above_entity = hass.states.get(above) + if ( + not above_entity + or above_entity.state in (STATE_UNAVAILABLE, STATE_UNKNOWN) + or fvalue <= float(above_entity.state) + ): + return False + elif fvalue <= above: + return False return True diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index cc8adea81da..c3842c538d8 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -906,8 +906,12 @@ NUMERIC_STATE_CONDITION_SCHEMA = vol.All( vol.Required(CONF_CONDITION): "numeric_state", vol.Required(CONF_ENTITY_ID): entity_ids, vol.Optional(CONF_ATTRIBUTE): str, - CONF_BELOW: vol.Coerce(float), - CONF_ABOVE: vol.Coerce(float), + CONF_BELOW: vol.Any( + vol.Coerce(float), vol.All(str, entity_domain("input_number")) + ), + CONF_ABOVE: vol.Any( + vol.Coerce(float), vol.All(str, entity_domain("input_number")) + ), vol.Optional(CONF_VALUE_TEMPLATE): template, } ), diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index dcd652913e5..3f25ab598d5 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -505,6 +505,62 @@ async def test_numberic_state_attribute(hass): assert not test(hass) +async def test_numeric_state_using_input_number(hass): + """Test numeric_state conditions using input_number entities.""" + await async_setup_component( + hass, + "input_number", + { + "input_number": { + "low": {"min": 0, "max": 255, "initial": 10}, + "high": {"min": 0, "max": 255, "initial": 100}, + } + }, + ) + + test = await condition.async_from_config( + hass, + { + "condition": "and", + "conditions": [ + { + "condition": "numeric_state", + "entity_id": "sensor.temperature", + "below": "input_number.high", + "above": "input_number.low", + }, + ], + }, + ) + + hass.states.async_set("sensor.temperature", 42) + assert test(hass) + + hass.states.async_set("sensor.temperature", 10) + assert not test(hass) + + hass.states.async_set("sensor.temperature", 100) + assert not test(hass) + + await hass.services.async_call( + "input_number", + "set_value", + { + "entity_id": "input_number.high", + "value": 101, + }, + blocking=True, + ) + assert test(hass) + + assert not condition.async_numeric_state( + hass, entity="sensor.temperature", below="input_number.not_exist" + ) + assert not condition.async_numeric_state( + hass, entity="sensor.temperature", above="input_number.not_exist" + ) + + async def test_zone_multiple_entities(hass): """Test with multiple entities in condition.""" test = await condition.async_from_config(