mirror of
https://github.com/home-assistant/core.git
synced 2026-10-07 14:58:11 -04:00
Log MELCloud Home telemetry unavailability once (#183649)
This commit is contained in:
@@ -5,7 +5,7 @@ from collections.abc import Callable, Coroutine
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from typing import override
|
||||
from typing import Any, override
|
||||
|
||||
from aiomelcloudhome import ATAUnit, ATWUnit, MELCloudHome, UserContext
|
||||
from aiomelcloudhome.exceptions import (
|
||||
@@ -180,35 +180,51 @@ class MelCloudHomeTelemetryCoordinator(
|
||||
update_interval=TELEMETRY_UPDATE_INTERVAL,
|
||||
)
|
||||
self.client = client
|
||||
self._unavailable_telemetry: set[tuple[str, str]] = set()
|
||||
|
||||
async def _async_fetch_telemetry[_T](
|
||||
self, name: str, unit_id: str, coroutine: Coroutine[Any, Any, _T]
|
||||
) -> _T | None:
|
||||
"""Fetch telemetry for a unit, logging once when it becomes unavailable."""
|
||||
key = (name, unit_id)
|
||||
try:
|
||||
result = await coroutine
|
||||
except (
|
||||
MelCloudHomeAuthenticationError,
|
||||
MelCloudHomeConnectionError,
|
||||
MelCloudHomeTimeoutError,
|
||||
):
|
||||
if key not in self._unavailable_telemetry:
|
||||
self._unavailable_telemetry.add(key)
|
||||
_LOGGER.info("%s for %s is unavailable", name, unit_id)
|
||||
return None
|
||||
if key in self._unavailable_telemetry:
|
||||
self._unavailable_telemetry.remove(key)
|
||||
_LOGGER.info("%s for %s is available again", name, unit_id)
|
||||
return result
|
||||
|
||||
async def _async_get_energy(
|
||||
self, unit_id: str, start_of_month: datetime, now: datetime
|
||||
) -> float | None:
|
||||
"""Fetch energy telemetry for a unit without failing the whole update."""
|
||||
try:
|
||||
energy = await self.client.get_energy_telemetry(
|
||||
energy = await self._async_fetch_telemetry(
|
||||
"Energy telemetry",
|
||||
unit_id,
|
||||
self.client.get_energy_telemetry(
|
||||
unit_id, from_dt=start_of_month, to_dt=now, interval="Day"
|
||||
)
|
||||
except (
|
||||
MelCloudHomeAuthenticationError,
|
||||
MelCloudHomeConnectionError,
|
||||
MelCloudHomeTimeoutError,
|
||||
):
|
||||
_LOGGER.warning("Failed to fetch energy telemetry for %s:", unit_id)
|
||||
),
|
||||
)
|
||||
if energy is None:
|
||||
return None
|
||||
return sum(float(e.value) for e in energy)
|
||||
|
||||
async def _async_get_outdoor_temperature(self, unit_id: str) -> float | None:
|
||||
"""Fetch outdoor temperature for a unit without failing the whole update."""
|
||||
try:
|
||||
return await self.client.get_outdoor_temperature(unit_id)
|
||||
except (
|
||||
MelCloudHomeAuthenticationError,
|
||||
MelCloudHomeConnectionError,
|
||||
MelCloudHomeTimeoutError,
|
||||
):
|
||||
_LOGGER.warning("Failed to fetch outdoor temperature for %s", unit_id)
|
||||
return None
|
||||
return await self._async_fetch_telemetry(
|
||||
"Outdoor temperature",
|
||||
unit_id,
|
||||
self.client.get_outdoor_temperature(unit_id),
|
||||
)
|
||||
|
||||
@override
|
||||
async def _async_update_data(self) -> MelCloudHomeTelemetryData:
|
||||
|
||||
@@ -346,3 +346,45 @@ async def test_outdoor_temperature_update_cycle_fails(
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
assert telemetry_coordinator.data.outdoor_temperature["ata-unit-uuid-1"] is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "name"),
|
||||
[
|
||||
pytest.param("get_energy_telemetry", "Energy telemetry", id="energy"),
|
||||
pytest.param(
|
||||
"get_outdoor_temperature", "Outdoor temperature", id="outdoor_temperature"
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_telemetry_unavailable_logged_once(
|
||||
hass: HomeAssistant,
|
||||
mock_melcloud_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
method: str,
|
||||
name: str,
|
||||
) -> None:
|
||||
"""Test a failing telemetry fetch is logged once, and once when it recovers."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
unavailable = f"{name} for ata-unit-uuid-1 is unavailable"
|
||||
available = f"{name} for ata-unit-uuid-1 is available again"
|
||||
|
||||
getattr(mock_melcloud_client, method).side_effect = MelCloudHomeConnectionError
|
||||
for _ in range(2):
|
||||
freezer.tick(TELEMETRY_UPDATE_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
assert caplog.text.count(unavailable) == 1
|
||||
assert available not in caplog.text
|
||||
|
||||
getattr(mock_melcloud_client, method).side_effect = None
|
||||
for _ in range(2):
|
||||
freezer.tick(TELEMETRY_UPDATE_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
assert caplog.text.count(unavailable) == 1
|
||||
assert caplog.text.count(available) == 1
|
||||
|
||||
Reference in New Issue
Block a user