Skip to content

Commit

Permalink
Reduce data load, if only the device description is updated (#1623)
Browse files Browse the repository at this point in the history
* Reduce data load, if only device description is updated

* small fixes

* Update __init__.py

* Update requirements_test.txt
  • Loading branch information
SukramJ authored Aug 1, 2024
1 parent 9bd74c7 commit efa6e81
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 30 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Version 2024.8.0(2024-08-01)

- Reduce data load, if only device description is updated

# Version 2024.7.1 (2024-07-27)

- Enable button lock for hm devices
Expand Down
13 changes: 6 additions & 7 deletions hahomematic/caches/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@ async def load(self, direct_call: bool = False) -> None:
):
return
self.clear()
_LOGGER.debug("load: Loading names for %s", self._central.name)
_LOGGER.debug("LOAD: Loading names for %s", self._central.name)
if client := self._central.primary_client:
await client.fetch_device_details()
_LOGGER.debug("load: Loading rooms for %s", self._central.name)
_LOGGER.debug("LOAD: Loading rooms for %s", self._central.name)
self._channel_rooms.clear()
self._channel_rooms.update(await self._get_all_rooms())
_LOGGER.debug("load: Loading functions for %s", self._central.name)
_LOGGER.debug("LOAD: Loading functions for %s", self._central.name)
self._functions.clear()
self._functions.update(await self._get_all_functions())
self._refreshed_at = datetime.now()
Expand All @@ -159,17 +159,15 @@ def device_channel_ids(self) -> Mapping[str, str]:

def add_name(self, address: str, name: str) -> None:
"""Add name to cache."""
if address not in self._names_cache:
self._names_cache[address] = name
self._names_cache[address] = name

def get_name(self, address: str) -> str | None:
"""Get name from cache."""
return self._names_cache.get(address)

def add_interface(self, address: str, interface: str) -> None:
"""Add interface to cache."""
if address not in self._interface_cache:
self._interface_cache[address] = interface
self._interface_cache[address] = interface

def get_interface(self, address: str) -> str:
"""Get interface from cache."""
Expand Down Expand Up @@ -263,6 +261,7 @@ async def refresh_entity_data(self, paramset_key: str | None = None) -> None:

def add_data(self, all_device_data: dict[str, Any]) -> None:
"""Add data to cache."""
self.clear()
self._value_cache.update(all_device_data)
self._refreshed_at = datetime.now()

Expand Down
66 changes: 50 additions & 16 deletions hahomematic/central/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from datetime import datetime
from functools import partial
import logging
from logging import DEBUG
import socket
import threading
from time import sleep
Expand Down Expand Up @@ -399,7 +400,8 @@ async def _start_clients(self) -> None:
"""Start clients ."""
if await self._create_clients():
await self._load_caches()
await self._create_devices()
if new_device_addresses := self._check_for_new_device_addresses():
await self._create_devices(new_device_addresses=new_device_addresses)
await self._init_hub()
await self._init_clients()

Expand Down Expand Up @@ -691,7 +693,7 @@ async def _load_caches(self) -> None:
_LOGGER.warning("LOAD_CACHES failed: Unable to load caches for %s", self._name)
await self.clear_caches()

async def _create_devices(self) -> None:
async def _create_devices(self, new_device_addresses: dict[str, set[str]]) -> None:
"""Trigger creation of the objects that expose the functionality."""
if not self._clients:
raise HaHomematicException(
Expand All @@ -700,20 +702,13 @@ async def _create_devices(self) -> None:
_LOGGER.debug("CREATE_DEVICES: Starting to create devices for %s", self._name)

new_devices = set[HmDevice]()
for interface_id in self.interface_ids:
if not self.paramset_descriptions.has_interface_id(interface_id=interface_id):
_LOGGER.debug(
"CREATE_DEVICES: Skipping interface %s, missing paramsets",
interface_id,
)
continue
for device_address in self.device_descriptions.get_addresses(
interface_id=interface_id
):

for interface_id, device_addresses in new_device_addresses.items():
for device_address in device_addresses:
# Do we check for duplicates here? For now, we do.
device: HmDevice | None = None
if device_address in self._devices:
continue
device: HmDevice | None = None
try:
device = HmDevice(
central=self,
Expand Down Expand Up @@ -828,9 +823,48 @@ async def _add_new_devices(

await self.device_descriptions.save()
await self.paramset_descriptions.save()
await self.device_details.load()
await self.data_cache.load()
await self._create_devices()
if new_device_addresses := self._check_for_new_device_addresses():
await self.device_details.load()
await self.data_cache.load()
await self._create_devices(new_device_addresses=new_device_addresses)

def _check_for_new_device_addresses(self) -> dict[str, set[str]]:
"""Check if there are new devices, that needs to be created."""
new_device_addresses: dict[str, set[str]] = {}
for interface_id in self.interface_ids:
if not self.paramset_descriptions.has_interface_id(interface_id=interface_id):
_LOGGER.debug(
"CHECK_FOR_NEW_DEVICE_ADDRESSES: Skipping interface %s, missing paramsets",
interface_id,
)
continue

if interface_id not in new_device_addresses:
new_device_addresses[interface_id] = set()

for device_address in self.device_descriptions.get_addresses(
interface_id=interface_id
):
if device_address not in self._devices:
new_device_addresses[interface_id].add(device_address)

if not new_device_addresses[interface_id]:
del new_device_addresses[interface_id]

if _LOGGER.isEnabledFor(level=DEBUG):
count: int = 0
for item in new_device_addresses.values():
count += len(item)

_LOGGER.debug(
"CHECK_FOR_NEW_DEVICE_ADDRESSES: %s: %i.",
"Found new device addresses"
if new_device_addresses
else "Did not find any new device addresses",
count,
)

return new_device_addresses

@callback_event
async def event(
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "hahomematic"
version = "2024.7.1"
version = "2024.8.0"
license = {text = "MIT License"}
description = "Homematic interface for Home Assistant running on Python 3."
readme = "README.md"
Expand Down
4 changes: 2 additions & 2 deletions requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
coverage==7.6.0
freezegun==1.5.1
mypy-dev==1.11.0a9
pip==24.1.2
pre-commit==3.7.1
pip==24.2
pre-commit==3.8.0
pydantic==2.8.2
pydevccu==0.1.8
pylint-per-file-ignores==1.3.2
Expand Down
3 changes: 2 additions & 1 deletion tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ async def get_default_central(
).start()

await central.start()
await central._create_devices()
if new_device_addresses := central._check_for_new_device_addresses():
await central._create_devices(new_device_addresses=new_device_addresses)
await central._init_hub()

assert central
Expand Down
3 changes: 0 additions & 3 deletions tests/test_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,9 +819,6 @@ async def test_central_without_interface_config(factory: helper.Factory) -> None
with pytest.raises(HaHomematicException):
central.get_client("NOT_A_VALID_INTERFACE_ID")

with pytest.raises(Exception):
await central._create_devices()

await central.start()
assert central.has_clients is False

Expand Down

0 comments on commit efa6e81

Please sign in to comment.