aiohomematic 2025.10.1__py3-none-any.whl → 2025.10.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aiohomematic might be problematic. Click here for more details.

Files changed (57) hide show
  1. aiohomematic/async_support.py +8 -8
  2. aiohomematic/caches/dynamic.py +31 -26
  3. aiohomematic/caches/persistent.py +34 -32
  4. aiohomematic/caches/visibility.py +19 -7
  5. aiohomematic/central/__init__.py +88 -75
  6. aiohomematic/central/decorators.py +2 -2
  7. aiohomematic/central/xml_rpc_server.py +33 -25
  8. aiohomematic/client/__init__.py +72 -56
  9. aiohomematic/client/_rpc_errors.py +3 -3
  10. aiohomematic/client/json_rpc.py +33 -25
  11. aiohomematic/client/xml_rpc.py +14 -9
  12. aiohomematic/const.py +2 -1
  13. aiohomematic/converter.py +19 -19
  14. aiohomematic/exceptions.py +2 -1
  15. aiohomematic/model/__init__.py +4 -3
  16. aiohomematic/model/calculated/__init__.py +1 -1
  17. aiohomematic/model/calculated/climate.py +9 -9
  18. aiohomematic/model/calculated/data_point.py +13 -7
  19. aiohomematic/model/calculated/operating_voltage_level.py +2 -2
  20. aiohomematic/model/calculated/support.py +7 -7
  21. aiohomematic/model/custom/__init__.py +3 -3
  22. aiohomematic/model/custom/climate.py +57 -34
  23. aiohomematic/model/custom/cover.py +32 -18
  24. aiohomematic/model/custom/data_point.py +9 -7
  25. aiohomematic/model/custom/definition.py +23 -17
  26. aiohomematic/model/custom/light.py +52 -23
  27. aiohomematic/model/custom/lock.py +16 -12
  28. aiohomematic/model/custom/siren.py +8 -3
  29. aiohomematic/model/custom/switch.py +3 -2
  30. aiohomematic/model/custom/valve.py +3 -2
  31. aiohomematic/model/data_point.py +63 -49
  32. aiohomematic/model/device.py +48 -42
  33. aiohomematic/model/event.py +6 -5
  34. aiohomematic/model/generic/__init__.py +6 -4
  35. aiohomematic/model/generic/action.py +1 -1
  36. aiohomematic/model/generic/data_point.py +8 -6
  37. aiohomematic/model/generic/number.py +3 -3
  38. aiohomematic/model/generic/select.py +1 -1
  39. aiohomematic/model/generic/sensor.py +2 -2
  40. aiohomematic/model/generic/switch.py +3 -3
  41. aiohomematic/model/hub/__init__.py +17 -16
  42. aiohomematic/model/hub/data_point.py +12 -7
  43. aiohomematic/model/hub/number.py +3 -3
  44. aiohomematic/model/hub/select.py +3 -3
  45. aiohomematic/model/hub/text.py +2 -2
  46. aiohomematic/model/support.py +10 -9
  47. aiohomematic/model/update.py +6 -6
  48. aiohomematic/property_decorators.py +2 -0
  49. aiohomematic/support.py +44 -38
  50. aiohomematic/validator.py +6 -6
  51. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/METADATA +1 -1
  52. aiohomematic-2025.10.3.dist-info/RECORD +78 -0
  53. aiohomematic_support/client_local.py +26 -14
  54. aiohomematic-2025.10.1.dist-info/RECORD +0 -78
  55. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/WHEEL +0 -0
  56. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/licenses/LICENSE +0 -0
  57. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/top_level.txt +0 -0
@@ -129,7 +129,7 @@ _CCU_JSON_VALUE_TYPE: Final = {
129
129
  class Client(ABC, LogContextMixin):
130
130
  """Client object to access the backends via XML-RPC or JSON-RPC."""
131
131
 
132
- def __init__(self, client_config: _ClientConfig) -> None:
132
+ def __init__(self, *, client_config: _ClientConfig) -> None:
133
133
  """Initialize the Client."""
134
134
  self._config: Final = client_config
135
135
  self._supports_xml_rpc = self.interface in INTERFACES_SUPPORTING_XML_RPC
@@ -211,7 +211,7 @@ class Client(ABC, LogContextMixin):
211
211
  """Return the version id of the client."""
212
212
  return self._config.version
213
213
 
214
- def get_product_group(self, model: str) -> ProductGroup:
214
+ def get_product_group(self, *, model: str) -> ProductGroup:
215
215
  """Return the product group."""
216
216
  l_model = model.lower()
217
217
  if l_model.startswith("hmipw-"):
@@ -309,7 +309,7 @@ class Client(ABC, LogContextMixin):
309
309
  return await self.initialize_proxy()
310
310
  return ProxyInitState.DE_INIT_FAILED
311
311
 
312
- def _mark_all_devices_forced_availability(self, forced_availability: ForcedDeviceAvailability) -> None:
312
+ def _mark_all_devices_forced_availability(self, *, forced_availability: ForcedDeviceAvailability) -> None:
313
313
  """Mark device's availability state for this interface."""
314
314
  available = forced_availability != ForcedDeviceAvailability.FORCE_FALSE
315
315
  if self._available != available:
@@ -419,44 +419,44 @@ class Client(ABC, LogContextMixin):
419
419
 
420
420
  @abstractmethod
421
421
  @inspector(re_raise=False, no_raise_return=False)
422
- async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
422
+ async def check_connection_availability(self, *, handle_ping_pong: bool) -> bool:
423
423
  """Send ping to the backend to generate PONG event."""
424
424
 
425
425
  @abstractmethod
426
426
  @inspector
427
- async def execute_program(self, pid: str) -> bool:
427
+ async def execute_program(self, *, pid: str) -> bool:
428
428
  """Execute a program on the backend."""
429
429
 
430
430
  @abstractmethod
431
431
  @inspector
432
- async def set_program_state(self, pid: str, state: bool) -> bool:
432
+ async def set_program_state(self, *, pid: str, state: bool) -> bool:
433
433
  """Set the program state on the backend."""
434
434
 
435
435
  @abstractmethod
436
436
  @inspector(measure_performance=True)
437
- async def set_system_variable(self, legacy_name: str, value: Any) -> bool:
437
+ async def set_system_variable(self, *, legacy_name: str, value: Any) -> bool:
438
438
  """Set a system variable on the backend."""
439
439
 
440
440
  @abstractmethod
441
441
  @inspector
442
- async def delete_system_variable(self, name: str) -> bool:
442
+ async def delete_system_variable(self, *, name: str) -> bool:
443
443
  """Delete a system variable from the backend."""
444
444
 
445
445
  @abstractmethod
446
446
  @inspector
447
- async def get_system_variable(self, name: str) -> Any:
447
+ async def get_system_variable(self, *, name: str) -> Any:
448
448
  """Get single system variable from the backend."""
449
449
 
450
450
  @abstractmethod
451
451
  @inspector(re_raise=False)
452
452
  async def get_all_system_variables(
453
- self, markers: tuple[DescriptionMarker | str, ...]
453
+ self, *, markers: tuple[DescriptionMarker | str, ...]
454
454
  ) -> tuple[SystemVariableData, ...] | None:
455
455
  """Get all system variables from the backend."""
456
456
 
457
457
  @abstractmethod
458
458
  @inspector(re_raise=False)
459
- async def get_all_programs(self, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...] | None:
459
+ async def get_all_programs(self, *, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...] | None:
460
460
  """Get all programs, if available."""
461
461
 
462
462
  @abstractmethod
@@ -482,7 +482,7 @@ class Client(ABC, LogContextMixin):
482
482
  return None
483
483
 
484
484
  @inspector(re_raise=False)
485
- async def get_device_description(self, device_address: str) -> DeviceDescription | None:
485
+ async def get_device_description(self, *, device_address: str) -> DeviceDescription | None:
486
486
  """Get device descriptions from the backend."""
487
487
  try:
488
488
  if device_description := cast(
@@ -495,7 +495,7 @@ class Client(ABC, LogContextMixin):
495
495
  return None
496
496
 
497
497
  @inspector
498
- async def add_link(self, sender_address: str, receiver_address: str, name: str, description: str) -> None:
498
+ async def add_link(self, *, sender_address: str, receiver_address: str, name: str, description: str) -> None:
499
499
  """Return a list of links."""
500
500
  try:
501
501
  await self._proxy.addLink(sender_address, receiver_address, name, description)
@@ -505,7 +505,7 @@ class Client(ABC, LogContextMixin):
505
505
  ) from bhexc
506
506
 
507
507
  @inspector
508
- async def remove_link(self, sender_address: str, receiver_address: str) -> None:
508
+ async def remove_link(self, *, sender_address: str, receiver_address: str) -> None:
509
509
  """Return a list of links."""
510
510
  try:
511
511
  await self._proxy.removeLink(sender_address, receiver_address)
@@ -515,7 +515,7 @@ class Client(ABC, LogContextMixin):
515
515
  ) from bhexc
516
516
 
517
517
  @inspector
518
- async def get_link_peers(self, address: str) -> tuple[str, ...] | None:
518
+ async def get_link_peers(self, *, address: str) -> tuple[str, ...] | None:
519
519
  """Return a list of link pers."""
520
520
  try:
521
521
  return tuple(await self._proxy.getLinkPeers(address))
@@ -525,7 +525,7 @@ class Client(ABC, LogContextMixin):
525
525
  ) from bhexc
526
526
 
527
527
  @inspector
528
- async def get_links(self, address: str, flags: int) -> dict[str, Any]:
528
+ async def get_links(self, *, address: str, flags: int) -> dict[str, Any]:
529
529
  """Return a list of links."""
530
530
  try:
531
531
  return cast(dict[str, Any], await self._proxy.getLinks(address, flags))
@@ -533,7 +533,7 @@ class Client(ABC, LogContextMixin):
533
533
  raise ClientException(f"GET_LINKS failed with for: {address}: {extract_exc_args(exc=bhexc)}") from bhexc
534
534
 
535
535
  @inspector
536
- async def get_metadata(self, address: str, data_id: str) -> dict[str, Any]:
536
+ async def get_metadata(self, *, address: str, data_id: str) -> dict[str, Any]:
537
537
  """Return the metadata for an object."""
538
538
  try:
539
539
  return cast(dict[str, Any], await self._proxy.getMetadata(address, data_id))
@@ -543,7 +543,7 @@ class Client(ABC, LogContextMixin):
543
543
  ) from bhexc
544
544
 
545
545
  @inspector
546
- async def set_metadata(self, address: str, data_id: str, value: dict[str, Any]) -> dict[str, Any]:
546
+ async def set_metadata(self, *, address: str, data_id: str, value: dict[str, Any]) -> dict[str, Any]:
547
547
  """Write the metadata for an object."""
548
548
  try:
549
549
  return cast(dict[str, Any], await self._proxy.setMetadata(address, data_id, value))
@@ -555,6 +555,7 @@ class Client(ABC, LogContextMixin):
555
555
  @inspector(log_level=logging.NOTSET)
556
556
  async def get_value(
557
557
  self,
558
+ *,
558
559
  channel_address: str,
559
560
  paramset_key: ParamsetKey,
560
561
  parameter: str,
@@ -581,6 +582,7 @@ class Client(ABC, LogContextMixin):
581
582
  @inspector(measure_performance=True)
582
583
  async def _set_value(
583
584
  self,
585
+ *,
584
586
  channel_address: str,
585
587
  parameter: str,
586
588
  value: Any,
@@ -636,6 +638,7 @@ class Client(ABC, LogContextMixin):
636
638
 
637
639
  async def _exec_set_value(
638
640
  self,
641
+ *,
639
642
  channel_address: str,
640
643
  parameter: str,
641
644
  value: Any,
@@ -647,7 +650,7 @@ class Client(ABC, LogContextMixin):
647
650
  else:
648
651
  await self._proxy.setValue(channel_address, parameter, value)
649
652
 
650
- def _check_set_value(self, channel_address: str, paramset_key: ParamsetKey, parameter: str, value: Any) -> Any:
653
+ def _check_set_value(self, *, channel_address: str, paramset_key: ParamsetKey, parameter: str, value: Any) -> Any:
651
654
  """Check set_value."""
652
655
  return self._convert_value(
653
656
  channel_address=channel_address,
@@ -657,7 +660,7 @@ class Client(ABC, LogContextMixin):
657
660
  operation=Operations.WRITE,
658
661
  )
659
662
 
660
- def _write_temporary_value(self, dpk_values: set[DP_KEY_VALUE]) -> None:
663
+ def _write_temporary_value(self, *, dpk_values: set[DP_KEY_VALUE]) -> None:
661
664
  """Write data point temp value."""
662
665
  for dpk, value in dpk_values:
663
666
  if (
@@ -672,6 +675,7 @@ class Client(ABC, LogContextMixin):
672
675
  @inspector(re_raise=False, no_raise_return=set())
673
676
  async def set_value(
674
677
  self,
678
+ *,
675
679
  channel_address: str,
676
680
  paramset_key: ParamsetKey,
677
681
  parameter: str,
@@ -702,6 +706,7 @@ class Client(ABC, LogContextMixin):
702
706
  @inspector
703
707
  async def get_paramset(
704
708
  self,
709
+ *,
705
710
  address: str,
706
711
  paramset_key: ParamsetKey | str,
707
712
  call_source: CallSource = CallSource.MANUAL_OR_SCHEDULED,
@@ -728,6 +733,7 @@ class Client(ABC, LogContextMixin):
728
733
  @inspector(measure_performance=True)
729
734
  async def put_paramset(
730
735
  self,
736
+ *,
731
737
  channel_address: str,
732
738
  paramset_key_or_link_address: ParamsetKey | str,
733
739
  values: dict[str, Any],
@@ -830,6 +836,7 @@ class Client(ABC, LogContextMixin):
830
836
 
831
837
  async def _exec_put_paramset(
832
838
  self,
839
+ *,
833
840
  channel_address: str,
834
841
  paramset_key: ParamsetKey | str,
835
842
  values: dict[str, Any],
@@ -842,7 +849,7 @@ class Client(ABC, LogContextMixin):
842
849
  await self._proxy.putParamset(channel_address, paramset_key, values)
843
850
 
844
851
  def _check_put_paramset(
845
- self, channel_address: str, paramset_key: ParamsetKey, values: dict[str, Any]
852
+ self, *, channel_address: str, paramset_key: ParamsetKey, values: dict[str, Any]
846
853
  ) -> dict[str, Any]:
847
854
  """Check put_paramset."""
848
855
  checked_values: dict[str, Any] = {}
@@ -858,6 +865,7 @@ class Client(ABC, LogContextMixin):
858
865
 
859
866
  def _convert_value(
860
867
  self,
868
+ *,
861
869
  channel_address: str,
862
870
  paramset_key: ParamsetKey,
863
871
  parameter: str,
@@ -886,6 +894,7 @@ class Client(ABC, LogContextMixin):
886
894
 
887
895
  def _get_parameter_type(
888
896
  self,
897
+ *,
889
898
  channel_address: str,
890
899
  paramset_key: ParamsetKey,
891
900
  parameter: str,
@@ -900,7 +909,7 @@ class Client(ABC, LogContextMixin):
900
909
  return None
901
910
 
902
911
  @inspector(re_raise=False)
903
- async def fetch_paramset_description(self, channel_address: str, paramset_key: ParamsetKey) -> None:
912
+ async def fetch_paramset_description(self, *, channel_address: str, paramset_key: ParamsetKey) -> None:
904
913
  """Fetch a specific paramset and add it to the known ones."""
905
914
  _LOGGER.debug("FETCH_PARAMSET_DESCRIPTION: %s for %s", paramset_key, channel_address)
906
915
 
@@ -915,7 +924,7 @@ class Client(ABC, LogContextMixin):
915
924
  )
916
925
 
917
926
  @inspector(re_raise=False)
918
- async def fetch_paramset_descriptions(self, device_description: DeviceDescription) -> None:
927
+ async def fetch_paramset_descriptions(self, *, device_description: DeviceDescription) -> None:
919
928
  """Fetch paramsets for provided device description."""
920
929
  data = await self.get_paramset_descriptions(device_description=device_description)
921
930
  for address, paramsets in data.items():
@@ -930,7 +939,7 @@ class Client(ABC, LogContextMixin):
930
939
 
931
940
  @inspector(re_raise=False, no_raise_return={})
932
941
  async def get_paramset_descriptions(
933
- self, device_description: DeviceDescription
942
+ self, *, device_description: DeviceDescription
934
943
  ) -> dict[str, dict[ParamsetKey, dict[str, ParameterData]]]:
935
944
  """Get paramsets for provided device description."""
936
945
  paramsets: dict[str, dict[ParamsetKey, dict[str, ParameterData]]] = {}
@@ -944,7 +953,7 @@ class Client(ABC, LogContextMixin):
944
953
  return paramsets
945
954
 
946
955
  async def _get_paramset_description(
947
- self, address: str, paramset_key: ParamsetKey
956
+ self, *, address: str, paramset_key: ParamsetKey
948
957
  ) -> dict[str, ParameterData] | None:
949
958
  """Get paramset description from the backend."""
950
959
  try:
@@ -964,7 +973,7 @@ class Client(ABC, LogContextMixin):
964
973
 
965
974
  @inspector
966
975
  async def get_all_paramset_descriptions(
967
- self, device_descriptions: tuple[DeviceDescription, ...]
976
+ self, *, device_descriptions: tuple[DeviceDescription, ...]
968
977
  ) -> dict[str, dict[ParamsetKey, dict[str, ParameterData]]]:
969
978
  """Get all paramset descriptions for provided device descriptions."""
970
979
  all_paramsets: dict[str, dict[ParamsetKey, dict[str, ParameterData]]] = {}
@@ -973,7 +982,7 @@ class Client(ABC, LogContextMixin):
973
982
  return all_paramsets
974
983
 
975
984
  @inspector
976
- async def has_program_ids(self, channel_hmid: str) -> bool:
985
+ async def has_program_ids(self, *, channel_hmid: str) -> bool:
977
986
  """Return if a channel has program ids."""
978
987
  return False
979
988
 
@@ -991,12 +1000,12 @@ class Client(ABC, LogContextMixin):
991
1000
  return None
992
1001
 
993
1002
  @inspector
994
- async def report_value_usage(self, address: str, value_id: str, ref_counter: int) -> bool:
1003
+ async def report_value_usage(self, *, address: str, value_id: str, ref_counter: int) -> bool:
995
1004
  """Report value usage."""
996
1005
  return False
997
1006
 
998
1007
  @inspector
999
- async def update_device_firmware(self, device_address: str) -> bool:
1008
+ async def update_device_firmware(self, *, device_address: str) -> bool:
1000
1009
  """Update the firmware of a Homematic device."""
1001
1010
  if device := self.central.get_device(address=device_address):
1002
1011
  _LOGGER.info(
@@ -1021,7 +1030,7 @@ class Client(ABC, LogContextMixin):
1021
1030
  return False
1022
1031
 
1023
1032
  @inspector(re_raise=False)
1024
- async def update_paramset_descriptions(self, device_address: str) -> None:
1033
+ async def update_paramset_descriptions(self, *, device_address: str) -> None:
1025
1034
  """Update paramsets descriptions for provided device_address."""
1026
1035
  if not self.central.device_descriptions.get_device_descriptions(interface_id=self.interface_id):
1027
1036
  _LOGGER.warning(
@@ -1052,7 +1061,7 @@ class Client(ABC, LogContextMixin):
1052
1061
  class ClientCCU(Client):
1053
1062
  """Client implementation for CCU backend."""
1054
1063
 
1055
- def __init__(self, client_config: _ClientConfig) -> None:
1064
+ def __init__(self, *, client_config: _ClientConfig) -> None:
1056
1065
  """Initialize the Client."""
1057
1066
  self._json_rpc_client: Final = client_config.central.json_rpc_client
1058
1067
  super().__init__(client_config=client_config)
@@ -1112,7 +1121,7 @@ class ClientCCU(Client):
1112
1121
  )
1113
1122
 
1114
1123
  @inspector(re_raise=False, no_raise_return=False)
1115
- async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
1124
+ async def check_connection_availability(self, *, handle_ping_pong: bool) -> bool:
1116
1125
  """Check if _proxy is still initialized."""
1117
1126
  try:
1118
1127
  dt_now = datetime.now()
@@ -1139,22 +1148,22 @@ class ClientCCU(Client):
1139
1148
  return False
1140
1149
 
1141
1150
  @inspector
1142
- async def execute_program(self, pid: str) -> bool:
1151
+ async def execute_program(self, *, pid: str) -> bool:
1143
1152
  """Execute a program on the backend."""
1144
1153
  return await self._json_rpc_client.execute_program(pid=pid)
1145
1154
 
1146
1155
  @inspector
1147
- async def set_program_state(self, pid: str, state: bool) -> bool:
1156
+ async def set_program_state(self, *, pid: str, state: bool) -> bool:
1148
1157
  """Set the program state on the backend."""
1149
1158
  return await self._json_rpc_client.set_program_state(pid=pid, state=state)
1150
1159
 
1151
1160
  @inspector
1152
- async def has_program_ids(self, channel_hmid: str) -> bool:
1161
+ async def has_program_ids(self, *, channel_hmid: str) -> bool:
1153
1162
  """Return if a channel has program ids."""
1154
1163
  return await self._json_rpc_client.has_program_ids(channel_hmid=channel_hmid)
1155
1164
 
1156
1165
  @inspector
1157
- async def report_value_usage(self, address: str, value_id: str, ref_counter: int) -> bool:
1166
+ async def report_value_usage(self, *, address: str, value_id: str, ref_counter: int) -> bool:
1158
1167
  """Report value usage."""
1159
1168
  try:
1160
1169
  return bool(await self._proxy.reportValueUsage(address, value_id, ref_counter))
@@ -1164,29 +1173,29 @@ class ClientCCU(Client):
1164
1173
  ) from bhexc
1165
1174
 
1166
1175
  @inspector(measure_performance=True)
1167
- async def set_system_variable(self, legacy_name: str, value: Any) -> bool:
1176
+ async def set_system_variable(self, *, legacy_name: str, value: Any) -> bool:
1168
1177
  """Set a system variable on the backend."""
1169
1178
  return await self._json_rpc_client.set_system_variable(legacy_name=legacy_name, value=value)
1170
1179
 
1171
1180
  @inspector
1172
- async def delete_system_variable(self, name: str) -> bool:
1181
+ async def delete_system_variable(self, *, name: str) -> bool:
1173
1182
  """Delete a system variable from the backend."""
1174
1183
  return await self._json_rpc_client.delete_system_variable(name=name)
1175
1184
 
1176
1185
  @inspector
1177
- async def get_system_variable(self, name: str) -> Any:
1186
+ async def get_system_variable(self, *, name: str) -> Any:
1178
1187
  """Get single system variable from the backend."""
1179
1188
  return await self._json_rpc_client.get_system_variable(name=name)
1180
1189
 
1181
1190
  @inspector(re_raise=False)
1182
1191
  async def get_all_system_variables(
1183
- self, markers: tuple[DescriptionMarker | str, ...]
1192
+ self, *, markers: tuple[DescriptionMarker | str, ...]
1184
1193
  ) -> tuple[SystemVariableData, ...] | None:
1185
1194
  """Get all system variables from the backend."""
1186
1195
  return await self._json_rpc_client.get_all_system_variables(markers=markers)
1187
1196
 
1188
1197
  @inspector(re_raise=False)
1189
- async def get_all_programs(self, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...]:
1198
+ async def get_all_programs(self, *, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...]:
1190
1199
  """Get all programs, if available."""
1191
1200
  return await self._json_rpc_client.get_all_programs(markers=markers)
1192
1201
 
@@ -1228,7 +1237,7 @@ class ClientJsonCCU(ClientCCU):
1228
1237
  self._system_information = await self._get_system_information()
1229
1238
 
1230
1239
  @inspector(re_raise=False, no_raise_return=False)
1231
- async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
1240
+ async def check_connection_availability(self, *, handle_ping_pong: bool) -> bool:
1232
1241
  """Check if proxy is still initialized."""
1233
1242
  return await self._json_rpc_client.is_present(interface=self.interface)
1234
1243
 
@@ -1238,7 +1247,7 @@ class ClientJsonCCU(ClientCCU):
1238
1247
  return False
1239
1248
 
1240
1249
  @inspector(re_raise=False)
1241
- async def get_device_description(self, device_address: str) -> DeviceDescription | None:
1250
+ async def get_device_description(self, *, device_address: str) -> DeviceDescription | None:
1242
1251
  """Get device descriptions from the backend."""
1243
1252
  try:
1244
1253
  if device_description := await self._json_rpc_client.get_device_description(
@@ -1252,6 +1261,7 @@ class ClientJsonCCU(ClientCCU):
1252
1261
  @inspector
1253
1262
  async def get_paramset(
1254
1263
  self,
1264
+ *,
1255
1265
  address: str,
1256
1266
  paramset_key: ParamsetKey | str,
1257
1267
  call_source: CallSource = CallSource.MANUAL_OR_SCHEDULED,
@@ -1283,6 +1293,7 @@ class ClientJsonCCU(ClientCCU):
1283
1293
  @inspector(log_level=logging.NOTSET)
1284
1294
  async def get_value(
1285
1295
  self,
1296
+ *,
1286
1297
  channel_address: str,
1287
1298
  paramset_key: ParamsetKey,
1288
1299
  parameter: str,
@@ -1332,7 +1343,7 @@ class ClientJsonCCU(ClientCCU):
1332
1343
  return None
1333
1344
 
1334
1345
  async def _get_paramset_description(
1335
- self, address: str, paramset_key: ParamsetKey
1346
+ self, *, address: str, paramset_key: ParamsetKey
1336
1347
  ) -> dict[str, ParameterData] | None:
1337
1348
  """Get paramset description from the backend."""
1338
1349
  try:
@@ -1354,6 +1365,7 @@ class ClientJsonCCU(ClientCCU):
1354
1365
 
1355
1366
  async def _exec_put_paramset(
1356
1367
  self,
1368
+ *,
1357
1369
  channel_address: str,
1358
1370
  paramset_key: ParamsetKey | str,
1359
1371
  values: dict[str, Any],
@@ -1390,6 +1402,7 @@ class ClientJsonCCU(ClientCCU):
1390
1402
 
1391
1403
  async def _exec_set_value(
1392
1404
  self,
1405
+ *,
1393
1406
  channel_address: str,
1394
1407
  parameter: str,
1395
1408
  value: Any,
@@ -1463,7 +1476,7 @@ class ClientHomegear(Client):
1463
1476
  )
1464
1477
 
1465
1478
  @inspector(re_raise=False, no_raise_return=False)
1466
- async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
1479
+ async def check_connection_availability(self, *, handle_ping_pong: bool) -> bool:
1467
1480
  """Check if proxy is still initialized."""
1468
1481
  try:
1469
1482
  await self._proxy.clientServerInitialized(self.interface_id)
@@ -1480,35 +1493,35 @@ class ClientHomegear(Client):
1480
1493
  return False
1481
1494
 
1482
1495
  @inspector
1483
- async def execute_program(self, pid: str) -> bool:
1496
+ async def execute_program(self, *, pid: str) -> bool:
1484
1497
  """Execute a program on the backend."""
1485
1498
  return True
1486
1499
 
1487
1500
  @inspector
1488
- async def set_program_state(self, pid: str, state: bool) -> bool:
1501
+ async def set_program_state(self, *, pid: str, state: bool) -> bool:
1489
1502
  """Set the program state on the backend."""
1490
1503
  return True
1491
1504
 
1492
1505
  @inspector(measure_performance=True)
1493
- async def set_system_variable(self, legacy_name: str, value: Any) -> bool:
1506
+ async def set_system_variable(self, *, legacy_name: str, value: Any) -> bool:
1494
1507
  """Set a system variable on the backend."""
1495
1508
  await self._proxy.setSystemVariable(legacy_name, value)
1496
1509
  return True
1497
1510
 
1498
1511
  @inspector
1499
- async def delete_system_variable(self, name: str) -> bool:
1512
+ async def delete_system_variable(self, *, name: str) -> bool:
1500
1513
  """Delete a system variable from the backend."""
1501
1514
  await self._proxy.deleteSystemVariable(name)
1502
1515
  return True
1503
1516
 
1504
1517
  @inspector
1505
- async def get_system_variable(self, name: str) -> Any:
1518
+ async def get_system_variable(self, *, name: str) -> Any:
1506
1519
  """Get single system variable from the backend."""
1507
1520
  return await self._proxy.getSystemVariable(name)
1508
1521
 
1509
1522
  @inspector(re_raise=False)
1510
1523
  async def get_all_system_variables(
1511
- self, markers: tuple[DescriptionMarker | str, ...]
1524
+ self, *, markers: tuple[DescriptionMarker | str, ...]
1512
1525
  ) -> tuple[SystemVariableData, ...] | None:
1513
1526
  """Get all system variables from the backend."""
1514
1527
  variables: list[SystemVariableData] = []
@@ -1518,7 +1531,7 @@ class ClientHomegear(Client):
1518
1531
  return tuple(variables)
1519
1532
 
1520
1533
  @inspector(re_raise=False)
1521
- async def get_all_programs(self, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...] | None:
1534
+ async def get_all_programs(self, *, markers: tuple[DescriptionMarker | str, ...]) -> tuple[ProgramData, ...] | None:
1522
1535
  """Get all programs, if available."""
1523
1536
  return ()
1524
1537
 
@@ -1542,6 +1555,7 @@ class _ClientConfig:
1542
1555
 
1543
1556
  def __init__(
1544
1557
  self,
1558
+ *,
1545
1559
  central: hmcu.CentralUnit,
1546
1560
  interface_config: InterfaceConfig,
1547
1561
  ) -> None:
@@ -1599,7 +1613,7 @@ class _ClientConfig:
1599
1613
  return "0"
1600
1614
 
1601
1615
  async def create_xml_rpc_proxy(
1602
- self, auth_enabled: bool | None = None, max_workers: int = DEFAULT_MAX_WORKERS
1616
+ self, *, auth_enabled: bool | None = None, max_workers: int = DEFAULT_MAX_WORKERS
1603
1617
  ) -> XmlRpcProxy:
1604
1618
  """Return a XmlRPC proxy for the backend communication."""
1605
1619
  config = self.central.config
@@ -1633,6 +1647,7 @@ class InterfaceConfig:
1633
1647
 
1634
1648
  def __init__(
1635
1649
  self,
1650
+ *,
1636
1651
  central_name: str,
1637
1652
  interface: Interface,
1638
1653
  port: int | None = None,
@@ -1679,6 +1694,7 @@ def get_client(interface_id: str) -> Client | None:
1679
1694
 
1680
1695
  @measure_execution_time
1681
1696
  async def _wait_for_state_change_or_timeout(
1697
+ *,
1682
1698
  device: Device,
1683
1699
  dpk_values: set[DP_KEY_VALUE],
1684
1700
  wait_for_callback: int,
@@ -1697,7 +1713,7 @@ async def _wait_for_state_change_or_timeout(
1697
1713
 
1698
1714
  @measure_execution_time
1699
1715
  async def _track_single_data_point_state_change_or_timeout(
1700
- device: Device, dpk_value: DP_KEY_VALUE, wait_for_callback: int
1716
+ *, device: Device, dpk_value: DP_KEY_VALUE, wait_for_callback: int
1701
1717
  ) -> None:
1702
1718
  """Wait for a data_point to change state."""
1703
1719
  ev = asyncio.Event()
@@ -1710,7 +1726,7 @@ async def _track_single_data_point_state_change_or_timeout(
1710
1726
  dpk,
1711
1727
  dp.value,
1712
1728
  )
1713
- if _isclose(value, dp.value):
1729
+ if _isclose(value1=value, value2=dp.value):
1714
1730
  _LOGGER.debug(
1715
1731
  "TRACK_SINGLE_DATA_POINT_STATE_CHANGE_OR_TIMEOUT: Finished event %s with value %s",
1716
1732
  dpk,
@@ -1747,7 +1763,7 @@ async def _track_single_data_point_state_change_or_timeout(
1747
1763
  unsub()
1748
1764
 
1749
1765
 
1750
- def _isclose(value1: Any, value2: Any) -> bool:
1766
+ def _isclose(*, value1: Any, value2: Any) -> bool:
1751
1767
  """Check if the both values are close to each other."""
1752
1768
  if isinstance(value1, float):
1753
1769
  return bool(round(value1, 2) == round(value2, 2))
@@ -44,7 +44,7 @@ class RpcContext:
44
44
  return ", ".join(parts)
45
45
 
46
46
 
47
- def map_jsonrpc_error(error: Mapping[str, Any], ctx: RpcContext) -> Exception:
47
+ def map_jsonrpc_error(*, error: Mapping[str, Any], ctx: RpcContext) -> Exception:
48
48
  """Map JSON-RPC error to exception."""
49
49
  # JSON-RPC 2.0 like error: {code, message, data?}
50
50
  code = int(error.get("code", 0))
@@ -61,7 +61,7 @@ def map_jsonrpc_error(error: Mapping[str, Any], ctx: RpcContext) -> Exception:
61
61
  return ClientException(base_msg)
62
62
 
63
63
 
64
- def map_transport_error(exc: BaseException, ctx: RpcContext) -> Exception:
64
+ def map_transport_error(*, exc: BaseException, ctx: RpcContext) -> Exception:
65
65
  """Map transport error to exception."""
66
66
  msg = f"{exc} ({ctx.fmt()})"
67
67
  if isinstance(exc, OSError):
@@ -69,7 +69,7 @@ def map_transport_error(exc: BaseException, ctx: RpcContext) -> Exception:
69
69
  return ClientException(msg)
70
70
 
71
71
 
72
- def map_xmlrpc_fault(code: int, fault_string: str, ctx: RpcContext) -> Exception:
72
+ def map_xmlrpc_fault(*, code: int, fault_string: str, ctx: RpcContext) -> Exception:
73
73
  """Map XML-RPC fault to exception."""
74
74
  # Enrich message with context
75
75
  fault_msg = f"XMLRPC Fault {code}: {fault_string} ({ctx.fmt()})"