mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 15:47:12 +00:00
Re-enable Home Connect updates automatically (#148657)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
b2fe17c6d4
commit
74288a3bc8
@ -38,7 +38,7 @@ from propcache.api import cached_property
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr, issue_registry as ir
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import (
|
||||
@ -626,39 +626,37 @@ class HomeConnectCoordinator(
|
||||
"""Check if the appliance data hasn't been refreshed too often recently."""
|
||||
|
||||
now = self.hass.loop.time()
|
||||
if len(self._execution_tracker[appliance_ha_id]) >= MAX_EXECUTIONS:
|
||||
return True
|
||||
|
||||
execution_tracker = self._execution_tracker[appliance_ha_id]
|
||||
initial_len = len(execution_tracker)
|
||||
|
||||
execution_tracker = self._execution_tracker[appliance_ha_id] = [
|
||||
timestamp
|
||||
for timestamp in self._execution_tracker[appliance_ha_id]
|
||||
for timestamp in execution_tracker
|
||||
if now - timestamp < MAX_EXECUTIONS_TIME_WINDOW
|
||||
]
|
||||
|
||||
execution_tracker.append(now)
|
||||
|
||||
if len(execution_tracker) >= MAX_EXECUTIONS:
|
||||
ir.async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
f"home_connect_too_many_connected_paired_events_{appliance_ha_id}",
|
||||
is_fixable=True,
|
||||
is_persistent=True,
|
||||
severity=ir.IssueSeverity.ERROR,
|
||||
translation_key="home_connect_too_many_connected_paired_events",
|
||||
data={
|
||||
"entry_id": self.config_entry.entry_id,
|
||||
"appliance_ha_id": appliance_ha_id,
|
||||
},
|
||||
translation_placeholders={
|
||||
"appliance_name": self.data[appliance_ha_id].info.name,
|
||||
"times": str(MAX_EXECUTIONS),
|
||||
"time_window": str(MAX_EXECUTIONS_TIME_WINDOW // 60),
|
||||
"home_connect_resource_url": "https://www.home-connect.com/global/help-support/error-codes#/Togglebox=15362315-13320636-1/",
|
||||
"home_assistant_core_issue_url": "https://github.com/home-assistant/core/issues/147299",
|
||||
},
|
||||
)
|
||||
if initial_len < MAX_EXECUTIONS:
|
||||
_LOGGER.warning(
|
||||
'Too many connected/paired events for appliance "%s" '
|
||||
"(%s times in less than %s minutes), updates have been disabled "
|
||||
"and they will be enabled again whenever the connection stabilizes. "
|
||||
"Consider trying to unplug the appliance "
|
||||
"for a while to perform a soft reset",
|
||||
self.data[appliance_ha_id].info.name,
|
||||
MAX_EXECUTIONS,
|
||||
MAX_EXECUTIONS_TIME_WINDOW // 60,
|
||||
)
|
||||
return True
|
||||
if initial_len >= MAX_EXECUTIONS:
|
||||
_LOGGER.info(
|
||||
'Connected/paired events from the appliance "%s" have stabilized,'
|
||||
" updates have been re-enabled",
|
||||
self.data[appliance_ha_id].info.name,
|
||||
)
|
||||
|
||||
return False
|
||||
|
||||
|
@ -124,17 +124,6 @@
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"home_connect_too_many_connected_paired_events": {
|
||||
"title": "{appliance_name} sent too many connected or paired events",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
"title": "[%key:component::home_connect::issues::home_connect_too_many_connected_paired_events::title%]",
|
||||
"description": "The appliance \"{appliance_name}\" has been reported as connected or paired {times} times in less than {time_window} minutes, so refreshes on connected or paired events has been disabled to avoid exceeding the API rate limit.\n\nPlease refer to the [Home Connect Wi-Fi requirements and recommendations]({home_connect_resource_url}). If everything seems right with your network configuration, restart the appliance.\n\nClick \"submit\" to re-enable the updates.\nIf the issue persists, please see the following issue in the [Home Assistant core repository]({home_assistant_core_issue_url})."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated_time_alarm_clock_in_automations_scripts": {
|
||||
"title": "Deprecated alarm clock entity detected in some automations or scripts",
|
||||
"fix_flow": {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from datetime import timedelta
|
||||
from http import HTTPStatus
|
||||
from typing import Any, cast
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
@ -53,16 +52,11 @@ from homeassistant.core import (
|
||||
HomeAssistant,
|
||||
callback,
|
||||
)
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
)
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
INITIAL_FETCH_CLIENT_METHODS = [
|
||||
"get_settings",
|
||||
@ -580,8 +574,7 @@ async def test_paired_disconnected_devices_not_fetching(
|
||||
|
||||
async def test_coordinator_disabling_updates_for_appliance(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
client: MagicMock,
|
||||
config_entry: MockConfigEntry,
|
||||
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||
@ -592,7 +585,6 @@ async def test_coordinator_disabling_updates_for_appliance(
|
||||
When the user confirms the issue the updates should be enabled again.
|
||||
"""
|
||||
appliance_ha_id = "SIEMENS-HCS02DWH1-6BE58C26DCC1"
|
||||
issue_id = f"home_connect_too_many_connected_paired_events_{appliance_ha_id}"
|
||||
|
||||
assert await integration_setup(client)
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
@ -606,13 +598,26 @@ async def test_coordinator_disabling_updates_for_appliance(
|
||||
EventType.CONNECTED,
|
||||
data=ArrayOfEvents([]),
|
||||
)
|
||||
for _ in range(8)
|
||||
for _ in range(6)
|
||||
]
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert issue
|
||||
freezer.tick(timedelta(minutes=10))
|
||||
await client.add_events(
|
||||
[
|
||||
EventMessage(
|
||||
appliance_ha_id,
|
||||
EventType.CONNECTED,
|
||||
data=ArrayOfEvents([]),
|
||||
)
|
||||
for _ in range(2)
|
||||
]
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# At this point, the updates have been blocked because
|
||||
# 6 + 2 connected events have been received in less than an hour
|
||||
|
||||
get_settings_original_side_effect = client.get_settings.side_effect
|
||||
|
||||
@ -644,18 +649,36 @@ async def test_coordinator_disabling_updates_for_appliance(
|
||||
|
||||
assert hass.states.is_state("switch.dishwasher_power", STATE_ON)
|
||||
|
||||
_client = await hass_client()
|
||||
resp = await _client.post(
|
||||
"/api/repairs/issues/fix",
|
||||
json={"handler": DOMAIN, "issue_id": issue.issue_id},
|
||||
# After 55 minutes, the updates should be enabled again
|
||||
# because one hour has passed since the first connect events,
|
||||
# so there are 2 connected events in the execution_tracker
|
||||
freezer.tick(timedelta(minutes=55))
|
||||
await client.add_events(
|
||||
[
|
||||
EventMessage(
|
||||
appliance_ha_id,
|
||||
EventType.CONNECTED,
|
||||
data=ArrayOfEvents([]),
|
||||
)
|
||||
]
|
||||
)
|
||||
assert resp.status == HTTPStatus.OK
|
||||
flow_id = (await resp.json())["flow_id"]
|
||||
resp = await _client.post(f"/api/repairs/issues/fix/{flow_id}")
|
||||
assert resp.status == HTTPStatus.OK
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert hass.states.is_state("switch.dishwasher_power", STATE_OFF)
|
||||
|
||||
# If more connect events are sent, it should be blocked again
|
||||
await client.add_events(
|
||||
[
|
||||
EventMessage(
|
||||
appliance_ha_id,
|
||||
EventType.CONNECTED,
|
||||
data=ArrayOfEvents([]),
|
||||
)
|
||||
for _ in range(5) # 2 + 1 + 5 = 8 connect events in less than an hour
|
||||
]
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
client.get_settings = get_settings_original_side_effect
|
||||
await client.add_events(
|
||||
[
|
||||
EventMessage(
|
||||
@ -672,7 +695,6 @@ async def test_coordinator_disabling_updates_for_appliance(
|
||||
|
||||
async def test_coordinator_disabling_updates_for_appliance_is_gone_after_entry_reload(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
client: MagicMock,
|
||||
config_entry: MockConfigEntry,
|
||||
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||
@ -682,7 +704,6 @@ async def test_coordinator_disabling_updates_for_appliance_is_gone_after_entry_r
|
||||
The repair issue should also be deleted.
|
||||
"""
|
||||
appliance_ha_id = "SIEMENS-HCS02DWH1-6BE58C26DCC1"
|
||||
issue_id = f"home_connect_too_many_connected_paired_events_{appliance_ha_id}"
|
||||
|
||||
assert await integration_setup(client)
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
@ -701,14 +722,9 @@ async def test_coordinator_disabling_updates_for_appliance_is_gone_after_entry_r
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert issue
|
||||
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
|
||||
assert await integration_setup(client)
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user