1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Cache get api calls in FRITZ!Box tools (#160246)

Co-authored-by: Simone Chemelli <simone.chemelli@gmail.com>
This commit is contained in:
Michael
2026-02-13 01:54:33 +01:00
committed by GitHub
parent fc52885c21
commit 89f5b33a5e
3 changed files with 58 additions and 9 deletions
+50 -6
View File
@@ -36,6 +36,7 @@ from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import slugify
from homeassistant.util.hass_dict import HassKey
from .const import (
@@ -90,10 +91,56 @@ class UpdateCoordinatorDataType(TypedDict):
entity_states: dict[str, StateType | bool]
class FritzConnectionCached(FritzConnection): # type: ignore[misc]
"""FritzConnection with cached call action."""
_call_cache: dict[str, dict[str, Any]]
def clear_cache(self) -> None:
"""Clear cached calls."""
self._call_cache = {}
_LOGGER.debug("Cleared FritzConnection call action cache")
def call_action(
self,
service_name: str,
action_name: str,
*,
arguments: dict | None = None,
**kwargs: Any,
) -> dict[str, Any]:
"""Call action with cached services. Only get actions are cached."""
if not action_name.lower().startswith("get"):
return super().call_action( # type: ignore[no-any-return]
service_name, action_name, arguments=arguments, **kwargs
)
if not hasattr(self, "_call_cache"):
self._call_cache = {}
kwargs_key = ",".join(f"{k}={v!r}" for k, v in sorted(kwargs.items()))
cache_key = slugify(f"{service_name}:{action_name}:{arguments}:{kwargs_key}")
if (result := self._call_cache.get(cache_key)) is not None:
_LOGGER.debug("Using cached result for %s %s", service_name, action_name)
return result
result = super().call_action(
service_name, action_name, arguments=arguments, **kwargs
)
self._call_cache[cache_key] = result
return result # type: ignore[no-any-return]
class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
"""FritzBoxTools class."""
config_entry: FritzConfigEntry
connection: FritzConnectionCached
fritz_guest_wifi: FritzGuestWLAN
fritz_hosts: FritzHosts
fritz_status: FritzStatus
fritz_call: FritzCall
def __init__(
self,
@@ -118,11 +165,6 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
self._devices: dict[str, FritzDevice] = {}
self._options: Mapping[str, Any] | None = None
self._unique_id: str | None = None
self.connection: FritzConnection = None
self.fritz_guest_wifi: FritzGuestWLAN = None
self.fritz_hosts: FritzHosts = None
self.fritz_status: FritzStatus = None
self.fritz_call: FritzCall = None
self.host = host
self.mesh_role = MeshRoles.NONE
self.mesh_wifi_uplink = False
@@ -159,11 +201,12 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
name=self.config_entry.title,
sw_version=self.current_firmware,
)
self.connection.clear_cache()
def setup(self) -> None:
"""Set up FritzboxTools class."""
self.connection = FritzConnection(
self.connection = FritzConnectionCached(
address=self.host,
port=self.port,
user=self.username,
@@ -263,6 +306,7 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
"call_deflections": {},
"entity_states": {},
}
self.connection.clear_cache()
try:
await self.async_update_device_info()
+6 -1
View File
@@ -58,6 +58,10 @@ class FritzConnectionMock:
"""Overrire services data."""
self._services = services
def clear_cache(self) -> None:
"""Mock clear_cache method."""
return
def _call_action(self, service: str, action: str, **kwargs):
LOGGER.debug(
"_call_action service: %s, action: %s, **kwargs: %s",
@@ -89,7 +93,8 @@ def fc_data_mock():
def fc_class_mock(fc_data):
"""Fixture that sets up a mocked FritzConnection class."""
with patch(
"homeassistant.components.fritz.coordinator.FritzConnection", autospec=True
"homeassistant.components.fritz.coordinator.FritzConnectionCached",
autospec=True,
) as result:
result.return_value = FritzConnectionMock(fc_data)
yield result
+2 -2
View File
@@ -75,7 +75,7 @@ async def test_setup_auth_fail(hass: HomeAssistant, error) -> None:
entry.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.coordinator.FritzConnection",
"homeassistant.components.fritz.coordinator.FritzConnectionCached",
side_effect=error,
):
await hass.config_entries.async_setup(entry.entry_id)
@@ -95,7 +95,7 @@ async def test_setup_fail(hass: HomeAssistant, error) -> None:
entry.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.coordinator.FritzConnection",
"homeassistant.components.fritz.coordinator.FritzConnectionCached",
side_effect=error,
):
await hass.config_entries.async_setup(entry.entry_id)