Adjust cover reproduce state to prefer setting positions if supported (#143226)

This commit is contained in:
J. Nick Koston 2025-04-18 11:34:33 -10:00 committed by GitHub
parent 5541de2bcb
commit a7922690c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 84 additions and 32 deletions

View File

@ -73,14 +73,14 @@ async def _async_set_position(
Returns True if the position was set, False if there is no
supported method for setting the position.
"""
if target_position == FULL_CLOSE and CoverEntityFeature.CLOSE in features:
await service_call(SERVICE_CLOSE_COVER, service_data)
elif target_position == FULL_OPEN and CoverEntityFeature.OPEN in features:
await service_call(SERVICE_OPEN_COVER, service_data)
elif CoverEntityFeature.SET_POSITION in features:
if CoverEntityFeature.SET_POSITION in features:
await service_call(
SERVICE_SET_COVER_POSITION, service_data | {ATTR_POSITION: target_position}
)
elif target_position == FULL_CLOSE and CoverEntityFeature.CLOSE in features:
await service_call(SERVICE_CLOSE_COVER, service_data)
elif target_position == FULL_OPEN and CoverEntityFeature.OPEN in features:
await service_call(SERVICE_OPEN_COVER, service_data)
else:
# Requested a position but the cover doesn't support it
return False
@ -98,15 +98,17 @@ async def _async_set_tilt_position(
Returns True if the tilt position was set, False if there is no
supported method for setting the tilt position.
"""
if target_tilt_position == FULL_CLOSE and CoverEntityFeature.CLOSE_TILT in features:
await service_call(SERVICE_CLOSE_COVER_TILT, service_data)
elif target_tilt_position == FULL_OPEN and CoverEntityFeature.OPEN_TILT in features:
await service_call(SERVICE_OPEN_COVER_TILT, service_data)
elif CoverEntityFeature.SET_TILT_POSITION in features:
if CoverEntityFeature.SET_TILT_POSITION in features:
await service_call(
SERVICE_SET_COVER_TILT_POSITION,
service_data | {ATTR_TILT_POSITION: target_tilt_position},
)
elif (
target_tilt_position == FULL_CLOSE and CoverEntityFeature.CLOSE_TILT in features
):
await service_call(SERVICE_CLOSE_COVER_TILT, service_data)
elif target_tilt_position == FULL_OPEN and CoverEntityFeature.OPEN_TILT in features:
await service_call(SERVICE_OPEN_COVER_TILT, service_data)
else:
# Requested a tilt position but the cover doesn't support it
return False
@ -183,12 +185,12 @@ async def _async_reproduce_state(
current_attrs = cur_state.attributes
target_attrs = state.attributes
current_position = current_attrs.get(ATTR_CURRENT_POSITION)
target_position = target_attrs.get(ATTR_CURRENT_POSITION)
current_position: int | None = current_attrs.get(ATTR_CURRENT_POSITION)
target_position: int | None = target_attrs.get(ATTR_CURRENT_POSITION)
position_matches = current_position == target_position
current_tilt_position = current_attrs.get(ATTR_CURRENT_TILT_POSITION)
target_tilt_position = target_attrs.get(ATTR_CURRENT_TILT_POSITION)
current_tilt_position: int | None = current_attrs.get(ATTR_CURRENT_TILT_POSITION)
target_tilt_position: int | None = target_attrs.get(ATTR_CURRENT_TILT_POSITION)
tilt_position_matches = current_tilt_position == target_tilt_position
state_matches = cur_state.state == target_state
@ -214,19 +216,11 @@ async def _async_reproduce_state(
)
service_data = {ATTR_ENTITY_ID: entity_id}
set_position = (
not position_matches
and target_position is not None
and await _async_set_position(
service_call, service_data, features, target_position
)
set_position = target_position is not None and await _async_set_position(
service_call, service_data, features, target_position
)
set_tilt = (
not tilt_position_matches
and target_tilt_position is not None
and await _async_set_tilt_position(
service_call, service_data, features, target_tilt_position
)
set_tilt = target_tilt_position is not None and await _async_set_tilt_position(
service_call, service_data, features, target_tilt_position
)
if target_state in CLOSING_STATES:

View File

@ -178,6 +178,22 @@ async def test_reproducing_states(
| CoverEntityFeature.OPEN,
},
)
hass.states.async_set(
"cover.closed_supports_all_features",
CoverState.CLOSED,
{
ATTR_CURRENT_POSITION: 0,
ATTR_CURRENT_TILT_POSITION: 0,
ATTR_SUPPORTED_FEATURES: CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.SET_POSITION
| CoverEntityFeature.STOP
| CoverEntityFeature.OPEN_TILT
| CoverEntityFeature.CLOSE_TILT
| CoverEntityFeature.STOP_TILT
| CoverEntityFeature.SET_TILT_POSITION,
},
)
hass.states.async_set(
"cover.tilt_only_open",
CoverState.OPEN,
@ -249,6 +265,14 @@ async def test_reproducing_states(
await async_reproduce_state(
hass,
[
State(
"cover.closed_supports_all_features",
CoverState.CLOSED,
{
ATTR_CURRENT_POSITION: 0,
ATTR_CURRENT_TILT_POSITION: 0,
},
),
State("cover.entity_close", CoverState.CLOSED),
State("cover.closed_only_supports_close_open", CoverState.CLOSED),
State("cover.closed_only_supports_tilt_close_open", CoverState.CLOSED),
@ -364,6 +388,11 @@ async def test_reproducing_states(
await async_reproduce_state(
hass,
[
State(
"cover.closed_supports_all_features",
CoverState.CLOSED,
{ATTR_CURRENT_POSITION: 0, ATTR_CURRENT_TILT_POSITION: 50},
),
State("cover.entity_close", CoverState.OPEN),
State(
"cover.closed_only_supports_close_open",
@ -458,7 +487,6 @@ async def test_reproducing_states(
valid_close_calls = [
{"entity_id": "cover.entity_open"},
{"entity_id": "cover.entity_open_attr"},
{"entity_id": "cover.entity_entirely_open"},
{"entity_id": "cover.open_only_supports_close_open"},
{"entity_id": "cover.open_missing_all_features"},
]
@ -481,11 +509,8 @@ async def test_reproducing_states(
valid_open_calls.remove(call.data)
valid_close_tilt_calls = [
{"entity_id": "cover.entity_open_tilt"},
{"entity_id": "cover.entity_entirely_open"},
{"entity_id": "cover.tilt_only_open"},
{"entity_id": "cover.entity_open_attr"},
{"entity_id": "cover.tilt_only_tilt_position_100"},
{"entity_id": "cover.open_only_supports_tilt_close_open"},
]
assert len(close_tilt_calls) == len(valid_close_tilt_calls)
@ -495,9 +520,7 @@ async def test_reproducing_states(
valid_close_tilt_calls.remove(call.data)
valid_open_tilt_calls = [
{"entity_id": "cover.entity_close_tilt"},
{"entity_id": "cover.tilt_only_closed"},
{"entity_id": "cover.tilt_only_tilt_position_0"},
{"entity_id": "cover.closed_only_supports_tilt_close_open"},
]
assert len(open_tilt_calls) == len(valid_open_tilt_calls)
@ -523,6 +546,14 @@ async def test_reproducing_states(
"entity_id": "cover.open_only_supports_position",
ATTR_POSITION: 0,
},
{
"entity_id": "cover.closed_supports_all_features",
ATTR_POSITION: 0,
},
{
"entity_id": "cover.entity_entirely_open",
ATTR_POSITION: 0,
},
]
assert len(position_calls) == len(valid_position_calls)
for call in position_calls:
@ -551,7 +582,34 @@ async def test_reproducing_states(
"entity_id": "cover.tilt_partial_open_only_supports_tilt_position",
ATTR_TILT_POSITION: 70,
},
{
"entity_id": "cover.closed_supports_all_features",
ATTR_TILT_POSITION: 50,
},
{
"entity_id": "cover.entity_close_tilt",
ATTR_TILT_POSITION: 100,
},
{
"entity_id": "cover.entity_open_tilt",
ATTR_TILT_POSITION: 0,
},
{
"entity_id": "cover.entity_entirely_open",
ATTR_TILT_POSITION: 0,
},
{
"entity_id": "cover.tilt_only_tilt_position_100",
ATTR_TILT_POSITION: 0,
},
{
"entity_id": "cover.tilt_only_tilt_position_0",
ATTR_TILT_POSITION: 100,
},
]
for call in position_tilt_calls:
if ATTR_TILT_POSITION not in call.data:
continue
assert len(position_tilt_calls) == len(valid_position_tilt_calls)
for call in position_tilt_calls:
assert call.domain == "cover"