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.
- aiohomematic/async_support.py +8 -8
- aiohomematic/caches/dynamic.py +31 -26
- aiohomematic/caches/persistent.py +34 -32
- aiohomematic/caches/visibility.py +19 -7
- aiohomematic/central/__init__.py +88 -75
- aiohomematic/central/decorators.py +2 -2
- aiohomematic/central/xml_rpc_server.py +33 -25
- 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 +8 -3
- aiohomematic/model/custom/switch.py +3 -2
- aiohomematic/model/custom/valve.py +3 -2
- aiohomematic/model/data_point.py +63 -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 +8 -6
- 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 +10 -9
- aiohomematic/model/update.py +6 -6
- aiohomematic/property_decorators.py +2 -0
- aiohomematic/support.py +44 -38
- aiohomematic/validator.py +6 -6
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/METADATA +1 -1
- aiohomematic-2025.10.3.dist-info/RECORD +78 -0
- aiohomematic_support/client_local.py +26 -14
- aiohomematic-2025.10.1.dist-info/RECORD +0 -78
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/WHEEL +0 -0
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/licenses/LICENSE +0 -0
- {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.3.dist-info}/top_level.txt +0 -0
aiohomematic/model/data_point.py
CHANGED
|
@@ -44,6 +44,7 @@ from aiohomematic.const import (
|
|
|
44
44
|
DP_KEY_VALUE,
|
|
45
45
|
INIT_DATETIME,
|
|
46
46
|
KEY_CHANNEL_OPERATION_MODE_VISIBILITY,
|
|
47
|
+
KWARGS_ARG_CUSTOM_ID,
|
|
47
48
|
KWARGS_ARG_DATA_POINT,
|
|
48
49
|
NO_CACHE_ENTRY,
|
|
49
50
|
WAIT_FOR_CALLBACK,
|
|
@@ -142,7 +143,7 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
142
143
|
"_custom_id",
|
|
143
144
|
"_data_point_updated_callbacks",
|
|
144
145
|
"_device_removed_callbacks",
|
|
145
|
-
"
|
|
146
|
+
"_fired_event_at",
|
|
146
147
|
"_modified_at",
|
|
147
148
|
"_path_data",
|
|
148
149
|
"_refreshed_at",
|
|
@@ -154,7 +155,7 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
154
155
|
|
|
155
156
|
_category = DataPointCategory.UNDEFINED
|
|
156
157
|
|
|
157
|
-
def __init__(self, central: hmcu.CentralUnit, unique_id: str) -> None:
|
|
158
|
+
def __init__(self, *, central: hmcu.CentralUnit, unique_id: str) -> None:
|
|
158
159
|
"""Init the callback data_point."""
|
|
159
160
|
self._central: Final = central
|
|
160
161
|
self._unique_id: Final = unique_id
|
|
@@ -162,7 +163,7 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
162
163
|
self._device_removed_callbacks: list[Callable] = []
|
|
163
164
|
self._custom_id: str | None = None
|
|
164
165
|
self._path_data = self._get_path_data()
|
|
165
|
-
self.
|
|
166
|
+
self._fired_event_at: datetime = INIT_DATETIME
|
|
166
167
|
self._modified_at: datetime = INIT_DATETIME
|
|
167
168
|
self._refreshed_at: datetime = INIT_DATETIME
|
|
168
169
|
self._signature: Final = self._get_signature()
|
|
@@ -190,16 +191,16 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
190
191
|
return self._custom_id
|
|
191
192
|
|
|
192
193
|
@property
|
|
193
|
-
def
|
|
194
|
-
"""Return the data point updated fired at."""
|
|
195
|
-
return self.
|
|
194
|
+
def fired_event_at(self) -> datetime:
|
|
195
|
+
"""Return the data point updated fired an event at."""
|
|
196
|
+
return self._fired_event_at
|
|
196
197
|
|
|
197
198
|
@state_property
|
|
198
|
-
def
|
|
199
|
-
"""Return the data point fired within 500 milliseconds."""
|
|
200
|
-
if self.
|
|
199
|
+
def fired_event_recently(self) -> bool:
|
|
200
|
+
"""Return the data point fired an event within 500 milliseconds."""
|
|
201
|
+
if self._fired_event_at == INIT_DATETIME:
|
|
201
202
|
return False
|
|
202
|
-
return (datetime.now() - self.
|
|
203
|
+
return (datetime.now() - self._fired_event_at).total_seconds() < 0.5
|
|
203
204
|
|
|
204
205
|
@classmethod
|
|
205
206
|
def default_category(cls) -> DataPointCategory:
|
|
@@ -305,11 +306,11 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
305
306
|
"""Return all service methods."""
|
|
306
307
|
return tuple(self.service_methods.keys())
|
|
307
308
|
|
|
308
|
-
def register_internal_data_point_updated_callback(self, cb: Callable) -> CALLBACK_TYPE:
|
|
309
|
+
def register_internal_data_point_updated_callback(self, *, cb: Callable) -> CALLBACK_TYPE:
|
|
309
310
|
"""Register internal data_point updated callback."""
|
|
310
311
|
return self.register_data_point_updated_callback(cb=cb, custom_id=DEFAULT_CUSTOM_ID)
|
|
311
312
|
|
|
312
|
-
def register_data_point_updated_callback(self, cb: Callable, custom_id: str) -> CALLBACK_TYPE:
|
|
313
|
+
def register_data_point_updated_callback(self, *, cb: Callable, custom_id: str) -> CALLBACK_TYPE:
|
|
313
314
|
"""Register data_point updated callback."""
|
|
314
315
|
if custom_id != DEFAULT_CUSTOM_ID:
|
|
315
316
|
if self._custom_id is not None and self._custom_id != custom_id:
|
|
@@ -336,45 +337,46 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
336
337
|
def _get_signature(self) -> str:
|
|
337
338
|
"""Return the signature of the data_point."""
|
|
338
339
|
|
|
339
|
-
def _unregister_data_point_updated_callback(self, cb: Callable, custom_id: str) -> None:
|
|
340
|
+
def _unregister_data_point_updated_callback(self, *, cb: Callable, custom_id: str) -> None:
|
|
340
341
|
"""Unregister data_point updated callback."""
|
|
341
342
|
if cb in self._data_point_updated_callbacks:
|
|
342
343
|
del self._data_point_updated_callbacks[cb]
|
|
343
344
|
if self.custom_id == custom_id:
|
|
344
345
|
self._custom_id = None
|
|
345
346
|
|
|
346
|
-
def register_device_removed_callback(self, cb: Callable) -> CALLBACK_TYPE:
|
|
347
|
+
def register_device_removed_callback(self, *, cb: Callable) -> CALLBACK_TYPE:
|
|
347
348
|
"""Register the device removed callback."""
|
|
348
349
|
if callable(cb) and cb not in self._device_removed_callbacks:
|
|
349
350
|
self._device_removed_callbacks.append(cb)
|
|
350
351
|
return partial(self._unregister_device_removed_callback, cb=cb)
|
|
351
352
|
return None
|
|
352
353
|
|
|
353
|
-
def _unregister_device_removed_callback(self, cb: Callable) -> None:
|
|
354
|
+
def _unregister_device_removed_callback(self, *, cb: Callable) -> None:
|
|
354
355
|
"""Unregister the device removed callback."""
|
|
355
356
|
if cb in self._device_removed_callbacks:
|
|
356
357
|
self._device_removed_callbacks.remove(cb)
|
|
357
358
|
|
|
358
359
|
@loop_check
|
|
359
|
-
def fire_data_point_updated_callback(self,
|
|
360
|
+
def fire_data_point_updated_callback(self, **kwargs: Any) -> None:
|
|
360
361
|
"""Do what is needed when the value of the data_point has been updated/refreshed."""
|
|
361
362
|
if not self._should_fire_data_point_updated_callback:
|
|
362
363
|
return
|
|
363
|
-
self.
|
|
364
|
-
|
|
365
|
-
kwargs[KWARGS_ARG_DATA_POINT] = self
|
|
366
|
-
for callback_handler in self._data_point_updated_callbacks:
|
|
364
|
+
self._fired_event_at = datetime.now()
|
|
365
|
+
for callback_handler, custom_id in self._data_point_updated_callbacks.items():
|
|
367
366
|
try:
|
|
368
|
-
|
|
367
|
+
# Add the data_point reference once to kwargs to avoid per-callback writes.
|
|
368
|
+
kwargs[KWARGS_ARG_DATA_POINT] = self
|
|
369
|
+
kwargs[KWARGS_ARG_CUSTOM_ID] = custom_id
|
|
370
|
+
callback_handler(**kwargs)
|
|
369
371
|
except Exception as exc:
|
|
370
372
|
_LOGGER.warning("FIRE_DATA_POINT_UPDATED_EVENT failed: %s", extract_exc_args(exc=exc))
|
|
371
373
|
|
|
372
374
|
@loop_check
|
|
373
|
-
def fire_device_removed_callback(self
|
|
375
|
+
def fire_device_removed_callback(self) -> None:
|
|
374
376
|
"""Do what is needed when the data_point has been removed."""
|
|
375
377
|
for callback_handler in self._device_removed_callbacks:
|
|
376
378
|
try:
|
|
377
|
-
callback_handler(
|
|
379
|
+
callback_handler()
|
|
378
380
|
except Exception as exc:
|
|
379
381
|
_LOGGER.warning("FIRE_DEVICE_REMOVED_EVENT failed: %s", extract_exc_args(exc=exc))
|
|
380
382
|
|
|
@@ -383,21 +385,21 @@ class CallbackDataPoint(ABC, LogContextMixin):
|
|
|
383
385
|
"""Check if a data point has been updated or refreshed."""
|
|
384
386
|
return True
|
|
385
387
|
|
|
386
|
-
def _set_modified_at(self, modified_at: datetime) -> None:
|
|
388
|
+
def _set_modified_at(self, *, modified_at: datetime) -> None:
|
|
387
389
|
"""Set modified_at to current datetime."""
|
|
388
390
|
self._modified_at = modified_at
|
|
389
391
|
self._set_refreshed_at(refreshed_at=modified_at)
|
|
390
392
|
|
|
391
|
-
def _set_refreshed_at(self, refreshed_at: datetime) -> None:
|
|
393
|
+
def _set_refreshed_at(self, *, refreshed_at: datetime) -> None:
|
|
392
394
|
"""Set refreshed_at to current datetime."""
|
|
393
395
|
self._refreshed_at = refreshed_at
|
|
394
396
|
|
|
395
|
-
def _set_temporary_modified_at(self, modified_at: datetime) -> None:
|
|
397
|
+
def _set_temporary_modified_at(self, *, modified_at: datetime) -> None:
|
|
396
398
|
"""Set temporary_modified_at to current datetime."""
|
|
397
399
|
self._temporary_modified_at = modified_at
|
|
398
400
|
self._set_temporary_refreshed_at(refreshed_at=modified_at)
|
|
399
401
|
|
|
400
|
-
def _set_temporary_refreshed_at(self, refreshed_at: datetime) -> None:
|
|
402
|
+
def _set_temporary_refreshed_at(self, *, refreshed_at: datetime) -> None:
|
|
401
403
|
"""Set temporary_refreshed_at to current datetime."""
|
|
402
404
|
self._temporary_refreshed_at = refreshed_at
|
|
403
405
|
|
|
@@ -426,6 +428,7 @@ class BaseDataPoint(CallbackDataPoint, PayloadMixin):
|
|
|
426
428
|
|
|
427
429
|
def __init__(
|
|
428
430
|
self,
|
|
431
|
+
*,
|
|
429
432
|
channel: hmd.Channel,
|
|
430
433
|
unique_id: str,
|
|
431
434
|
is_in_multiple_channels: bool,
|
|
@@ -507,7 +510,7 @@ class BaseDataPoint(CallbackDataPoint, PayloadMixin):
|
|
|
507
510
|
"""Return the data_point usage."""
|
|
508
511
|
return self._get_data_point_usage()
|
|
509
512
|
|
|
510
|
-
def force_usage(self, forced_usage: DataPointUsage) -> None:
|
|
513
|
+
def force_usage(self, *, forced_usage: DataPointUsage) -> None:
|
|
511
514
|
"""Set the data_point usage."""
|
|
512
515
|
self._forced_usage = forced_usage
|
|
513
516
|
|
|
@@ -525,7 +528,7 @@ class BaseDataPoint(CallbackDataPoint, PayloadMixin):
|
|
|
525
528
|
return on_time
|
|
526
529
|
|
|
527
530
|
@abstractmethod
|
|
528
|
-
async def load_data_point_value(self, call_source: CallSource, direct_call: bool = False) -> None:
|
|
531
|
+
async def load_data_point_value(self, *, call_source: CallSource, direct_call: bool = False) -> None:
|
|
529
532
|
"""Init the data_point data."""
|
|
530
533
|
|
|
531
534
|
@abstractmethod
|
|
@@ -536,7 +539,7 @@ class BaseDataPoint(CallbackDataPoint, PayloadMixin):
|
|
|
536
539
|
def _get_data_point_usage(self) -> DataPointUsage:
|
|
537
540
|
"""Generate the usage for the data_point."""
|
|
538
541
|
|
|
539
|
-
def set_timer_on_time(self, on_time: float) -> None:
|
|
542
|
+
def set_timer_on_time(self, *, on_time: float) -> None:
|
|
540
543
|
"""Set the on_time."""
|
|
541
544
|
self._timer_on_time = on_time
|
|
542
545
|
self._timer_on_time_end = INIT_DATETIME
|
|
@@ -580,6 +583,7 @@ class BaseParameterDataPoint[
|
|
|
580
583
|
|
|
581
584
|
def __init__(
|
|
582
585
|
self,
|
|
586
|
+
*,
|
|
583
587
|
channel: hmd.Channel,
|
|
584
588
|
paramset_key: ParamsetKey,
|
|
585
589
|
parameter: str,
|
|
@@ -618,13 +622,13 @@ class BaseParameterDataPoint[
|
|
|
618
622
|
self._is_forced_sensor: bool = False
|
|
619
623
|
self._assign_parameter_data(parameter_data=parameter_data)
|
|
620
624
|
|
|
621
|
-
def _assign_parameter_data(self, parameter_data: ParameterData) -> None:
|
|
625
|
+
def _assign_parameter_data(self, *, parameter_data: ParameterData) -> None:
|
|
622
626
|
"""Assign parameter data to instance variables."""
|
|
623
627
|
self._type: ParameterType = ParameterType(parameter_data["TYPE"])
|
|
624
628
|
self._values = tuple(parameter_data["VALUE_LIST"]) if parameter_data.get("VALUE_LIST") else None
|
|
625
|
-
self._max: ParameterT = self._convert_value(parameter_data["MAX"])
|
|
626
|
-
self._min: ParameterT = self._convert_value(parameter_data["MIN"])
|
|
627
|
-
self._default: ParameterT = self._convert_value(parameter_data.get("DEFAULT")) or self._min
|
|
629
|
+
self._max: ParameterT = self._convert_value(value=parameter_data["MAX"])
|
|
630
|
+
self._min: ParameterT = self._convert_value(value=parameter_data["MIN"])
|
|
631
|
+
self._default: ParameterT = self._convert_value(value=parameter_data.get("DEFAULT")) or self._min
|
|
628
632
|
flags: int = parameter_data["FLAGS"]
|
|
629
633
|
self._visible: bool = flags & Flag.VISIBLE == Flag.VISIBLE
|
|
630
634
|
self._service: bool = flags & Flag.SERVICE == Flag.SERVICE
|
|
@@ -832,7 +836,7 @@ class BaseParameterDataPoint[
|
|
|
832
836
|
)
|
|
833
837
|
self._is_forced_sensor = True
|
|
834
838
|
|
|
835
|
-
def _cleanup_unit(self, raw_unit: str | None) -> str | None:
|
|
839
|
+
def _cleanup_unit(self, *, raw_unit: str | None) -> str | None:
|
|
836
840
|
"""Replace given unit."""
|
|
837
841
|
if new_unit := _FIX_UNIT_BY_PARAM.get(self._parameter):
|
|
838
842
|
return new_unit
|
|
@@ -843,7 +847,7 @@ class BaseParameterDataPoint[
|
|
|
843
847
|
return fix
|
|
844
848
|
return raw_unit
|
|
845
849
|
|
|
846
|
-
def _get_multiplier(self, raw_unit: str | None) -> float:
|
|
850
|
+
def _get_multiplier(self, *, raw_unit: str | None) -> float:
|
|
847
851
|
"""Replace given unit."""
|
|
848
852
|
if not raw_unit:
|
|
849
853
|
return DEFAULT_MULTIPLIER
|
|
@@ -856,10 +860,10 @@ class BaseParameterDataPoint[
|
|
|
856
860
|
return f"{self._category}/{self._channel.device.model}/{self._parameter}"
|
|
857
861
|
|
|
858
862
|
@abstractmethod
|
|
859
|
-
async def event(self, value: Any, received_at: datetime) -> None:
|
|
863
|
+
async def event(self, *, value: Any, received_at: datetime) -> None:
|
|
860
864
|
"""Handle event for which this handler has subscribed."""
|
|
861
865
|
|
|
862
|
-
async def load_data_point_value(self, call_source: CallSource, direct_call: bool = False) -> None:
|
|
866
|
+
async def load_data_point_value(self, *, call_source: CallSource, direct_call: bool = False) -> None:
|
|
863
867
|
"""Init the data_point data."""
|
|
864
868
|
if (self._ignore_on_initial_load or self._channel.device.ignore_on_initial_load) and call_source in (
|
|
865
869
|
CallSource.HM_INIT,
|
|
@@ -883,7 +887,7 @@ class BaseParameterDataPoint[
|
|
|
883
887
|
write_at=datetime.now(),
|
|
884
888
|
)
|
|
885
889
|
|
|
886
|
-
def write_value(self, value: Any, write_at: datetime) -> tuple[ParameterT, ParameterT]:
|
|
890
|
+
def write_value(self, *, value: Any, write_at: datetime) -> tuple[ParameterT, ParameterT]:
|
|
887
891
|
"""Update value of the data_point."""
|
|
888
892
|
self._reset_temporary_value()
|
|
889
893
|
|
|
@@ -894,7 +898,7 @@ class BaseParameterDataPoint[
|
|
|
894
898
|
self.fire_data_point_updated_callback()
|
|
895
899
|
return (old_value, None) # type: ignore[return-value]
|
|
896
900
|
|
|
897
|
-
new_value = self._convert_value(value)
|
|
901
|
+
new_value = self._convert_value(value=value)
|
|
898
902
|
if old_value == new_value:
|
|
899
903
|
self._set_refreshed_at(refreshed_at=write_at)
|
|
900
904
|
else:
|
|
@@ -905,11 +909,11 @@ class BaseParameterDataPoint[
|
|
|
905
909
|
self.fire_data_point_updated_callback()
|
|
906
910
|
return (old_value, new_value)
|
|
907
911
|
|
|
908
|
-
def write_temporary_value(self, value: Any, write_at: datetime) -> None:
|
|
912
|
+
def write_temporary_value(self, *, value: Any, write_at: datetime) -> None:
|
|
909
913
|
"""Update the temporary value of the data_point."""
|
|
910
914
|
self._reset_temporary_value()
|
|
911
915
|
|
|
912
|
-
temp_value = self._convert_value(value)
|
|
916
|
+
temp_value = self._convert_value(value=value)
|
|
913
917
|
if self._value == temp_value:
|
|
914
918
|
self._set_temporary_refreshed_at(refreshed_at=write_at)
|
|
915
919
|
else:
|
|
@@ -928,7 +932,7 @@ class BaseParameterDataPoint[
|
|
|
928
932
|
):
|
|
929
933
|
self._assign_parameter_data(parameter_data=parameter_data)
|
|
930
934
|
|
|
931
|
-
def _convert_value(self, value: Any) -> ParameterT:
|
|
935
|
+
def _convert_value(self, *, value: Any) -> ParameterT:
|
|
932
936
|
"""Convert to value to ParameterT."""
|
|
933
937
|
if value is None:
|
|
934
938
|
return None # type: ignore[return-value]
|
|
@@ -963,7 +967,7 @@ class BaseParameterDataPoint[
|
|
|
963
967
|
self._temporary_value = None # type: ignore[assignment]
|
|
964
968
|
self._reset_temporary_timestamps()
|
|
965
969
|
|
|
966
|
-
def get_event_data(self, value: Any = None) -> dict[EventKey, Any]:
|
|
970
|
+
def get_event_data(self, *, value: Any = None) -> dict[EventKey, Any]:
|
|
967
971
|
"""Get the event_data."""
|
|
968
972
|
event_data = {
|
|
969
973
|
EventKey.ADDRESS: self._device.address,
|
|
@@ -986,7 +990,7 @@ class CallParameterCollector:
|
|
|
986
990
|
"_paramsets",
|
|
987
991
|
)
|
|
988
992
|
|
|
989
|
-
def __init__(self, client: hmcl.Client) -> None:
|
|
993
|
+
def __init__(self, *, client: hmcl.Client) -> None:
|
|
990
994
|
"""Init the generator."""
|
|
991
995
|
self._client: Final = client
|
|
992
996
|
self._central: Final = client.central
|
|
@@ -995,6 +999,7 @@ class CallParameterCollector:
|
|
|
995
999
|
|
|
996
1000
|
def add_data_point(
|
|
997
1001
|
self,
|
|
1002
|
+
*,
|
|
998
1003
|
data_point: BaseParameterDataPoint,
|
|
999
1004
|
value: Any,
|
|
1000
1005
|
collector_order: int,
|
|
@@ -1010,7 +1015,7 @@ class CallParameterCollector:
|
|
|
1010
1015
|
value
|
|
1011
1016
|
)
|
|
1012
1017
|
|
|
1013
|
-
async def send_data(self, wait_for_callback: int | None) -> set[DP_KEY_VALUE]:
|
|
1018
|
+
async def send_data(self, *, wait_for_callback: int | None) -> set[DP_KEY_VALUE]:
|
|
1014
1019
|
"""Send data to the backend."""
|
|
1015
1020
|
dpk_values: set[DP_KEY_VALUE] = set()
|
|
1016
1021
|
for paramset_key, paramsets in self._paramsets.items():
|
|
@@ -1040,6 +1045,7 @@ class CallParameterCollector:
|
|
|
1040
1045
|
|
|
1041
1046
|
|
|
1042
1047
|
def bind_collector(
|
|
1048
|
+
*,
|
|
1043
1049
|
wait_for_callback: int | None = WAIT_FOR_CALLBACK,
|
|
1044
1050
|
enabled: bool = True,
|
|
1045
1051
|
log_level: int = logging.ERROR,
|
|
@@ -1052,7 +1058,12 @@ def bind_collector(
|
|
|
1052
1058
|
|
|
1053
1059
|
def bind_decorator[CallableT: Callable[..., Any]](func: CallableT) -> CallableT:
|
|
1054
1060
|
"""Decorate function to automatically add collector if not set."""
|
|
1055
|
-
|
|
1061
|
+
spec = getfullargspec(func)
|
|
1062
|
+
# Support both positional and keyword-only 'collector' parameters
|
|
1063
|
+
if _COLLECTOR_ARGUMENT_NAME in spec.args:
|
|
1064
|
+
argument_index: int | None = spec.args.index(_COLLECTOR_ARGUMENT_NAME)
|
|
1065
|
+
else:
|
|
1066
|
+
argument_index = None
|
|
1056
1067
|
|
|
1057
1068
|
@wraps(func)
|
|
1058
1069
|
async def bind_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -1067,8 +1078,10 @@ def bind_collector(
|
|
|
1067
1078
|
IN_SERVICE_VAR.reset(token)
|
|
1068
1079
|
return return_value
|
|
1069
1080
|
try:
|
|
1070
|
-
collector_exists =
|
|
1071
|
-
|
|
1081
|
+
collector_exists = (
|
|
1082
|
+
argument_index is not None and len(args) > argument_index and args[argument_index] is not None
|
|
1083
|
+
) or kwargs.get(_COLLECTOR_ARGUMENT_NAME) is not None
|
|
1084
|
+
except Exception:
|
|
1072
1085
|
collector_exists = kwargs.get(_COLLECTOR_ARGUMENT_NAME) is not None
|
|
1073
1086
|
|
|
1074
1087
|
if collector_exists:
|
|
@@ -1127,6 +1140,7 @@ class NoneTypeDataPoint:
|
|
|
1127
1140
|
|
|
1128
1141
|
async def send_value(
|
|
1129
1142
|
self,
|
|
1143
|
+
*,
|
|
1130
1144
|
value: Any,
|
|
1131
1145
|
collector: CallParameterCollector | None = None,
|
|
1132
1146
|
do_validate: bool = True,
|