aiohomematic 2025.10.1__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.
- aiohomematic/async_support.py +7 -7
- aiohomematic/caches/dynamic.py +31 -26
- aiohomematic/caches/persistent.py +34 -32
- aiohomematic/caches/visibility.py +19 -7
- aiohomematic/central/__init__.py +87 -74
- aiohomematic/central/decorators.py +2 -2
- aiohomematic/central/xml_rpc_server.py +27 -24
- aiohomematic/client/__init__.py +72 -56
- aiohomematic/client/_rpc_errors.py +3 -3
- aiohomematic/client/json_rpc.py +33 -25
- aiohomematic/client/xml_rpc.py +14 -9
- aiohomematic/const.py +2 -1
- aiohomematic/converter.py +19 -19
- aiohomematic/exceptions.py +2 -1
- aiohomematic/model/__init__.py +4 -3
- aiohomematic/model/calculated/__init__.py +1 -1
- aiohomematic/model/calculated/climate.py +9 -9
- aiohomematic/model/calculated/data_point.py +13 -7
- aiohomematic/model/calculated/operating_voltage_level.py +2 -2
- aiohomematic/model/calculated/support.py +7 -7
- aiohomematic/model/custom/__init__.py +3 -3
- aiohomematic/model/custom/climate.py +57 -34
- aiohomematic/model/custom/cover.py +32 -18
- aiohomematic/model/custom/data_point.py +9 -7
- aiohomematic/model/custom/definition.py +23 -17
- aiohomematic/model/custom/light.py +52 -23
- aiohomematic/model/custom/lock.py +16 -12
- aiohomematic/model/custom/siren.py +6 -3
- aiohomematic/model/custom/switch.py +3 -2
- aiohomematic/model/custom/valve.py +3 -2
- aiohomematic/model/data_point.py +62 -49
- aiohomematic/model/device.py +48 -42
- aiohomematic/model/event.py +6 -5
- aiohomematic/model/generic/__init__.py +6 -4
- aiohomematic/model/generic/action.py +1 -1
- aiohomematic/model/generic/data_point.py +7 -5
- aiohomematic/model/generic/number.py +3 -3
- aiohomematic/model/generic/select.py +1 -1
- aiohomematic/model/generic/sensor.py +2 -2
- aiohomematic/model/generic/switch.py +3 -3
- aiohomematic/model/hub/__init__.py +17 -16
- aiohomematic/model/hub/data_point.py +12 -7
- aiohomematic/model/hub/number.py +3 -3
- aiohomematic/model/hub/select.py +3 -3
- aiohomematic/model/hub/text.py +2 -2
- aiohomematic/model/support.py +8 -7
- aiohomematic/model/update.py +6 -6
- aiohomematic/support.py +44 -38
- aiohomematic/validator.py +6 -6
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/METADATA +1 -1
- aiohomematic-2025.10.2.dist-info/RECORD +78 -0
- aiohomematic_support/client_local.py +19 -12
- aiohomematic-2025.10.1.dist-info/RECORD +0 -78
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/WHEEL +0 -0
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/licenses/LICENSE +0 -0
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/top_level.txt +0 -0
aiohomematic/model/device.py
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
|
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),
|
aiohomematic/model/event.py
CHANGED
|
@@ -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(
|
|
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,
|
|
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,
|