Handle unavailable UniFi configuration endpoint (#182574)

This commit is contained in:
Robert Svensson
2026-09-19 11:24:03 +02:00
committed by GitHub
parent 3199454185
commit fee52805ab
3 changed files with 69 additions and 3 deletions
+22 -2
View File
@@ -3,10 +3,11 @@
from datetime import timedelta
from typing import TYPE_CHECKING, override
from aiounifi import EndpointNotFound
from aiounifi.interfaces.api_handlers import APIHandler, ItemEvent
from homeassistant.core import callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import LOGGER
@@ -25,6 +26,8 @@ class UnifiDataUpdateCoordinator[HandlerT: APIHandler](
self,
hub: UnifiHub,
handler: HandlerT,
*,
disable_polling_on_endpoint_not_found: bool = False,
) -> None:
"""Initialize coordinator."""
supports_websocket = bool(handler.process_messages or handler.remove_messages)
@@ -36,6 +39,10 @@ class UnifiDataUpdateCoordinator[HandlerT: APIHandler](
update_interval=None if supports_websocket else POLL_INTERVAL,
)
self._handler = handler
self._disable_polling_on_endpoint_not_found = (
disable_polling_on_endpoint_not_found
)
self._endpoint_not_found_logged = False
hub.config.entry.async_on_unload(handler.subscribe(self._async_handle_update))
@@ -47,7 +54,20 @@ class UnifiDataUpdateCoordinator[HandlerT: APIHandler](
@override
async def _async_update_data(self) -> None:
"""Update data from the API handler."""
await self._handler.update()
try:
await self._handler.update()
except EndpointNotFound as err:
if (
self._disable_polling_on_endpoint_not_found
and not self._endpoint_not_found_logged
):
self._endpoint_not_found_logged = True
self.update_interval = None
self.logger.warning(
"UniFi %s endpoint is unavailable; disabling polling",
type(self._handler).__name__,
)
raise UpdateFailed(str(err)) from err
@callback
def _async_handle_update(self, event: ItemEvent, obj_id: str) -> None:
@@ -53,7 +53,9 @@ class UnifiEntityLoader:
hub, hub.api.firewall_policies
),
id(hub.api.object_oriented_network_configs): UnifiDataUpdateCoordinator(
hub, hub.api.object_oriented_network_configs
hub,
hub.api.object_oriented_network_configs,
disable_polling_on_endpoint_not_found=True,
),
id(hub.api.port_forwarding): UnifiDataUpdateCoordinator(
hub, hub.api.port_forwarding
+44
View File
@@ -6,6 +6,7 @@ from typing import Any
from unittest.mock import patch
import aiounifi
from aiounifi import EndpointNotFound
from aiounifi.interfaces.api_handlers import ItemEvent
from aiounifi.models.message import MessageKey
import pytest
@@ -122,6 +123,49 @@ async def test_polling_coordinator_refreshes_after_interval(
assert mock_update.call_count >= 1
async def test_endpoint_not_found_disables_object_oriented_network_config_polling(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
config_entry_setup: MockConfigEntry,
) -> None:
"""Ensure an unavailable optional endpoint stops polling after one warning."""
loader = config_entry_setup.runtime_data.entity_loader
api = config_entry_setup.runtime_data.api
coordinator = loader.get_data_update_coordinator(
api.object_oriented_network_configs
)
traffic_rules_coordinator = loader.get_data_update_coordinator(api.traffic_rules)
with patch.object(
coordinator.handler,
"update",
side_effect=EndpointNotFound("endpoint not found"),
) as mock_update:
await coordinator.async_refresh()
await hass.async_block_till_done()
assert coordinator.update_interval is None
assert coordinator.last_update_success is False
assert mock_update.call_count == 1
async_fire_time_changed(hass, dt_util.utcnow() + POLL_INTERVAL)
await hass.async_block_till_done()
assert mock_update.call_count == 1
await coordinator.async_refresh()
await hass.async_block_till_done()
assert mock_update.call_count == 2
assert traffic_rules_coordinator.update_interval == POLL_INTERVAL
assert (
caplog.text.count(
"UniFi ObjectOrientedNetworkConfigs endpoint is unavailable; disabling polling"
)
== 1
)
@pytest.mark.parametrize(
"object_oriented_network_config_payload",
[