Delete refresh after a non-breaking error at event stream at Home Connect (#139740)

* Delete refresh after non-breaking error

And improve how many time does it take to retry to open stream

* Update tests
This commit is contained in:
J. Diego Rodríguez Royo 2025-03-04 11:07:44 +01:00 committed by GitHub
parent 13001faf51
commit 973fee9fe1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 10 additions and 28 deletions

View File

@ -47,8 +47,6 @@ _LOGGER = logging.getLogger(__name__)
type HomeConnectConfigEntry = ConfigEntry[HomeConnectCoordinator] type HomeConnectConfigEntry = ConfigEntry[HomeConnectCoordinator]
EVENT_STREAM_RECONNECT_DELAY = 30
@dataclass(frozen=True, kw_only=True) @dataclass(frozen=True, kw_only=True)
class HomeConnectApplianceData: class HomeConnectApplianceData:
@ -157,9 +155,11 @@ class HomeConnectCoordinator(
async def _event_listener(self) -> None: async def _event_listener(self) -> None:
"""Match event with listener for event type.""" """Match event with listener for event type."""
retry_time = 10
while True: while True:
try: try:
async for event_message in self.client.stream_all_events(): async for event_message in self.client.stream_all_events():
retry_time = 10
event_message_ha_id = event_message.ha_id event_message_ha_id = event_message.ha_id
match event_message.type: match event_message.type:
case EventType.STATUS: case EventType.STATUS:
@ -256,20 +256,18 @@ class HomeConnectCoordinator(
except (EventStreamInterruptedError, HomeConnectRequestError) as error: except (EventStreamInterruptedError, HomeConnectRequestError) as error:
_LOGGER.debug( _LOGGER.debug(
"Non-breaking error (%s) while listening for events," "Non-breaking error (%s) while listening for events,"
" continuing in 30 seconds", " continuing in %s seconds",
type(error).__name__, type(error).__name__,
retry_time,
) )
await asyncio.sleep(EVENT_STREAM_RECONNECT_DELAY) await asyncio.sleep(retry_time)
retry_time = min(retry_time * 2, 3600)
except HomeConnectApiError as error: except HomeConnectApiError as error:
_LOGGER.error("Error while listening for events: %s", error) _LOGGER.error("Error while listening for events: %s", error)
self.hass.config_entries.async_schedule_reload( self.hass.config_entries.async_schedule_reload(
self.config_entry.entry_id self.config_entry.entry_id
) )
break break
# if there was a non-breaking error, we continue listening
# but we need to refresh the data to get the possible changes
# that happened while the event stream was interrupted
await self.async_refresh()
@callback @callback
def _call_event_listener(self, event_message: EventMessage) -> None: def _call_event_listener(self, event_message: EventMessage) -> None:

View File

@ -1,6 +1,7 @@
"""Test for Home Connect coordinator.""" """Test for Home Connect coordinator."""
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from datetime import timedelta
from typing import Any from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
@ -12,8 +13,6 @@ from aiohomeconnect.model import (
EventKey, EventKey,
EventMessage, EventMessage,
EventType, EventType,
Status,
StatusKey,
) )
from aiohomeconnect.model.error import ( from aiohomeconnect.model.error import (
EventStreamInterruptedError, EventStreamInterruptedError,
@ -24,7 +23,6 @@ from aiohomeconnect.model.error import (
import pytest import pytest
from homeassistant.components.home_connect.const import ( from homeassistant.components.home_connect.const import (
BSH_DOOR_STATE_LOCKED,
BSH_DOOR_STATE_OPEN, BSH_DOOR_STATE_OPEN,
BSH_EVENT_PRESENT_STATE_PRESENT, BSH_EVENT_PRESENT_STATE_PRESENT,
BSH_POWER_OFF, BSH_POWER_OFF,
@ -38,8 +36,9 @@ from homeassistant.core import (
callback, callback,
) )
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.fixture @pytest.fixture
@ -286,9 +285,6 @@ async def test_event_listener_error(
( (
"entity_id", "entity_id",
"initial_state", "initial_state",
"status_key",
"status_value",
"after_refresh_expected_state",
"event_key", "event_key",
"event_value", "event_value",
"after_event_expected_state", "after_event_expected_state",
@ -297,24 +293,15 @@ async def test_event_listener_error(
( (
"sensor.washer_door", "sensor.washer_door",
"closed", "closed",
StatusKey.BSH_COMMON_DOOR_STATE,
BSH_DOOR_STATE_LOCKED,
"locked",
EventKey.BSH_COMMON_STATUS_DOOR_STATE, EventKey.BSH_COMMON_STATUS_DOOR_STATE,
BSH_DOOR_STATE_OPEN, BSH_DOOR_STATE_OPEN,
"open", "open",
), ),
], ],
) )
@patch(
"homeassistant.components.home_connect.coordinator.EVENT_STREAM_RECONNECT_DELAY", 0
)
async def test_event_listener_resilience( async def test_event_listener_resilience(
entity_id: str, entity_id: str,
initial_state: str, initial_state: str,
status_key: StatusKey,
status_value: Any,
after_refresh_expected_state: str,
event_key: EventKey, event_key: EventKey,
event_value: Any, event_value: Any,
after_event_expected_state: str, after_event_expected_state: str,
@ -345,16 +332,13 @@ async def test_event_listener_resilience(
assert hass.states.is_state(entity_id, initial_state) assert hass.states.is_state(entity_id, initial_state)
client.get_status.return_value = ArrayOfStatus(
[Status(key=status_key, raw_key=status_key.value, value=status_value)],
)
await hass.async_block_till_done() await hass.async_block_till_done()
future.set_exception(exception) future.set_exception(exception)
await hass.async_block_till_done() await hass.async_block_till_done()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done()
assert client.stream_all_events.call_count == 2 assert client.stream_all_events.call_count == 2
assert hass.states.is_state(entity_id, after_refresh_expected_state)
await client.add_events( await client.add_events(
[ [