From cbeb9e7dc1e255bf7856400fd97c8e8e799ae232 Mon Sep 17 00:00:00 2001 From: Bilal Atique <74999164+BilalAtique@users.noreply.github.com> Date: Wed, 30 Sep 2026 19:46:02 +0500 Subject: [PATCH] Fix Alexa AdjustRangeValue for a fully closed cover or valve (#183595) --- homeassistant/components/alexa/handlers.py | 8 +-- tests/components/alexa/test_smart_home.py | 71 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index 543d4f6ff438..abf02137a632 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -1619,9 +1619,9 @@ async def async_api_adjust_range( if instance == f"{COVER_DOMAIN}.{cover.ATTR_POSITION}": range_delta = int(range_delta * 20) if range_delta_default else int(range_delta) service = SERVICE_SET_COVER_POSITION - if not ( + if ( current := entity.attributes.get(CoverEntityStateAttribute.CURRENT_POSITION) - ): + ) is None: msg = f"Unable to determine {entity.entity_id} current position" raise AlexaInvalidValueError(msg) position = response_value = min(100, max(0, range_delta + current)) @@ -1637,7 +1637,7 @@ async def async_api_adjust_range( range_delta = int(range_delta * 20) if range_delta_default else int(range_delta) service = SERVICE_SET_COVER_TILT_POSITION current = entity.attributes.get(cover.ATTR_TILT_POSITION) - if not current: + if current is None: msg = f"Unable to determine {entity.entity_id} current tilt position" raise AlexaInvalidValueError(msg) tilt_position = response_value = min(100, max(0, range_delta + current)) @@ -1737,7 +1737,7 @@ async def async_api_adjust_range( elif instance == f"{VALVE_DOMAIN}.{valve.ATTR_POSITION}": range_delta = int(range_delta * 20) if range_delta_default else int(range_delta) service = valve.SERVICE_SET_VALVE_POSITION - if not (current := entity.attributes.get(valve.ATTR_POSITION)): + if (current := entity.attributes.get(valve.ATTR_POSITION)) is None: msg = f"Unable to determine {entity.entity_id} current position" raise AlexaInvalidValueError(msg) position = response_value = min(100, max(0, range_delta + current)) diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index e77bb3ffa37d..ca3a7a23ac3f 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -4769,6 +4769,77 @@ async def test_cover_tilt_position_range(hass: HomeAssistant) -> None: ) +@pytest.mark.parametrize( + ("entity_id", "supported_features", "position_attr", "instance", "service"), + [ + ( + "cover.test_closed", + CoverEntityFeature.SET_POSITION, + "current_position", + "cover.position", + "cover.set_cover_position", + ), + ( + "cover.test_closed", + CoverEntityFeature.SET_TILT_POSITION, + "tilt_position", + "cover.tilt", + "cover.set_cover_tilt_position", + ), + ( + "valve.test_closed", + ValveEntityFeature.SET_POSITION, + "position", + "valve.position", + "valve.set_valve_position", + ), + ], + ids=["cover_position", "cover_tilt", "valve_position"], +) +async def test_adjust_range_from_closed_position( + hass: HomeAssistant, + entity_id: str, + supported_features: int, + position_attr: str, + instance: str, + service: str, +) -> None: + """Test AdjustRangeValue treats position 0 as known and a missing one as unknown.""" + endpoint = entity_id.replace(".", "#") + hass.states.async_set( + entity_id, + "closed", + {"supported_features": supported_features, position_attr: 0}, + ) + + call, msg = await assert_request_calls_service( + "Alexa.RangeController", + "AdjustRangeValue", + endpoint, + service, + hass, + payload={"rangeValueDelta": 10, "rangeValueDeltaDefault": False}, + instance=instance, + ) + assert call.data[position_attr.removeprefix("current_")] == 10 + assert msg["context"]["properties"][0]["value"] == 10 + + hass.states.async_set( + entity_id, "closed", {"supported_features": supported_features} + ) + + msg = await assert_request_fails( + "Alexa.RangeController", + "AdjustRangeValue", + endpoint, + service, + hass, + payload={"rangeValueDelta": 10, "rangeValueDeltaDefault": False}, + instance=instance, + ) + assert msg["event"]["payload"]["type"] == "INVALID_VALUE" + + @pytest.mark.parametrize( ("supported_stop_features", "cover_stop_calls", "cover_stop_tilt_calls"), [