Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve @service #1869

Merged
merged 7 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Version 2024.11.8 (2024-11-21)

- Add missing @service annotations
- Add performance measurement to @service
- Don't re-raise exception on internal services
- Move @service
- Remove @service from abstract methods

# Version 2024.11.7 (2024-11-19)

- Set state_uncertain on value write
-

# Version 2024.11.6 (2024-11-19)

Expand Down
4 changes: 2 additions & 2 deletions hahomematic/caches/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def get_address_id(self, address: str) -> str:
async def _get_all_rooms(self) -> dict[str, set[str]]:
"""Get all rooms, if available."""
if client := self._central.primary_client:
return await client.get_all_rooms() # type: ignore[no-any-return]
return await client.get_all_rooms()
return {}

def get_device_rooms(self, device_address: str) -> set[str]:
Expand All @@ -203,7 +203,7 @@ def get_channel_rooms(self, channel_address: str) -> set[str]:
async def _get_all_functions(self) -> dict[str, set[str]]:
"""Get all functions, if available."""
if client := self._central.primary_client:
return await client.get_all_functions() # type: ignore[no-any-return]
return await client.get_all_functions()
return {}

def get_function_text(self, address: str) -> str | None:
Expand Down
4 changes: 2 additions & 2 deletions hahomematic/caches/persistent.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
from hahomematic import central as hmcu
from hahomematic.const import (
CACHE_PATH,
DEFAULT_ENCODING,
FILE_DEVICES,
FILE_PARAMSETS,
INIT_DATETIME,
UTF8,
DataOperationResult,
DeviceDescription,
ParameterData,
Expand Down Expand Up @@ -106,7 +106,7 @@ async def load(self) -> DataOperationResult:
def _load() -> DataOperationResult:
with open(
file=os.path.join(self._cache_dir, self._filename),
encoding=DEFAULT_ENCODING,
encoding=UTF8,
) as fptr:
data = orjson.loads(fptr.read())
if (converted_hash := hash_sha256(value=data)) == self.last_hash_saved:
Expand Down
10 changes: 2 additions & 8 deletions hahomematic/caches/visibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@
from typing import Any, Final

from hahomematic import central as hmcu, support as hms
from hahomematic.const import (
CLICK_EVENTS,
DEFAULT_ENCODING,
UN_IGNORE_WILDCARD,
Parameter,
ParamsetKey,
)
from hahomematic.const import CLICK_EVENTS, UN_IGNORE_WILDCARD, UTF8, Parameter, ParamsetKey
from hahomematic.model.custom import get_required_parameters
from hahomematic.support import element_matches_key, reduce_args

Expand Down Expand Up @@ -713,7 +707,7 @@ def _load() -> None:
self._storage_folder,
_FILE_CUSTOM_UN_IGNORE_PARAMETERS,
),
encoding=DEFAULT_ENCODING,
encoding=UTF8,
) as fptr:
for file_line in fptr.readlines():
if "#" not in file_line:
Expand Down
12 changes: 7 additions & 5 deletions hahomematic/central/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
ProxyInitState,
SystemInformation,
)
from hahomematic.decorators import service
from hahomematic.exceptions import (
BaseHomematicException,
HaHomematicConfigException,
Expand All @@ -75,13 +76,12 @@
from hahomematic.model import create_data_points_and_events
from hahomematic.model.custom import CustomDataPoint, create_custom_data_points
from hahomematic.model.data_point import BaseParameterDataPoint, CallbackDataPoint
from hahomematic.model.decorators import info_property, service
from hahomematic.model.decorators import info_property
from hahomematic.model.device import Device
from hahomematic.model.event import GenericEvent
from hahomematic.model.generic import GenericDataPoint
from hahomematic.model.hub import GenericHubDataPoint, GenericSysvarDataPoint, Hub, ProgramDpButton
from hahomematic.model.support import PayloadMixin
from hahomematic.performance import measure_execution_time
from hahomematic.support import (
check_config,
get_channel_no,
Expand Down Expand Up @@ -917,7 +917,7 @@ async def add_new_devices(
interface_id=interface_id, device_descriptions=device_descriptions
)

@measure_execution_time
@service(measure_performance=True)
async def _add_new_devices(
self, interface_id: str, device_descriptions: tuple[DeviceDescription, ...]
) -> None:
Expand Down Expand Up @@ -1163,18 +1163,20 @@ def set_last_event_dt(self, interface_id: str) -> None:
async def execute_program(self, pid: str) -> bool:
"""Execute a program on CCU / Homegear."""
if client := self.primary_client:
return await client.execute_program(pid=pid) # type: ignore[no-any-return]
return await client.execute_program(pid=pid)
return False

@service(re_raise=False)
async def fetch_sysvar_data(self, scheduled: bool) -> None:
"""Fetch sysvar data for the hub."""
await self._hub.fetch_sysvar_data(scheduled=scheduled)

@service(re_raise=False)
async def fetch_program_data(self, scheduled: bool) -> None:
"""Fetch program data for the hub."""
await self._hub.fetch_program_data(scheduled=scheduled)

@measure_execution_time
@service(measure_performance=True)
async def load_and_refresh_data_point_data(
self,
interface: Interface,
Expand Down
53 changes: 19 additions & 34 deletions hahomematic/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@
SystemInformation,
SystemVariableData,
)
from hahomematic.decorators import measure_execution_time, service
from hahomematic.exceptions import BaseHomematicException, ClientException, NoConnectionException
from hahomematic.model.decorators import service
from hahomematic.model.device import Device
from hahomematic.model.support import convert_value
from hahomematic.performance import measure_execution_time
from hahomematic.support import (
build_headers,
build_xml_rpc_uri,
Expand Down Expand Up @@ -294,15 +293,14 @@ async def stop(self) -> None:
await self._proxy_read.stop()

@abstractmethod
@service()
async def fetch_all_device_data(self) -> None:
"""Fetch all device data from CCU."""

@abstractmethod
@service()
async def fetch_device_details(self) -> None:
"""Fetch names from backend."""

@service(re_raise=False, no_raise_return=False)
async def is_connected(self) -> bool:
"""
Perform actions required for connectivity check.
Expand Down Expand Up @@ -364,44 +362,36 @@ async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
"""Send ping to CCU to generate PONG event."""

@abstractmethod
@service()
async def execute_program(self, pid: str) -> bool:
"""Execute a program on CCU / Homegear.."""

@abstractmethod
@service()
async def set_system_variable(self, name: str, value: Any) -> bool:
"""Set a system variable on CCU / Homegear."""

@abstractmethod
@service()
async def delete_system_variable(self, name: str) -> bool:
"""Delete a system variable from CCU / Homegear."""

@abstractmethod
@service()
async def get_system_variable(self, name: str) -> str:
"""Get single system variable from CCU / Homegear."""

@abstractmethod
@service(re_raise=False, no_raise_return=())
async def get_all_system_variables(
self, include_internal: bool
) -> tuple[SystemVariableData, ...]:
"""Get all system variables from CCU / Homegear."""

@abstractmethod
@service(re_raise=False, no_raise_return=())
async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]:
"""Get all programs, if available."""

@abstractmethod
@service(re_raise=False, no_raise_return={})
async def get_all_rooms(self) -> dict[str, set[str]]:
"""Get all rooms, if available."""

@abstractmethod
@service(re_raise=False, no_raise_return={})
async def get_all_functions(self) -> dict[str, set[str]]:
"""Get all functions, if available."""

Expand Down Expand Up @@ -555,8 +545,7 @@ async def get_value(
f"GET_VALUE failed with for: {channel_address}/{parameter}/{paramset_key}: {reduce_args(args=ex.args)}"
) from ex

@measure_execution_time
@service()
@service(measure_performance=True)
async def _set_value(
self,
channel_address: str,
Expand Down Expand Up @@ -653,6 +642,7 @@ def _write_temporary_value(self, data_point_key_values: set[DP_KEY_VALUE]) -> No
):
data_point.write_temporary_value(value=value)

@service(re_raise=False, no_raise_return=set())
async def set_value(
self,
channel_address: str,
Expand Down Expand Up @@ -708,8 +698,7 @@ async def get_paramset(
f"GET_PARAMSET failed with for {address}/{paramset_key}: {reduce_args(args=ex.args)}"
) from ex

@measure_execution_time
@service()
@service(measure_performance=True)
async def put_paramset(
self,
channel_address: str,
Expand Down Expand Up @@ -872,7 +861,7 @@ def _get_parameter_type(
return parameter_data["TYPE"]
return None

@service()
@service(re_raise=False)
async def fetch_paramset_description(
self, channel_address: str, paramset_key: ParamsetKey
) -> None:
Expand All @@ -889,7 +878,7 @@ async def fetch_paramset_description(
paramset_description=paramset_description,
)

@service()
@service(re_raise=False)
async def fetch_paramset_descriptions(self, device_description: DeviceDescription) -> None:
"""Fetch paramsets for provided device description."""
data = await self.get_paramset_descriptions(device_description=device_description)
Expand Down Expand Up @@ -956,8 +945,7 @@ async def has_program_ids(self, channel_hmid: str) -> bool:
"""Return if a channel has program ids."""
return False

@measure_execution_time
@service(re_raise=False)
@service(re_raise=False, measure_performance=True)
async def list_devices(self) -> tuple[DeviceDescription, ...] | None:
"""List devices of homematic backend."""
try:
Expand Down Expand Up @@ -1006,7 +994,7 @@ async def update_device_firmware(self, device_address: str) -> bool:
return result
return False

@service()
@service(re_raise=False)
async def update_paramset_descriptions(self, device_address: str) -> None:
"""Update paramsets descriptions for provided device_address."""
if not self.central.device_descriptions.get_device_descriptions(
Expand Down Expand Up @@ -1052,8 +1040,7 @@ def supports_ping_pong(self) -> bool:
"""Return the supports_ping_pong info of the backend."""
return True

@measure_execution_time
@service()
@service(re_raise=False, measure_performance=True)
async def fetch_device_details(self) -> None:
"""Get all names via JSON-RPS and store in data.NAMES."""
if json_result := await self._json_rpc_client.get_device_details():
Expand Down Expand Up @@ -1083,8 +1070,7 @@ async def fetch_device_details(self) -> None:
else:
_LOGGER.debug("FETCH_DEVICE_DETAILS: Unable to fetch device details via JSON-RPC")

@measure_execution_time
@service()
@service(re_raise=False, measure_performance=True)
async def fetch_all_device_data(self) -> None:
"""Fetch all device data from CCU."""
try:
Expand All @@ -1105,12 +1091,14 @@ async def fetch_all_device_data(self) -> None:
interface_event_type=InterfaceEventType.FETCH_DATA,
data={EventKey.AVAILABLE: False},
)
raise

_LOGGER.debug(
"FETCH_ALL_DEVICE_DATA: Unable to get all device data via JSON-RPC RegaScript for interface %s",
self.interface,
)

@service(re_raise=False, no_raise_return=False)
async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
"""Check if _proxy is still initialized."""
try:
Expand Down Expand Up @@ -1155,8 +1143,7 @@ async def report_value_usage(self, address: str, value_id: str, ref_counter: int
f"REPORT_VALUE_USAGE failed with: {address}/{value_id}/{ref_counter}: {reduce_args(args=ex.args)}"
) from ex

@measure_execution_time
@service()
@service(measure_performance=True)
async def set_system_variable(self, name: str, value: Any) -> bool:
"""Set a system variable on CCU / Homegear."""
return await self._json_rpc_client.set_system_variable(name=name, value=value)
Expand Down Expand Up @@ -1314,8 +1301,7 @@ async def get_value(
f"GET_VALUE failed with for: {channel_address}/{parameter}/{paramset_key}: {reduce_args(args=ex.args)}"
) from ex

@measure_execution_time
@service(re_raise=False)
@service(re_raise=False, measure_performance=True)
async def list_devices(self) -> tuple[DeviceDescription, ...] | None:
"""List devices of homematic backend."""
try:
Expand Down Expand Up @@ -1440,13 +1426,12 @@ def supports_ping_pong(self) -> bool:
"""Return the supports_ping_pong info of the backend."""
return False

@measure_execution_time
@service(re_raise=False)
async def fetch_all_device_data(self) -> None:
"""Fetch all device data from CCU."""
return

@measure_execution_time
@service()
@service(re_raise=False, measure_performance=True)
async def fetch_device_details(self) -> None:
"""Get all names from metadata (Homegear)."""
_LOGGER.debug("FETCH_DEVICE_DETAILS: Fetching names via Metadata")
Expand All @@ -1466,6 +1451,7 @@ async def fetch_device_details(self) -> None:
address,
)

@service(re_raise=False, no_raise_return=False)
async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
"""Check if proxy is still initialized."""
try:
Expand All @@ -1487,8 +1473,7 @@ async def execute_program(self, pid: str) -> bool:
"""Execute a program on Homegear."""
return True

@measure_execution_time
@service()
@service(measure_performance=True)
async def set_system_variable(self, name: str, value: Any) -> bool:
"""Set a system variable on CCU / Homegear."""
try:
Expand Down
Loading