Skip to content

Commit

Permalink
Add sysvar_data_point_path_event entry point (#1874)
Browse files Browse the repository at this point in the history
  • Loading branch information
SukramJ authored Nov 22, 2024
1 parent 649625e commit 49adb26
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 36 deletions.
43 changes: 35 additions & 8 deletions hahomematic/central/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ def __init__(self, central_config: CentralConfig) -> None:
dict[DP_KEY, list[Callable[[Any], Coroutine[Any, Any, None]]]]
] = {}
self._data_point_path_event_subscriptions: Final[dict[str, DP_KEY]] = {}
self._sysvar_data_point_event_subscriptions: Final[
dict[str, Callable[[Any], Coroutine[Any, Any, None]]]
] = {}
self._sysvar_data_point_event_subscriptions: Final[dict[str, Callable]] = {}
# {device_address, device}
self._devices: Final[dict[str, Device]] = {}
# {sysvar_name, sysvar_data_point}
Expand Down Expand Up @@ -445,8 +443,9 @@ async def stop(self) -> None:
# wait until tasks are finished
await self.looper.block_till_done()

while self._has_active_threads: # noqa: ASYNC110
await asyncio.sleep(1)
DONE = asyncio.Event()
while self._has_active_threads:
await DONE.wait()
self._started = False

async def restart_clients(self) -> None:
Expand Down Expand Up @@ -1096,9 +1095,37 @@ def data_point_path_event(self, state_path: str, value: str) -> None:
parameter=parameter,
value=value,
),
name=f"event-{interface_id}-{channel_address}-{parameter}",
name=f"device-data-point-event-{interface_id}-{channel_address}-{parameter}",
)

def sysvar_data_point_path_event(self, state_path: str, value: str) -> None:
"""If a device emits some sort event, we will handle it here."""
_LOGGER.debug(
"SYSVAR_DATA_POINT_PATH_EVENT: topic = %s, payload = %s",
state_path,
value,
)

if state_path in self._sysvar_data_point_event_subscriptions:
try:
callback_handler = self._sysvar_data_point_event_subscriptions[state_path]
if callable(callback_handler):
self._looper.create_task(
callback_handler(value), name=f"sysvar-data-point-event-{state_path}"
)
except RuntimeError as rte: # pragma: no cover
_LOGGER.debug(
"EVENT: RuntimeError [%s]. Failed to call callback for: %s",
reduce_args(args=rte.args),
state_path,
)
except Exception as ex: # pragma: no cover
_LOGGER.warning(
"EVENT failed: Unable to call callback for: %s, %s",
state_path,
reduce_args(args=ex.args),
)

@callback_backend_system(system_event=BackendSystemEvent.LIST_DEVICES)
def list_devices(self, interface_id: str) -> list[DeviceDescription]:
"""Return already existing devices to CCU / Homegear."""
Expand Down Expand Up @@ -1834,8 +1861,8 @@ def _get_new_data_points(
}

for device in new_devices:
for category in data_points_by_category:
data_points_by_category[category].update(
for category, data_points in data_points_by_category.items():
data_points.update(
device.get_data_points(category=category, exclude_no_create=True, registered=False)
)

Expand Down
6 changes: 4 additions & 2 deletions hahomematic/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,11 +598,12 @@ async def _set_value(
data_point_key_values=data_point_key_values,
wait_for_callback=wait_for_callback,
)
return data_point_key_values # noqa: TRY300
except BaseHomematicException as ex:
raise ClientException(
f"SET_VALUE failed for {channel_address}/{parameter}/{value}: {reduce_args(args=ex.args)}"
) from ex
else:
return data_point_key_values

async def _exec_set_value(
self,
Expand Down Expand Up @@ -779,11 +780,12 @@ async def put_paramset(
data_point_key_values=data_point_key_values,
wait_for_callback=wait_for_callback,
)
return data_point_key_values # noqa: TRY300
except BaseHomematicException as ex:
raise ClientException(
f"PUT_PARAMSET failed for {channel_address}/{paramset_key}/{values}: {reduce_args(args=ex.args)}"
) from ex
else:
return data_point_key_values

async def _exec_put_paramset(
self,
Expand Down
4 changes: 1 addition & 3 deletions hahomematic/client/xml_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,7 @@ async def __async_request(self, *args, **kwargs): # type: ignore[no-untyped-def

if (
method in _VALID_XMLRPC_COMMANDS_ON_NO_CONNECTION
or not self._connection_state.has_issue( # noqa: E501
issuer=self, iid=self.interface_id
)
or not self._connection_state.has_issue(issuer=self, iid=self.interface_id)
):
args = _cleanup_args(*args)
_LOGGER.debug("__ASYNC_REQUEST: %s", args)
Expand Down
7 changes: 4 additions & 3 deletions hahomematic/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ async def service_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
token = IN_SERVICE_VAR.set(True)
try:
return_value = await func(*args, **kwargs)
if token:
IN_SERVICE_VAR.reset(token)
return return_value # noqa: TRY300
except BaseHomematicException as bhe:
if token:
IN_SERVICE_VAR.reset(token)
Expand All @@ -59,6 +56,10 @@ async def service_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
if re_raise:
raise
return cast(T, no_raise_return)
else:
if token:
IN_SERVICE_VAR.reset(token)
return return_value
finally:
if do_measure_performance:
_log_performance_message(func, start, *args, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion hahomematic/hmcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def main() -> None:
sys.exit(0)
elif args.paramset_key == ParamsetKey.MASTER and args.value is None:
paramset: dict[str, Any] | None
if (paramset := proxy.getParamset(args.address, args.paramset_key)) and paramset.get( # type: ignore[assignment] # noqa: E501
if (paramset := proxy.getParamset(args.address, args.paramset_key)) and paramset.get( # type: ignore[assignment]
args.parameter
):
if args.json:
Expand Down
10 changes: 5 additions & 5 deletions hahomematic/model/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def fire_data_point_updated_callback(self, *args: Any, **kwargs: Any) -> None:
callback_handler(*args, **kwargs)
except Exception as ex:
_LOGGER.warning(
"FIRE_data_point_updated_EVENT failed: %s", reduce_args(args=ex.args)
"FIRE_DATA_POINT_UPDATED_EVENT failed: %s", reduce_args(args=ex.args)
)

@loop_check
Expand Down Expand Up @@ -904,9 +904,6 @@ async def bind_wrapper(*args: Any, **kwargs: Any) -> Any:
kwargs[_COLLECTOR_ARGUMENT_NAME] = collector
return_value = await func(*args, **kwargs)
await collector.send_data(wait_for_callback=wait_for_callback)
if token:
IN_SERVICE_VAR.reset(token)
return return_value # noqa:TRY300
except BaseHomematicException as bhe:
if token:
IN_SERVICE_VAR.reset(token)
Expand All @@ -915,7 +912,10 @@ async def bind_wrapper(*args: Any, **kwargs: Any) -> Any:
logging.getLogger(args[0].__module__).log(
level=log_level, msg=reduce_args(args=bhe.args)
)

else:
if token:
IN_SERVICE_VAR.reset(token)
return return_value
return None

setattr(bind_wrapper, "ha_service", True)
Expand Down
26 changes: 13 additions & 13 deletions hahomematic/model/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,37 +41,37 @@ def __init__(
doc = fget.__doc__
self.__doc__ = doc

def getter(self, __fget: Callable[[Any], _GETTER]) -> generic_property:
def getter(self, fget: Callable[[Any], _GETTER], /) -> generic_property:
"""Return generic getter."""
return type(self)(__fget, self.fset, self.fdel, self.__doc__) # pragma: no cover
return type(self)(fget, self.fset, self.fdel, self.__doc__) # pragma: no cover

def setter(self, __fset: Callable[[Any, _SETTER], None]) -> generic_property:
def setter(self, fset: Callable[[Any, _SETTER], None], /) -> generic_property:
"""Return generic setter."""
return type(self)(self.fget, __fset, self.fdel, self.__doc__)
return type(self)(self.fget, fset, self.fdel, self.__doc__)

def deleter(self, __fdel: Callable[[Any], None]) -> generic_property:
def deleter(self, fdel: Callable[[Any], None], /) -> generic_property:
"""Return generic deleter."""
return type(self)(self.fget, self.fset, __fdel, self.__doc__)
return type(self)(self.fget, self.fset, fdel, self.__doc__)

def __get__(self, __obj: Any, __type: type | None = None) -> _GETTER:
def __get__(self, obj: Any, gtype: type | None = None, /) -> _GETTER:
"""Return the attribute."""
if __obj is None:
if obj is None:
return self # type: ignore[return-value]
if self.fget is None:
raise AttributeError("unreadable attribute") # pragma: no cover
return self.fget(__obj)
return self.fget(obj)

def __set__(self, __obj: Any, __value: Any) -> None:
def __set__(self, obj: Any, value: Any, /) -> None:
"""Set the attribute."""
if self.fset is None:
raise AttributeError("can't set attribute") # pragma: no cover
self.fset(__obj, __value)
self.fset(obj, value)

def __delete__(self, __obj: Any) -> None:
def __delete__(self, obj: Any, /) -> None:
"""Delete the attribute."""
if self.fdel is None:
raise AttributeError("can't delete attribute") # pragma: no cover
self.fdel(__obj)
self.fdel(obj)


# pylint: disable=invalid-name
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ disable = [
"missing-function-docstring", # D103
"missing-module-docstring", # D100
"multiple-imports", #E401
"no-else-raise", # RET506
"no-else-return", # RET505
"singleton-comparison", # E711, E712
"subprocess-run-check", # PLW1510
"superfluous-parens", # UP034
Expand Down Expand Up @@ -497,7 +499,6 @@ lint.ignore = [
"PLR0915", # Too many statements ({statements} > {max_statements})
"PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
"PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
"PT004", # Fixture {fixture} does not return anything, add leading underscore
"PT011", # pytest.raises({exception}) is too broad, set the `match` parameter or use a more specific exception
"PT012", # `pytest.raises()` block should contain a single simple statement
"PT018", # Assertion should be broken down into multiple parts
Expand Down

0 comments on commit 49adb26

Please sign in to comment.