aiohomematic 2025.10.0__py3-none-any.whl → 2025.10.2__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 (56) hide show
  1. aiohomematic/async_support.py +7 -7
  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 +90 -74
  6. aiohomematic/central/decorators.py +2 -2
  7. aiohomematic/central/xml_rpc_server.py +27 -24
  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 +3 -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 +44 -20
  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 +6 -3
  29. aiohomematic/model/custom/switch.py +3 -2
  30. aiohomematic/model/custom/valve.py +3 -2
  31. aiohomematic/model/data_point.py +62 -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 +7 -5
  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 +8 -7
  47. aiohomematic/model/update.py +6 -6
  48. aiohomematic/support.py +44 -38
  49. aiohomematic/validator.py +6 -6
  50. {aiohomematic-2025.10.0.dist-info → aiohomematic-2025.10.2.dist-info}/METADATA +1 -1
  51. aiohomematic-2025.10.2.dist-info/RECORD +78 -0
  52. aiohomematic_support/client_local.py +19 -12
  53. aiohomematic-2025.10.0.dist-info/RECORD +0 -78
  54. {aiohomematic-2025.10.0.dist-info → aiohomematic-2025.10.2.dist-info}/WHEEL +0 -0
  55. {aiohomematic-2025.10.0.dist-info → aiohomematic-2025.10.2.dist-info}/licenses/LICENSE +0 -0
  56. {aiohomematic-2025.10.0.dist-info → aiohomematic-2025.10.2.dist-info}/top_level.txt +0 -0
@@ -131,7 +131,7 @@ class Device(LogContextMixin, PayloadMixin):
131
131
  "_value_cache",
132
132
  )
133
133
 
134
- def __init__(self, central: hmcu.CentralUnit, interface_id: str, device_address: str) -> None:
134
+ def __init__(self, *, central: hmcu.CentralUnit, interface_id: str, device_address: str) -> None:
135
135
  """Initialize the device object."""
136
136
  PayloadMixin.__init__(self)
137
137
  self._central: Final = central
@@ -164,7 +164,7 @@ class Device(LogContextMixin, PayloadMixin):
164
164
  model=self._model
165
165
  )
166
166
  self._manufacturer = self._identify_manufacturer()
167
- self._product_group: Final = self._client.get_product_group(self._model)
167
+ self._product_group: Final = self._client.get_product_group(model=self._model)
168
168
  # marker if device will be created as custom data_point
169
169
  self._has_custom_data_point_definition: Final = (
170
170
  hmed.data_point_definition_exists(model=self._model) and not self._ignore_for_custom_data_point
@@ -431,7 +431,7 @@ class Device(LogContextMixin, PayloadMixin):
431
431
  """Return th CONFIG_PENDING data_point."""
432
432
  return self.get_generic_data_point(channel_address=f"{self._address}:0", parameter=Parameter.CONFIG_PENDING)
433
433
 
434
- def add_channel_to_group(self, group_no: int, channel_no: int | None) -> None:
434
+ def add_channel_to_group(self, *, group_no: int, channel_no: int | None) -> None:
435
435
  """Add channel to group."""
436
436
  if group_no not in self._group_channels:
437
437
  self._group_channels[group_no] = set()
@@ -464,22 +464,22 @@ class Device(LogContextMixin, PayloadMixin):
464
464
  and self._model not in VIRTUAL_REMOTE_MODELS
465
465
  )
466
466
 
467
- def get_channel_group_no(self, channel_no: int | None) -> int | None:
467
+ def get_channel_group_no(self, *, channel_no: int | None) -> int | None:
468
468
  """Return the group no of the channel."""
469
469
  return self._channel_group.get(channel_no)
470
470
 
471
- def is_in_multi_channel_group(self, channel_no: int | None) -> bool:
471
+ def is_in_multi_channel_group(self, *, channel_no: int | None) -> bool:
472
472
  """Return if multiple channels are in the group."""
473
473
  if channel_no is None:
474
474
  return False
475
475
 
476
476
  return len([s for s, m in self._channel_group.items() if m == self._channel_group.get(channel_no)]) > 1
477
477
 
478
- def get_channel(self, channel_address: str) -> Channel | None:
478
+ def get_channel(self, *, channel_address: str) -> Channel | None:
479
479
  """Get channel of device."""
480
480
  return self._channels.get(channel_address)
481
481
 
482
- def identify_channel(self, text: str) -> Channel | None:
482
+ def identify_channel(self, *, text: str) -> Channel | None:
483
483
  """Identify channel within a text."""
484
484
  for channel_address, channel in self._channels.items():
485
485
  if text.endswith(channel_address):
@@ -496,26 +496,26 @@ class Device(LogContextMixin, PayloadMixin):
496
496
  for channel in self._channels.values():
497
497
  channel.remove()
498
498
 
499
- def register_device_updated_callback(self, cb: Callable) -> CALLBACK_TYPE:
499
+ def register_device_updated_callback(self, *, cb: Callable) -> CALLBACK_TYPE:
500
500
  """Register update callback."""
501
501
  if callable(cb) and cb not in self._device_updated_callbacks:
502
502
  self._device_updated_callbacks.append(cb)
503
503
  return partial(self.unregister_device_updated_callback, cb=cb)
504
504
  return None
505
505
 
506
- def unregister_device_updated_callback(self, cb: Callable) -> None:
506
+ def unregister_device_updated_callback(self, *, cb: Callable) -> None:
507
507
  """Remove update callback."""
508
508
  if cb in self._device_updated_callbacks:
509
509
  self._device_updated_callbacks.remove(cb)
510
510
 
511
- def register_firmware_update_callback(self, cb: Callable) -> CALLBACK_TYPE:
511
+ def register_firmware_update_callback(self, *, cb: Callable) -> CALLBACK_TYPE:
512
512
  """Register firmware update callback."""
513
513
  if callable(cb) and cb not in self._firmware_update_callbacks:
514
514
  self._firmware_update_callbacks.append(cb)
515
515
  return partial(self.unregister_firmware_update_callback, cb=cb)
516
516
  return None
517
517
 
518
- def unregister_firmware_update_callback(self, cb: Callable) -> None:
518
+ def unregister_firmware_update_callback(self, *, cb: Callable) -> None:
519
519
  """Remove firmware update callback."""
520
520
  if cb in self._firmware_update_callbacks:
521
521
  self._firmware_update_callbacks.remove(cb)
@@ -525,6 +525,7 @@ class Device(LogContextMixin, PayloadMixin):
525
525
 
526
526
  def get_data_points(
527
527
  self,
528
+ *,
528
529
  category: DataPointCategory | None = None,
529
530
  exclude_no_create: bool = True,
530
531
  registered: bool | None = None,
@@ -548,7 +549,7 @@ class Device(LogContextMixin, PayloadMixin):
548
549
  return tuple(all_data_points)
549
550
 
550
551
  def get_events(
551
- self, event_type: EventType, registered: bool | None = None
552
+ self, *, event_type: EventType, registered: bool | None = None
552
553
  ) -> Mapping[int | None, tuple[GenericEvent, ...]]:
553
554
  """Return a list of specific events of a channel."""
554
555
  events: dict[int | None, tuple[GenericEvent, ...]] = {}
@@ -557,13 +558,13 @@ class Device(LogContextMixin, PayloadMixin):
557
558
  events[channel.no] = values
558
559
  return events
559
560
 
560
- def get_calculated_data_point(self, channel_address: str, parameter: str) -> CalculatedDataPoint | None:
561
+ def get_calculated_data_point(self, *, channel_address: str, parameter: str) -> CalculatedDataPoint | None:
561
562
  """Return a calculated data_point from device."""
562
563
  if channel := self.get_channel(channel_address=channel_address):
563
564
  return channel.get_calculated_data_point(parameter=parameter)
564
565
  return None
565
566
 
566
- def get_custom_data_point(self, channel_no: int) -> hmce.CustomDataPoint | None:
567
+ def get_custom_data_point(self, *, channel_no: int) -> hmce.CustomDataPoint | None:
567
568
  """Return a custom data_point from device."""
568
569
  if channel := self.get_channel(
569
570
  channel_address=get_channel_address(device_address=self._address, channel_no=channel_no)
@@ -572,27 +573,27 @@ class Device(LogContextMixin, PayloadMixin):
572
573
  return None
573
574
 
574
575
  def get_generic_data_point(
575
- self, channel_address: str, parameter: str, paramset_key: ParamsetKey | None = None
576
+ self, *, channel_address: str, parameter: str, paramset_key: ParamsetKey | None = None
576
577
  ) -> GenericDataPoint | None:
577
578
  """Return a generic data_point from device."""
578
579
  if channel := self.get_channel(channel_address=channel_address):
579
580
  return channel.get_generic_data_point(parameter=parameter, paramset_key=paramset_key)
580
581
  return None
581
582
 
582
- def get_generic_event(self, channel_address: str, parameter: str) -> GenericEvent | None:
583
+ def get_generic_event(self, *, channel_address: str, parameter: str) -> GenericEvent | None:
583
584
  """Return a generic event from device."""
584
585
  if channel := self.get_channel(channel_address=channel_address):
585
586
  return channel.get_generic_event(parameter=parameter)
586
587
  return None
587
588
 
588
- def get_readable_data_points(self, paramset_key: ParamsetKey) -> tuple[GenericDataPoint, ...]:
589
+ def get_readable_data_points(self, *, paramset_key: ParamsetKey) -> tuple[GenericDataPoint, ...]:
589
590
  """Return the list of readable master data points."""
590
591
  data_points: list[GenericDataPoint] = []
591
592
  for channel in self._channels.values():
592
593
  data_points.extend(channel.get_readable_data_points(paramset_key=paramset_key))
593
594
  return tuple(data_points)
594
595
 
595
- def set_forced_availability(self, forced_availability: ForcedDeviceAvailability) -> None:
596
+ def set_forced_availability(self, *, forced_availability: ForcedDeviceAvailability) -> None:
596
597
  """Set the availability of the device."""
597
598
  if self._forced_availability != forced_availability:
598
599
  self._forced_availability = forced_availability
@@ -629,7 +630,7 @@ class Device(LogContextMixin, PayloadMixin):
629
630
  callback_handler()
630
631
 
631
632
  @inspector
632
- async def update_firmware(self, refresh_after_update_intervals: tuple[int, ...]) -> bool:
633
+ async def update_firmware(self, *, refresh_after_update_intervals: tuple[int, ...]) -> bool:
633
634
  """Update the firmware of the Homematic device."""
634
635
  update_result = await self._client.update_device_firmware(device_address=self._address)
635
636
 
@@ -676,12 +677,12 @@ class Device(LogContextMixin, PayloadMixin):
676
677
  self.fire_device_updated_callback()
677
678
 
678
679
  @loop_check
679
- def fire_device_updated_callback(self, *args: Any) -> None:
680
+ def fire_device_updated_callback(self) -> None:
680
681
  """Do what is needed when the state of the device has been updated."""
681
682
  self._set_modified_at()
682
683
  for callback_handler in self._device_updated_callbacks:
683
684
  try:
684
- callback_handler(*args)
685
+ callback_handler()
685
686
  except Exception as exc:
686
687
  _LOGGER.warning("FIRE_DEVICE_UPDATED failed: %s", extract_exc_args(exc=exc))
687
688
 
@@ -724,7 +725,7 @@ class Channel(LogContextMixin, PayloadMixin):
724
725
  "_unique_id",
725
726
  )
726
727
 
727
- def __init__(self, device: Device, channel_address: str) -> None:
728
+ def __init__(self, *, device: Device, channel_address: str) -> None:
728
729
  """Initialize the channel object."""
729
730
  PayloadMixin.__init__(self)
730
731
 
@@ -809,7 +810,9 @@ class Channel(LogContextMixin, PayloadMixin):
809
810
  return None
810
811
  if self._group_master is None:
811
812
  self._group_master = (
812
- self if self.is_group_master else self._device.get_channel(f"{self._device.address}:{self.group_no}")
813
+ self
814
+ if self.is_group_master
815
+ else self._device.get_channel(channel_address=f"{self._device.address}:{self.group_no}")
813
816
  )
814
817
  return self._group_master
815
818
 
@@ -952,7 +955,7 @@ class Channel(LogContextMixin, PayloadMixin):
952
955
  """Return if channel has KEYPRESS events."""
953
956
  return any(event for event in self.generic_events if event.event_type is EventType.KEYPRESS)
954
957
 
955
- def add_data_point(self, data_point: CallbackDataPoint) -> None:
958
+ def add_data_point(self, *, data_point: CallbackDataPoint) -> None:
956
959
  """Add a data_point to a channel."""
957
960
  if isinstance(data_point, BaseParameterDataPoint):
958
961
  self._central.add_event_subscription(data_point=data_point)
@@ -966,7 +969,7 @@ class Channel(LogContextMixin, PayloadMixin):
966
969
  if isinstance(data_point, GenericEvent):
967
970
  self._generic_events[data_point.dpk] = data_point
968
971
 
969
- def _remove_data_point(self, data_point: CallbackDataPoint) -> None:
972
+ def _remove_data_point(self, *, data_point: CallbackDataPoint) -> None:
970
973
  """Remove a data_point from a channel."""
971
974
  if isinstance(data_point, BaseParameterDataPoint):
972
975
  self._central.remove_event_subscription(data_point=data_point)
@@ -984,25 +987,26 @@ class Channel(LogContextMixin, PayloadMixin):
984
987
  def remove(self) -> None:
985
988
  """Remove data points from collections and central."""
986
989
  for event in self.generic_events:
987
- self._remove_data_point(event)
990
+ self._remove_data_point(data_point=event)
988
991
  self._generic_events.clear()
989
992
 
990
993
  for ccdp in self.calculated_data_points:
991
- self._remove_data_point(ccdp)
994
+ self._remove_data_point(data_point=ccdp)
992
995
  self._calculated_data_points.clear()
993
996
 
994
997
  for gdp in self.generic_data_points:
995
- self._remove_data_point(gdp)
998
+ self._remove_data_point(data_point=gdp)
996
999
  self._generic_data_points.clear()
997
1000
 
998
1001
  if self._custom_data_point:
999
- self._remove_data_point(self._custom_data_point)
1002
+ self._remove_data_point(data_point=self._custom_data_point)
1000
1003
 
1001
1004
  def _set_modified_at(self) -> None:
1002
1005
  self._modified_at = datetime.now()
1003
1006
 
1004
1007
  def get_data_points(
1005
1008
  self,
1009
+ *,
1006
1010
  category: DataPointCategory | None = None,
1007
1011
  exclude_no_create: bool = True,
1008
1012
  registered: bool | None = None,
@@ -1023,7 +1027,7 @@ class Channel(LogContextMixin, PayloadMixin):
1023
1027
  and (registered is None or dp.is_registered == registered)
1024
1028
  )
1025
1029
 
1026
- def get_events(self, event_type: EventType, registered: bool | None = None) -> tuple[GenericEvent, ...]:
1030
+ def get_events(self, *, event_type: EventType, registered: bool | None = None) -> tuple[GenericEvent, ...]:
1027
1031
  """Return a list of specific events of a channel."""
1028
1032
  return tuple(
1029
1033
  event
@@ -1031,7 +1035,7 @@ class Channel(LogContextMixin, PayloadMixin):
1031
1035
  if (event.event_type == event_type and (registered is None or event.is_registered == registered))
1032
1036
  )
1033
1037
 
1034
- def get_calculated_data_point(self, parameter: str) -> CalculatedDataPoint | None:
1038
+ def get_calculated_data_point(self, *, parameter: str) -> CalculatedDataPoint | None:
1035
1039
  """Return a calculated data_point from device."""
1036
1040
  return self._calculated_data_points.get(
1037
1041
  DataPointKey(
@@ -1043,7 +1047,7 @@ class Channel(LogContextMixin, PayloadMixin):
1043
1047
  )
1044
1048
 
1045
1049
  def get_generic_data_point(
1046
- self, parameter: str, paramset_key: ParamsetKey | None = None
1050
+ self, *, parameter: str, paramset_key: ParamsetKey | None = None
1047
1051
  ) -> GenericDataPoint | None:
1048
1052
  """Return a generic data_point from device."""
1049
1053
  if paramset_key:
@@ -1074,7 +1078,7 @@ class Channel(LogContextMixin, PayloadMixin):
1074
1078
  )
1075
1079
  )
1076
1080
 
1077
- def get_generic_event(self, parameter: str) -> GenericEvent | None:
1081
+ def get_generic_event(self, *, parameter: str) -> GenericEvent | None:
1078
1082
  """Return a generic event from device."""
1079
1083
  return self._generic_events.get(
1080
1084
  DataPointKey(
@@ -1085,7 +1089,7 @@ class Channel(LogContextMixin, PayloadMixin):
1085
1089
  )
1086
1090
  )
1087
1091
 
1088
- def get_readable_data_points(self, paramset_key: ParamsetKey) -> tuple[GenericDataPoint, ...]:
1092
+ def get_readable_data_points(self, *, paramset_key: ParamsetKey) -> tuple[GenericDataPoint, ...]:
1089
1093
  """Return the list of readable master data points."""
1090
1094
  return tuple(
1091
1095
  ge for ge in self._generic_data_points.values() if ge.is_readable and ge.paramset_key == paramset_key
@@ -1114,7 +1118,7 @@ class _ValueCache:
1114
1118
 
1115
1119
  _NO_VALUE_CACHE_ENTRY: Final = "NO_VALUE_CACHE_ENTRY"
1116
1120
 
1117
- def __init__(self, device: Device) -> None:
1121
+ def __init__(self, *, device: Device) -> None:
1118
1122
  """Init the value cache."""
1119
1123
  self._sema_get_or_load_value: Final = asyncio.Semaphore()
1120
1124
  self._device: Final = device
@@ -1166,6 +1170,7 @@ class _ValueCache:
1166
1170
 
1167
1171
  async def get_value(
1168
1172
  self,
1173
+ *,
1169
1174
  dpk: DataPointKey,
1170
1175
  call_source: CallSource,
1171
1176
  direct_call: bool = False,
@@ -1204,7 +1209,7 @@ class _ValueCache:
1204
1209
  else value
1205
1210
  )
1206
1211
 
1207
- async def _get_values_for_cache(self, dpk: DataPointKey) -> dict[str, Any]:
1212
+ async def _get_values_for_cache(self, *, dpk: DataPointKey) -> dict[str, Any]:
1208
1213
  """Return a value from the backend to store in cache."""
1209
1214
  if not self._device.available:
1210
1215
  _LOGGER.debug(
@@ -1224,7 +1229,7 @@ class _ValueCache:
1224
1229
  address=dpk.channel_address, paramset_key=dpk.paramset_key, call_source=CallSource.HM_INIT
1225
1230
  )
1226
1231
 
1227
- def _add_entry_to_device_cache(self, dpk: DataPointKey, value: Any) -> None:
1232
+ def _add_entry_to_device_cache(self, *, dpk: DataPointKey, value: Any) -> None:
1228
1233
  """Add value to cache."""
1229
1234
  # write value to cache even if an exception has occurred
1230
1235
  # to avoid repetitive calls to the backend within max_age
@@ -1232,6 +1237,7 @@ class _ValueCache:
1232
1237
 
1233
1238
  def _get_value_from_cache(
1234
1239
  self,
1240
+ *,
1235
1241
  dpk: DataPointKey,
1236
1242
  ) -> Any:
1237
1243
  """Load data from caches."""
@@ -1266,7 +1272,7 @@ class _DefinitionExporter:
1266
1272
  "_storage_folder",
1267
1273
  )
1268
1274
 
1269
- def __init__(self, device: Device) -> None:
1275
+ def __init__(self, *, device: Device) -> None:
1270
1276
  """Init the device exporter."""
1271
1277
  self._client: Final = device.client
1272
1278
  self._central: Final = device.client.central
@@ -1298,7 +1304,7 @@ class _DefinitionExporter:
1298
1304
  new_device_description["PARENT"] = new_device_description["ADDRESS"].split(ADDRESS_SEPARATOR)[0]
1299
1305
  elif new_device_description.get("CHILDREN"):
1300
1306
  new_device_description["CHILDREN"] = [
1301
- self._anonymize_address(a) for a in new_device_description["CHILDREN"]
1307
+ self._anonymize_address(address=a) for a in new_device_description["CHILDREN"]
1302
1308
  ]
1303
1309
  anonymize_device_descriptions.append(new_device_description)
1304
1310
 
@@ -1321,16 +1327,16 @@ class _DefinitionExporter:
1321
1327
  data=anonymize_paramset_descriptions,
1322
1328
  )
1323
1329
 
1324
- def _anonymize_address(self, address: str) -> str:
1330
+ def _anonymize_address(self, *, address: str) -> str:
1325
1331
  address_parts = address.split(ADDRESS_SEPARATOR)
1326
1332
  address_parts[0] = self._random_id
1327
1333
  return ADDRESS_SEPARATOR.join(address_parts)
1328
1334
 
1329
- async def _save(self, file_dir: str, filename: str, data: Any) -> DataOperationResult:
1335
+ async def _save(self, *, file_dir: str, filename: str, data: Any) -> DataOperationResult:
1330
1336
  """Save file to disk."""
1331
1337
 
1332
1338
  def perform_save() -> DataOperationResult:
1333
- if not check_or_create_directory(file_dir):
1339
+ if not check_or_create_directory(directory=file_dir):
1334
1340
  return DataOperationResult.NO_SAVE # pragma: no cover
1335
1341
  with open(
1336
1342
  file=os.path.join(file_dir, filename),
@@ -73,6 +73,7 @@ class GenericEvent(BaseParameterDataPoint[Any, Any]):
73
73
 
74
74
  def __init__(
75
75
  self,
76
+ *,
76
77
  channel: hmd.Channel,
77
78
  parameter: str,
78
79
  parameter_data: ParameterData,
@@ -98,15 +99,15 @@ class GenericEvent(BaseParameterDataPoint[Any, Any]):
98
99
  """Return the event_type of the event."""
99
100
  return self._event_type
100
101
 
101
- async def event(self, value: Any, received_at: datetime) -> None:
102
+ async def event(self, *, value: Any, received_at: datetime) -> None:
102
103
  """Handle event for which this handler has subscribed."""
103
104
  if self.event_type in DATA_POINT_EVENTS:
104
105
  self.fire_data_point_updated_callback()
105
106
  self._set_modified_at(modified_at=received_at)
106
- self.fire_event(value)
107
+ self.fire_event(value=value)
107
108
 
108
109
  @loop_check
109
- def fire_event(self, value: Any) -> None:
110
+ def fire_event(self, *, value: Any) -> None:
110
111
  """Do what is needed to fire an event."""
111
112
  self._central.fire_homematic_callback(event_type=self.event_type, event_data=self.get_event_data(value=value))
112
113
 
@@ -137,7 +138,7 @@ class DeviceErrorEvent(GenericEvent):
137
138
 
138
139
  _event_type = EventType.DEVICE_ERROR
139
140
 
140
- async def event(self, value: Any, received_at: datetime) -> None:
141
+ async def event(self, *, value: Any, received_at: datetime) -> None:
141
142
  """Handle event for which this handler has subscribed."""
142
143
  old_value, new_value = self.write_value(value=value, write_at=received_at)
143
144
 
@@ -173,7 +174,7 @@ def create_event_and_append_to_channel(channel: hmd.Channel, parameter: str, par
173
174
  event_t=event_t, channel=channel, parameter=parameter, parameter_data=parameter_data
174
175
  )
175
176
  ):
176
- channel.add_data_point(event)
177
+ channel.add_data_point(data_point=event)
177
178
 
178
179
 
179
180
  def _determine_event_type(parameter: str, parameter_data: ParameterData) -> type[GenericEvent] | None:
@@ -102,6 +102,7 @@ _SWITCH_DP_TO_SENSOR: Final[Mapping[str | tuple[str, ...], Parameter]] = {
102
102
 
103
103
  @inspector
104
104
  def create_data_point_and_append_to_channel(
105
+ *,
105
106
  channel: hmd.Channel,
106
107
  paramset_key: ParamsetKey,
107
108
  parameter: str,
@@ -115,7 +116,7 @@ def create_data_point_and_append_to_channel(
115
116
  channel.device.interface_id,
116
117
  )
117
118
 
118
- if (dp_t := _determine_data_point_type(channel, parameter, parameter_data)) and (
119
+ if (dp_t := _determine_data_point_type(channel=channel, parameter=parameter, parameter_data=parameter_data)) and (
119
120
  dp := _safe_create_data_point(
120
121
  dp_t=dp_t, channel=channel, paramset_key=paramset_key, parameter=parameter, parameter_data=parameter_data
121
122
  )
@@ -126,13 +127,13 @@ def create_data_point_and_append_to_channel(
126
127
  channel.address,
127
128
  parameter,
128
129
  )
129
- channel.add_data_point(dp)
130
+ channel.add_data_point(data_point=dp)
130
131
  if _check_switch_to_sensor(data_point=dp):
131
132
  dp.force_to_sensor()
132
133
 
133
134
 
134
135
  def _determine_data_point_type(
135
- channel: hmd.Channel, parameter: str, parameter_data: ParameterData
136
+ *, channel: hmd.Channel, parameter: str, parameter_data: ParameterData
136
137
  ) -> type[GenericDataPoint] | None:
137
138
  """Determine the type of data point based on parameter and operations."""
138
139
  p_type = parameter_data["TYPE"]
@@ -173,6 +174,7 @@ def _determine_data_point_type(
173
174
 
174
175
 
175
176
  def _safe_create_data_point(
177
+ *,
176
178
  dp_t: type[GenericDataPoint],
177
179
  channel: hmd.Channel,
178
180
  paramset_key: ParamsetKey,
@@ -193,7 +195,7 @@ def _safe_create_data_point(
193
195
  ) from exc
194
196
 
195
197
 
196
- def _check_switch_to_sensor(data_point: GenericDataPoint) -> bool:
198
+ def _check_switch_to_sensor(*, data_point: GenericDataPoint) -> bool:
197
199
  """Check if parameter of a device should be wrapped to a different category."""
198
200
  if data_point.device.central.parameter_visibility.parameter_is_un_ignored(
199
201
  channel=data_point.channel,
@@ -27,7 +27,7 @@ class DpAction(GenericDataPoint[None, Any]):
27
27
  _category = DataPointCategory.ACTION
28
28
  _validate_state_change = False
29
29
 
30
- def _prepare_value_for_sending(self, value: Any, do_validate: bool = True) -> Any:
30
+ def _prepare_value_for_sending(self, *, value: Any, do_validate: bool = True) -> Any:
31
31
  """Prepare value before sending."""
32
32
  if (index := get_index_of_value_from_value_list(value=value, value_list=self._values)) is not None:
33
33
  return index
@@ -38,6 +38,7 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
38
38
 
39
39
  def __init__(
40
40
  self,
41
+ *,
41
42
  channel: hmd.Channel,
42
43
  paramset_key: ParamsetKey,
43
44
  parameter: str,
@@ -60,7 +61,7 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
60
61
  return self._get_data_point_usage()
61
62
  return DataPointUsage.DATA_POINT if force_enabled else DataPointUsage.NO_CREATE # pylint: disable=using-constant-test
62
63
 
63
- async def event(self, value: Any, received_at: datetime) -> None:
64
+ async def event(self, *, value: Any, received_at: datetime) -> None:
64
65
  """Handle event for which this data_point has subscribed."""
65
66
  self._device.client.last_value_send_cache.remove_last_value_send(
66
67
  dpk=self.dpk,
@@ -82,15 +83,16 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
82
83
  Parameter.UN_REACH,
83
84
  Parameter.STICKY_UN_REACH,
84
85
  ):
85
- self._device.fire_device_updated_callback(self._unique_id)
86
+ self._device.fire_device_updated_callback()
86
87
  self._central.fire_homematic_callback(
87
88
  event_type=EventType.DEVICE_AVAILABILITY,
88
- event_data=self.get_event_data(new_value),
89
+ event_data=self.get_event_data(value=new_value),
89
90
  )
90
91
 
91
92
  @inspector
92
93
  async def send_value(
93
94
  self,
95
+ *,
94
96
  value: InputParameterT,
95
97
  collector: hme.CallParameterCollector | None = None,
96
98
  collector_order: int = 50,
@@ -123,7 +125,7 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
123
125
  value=converted_value,
124
126
  )
125
127
 
126
- def _prepare_value_for_sending(self, value: InputParameterT, do_validate: bool = True) -> ParameterT:
128
+ def _prepare_value_for_sending(self, *, value: InputParameterT, do_validate: bool = True) -> ParameterT:
127
129
  """Prepare value, if required, before send."""
128
130
  return value # type: ignore[return-value]
129
131
 
@@ -151,7 +153,7 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
151
153
  else DataPointUsage.DATA_POINT
152
154
  )
153
155
 
154
- def is_state_change(self, value: ParameterT) -> bool:
156
+ def is_state_change(self, *, value: ParameterT) -> bool:
155
157
  """
156
158
  Check if the state/value changes.
157
159
 
@@ -24,7 +24,7 @@ class BaseDpNumber[NumberParameterT: int | float | None](GenericDataPoint[Number
24
24
  _category = DataPointCategory.NUMBER
25
25
 
26
26
  def _prepare_number_for_sending(
27
- self, value: int | float | str, type_converter: type, do_validate: bool = True
27
+ self, *, value: int | float | str, type_converter: type, do_validate: bool = True
28
28
  ) -> NumberParameterT:
29
29
  """Prepare value before sending."""
30
30
  if not do_validate or (
@@ -47,7 +47,7 @@ class DpFloat(BaseDpNumber[float | None]):
47
47
 
48
48
  __slots__ = ()
49
49
 
50
- def _prepare_value_for_sending(self, value: int | float | str, do_validate: bool = True) -> float | None:
50
+ def _prepare_value_for_sending(self, *, value: int | float | str, do_validate: bool = True) -> float | None:
51
51
  """Prepare value before sending."""
52
52
  return self._prepare_number_for_sending(value=value, type_converter=float, do_validate=do_validate)
53
53
 
@@ -66,7 +66,7 @@ class DpInteger(BaseDpNumber[int | None]):
66
66
 
67
67
  __slots__ = ()
68
68
 
69
- def _prepare_value_for_sending(self, value: int | float | str, do_validate: bool = True) -> int | None:
69
+ def _prepare_value_for_sending(self, *, value: int | float | str, do_validate: bool = True) -> int | None:
70
70
  """Prepare value before sending."""
71
71
  return self._prepare_number_for_sending(value=value, type_converter=int, do_validate=do_validate)
72
72
 
@@ -29,7 +29,7 @@ class DpSelect(GenericDataPoint[int | str, int | float | str]):
29
29
  return value
30
30
  return str(self._default)
31
31
 
32
- def _prepare_value_for_sending(self, value: int | float | str, do_validate: bool = True) -> int:
32
+ def _prepare_value_for_sending(self, *, value: int | float | str, do_validate: bool = True) -> int:
33
33
  """Prepare value before sending."""
34
34
  # We allow setting the value via index as well, just in case.
35
35
  if isinstance(value, int | float) and self._values and 0 <= value < len(self._values):
@@ -33,7 +33,7 @@ class DpSensor[SensorT: float | int | str | None](GenericDataPoint[SensorT, None
33
33
  if (value := get_value_from_value_list(value=self._value, value_list=self.values)) is not None:
34
34
  return cast(SensorT, value)
35
35
  if convert_func := self._get_converter_func():
36
- return cast(SensorT, convert_func(self._value))
36
+ return cast(SensorT, convert_func(value=self._value))
37
37
  return cast(
38
38
  SensorT,
39
39
  check_length_and_log(name=self.name, value=self._value)
@@ -48,7 +48,7 @@ class DpSensor[SensorT: float | int | str | None](GenericDataPoint[SensorT, None
48
48
  return None
49
49
 
50
50
 
51
- def _fix_rssi(value: Any) -> int | None:
51
+ def _fix_rssi(*, value: Any) -> int | None:
52
52
  """
53
53
  Fix rssi value.
54
54
 
@@ -32,19 +32,19 @@ class DpSwitch(GenericDataPoint[bool | None, bool]):
32
32
  return cast(bool | None, self._value)
33
33
 
34
34
  @inspector
35
- async def turn_on(self, collector: CallParameterCollector | None = None, on_time: float | None = None) -> None:
35
+ async def turn_on(self, *, on_time: float | None = None, collector: CallParameterCollector | None = None) -> None:
36
36
  """Turn the switch on."""
37
37
  if on_time is not None:
38
38
  await self.set_on_time(on_time=on_time)
39
39
  await self.send_value(value=True, collector=collector)
40
40
 
41
41
  @inspector
42
- async def turn_off(self, collector: CallParameterCollector | None = None) -> None:
42
+ async def turn_off(self, *, collector: CallParameterCollector | None = None) -> None:
43
43
  """Turn the switch off."""
44
44
  await self.send_value(value=False, collector=collector)
45
45
 
46
46
  @inspector
47
- async def set_on_time(self, on_time: float) -> None:
47
+ async def set_on_time(self, *, on_time: float) -> None:
48
48
  """Set the on time value in seconds."""
49
49
  await self._client.set_value(
50
50
  channel_address=self._channel.address,