2020-04-25 18:07:15 +02:00
|
|
|
"""The tests for Cover."""
|
2024-03-08 14:50:25 +01:00
|
|
|
|
2024-04-01 11:11:59 +02:00
|
|
|
from homeassistant.components import cover
|
2024-10-08 18:39:04 +02:00
|
|
|
from homeassistant.components.cover import CoverState
|
|
|
|
|
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM, SERVICE_TOGGLE
|
2024-08-18 15:35:31 +02:00
|
|
|
from homeassistant.core import HomeAssistant, ServiceResponse
|
|
|
|
|
from homeassistant.helpers.entity import Entity
|
2021-11-10 09:03:20 +01:00
|
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
|
|
2024-06-10 12:52:34 +02:00
|
|
|
from .common import MockCover
|
|
|
|
|
|
2025-10-09 18:05:49 +02:00
|
|
|
from tests.common import setup_test_component_platform
|
2023-12-20 18:04:44 +01:00
|
|
|
|
2021-11-10 09:03:20 +01:00
|
|
|
|
2024-03-27 12:20:19 +01:00
|
|
|
async def test_services(
|
|
|
|
|
hass: HomeAssistant,
|
|
|
|
|
mock_cover_entities: list[MockCover],
|
|
|
|
|
) -> None:
|
2021-11-10 09:03:20 +01:00
|
|
|
"""Test the provided services."""
|
2024-03-27 12:20:19 +01:00
|
|
|
setup_test_component_platform(hass, cover.DOMAIN, mock_cover_entities)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
assert await async_setup_component(
|
|
|
|
|
hass, cover.DOMAIN, {cover.DOMAIN: {CONF_PLATFORM: "test"}}
|
|
|
|
|
)
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
|
|
# ent1 = cover without tilt and position
|
|
|
|
|
# ent2 = cover with position but no tilt
|
|
|
|
|
# ent3 = cover with simple tilt functions and no position
|
|
|
|
|
# ent4 = cover with all tilt functions but no position
|
|
|
|
|
# ent5 = cover with all functions
|
2024-01-09 06:32:27 -05:00
|
|
|
# ent6 = cover with only open/close, but also reports opening/closing
|
2024-03-27 12:20:19 +01:00
|
|
|
ent1, ent2, ent3, ent4, ent5, ent6 = mock_cover_entities
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# Test init all covers should be open
|
|
|
|
|
assert is_open(hass, ent1)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_open(hass, ent2, 50)
|
2021-11-10 09:03:20 +01:00
|
|
|
assert is_open(hass, ent3)
|
|
|
|
|
assert is_open(hass, ent4)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_open(hass, ent5, 50)
|
2024-01-09 06:32:27 -05:00
|
|
|
assert is_open(hass, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# call basic toggle services
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent1)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent2)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent3)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent4)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent5)
|
2024-01-09 06:32:27 -05:00
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
2024-01-09 06:32:27 -05:00
|
|
|
# entities should be either closed or closing, depending on if they report transitional states
|
2021-11-10 09:03:20 +01:00
|
|
|
assert is_closed(hass, ent1)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_closing(hass, ent2, 50)
|
2021-11-10 09:03:20 +01:00
|
|
|
assert is_closed(hass, ent3)
|
|
|
|
|
assert is_closed(hass, ent4)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_closing(hass, ent5, 50)
|
2024-01-09 06:32:27 -05:00
|
|
|
assert is_closing(hass, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# call basic toggle services and set different cover position states
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent1)
|
|
|
|
|
set_cover_position(ent2, 0)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent2)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent3)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent4)
|
|
|
|
|
set_cover_position(ent5, 15)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent5)
|
2024-01-09 06:32:27 -05:00
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# entities should be in correct state depending on the SUPPORT_STOP feature and cover position
|
|
|
|
|
assert is_open(hass, ent1)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_closed(hass, ent2, 0)
|
2021-11-10 09:03:20 +01:00
|
|
|
assert is_open(hass, ent3)
|
|
|
|
|
assert is_open(hass, ent4)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_open(hass, ent5, 15)
|
2024-01-09 06:32:27 -05:00
|
|
|
assert is_opening(hass, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# call basic toggle services
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent1)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent2)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent3)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent4)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent5)
|
2024-01-09 06:32:27 -05:00
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
# entities should be in correct state depending on the SUPPORT_STOP feature and cover position
|
|
|
|
|
assert is_closed(hass, ent1)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_opening(hass, ent2, 0, closed=True)
|
2021-11-10 09:03:20 +01:00
|
|
|
assert is_closed(hass, ent3)
|
|
|
|
|
assert is_closed(hass, ent4)
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_opening(hass, ent5, 15)
|
2024-01-09 06:32:27 -05:00
|
|
|
assert is_closing(hass, ent6)
|
|
|
|
|
|
|
|
|
|
# Without STOP but still reports opening/closing has a 4th possible toggle state
|
2024-10-08 18:39:04 +02:00
|
|
|
set_state(ent6, CoverState.CLOSED)
|
2024-01-09 06:32:27 -05:00
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent6)
|
|
|
|
|
assert is_opening(hass, ent6)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
2024-04-18 08:58:16 -04:00
|
|
|
# After the unusual state transition: closing -> fully open, toggle should close
|
2024-10-08 18:39:04 +02:00
|
|
|
set_state(ent5, CoverState.OPEN)
|
2024-04-18 08:58:16 -04:00
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent5) # Start closing
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_closing(hass, ent5, 15)
|
2024-10-08 18:39:04 +02:00
|
|
|
set_state(
|
|
|
|
|
ent5, CoverState.OPEN
|
|
|
|
|
) # Unusual state transition from closing -> fully open
|
2024-04-18 08:58:16 -04:00
|
|
|
set_cover_position(ent5, 100)
|
|
|
|
|
await call_service(hass, SERVICE_TOGGLE, ent5) # Should close, not open
|
2026-03-04 16:54:06 +01:00
|
|
|
assert is_closing(hass, ent5, 100)
|
2024-04-18 08:58:16 -04:00
|
|
|
|
2021-11-10 09:03:20 +01:00
|
|
|
|
2024-08-18 15:35:31 +02:00
|
|
|
def call_service(hass: HomeAssistant, service: str, ent: Entity) -> ServiceResponse:
|
2021-11-10 09:03:20 +01:00
|
|
|
"""Call any service on entity."""
|
|
|
|
|
return hass.services.async_call(
|
|
|
|
|
cover.DOMAIN, service, {ATTR_ENTITY_ID: ent.entity_id}, blocking=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_cover_position(ent, position) -> None:
|
|
|
|
|
"""Set a position value to a cover."""
|
|
|
|
|
ent._values["current_cover_position"] = position
|
|
|
|
|
|
|
|
|
|
|
2024-01-09 06:32:27 -05:00
|
|
|
def set_state(ent, state) -> None:
|
|
|
|
|
"""Set the state of a cover."""
|
|
|
|
|
ent._values["state"] = state
|
|
|
|
|
|
|
|
|
|
|
2026-03-04 16:54:06 +01:00
|
|
|
def _check_state(
|
|
|
|
|
hass: HomeAssistant,
|
|
|
|
|
ent: Entity,
|
|
|
|
|
*,
|
|
|
|
|
expected_state: str,
|
|
|
|
|
expected_position: int | None,
|
|
|
|
|
expected_is_closed: bool,
|
|
|
|
|
) -> bool:
|
|
|
|
|
"""Check if the state of a cover is as expected."""
|
|
|
|
|
state = hass.states.get(ent.entity_id)
|
|
|
|
|
correct_state = state.state == expected_state
|
|
|
|
|
correct_is_closed = state.attributes.get("is_closed") == expected_is_closed
|
|
|
|
|
correct_position = state.attributes.get("current_position") == expected_position
|
|
|
|
|
return all([correct_state, correct_is_closed, correct_position])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_open(hass: HomeAssistant, ent: Entity, position: int | None = None) -> bool:
|
|
|
|
|
"""Return if the cover is open based on the statemachine."""
|
|
|
|
|
return _check_state(
|
|
|
|
|
hass,
|
|
|
|
|
ent,
|
|
|
|
|
expected_state=CoverState.OPEN,
|
|
|
|
|
expected_position=position,
|
|
|
|
|
expected_is_closed=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_opening(
|
|
|
|
|
hass: HomeAssistant,
|
|
|
|
|
ent: Entity,
|
|
|
|
|
position: int | None = None,
|
|
|
|
|
*,
|
|
|
|
|
closed: bool = False,
|
|
|
|
|
) -> bool:
|
|
|
|
|
"""Return if the cover is opening based on the statemachine."""
|
|
|
|
|
return _check_state(
|
|
|
|
|
hass,
|
|
|
|
|
ent,
|
|
|
|
|
expected_state=CoverState.OPENING,
|
|
|
|
|
expected_position=position,
|
|
|
|
|
expected_is_closed=closed,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_closed(hass: HomeAssistant, ent: Entity, position: int | None = None) -> bool:
|
2021-11-10 09:03:20 +01:00
|
|
|
"""Return if the cover is closed based on the statemachine."""
|
2026-03-04 16:54:06 +01:00
|
|
|
return _check_state(
|
|
|
|
|
hass,
|
|
|
|
|
ent,
|
|
|
|
|
expected_state=CoverState.CLOSED,
|
|
|
|
|
expected_position=position,
|
|
|
|
|
expected_is_closed=True,
|
|
|
|
|
)
|
2021-11-10 09:03:20 +01:00
|
|
|
|
|
|
|
|
|
2026-03-04 16:54:06 +01:00
|
|
|
def is_closing(hass: HomeAssistant, ent: Entity, position: int | None = None) -> bool:
|
|
|
|
|
"""Return if the cover is closing based on the statemachine."""
|
|
|
|
|
return _check_state(
|
|
|
|
|
hass,
|
|
|
|
|
ent,
|
|
|
|
|
expected_state=CoverState.CLOSING,
|
|
|
|
|
expected_position=position,
|
|
|
|
|
expected_is_closed=False,
|
|
|
|
|
)
|