diff --git a/.coveragerc b/.coveragerc index 978c05af3c1..bff146ad46d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -309,7 +309,6 @@ omit = homeassistant/components/esphome/__init__.py homeassistant/components/esphome/bluetooth/* homeassistant/components/esphome/camera.py - homeassistant/components/esphome/cover.py homeassistant/components/esphome/domain_data.py homeassistant/components/esphome/entry_data.py homeassistant/components/esphome/light.py diff --git a/tests/components/esphome/test_cover.py b/tests/components/esphome/test_cover.py new file mode 100644 index 00000000000..59eadb3cfd9 --- /dev/null +++ b/tests/components/esphome/test_cover.py @@ -0,0 +1,208 @@ +"""Test ESPHome covers.""" + +from collections.abc import Awaitable, Callable +from unittest.mock import call + +from aioesphomeapi import ( + APIClient, + CoverInfo, + CoverOperation, + CoverState, + EntityInfo, + EntityState, + UserService, +) + +from homeassistant.components.cover import ( + ATTR_CURRENT_POSITION, + ATTR_CURRENT_TILT_POSITION, + ATTR_POSITION, + ATTR_TILT_POSITION, + DOMAIN as COVER_DOMAIN, + SERVICE_CLOSE_COVER, + SERVICE_CLOSE_COVER_TILT, + SERVICE_OPEN_COVER, + SERVICE_OPEN_COVER_TILT, + SERVICE_SET_COVER_POSITION, + SERVICE_SET_COVER_TILT_POSITION, + SERVICE_STOP_COVER, + STATE_CLOSED, + STATE_CLOSING, + STATE_OPEN, + STATE_OPENING, +) +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import HomeAssistant + +from .conftest import MockESPHomeDevice + + +async def test_cover_entity( + hass: HomeAssistant, + mock_client: APIClient, + mock_esphome_device: Callable[ + [APIClient, list[EntityInfo], list[UserService], list[EntityState]], + Awaitable[MockESPHomeDevice], + ], +) -> None: + """Test a generic cover entity.""" + entity_info = [ + CoverInfo( + object_id="mycover", + key=1, + name="my cover", + unique_id="my_cover", + supports_position=True, + supports_tilt=True, + supports_stop=True, + ) + ] + states = [ + CoverState( + key=1, + position=0.5, + tilt=0.5, + current_operation=CoverOperation.IS_OPENING, + ) + ] + user_service = [] + mock_device = await mock_esphome_device( + mock_client=mock_client, + entity_info=entity_info, + user_service=user_service, + states=states, + ) + state = hass.states.get("cover.test_my_cover") + assert state is not None + assert state.state == STATE_OPENING + assert state.attributes[ATTR_CURRENT_POSITION] == 50 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50 + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: "cover.test_my_cover"}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, position=0.0)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: "cover.test_my_cover"}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, position=1.0)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_SET_COVER_POSITION, + {ATTR_ENTITY_ID: "cover.test_my_cover", ATTR_POSITION: 50}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, position=0.5)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_STOP_COVER, + {ATTR_ENTITY_ID: "cover.test_my_cover"}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, stop=True)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: "cover.test_my_cover"}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, tilt=1.0)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_CLOSE_COVER_TILT, + {ATTR_ENTITY_ID: "cover.test_my_cover"}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.0)]) + mock_client.cover_command.reset_mock() + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_SET_COVER_TILT_POSITION, + {ATTR_ENTITY_ID: "cover.test_my_cover", ATTR_TILT_POSITION: 50}, + blocking=True, + ) + mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.5)]) + mock_client.cover_command.reset_mock() + + mock_device.set_state( + CoverState(key=1, position=0.0, current_operation=CoverOperation.IDLE) + ) + await hass.async_block_till_done() + state = hass.states.get("cover.test_my_cover") + assert state is not None + assert state.state == STATE_CLOSED + + mock_device.set_state( + CoverState(key=1, position=0.5, current_operation=CoverOperation.IS_CLOSING) + ) + await hass.async_block_till_done() + state = hass.states.get("cover.test_my_cover") + assert state is not None + assert state.state == STATE_CLOSING + + mock_device.set_state( + CoverState(key=1, position=1.0, current_operation=CoverOperation.IDLE) + ) + await hass.async_block_till_done() + state = hass.states.get("cover.test_my_cover") + assert state is not None + assert state.state == STATE_OPEN + + +async def test_cover_entity_without_position( + hass: HomeAssistant, + mock_client: APIClient, + mock_esphome_device: Callable[ + [APIClient, list[EntityInfo], list[UserService], list[EntityState]], + Awaitable[MockESPHomeDevice], + ], +) -> None: + """Test a generic cover entity without position, tilt, or stop.""" + entity_info = [ + CoverInfo( + object_id="mycover", + key=1, + name="my cover", + unique_id="my_cover", + supports_position=False, + supports_tilt=False, + supports_stop=False, + ) + ] + states = [ + CoverState( + key=1, + position=0.5, + tilt=0.5, + current_operation=CoverOperation.IS_OPENING, + ) + ] + user_service = [] + await mock_esphome_device( + mock_client=mock_client, + entity_info=entity_info, + user_service=user_service, + states=states, + ) + state = hass.states.get("cover.test_my_cover") + assert state is not None + assert state.state == STATE_OPENING + assert ATTR_CURRENT_TILT_POSITION not in state.attributes + assert ATTR_CURRENT_POSITION not in state.attributes