From 1b222ff5fd12791506c2de9d181a80ec3a239bb4 Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Tue, 7 Oct 2025 09:06:55 +0200 Subject: [PATCH] Fix restore cover state for Comelit SimpleHome (#153887) --- homeassistant/components/comelit/cover.py | 20 ++++++++--- tests/components/comelit/test_cover.py | 42 ++++++++++------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/comelit/cover.py b/homeassistant/components/comelit/cover.py index 70525ffe7123..1eff1449eb32 100644 --- a/homeassistant/components/comelit/cover.py +++ b/homeassistant/components/comelit/cover.py @@ -7,7 +7,14 @@ from typing import Any, cast from aiocomelit import ComelitSerialBridgeObject from aiocomelit.const import COVER, STATE_COVER, STATE_OFF, STATE_ON -from homeassistant.components.cover import CoverDeviceClass, CoverEntity +from homeassistant.components.cover import ( + STATE_CLOSED, + STATE_CLOSING, + STATE_OPEN, + STATE_OPENING, + CoverDeviceClass, + CoverEntity, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity @@ -62,7 +69,6 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity): super().__init__(coordinator, device, config_entry_entry_id) # Device doesn't provide a status so we assume UNKNOWN at first startup self._last_action: int | None = None - self._last_state: str | None = None def _current_action(self, action: str) -> bool: """Return the current cover action.""" @@ -98,7 +104,6 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity): @bridge_api_call async def _cover_set_state(self, action: int, state: int) -> None: """Set desired cover state.""" - self._last_state = self.state await self.coordinator.api.set_device_status(COVER, self._device.index, action) self.coordinator.data[COVER][self._device.index].status = state self.async_write_ha_state() @@ -124,5 +129,10 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity): await super().async_added_to_hass() - if last_state := await self.async_get_last_state(): - self._last_state = last_state.state + if (state := await self.async_get_last_state()) is not None: + if state.state == STATE_CLOSED: + self._last_action = STATE_COVER.index(STATE_CLOSING) + if state.state == STATE_OPEN: + self._last_action = STATE_COVER.index(STATE_OPENING) + + self._attr_is_closed = state.state == STATE_CLOSED diff --git a/tests/components/comelit/test_cover.py b/tests/components/comelit/test_cover.py index 02efff1dd94a..1e3b27e9c279 100644 --- a/tests/components/comelit/test_cover.py +++ b/tests/components/comelit/test_cover.py @@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, patch from aiocomelit.api import ComelitSerialBridgeObject from aiocomelit.const import COVER, WATT from freezegun.api import FrozenDateTimeFactory +import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.comelit.const import SCAN_INTERVAL @@ -17,14 +18,20 @@ from homeassistant.components.cover import ( STATE_CLOSING, STATE_OPEN, STATE_OPENING, + CoverState, ) from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, State from homeassistant.helpers import entity_registry as er from . import setup_integration -from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform +from tests.common import ( + MockConfigEntry, + async_fire_time_changed, + mock_restore_cache, + snapshot_platform, +) ENTITY_ID = "cover.cover0" @@ -162,37 +169,26 @@ async def test_cover_stop_if_stopped( assert state.state == STATE_UNKNOWN +@pytest.mark.parametrize( + "cover_state", + [ + CoverState.OPEN, + CoverState.CLOSED, + ], +) async def test_cover_restore_state( hass: HomeAssistant, - freezer: FrozenDateTimeFactory, mock_serial_bridge: AsyncMock, mock_serial_bridge_config_entry: MockConfigEntry, + cover_state: CoverState, ) -> None: """Test cover restore state on reload.""" - mock_serial_bridge.reset_mock() + mock_restore_cache(hass, [State(ENTITY_ID, cover_state)]) await setup_integration(hass, mock_serial_bridge_config_entry) assert (state := hass.states.get(ENTITY_ID)) - assert state.state == STATE_UNKNOWN - - # Open cover - await hass.services.async_call( - COVER_DOMAIN, - SERVICE_OPEN_COVER, - {ATTR_ENTITY_ID: ENTITY_ID}, - blocking=True, - ) - mock_serial_bridge.set_device_status.assert_called() - - assert (state := hass.states.get(ENTITY_ID)) - assert state.state == STATE_OPENING - - await hass.config_entries.async_reload(mock_serial_bridge_config_entry.entry_id) - await hass.async_block_till_done() - - assert (state := hass.states.get(ENTITY_ID)) - assert state.state == STATE_OPENING + assert state.state == cover_state async def test_cover_dynamic(