diff --git a/homeassistant/components/gogogate2/cover.py b/homeassistant/components/gogogate2/cover.py index 0097198f1c2..1410bc9e97d 100644 --- a/homeassistant/components/gogogate2/cover.py +++ b/homeassistant/components/gogogate2/cover.py @@ -3,7 +3,12 @@ from __future__ import annotations import logging -from ismartgate.common import AbstractDoor, DoorStatus, get_configured_doors +from ismartgate.common import ( + AbstractDoor, + DoorStatus, + TransitionDoorStatus, + get_configured_doors, +) from homeassistant.components.cover import ( DEVICE_CLASS_GARAGE, @@ -84,11 +89,10 @@ class DeviceCover(GoGoGate2Entity, CoverEntity): @property def is_closed(self): """Return true if cover is closed, else False.""" - door = self._get_door() - - if door.status == DoorStatus.OPENED: + door_status = self._get_door_status() + if door_status == DoorStatus.OPENED: return False - if door.status == DoorStatus.CLOSED: + if door_status == DoorStatus.CLOSED: return True return None @@ -96,8 +100,7 @@ class DeviceCover(GoGoGate2Entity, CoverEntity): @property def device_class(self): """Return the class of this device, from component DEVICE_CLASSES.""" - door = self._get_door() - if door.gate: + if self._get_door().gate: return DEVICE_CLASS_GATE return DEVICE_CLASS_GARAGE @@ -107,15 +110,32 @@ class DeviceCover(GoGoGate2Entity, CoverEntity): """Flag supported features.""" return SUPPORT_OPEN | SUPPORT_CLOSE + @property + def is_closing(self): + """Return if the cover is closing or not.""" + return self._get_door_status() == TransitionDoorStatus.CLOSING + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + return self._get_door_status() == TransitionDoorStatus.OPENING + async def async_open_cover(self, **kwargs): """Open the door.""" await self._api.async_open_door(self._get_door().door_id) + await self.coordinator.async_refresh() async def async_close_cover(self, **kwargs): """Close the door.""" await self._api.async_close_door(self._get_door().door_id) + await self.coordinator.async_refresh() @property def extra_state_attributes(self): """Return the state attributes.""" return {"door_id": self._get_door().door_id} + + def _get_door_status(self) -> AbstractDoor: + return self._api.async_get_door_statuses_from_info(self.coordinator.data)[ + self._door.door_id + ] diff --git a/tests/components/gogogate2/test_cover.py b/tests/components/gogogate2/test_cover.py index 3a044c33a94..9c4f3ee8e69 100644 --- a/tests/components/gogogate2/test_cover.py +++ b/tests/components/gogogate2/test_cover.py @@ -14,6 +14,7 @@ from ismartgate.common import ( ISmartGateInfoResponse, Network, Outputs, + TransitionDoorStatus, Wifi, ) @@ -44,7 +45,9 @@ from homeassistant.const import ( CONF_UNIT_SYSTEM_METRIC, CONF_USERNAME, STATE_CLOSED, + STATE_CLOSING, STATE_OPEN, + STATE_OPENING, STATE_UNAVAILABLE, STATE_UNKNOWN, ) @@ -331,6 +334,10 @@ async def test_open_close_update(gogogate2api_mock, hass: HomeAssistant) -> None api = MagicMock(GogoGate2Api) api.async_activate.return_value = GogoGate2ActivateResponse(result=True) api.async_info.return_value = info_response(DoorStatus.OPENED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.OPENED, + 2: DoorStatus.OPENED, + } gogogate2api_mock.return_value = api config_entry = MockConfigEntry( @@ -351,32 +358,102 @@ async def test_open_close_update(gogogate2api_mock, hass: HomeAssistant) -> None assert dict(hass.states.get("cover.door1").attributes) == expected_attributes api.async_info.return_value = info_response(DoorStatus.CLOSED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.CLOSED, + 2: DoorStatus.CLOSED, + } await hass.services.async_call( COVER_DOMAIN, "close_cover", service_data={"entity_id": "cover.door1"}, ) + api.async_get_door_statuses_from_info.return_value = { + 1: TransitionDoorStatus.CLOSING, + 2: TransitionDoorStatus.CLOSING, + } + async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) + await hass.async_block_till_done() + assert hass.states.get("cover.door1").state == STATE_CLOSING + api.async_close_door.assert_called_with(1) + + async_fire_time_changed(hass, utcnow() + timedelta(seconds=10)) + await hass.async_block_till_done() + assert hass.states.get("cover.door1").state == STATE_CLOSING + + api.async_info.return_value = info_response(DoorStatus.CLOSED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.CLOSED, + 2: DoorStatus.CLOSED, + } async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) await hass.async_block_till_done() assert hass.states.get("cover.door1").state == STATE_CLOSED - api.async_close_door.assert_called_with(1) api.async_info.return_value = info_response(DoorStatus.OPENED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.OPENED, + 2: DoorStatus.OPENED, + } await hass.services.async_call( COVER_DOMAIN, "open_cover", service_data={"entity_id": "cover.door1"}, ) + api.async_get_door_statuses_from_info.return_value = { + 1: TransitionDoorStatus.OPENING, + 2: TransitionDoorStatus.OPENING, + } + async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) + await hass.async_block_till_done() + assert hass.states.get("cover.door1").state == STATE_OPENING + api.async_open_door.assert_called_with(1) + + async_fire_time_changed(hass, utcnow() + timedelta(seconds=10)) + await hass.async_block_till_done() + assert hass.states.get("cover.door1").state == STATE_OPENING + + api.async_info.return_value = info_response(DoorStatus.OPENED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.OPENED, + 2: DoorStatus.OPENED, + } async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) await hass.async_block_till_done() assert hass.states.get("cover.door1").state == STATE_OPEN - api.async_open_door.assert_called_with(1) api.async_info.return_value = info_response(DoorStatus.UNDEFINED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.UNDEFINED, + 2: DoorStatus.UNDEFINED, + } async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) await hass.async_block_till_done() assert hass.states.get("cover.door1").state == STATE_UNKNOWN + api.async_info.return_value = info_response(DoorStatus.OPENED) + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.OPENED, + 2: DoorStatus.OPENED, + } + await hass.services.async_call( + COVER_DOMAIN, + "close_cover", + service_data={"entity_id": "cover.door1"}, + ) + await hass.services.async_call( + COVER_DOMAIN, + "open_cover", + service_data={"entity_id": "cover.door1"}, + ) + api.async_get_door_statuses_from_info.return_value = { + 1: TransitionDoorStatus.OPENING, + 2: TransitionDoorStatus.OPENING, + } + async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) + await hass.async_block_till_done() + assert hass.states.get("cover.door1").state == STATE_OPENING + api.async_open_door.assert_called_with(1) + assert await hass.config_entries.async_unload(config_entry.entry_id) assert not hass.states.async_entity_ids(DOMAIN) @@ -430,6 +507,10 @@ async def test_availability(ismartgateapi_mock, hass: HomeAssistant) -> None: api.async_info.side_effect = None api.async_info.return_value = closed_door_response + api.async_get_door_statuses_from_info.return_value = { + 1: DoorStatus.CLOSED, + 2: DoorStatus.CLOSED, + } async_fire_time_changed(hass, utcnow() + timedelta(hours=2)) await hass.async_block_till_done() assert hass.states.get("cover.door1").state == STATE_CLOSED