aiohomematic 2025.8.10__py3-none-any.whl → 2025.9.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 (55) hide show
  1. aiohomematic/caches/dynamic.py +1 -6
  2. aiohomematic/central/__init__.py +35 -24
  3. aiohomematic/central/xml_rpc_server.py +1 -1
  4. aiohomematic/client/__init__.py +35 -29
  5. aiohomematic/client/json_rpc.py +44 -12
  6. aiohomematic/client/xml_rpc.py +53 -20
  7. aiohomematic/const.py +2 -2
  8. aiohomematic/decorators.py +66 -27
  9. aiohomematic/model/__init__.py +1 -1
  10. aiohomematic/model/calculated/__init__.py +1 -1
  11. aiohomematic/model/calculated/climate.py +1 -1
  12. aiohomematic/model/calculated/data_point.py +2 -2
  13. aiohomematic/model/calculated/operating_voltage_level.py +7 -21
  14. aiohomematic/model/calculated/support.py +20 -0
  15. aiohomematic/model/custom/__init__.py +1 -1
  16. aiohomematic/model/custom/climate.py +18 -18
  17. aiohomematic/model/custom/cover.py +1 -1
  18. aiohomematic/model/custom/data_point.py +1 -1
  19. aiohomematic/model/custom/light.py +1 -1
  20. aiohomematic/model/custom/lock.py +1 -1
  21. aiohomematic/model/custom/siren.py +1 -1
  22. aiohomematic/model/custom/switch.py +1 -1
  23. aiohomematic/model/custom/valve.py +1 -1
  24. aiohomematic/model/data_point.py +18 -18
  25. aiohomematic/model/device.py +21 -20
  26. aiohomematic/model/event.py +3 -8
  27. aiohomematic/model/generic/__init__.py +1 -1
  28. aiohomematic/model/generic/binary_sensor.py +1 -1
  29. aiohomematic/model/generic/button.py +1 -1
  30. aiohomematic/model/generic/data_point.py +3 -5
  31. aiohomematic/model/generic/number.py +1 -1
  32. aiohomematic/model/generic/select.py +1 -1
  33. aiohomematic/model/generic/sensor.py +1 -1
  34. aiohomematic/model/generic/switch.py +4 -4
  35. aiohomematic/model/generic/text.py +1 -1
  36. aiohomematic/model/hub/binary_sensor.py +1 -1
  37. aiohomematic/model/hub/button.py +2 -2
  38. aiohomematic/model/hub/data_point.py +4 -7
  39. aiohomematic/model/hub/number.py +1 -1
  40. aiohomematic/model/hub/select.py +2 -2
  41. aiohomematic/model/hub/sensor.py +1 -1
  42. aiohomematic/model/hub/switch.py +3 -3
  43. aiohomematic/model/hub/text.py +1 -1
  44. aiohomematic/model/support.py +1 -40
  45. aiohomematic/model/update.py +5 -4
  46. aiohomematic/property_decorators.py +327 -0
  47. aiohomematic/support.py +70 -85
  48. {aiohomematic-2025.8.10.dist-info → aiohomematic-2025.9.2.dist-info}/METADATA +8 -5
  49. aiohomematic-2025.9.2.dist-info/RECORD +78 -0
  50. aiohomematic_support/client_local.py +5 -5
  51. aiohomematic/model/decorators.py +0 -194
  52. aiohomematic-2025.8.10.dist-info/RECORD +0 -78
  53. {aiohomematic-2025.8.10.dist-info → aiohomematic-2025.9.2.dist-info}/WHEEL +0 -0
  54. {aiohomematic-2025.8.10.dist-info → aiohomematic-2025.9.2.dist-info}/licenses/LICENSE +0 -0
  55. {aiohomematic-2025.8.10.dist-info → aiohomematic-2025.9.2.dist-info}/top_level.txt +0 -0
@@ -15,8 +15,8 @@ from aiohomematic.model.custom.const import DeviceProfile, Field
15
15
  from aiohomematic.model.custom.data_point import CustomDataPoint
16
16
  from aiohomematic.model.custom.support import CustomConfig, ExtendedConfig
17
17
  from aiohomematic.model.data_point import CallParameterCollector, bind_collector
18
- from aiohomematic.model.decorators import state_property
19
18
  from aiohomematic.model.generic import DpAction, DpSensor, DpSwitch
19
+ from aiohomematic.property_decorators import state_property
20
20
 
21
21
 
22
22
  class _LockActivity(StrEnum):
@@ -17,8 +17,8 @@ from aiohomematic.model.custom.const import DeviceProfile, Field
17
17
  from aiohomematic.model.custom.data_point import CustomDataPoint
18
18
  from aiohomematic.model.custom.support import CustomConfig
19
19
  from aiohomematic.model.data_point import CallParameterCollector, bind_collector
20
- from aiohomematic.model.decorators import state_property
21
20
  from aiohomematic.model.generic import DpAction, DpBinarySensor, DpSensor
21
+ from aiohomematic.property_decorators import state_property
22
22
 
23
23
  _SMOKE_DETECTOR_ALARM_STATUS_IDLE_OFF: Final = "IDLE_OFF"
24
24
 
@@ -16,8 +16,8 @@ from aiohomematic.model.custom.const import DeviceProfile, Field
16
16
  from aiohomematic.model.custom.data_point import CustomDataPoint
17
17
  from aiohomematic.model.custom.support import CustomConfig, ExtendedConfig
18
18
  from aiohomematic.model.data_point import CallParameterCollector, bind_collector
19
- from aiohomematic.model.decorators import state_property
20
19
  from aiohomematic.model.generic import DpAction, DpBinarySensor, DpSwitch
20
+ from aiohomematic.property_decorators import state_property
21
21
 
22
22
  _LOGGER: Final = logging.getLogger(__name__)
23
23
 
@@ -16,8 +16,8 @@ from aiohomematic.model.custom.const import DeviceProfile, Field
16
16
  from aiohomematic.model.custom.data_point import CustomDataPoint
17
17
  from aiohomematic.model.custom.support import CustomConfig
18
18
  from aiohomematic.model.data_point import CallParameterCollector, bind_collector
19
- from aiohomematic.model.decorators import state_property
20
19
  from aiohomematic.model.generic import DpAction, DpBinarySensor, DpSwitch
20
+ from aiohomematic.property_decorators import state_property
21
21
 
22
22
  _LOGGER: Final = logging.getLogger(__name__)
23
23
 
@@ -65,17 +65,16 @@ from aiohomematic.context import IN_SERVICE_VAR
65
65
  from aiohomematic.decorators import get_service_calls
66
66
  from aiohomematic.exceptions import AioHomematicException, BaseHomematicException
67
67
  from aiohomematic.model import device as hmd
68
- from aiohomematic.model.decorators import cached_slot_property, config_property, state_property
69
68
  from aiohomematic.model.support import (
70
69
  DataPointNameData,
71
70
  DataPointPathData,
72
71
  GenericParameterType,
73
72
  PathData,
74
- PayloadMixin,
75
73
  convert_value,
76
74
  generate_unique_id,
77
75
  )
78
- from aiohomematic.support import extract_exc_args
76
+ from aiohomematic.property_decorators import cached_slot_property, config_property, info_property, state_property
77
+ from aiohomematic.support import LogContextMixin, PayloadMixin, extract_exc_args, log_boundary_error
79
78
 
80
79
  __all__ = [
81
80
  "BaseDataPoint",
@@ -132,7 +131,7 @@ EVENT_DATA_SCHEMA = vol.Schema(
132
131
  )
133
132
 
134
133
 
135
- class CallbackDataPoint(ABC):
134
+ class CallbackDataPoint(ABC, LogContextMixin):
136
135
  """Base class for callback data point."""
137
136
 
138
137
  __slots__ = (
@@ -448,7 +447,7 @@ class BaseDataPoint(CallbackDataPoint, PayloadMixin):
448
447
  """Return the availability of the device."""
449
448
  return self._device.available
450
449
 
451
- @property
450
+ @info_property(log_context=True)
452
451
  def channel(self) -> hmd.Channel:
453
452
  """Return the channel the data_point."""
454
453
  return self._channel
@@ -685,7 +684,7 @@ class BaseParameterDataPoint[
685
684
  """Return multiplier value."""
686
685
  return self._multiplier
687
686
 
688
- @property
687
+ @info_property(log_context=True)
689
688
  def parameter(self) -> str:
690
689
  """Return parameter name."""
691
690
  return self._parameter
@@ -857,7 +856,7 @@ class BaseParameterDataPoint[
857
856
  return f"{self._category}/{self._channel.device.model}/{self._parameter}"
858
857
 
859
858
  @abstractmethod
860
- async def event(self, value: Any, received_at: datetime | None = None) -> None:
859
+ async def event(self, value: Any, received_at: datetime) -> None:
861
860
  """Handle event for which this handler has subscribed."""
862
861
 
863
862
  async def load_data_point_value(self, call_source: CallSource, direct_call: bool = False) -> None:
@@ -1086,17 +1085,18 @@ def bind_collector(
1086
1085
  IN_SERVICE_VAR.reset(token)
1087
1086
  in_service = IN_SERVICE_VAR.get()
1088
1087
  if not in_service and log_level > logging.NOTSET:
1089
- logger = logging.getLogger(args[0].__module__)
1090
- extra = {
1091
- "err_type": bhexc.__class__.__name__,
1092
- "err": extract_exc_args(exc=bhexc),
1093
- "function": func.__name__,
1094
- **hms.build_log_context_from_obj(obj=args[0]),
1095
- }
1096
- if log_level >= logging.ERROR:
1097
- logger.exception("service_error", extra=extra)
1098
- else:
1099
- logger.log(level=log_level, msg="service_error", extra=extra)
1088
+ context_obj = args[0]
1089
+ logger = logging.getLogger(context_obj.__module__)
1090
+ log_context = context_obj.log_context if isinstance(context_obj, LogContextMixin) else None
1091
+ # Reuse centralized boundary logging to ensure consistent 'extra' structure
1092
+ log_boundary_error(
1093
+ logger=logger,
1094
+ boundary="service",
1095
+ action=func.__name__,
1096
+ err=bhexc,
1097
+ level=log_level,
1098
+ log_context=log_context,
1099
+ )
1100
1100
  # Re-raise domain-specific exceptions so callers and tests can handle them
1101
1101
  raise
1102
1102
  else:
@@ -71,19 +71,20 @@ from aiohomematic.exceptions import AioHomematicException, BaseHomematicExceptio
71
71
  from aiohomematic.model.calculated import CalculatedDataPoint
72
72
  from aiohomematic.model.custom import data_point as hmce, definition as hmed
73
73
  from aiohomematic.model.data_point import BaseParameterDataPoint, CallbackDataPoint
74
- from aiohomematic.model.decorators import cached_slot_property, info_property, state_property
75
74
  from aiohomematic.model.event import GenericEvent
76
75
  from aiohomematic.model.generic import GenericDataPoint
77
76
  from aiohomematic.model.support import (
78
77
  ChannelNameData,
79
- PayloadMixin,
80
78
  generate_channel_unique_id,
81
79
  get_channel_name_data,
82
80
  get_device_name,
83
81
  )
84
82
  from aiohomematic.model.update import DpUpdate
83
+ from aiohomematic.property_decorators import cached_slot_property, info_property, state_property
85
84
  from aiohomematic.support import (
86
85
  CacheEntry,
86
+ LogContextMixin,
87
+ PayloadMixin,
87
88
  check_or_create_directory,
88
89
  extract_exc_args,
89
90
  get_channel_address,
@@ -96,7 +97,7 @@ __all__ = ["Channel", "Device"]
96
97
  _LOGGER: Final = logging.getLogger(__name__)
97
98
 
98
99
 
99
- class Device(PayloadMixin):
100
+ class Device(LogContextMixin, PayloadMixin):
100
101
  """Object to hold information about a device and associated data points."""
101
102
 
102
103
  __slots__ = (
@@ -196,7 +197,7 @@ class Device(PayloadMixin):
196
197
  return Manufacturer.MOEHLENHOFF
197
198
  return Manufacturer.EQ3
198
199
 
199
- @info_property
200
+ @info_property(log_context=True)
200
201
  def address(self) -> str:
201
202
  """Return the address of the device."""
202
203
  return self._address
@@ -326,7 +327,7 @@ class Device(PayloadMixin):
326
327
  """Return the interface of the device."""
327
328
  return self._interface
328
329
 
329
- @property
330
+ @info_property(log_context=True)
330
331
  def interface_id(self) -> str:
331
332
  """Return the interface_id of the device."""
332
333
  return self._interface_id
@@ -353,7 +354,7 @@ class Device(PayloadMixin):
353
354
  """Return the manufacturer of the device."""
354
355
  return self._manufacturer
355
356
 
356
- @info_property
357
+ @info_property(log_context=True)
357
358
  def model(self) -> str:
358
359
  """Return the model of the device."""
359
360
  return self._model
@@ -426,14 +427,14 @@ class Device(PayloadMixin):
426
427
  elif self._channel_groups[channel_no] != group_no:
427
428
  return
428
429
 
429
- @inspector()
430
+ @inspector
430
431
  async def create_central_links(self) -> None:
431
432
  """Create a central links to support press events on all channels with click events."""
432
433
  if self.relevant_for_central_link_management: # pylint: disable=using-constant-test
433
434
  for channel in self._channels.values():
434
435
  await channel.create_central_link()
435
436
 
436
- @inspector()
437
+ @inspector
437
438
  async def remove_central_links(self) -> None:
438
439
  """Remove central links."""
439
440
  if self.relevant_for_central_link_management: # pylint: disable=using-constant-test
@@ -583,7 +584,7 @@ class Device(PayloadMixin):
583
584
  for dp in self.generic_data_points:
584
585
  dp.fire_data_point_updated_callback()
585
586
 
586
- @inspector()
587
+ @inspector
587
588
  async def export_device_definition(self) -> None:
588
589
  """Export the device definition for current device."""
589
590
  try:
@@ -612,7 +613,7 @@ class Device(PayloadMixin):
612
613
  for callback_handler in self._firmware_update_callbacks:
613
614
  callback_handler()
614
615
 
615
- @inspector()
616
+ @inspector
616
617
  async def update_firmware(self, refresh_after_update_intervals: tuple[int, ...]) -> bool:
617
618
  """Update the firmware of the homematic device."""
618
619
  update_result = await self._client.update_device_firmware(device_address=self._address)
@@ -627,7 +628,7 @@ class Device(PayloadMixin):
627
628
 
628
629
  return update_result
629
630
 
630
- @inspector()
631
+ @inspector
631
632
  async def load_value_cache(self) -> None:
632
633
  """Init the parameter cache."""
633
634
  if len(self.generic_data_points) > 0:
@@ -639,7 +640,7 @@ class Device(PayloadMixin):
639
640
  self._address,
640
641
  )
641
642
 
642
- @inspector()
643
+ @inspector
643
644
  async def reload_paramset_descriptions(self) -> None:
644
645
  """Reload paramset for device."""
645
646
  for (
@@ -682,7 +683,7 @@ class Device(PayloadMixin):
682
683
  )
683
684
 
684
685
 
685
- class Channel(PayloadMixin):
686
+ class Channel(LogContextMixin, PayloadMixin):
686
687
  """Object to hold information about a channel and associated data points."""
687
688
 
688
689
  __slots__ = (
@@ -736,7 +737,7 @@ class Channel(PayloadMixin):
736
737
  self._rooms: Final = self._central.device_details.get_channel_rooms(channel_address=channel_address)
737
738
  self._function: Final = self._central.device_details.get_function_text(address=self._address)
738
739
 
739
- @property
740
+ @info_property
740
741
  def address(self) -> str:
741
742
  """Return the address of the channel."""
742
743
  return self._address
@@ -761,7 +762,7 @@ class Channel(PayloadMixin):
761
762
  """Return the device description for the channel."""
762
763
  return self._description
763
764
 
764
- @property
765
+ @info_property(log_context=True)
765
766
  def device(self) -> Device:
766
767
  """Return the device of the channel."""
767
768
  return self._device
@@ -831,7 +832,7 @@ class Channel(PayloadMixin):
831
832
  """Return the name data of the channel."""
832
833
  return self._name_data
833
834
 
834
- @property
835
+ @info_property(log_context=True)
835
836
  def no(self) -> int | None:
836
837
  """Return the channel_no of the channel."""
837
838
  return self._no
@@ -883,7 +884,7 @@ class Channel(PayloadMixin):
883
884
  """Return the unique_id of the channel."""
884
885
  return self._unique_id
885
886
 
886
- @inspector()
887
+ @inspector
887
888
  async def create_central_link(self) -> None:
888
889
  """Create a central link to support press events."""
889
890
  if self._has_key_press_events and not await self._has_central_link():
@@ -891,7 +892,7 @@ class Channel(PayloadMixin):
891
892
  address=self._address, value_id=REPORT_VALUE_USAGE_VALUE_ID, ref_counter=1
892
893
  )
893
894
 
894
- @inspector()
895
+ @inspector
895
896
  async def remove_central_link(self) -> None:
896
897
  """Remove a central link."""
897
898
  if self._has_key_press_events and await self._has_central_link() and not await self._has_program_ids():
@@ -899,7 +900,7 @@ class Channel(PayloadMixin):
899
900
  address=self._address, value_id=REPORT_VALUE_USAGE_VALUE_ID, ref_counter=0
900
901
  )
901
902
 
902
- @inspector()
903
+ @inspector
903
904
  async def cleanup_central_link_metadata(self) -> None:
904
905
  """Cleanup the metadata for central links."""
905
906
  if metadata := await self._device.client.get_metadata(address=self._address, data_id=REPORT_VALUE_USAGE_DATA):
@@ -1259,7 +1260,7 @@ class _DefinitionExporter:
1259
1260
  self._device_address: Final = device.address
1260
1261
  self._random_id: Final[str] = f"VCU{int(random.randint(1000000, 9999999))}"
1261
1262
 
1262
- @inspector()
1263
+ @inspector
1263
1264
  async def export_data(self) -> None:
1264
1265
  """Export data."""
1265
1266
  device_descriptions: Mapping[str, DeviceDescription] = (
@@ -98,10 +98,8 @@ class GenericEvent(BaseParameterDataPoint[Any, Any]):
98
98
  """Return the event_type of the event."""
99
99
  return self._event_type
100
100
 
101
- async def event(self, value: Any, received_at: datetime | None = None) -> None:
101
+ async def event(self, value: Any, received_at: datetime) -> None:
102
102
  """Handle event for which this handler has subscribed."""
103
- if received_at is None:
104
- received_at = datetime.now()
105
103
  if self.event_type in DATA_POINT_EVENTS:
106
104
  self.fire_data_point_updated_callback()
107
105
  self._set_modified_at(modified_at=received_at)
@@ -139,11 +137,8 @@ class DeviceErrorEvent(GenericEvent):
139
137
 
140
138
  _event_type = EventType.DEVICE_ERROR
141
139
 
142
- async def event(self, value: Any, received_at: datetime | None = None) -> None:
140
+ async def event(self, value: Any, received_at: datetime) -> None:
143
141
  """Handle event for which this handler has subscribed."""
144
- if received_at is None:
145
- received_at = datetime.now()
146
-
147
142
  old_value, new_value = self.write_value(value=value, write_at=received_at)
148
143
 
149
144
  if (
@@ -164,7 +159,7 @@ class ImpulseEvent(GenericEvent):
164
159
  _event_type = EventType.IMPULSE
165
160
 
166
161
 
167
- @inspector()
162
+ @inspector
168
163
  def create_event_and_append_to_channel(channel: hmd.Channel, parameter: str, parameter_data: ParameterData) -> None:
169
164
  """Create action event data_point."""
170
165
  _LOGGER.debug(
@@ -100,7 +100,7 @@ _SWITCH_DP_TO_SENSOR: Final[Mapping[str | tuple[str, ...], Parameter]] = {
100
100
  }
101
101
 
102
102
 
103
- @inspector()
103
+ @inspector
104
104
  def create_data_point_and_append_to_channel(
105
105
  channel: hmd.Channel,
106
106
  paramset_key: ParamsetKey,
@@ -7,8 +7,8 @@ from __future__ import annotations
7
7
  from typing import cast
8
8
 
9
9
  from aiohomematic.const import DataPointCategory
10
- from aiohomematic.model.decorators import state_property
11
10
  from aiohomematic.model.generic.data_point import GenericDataPoint
11
+ from aiohomematic.property_decorators import state_property
12
12
 
13
13
 
14
14
  class DpBinarySensor(GenericDataPoint[bool | None, bool]):
@@ -21,7 +21,7 @@ class DpButton(GenericDataPoint[None, bool]):
21
21
  _category = DataPointCategory.BUTTON
22
22
  _validate_state_change = False
23
23
 
24
- @inspector()
24
+ @inspector
25
25
  async def press(self) -> None:
26
26
  """Handle the button press."""
27
27
  await self.send_value(value=True)
@@ -20,8 +20,8 @@ from aiohomematic.const import (
20
20
  from aiohomematic.decorators import inspector
21
21
  from aiohomematic.exceptions import ValidationException
22
22
  from aiohomematic.model import data_point as hme, device as hmd
23
- from aiohomematic.model.decorators import cached_slot_property
24
23
  from aiohomematic.model.support import DataPointNameData, GenericParameterType, get_data_point_name_data
24
+ from aiohomematic.property_decorators import cached_slot_property
25
25
 
26
26
  _LOGGER: Final = logging.getLogger(__name__)
27
27
 
@@ -60,10 +60,8 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
60
60
  return self._get_data_point_usage()
61
61
  return DataPointUsage.DATA_POINT if force_enabled else DataPointUsage.NO_CREATE # pylint: disable=using-constant-test
62
62
 
63
- async def event(self, value: Any, received_at: datetime | None = None) -> None:
63
+ async def event(self, value: Any, received_at: datetime) -> None:
64
64
  """Handle event for which this data_point has subscribed."""
65
- if received_at is None:
66
- received_at = datetime.now()
67
65
  self._device.client.last_value_send_cache.remove_last_value_send(
68
66
  dpk=self.dpk,
69
67
  value=value,
@@ -90,7 +88,7 @@ class GenericDataPoint[ParameterT: GenericParameterType, InputParameterT: Generi
90
88
  event_data=self.get_event_data(new_value),
91
89
  )
92
90
 
93
- @inspector()
91
+ @inspector
94
92
  async def send_value(
95
93
  self,
96
94
  value: InputParameterT,
@@ -8,8 +8,8 @@ from typing import cast
8
8
 
9
9
  from aiohomematic.const import DataPointCategory
10
10
  from aiohomematic.exceptions import ValidationException
11
- from aiohomematic.model.decorators import state_property
12
11
  from aiohomematic.model.generic.data_point import GenericDataPoint
12
+ from aiohomematic.property_decorators import state_property
13
13
 
14
14
 
15
15
  class BaseDpNumber[NumberParameterT: int | float | None](GenericDataPoint[NumberParameterT, int | float | str]):
@@ -6,9 +6,9 @@ from __future__ import annotations
6
6
 
7
7
  from aiohomematic.const import DataPointCategory
8
8
  from aiohomematic.exceptions import ValidationException
9
- from aiohomematic.model.decorators import state_property
10
9
  from aiohomematic.model.generic.data_point import GenericDataPoint
11
10
  from aiohomematic.model.support import get_value_from_value_list
11
+ from aiohomematic.property_decorators import state_property
12
12
 
13
13
 
14
14
  class DpSelect(GenericDataPoint[int | str, int | float | str]):
@@ -9,9 +9,9 @@ import logging
9
9
  from typing import Any, Final, cast
10
10
 
11
11
  from aiohomematic.const import DataPointCategory, Parameter, ParameterType
12
- from aiohomematic.model.decorators import state_property
13
12
  from aiohomematic.model.generic.data_point import GenericDataPoint
14
13
  from aiohomematic.model.support import check_length_and_log, get_value_from_value_list
14
+ from aiohomematic.property_decorators import state_property
15
15
 
16
16
  _LOGGER: Final = logging.getLogger(__name__)
17
17
 
@@ -9,8 +9,8 @@ from typing import cast
9
9
  from aiohomematic.const import DataPointCategory, Parameter, ParameterType
10
10
  from aiohomematic.decorators import inspector
11
11
  from aiohomematic.model.data_point import CallParameterCollector
12
- from aiohomematic.model.decorators import state_property
13
12
  from aiohomematic.model.generic.data_point import GenericDataPoint
13
+ from aiohomematic.property_decorators import state_property
14
14
 
15
15
 
16
16
  class DpSwitch(GenericDataPoint[bool | None, bool]):
@@ -31,19 +31,19 @@ class DpSwitch(GenericDataPoint[bool | None, bool]):
31
31
  return False
32
32
  return cast(bool | None, self._value)
33
33
 
34
- @inspector()
34
+ @inspector
35
35
  async def turn_on(self, collector: CallParameterCollector | None = None, on_time: float | 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
- @inspector()
41
+ @inspector
42
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
- @inspector()
46
+ @inspector
47
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(
@@ -7,9 +7,9 @@ from __future__ import annotations
7
7
  from typing import cast
8
8
 
9
9
  from aiohomematic.const import DataPointCategory
10
- from aiohomematic.model.decorators import state_property
11
10
  from aiohomematic.model.generic.data_point import GenericDataPoint
12
11
  from aiohomematic.model.support import check_length_and_log
12
+ from aiohomematic.property_decorators import state_property
13
13
 
14
14
 
15
15
  class DpText(GenericDataPoint[str, str]):
@@ -5,8 +5,8 @@
5
5
  from __future__ import annotations
6
6
 
7
7
  from aiohomematic.const import DataPointCategory
8
- from aiohomematic.model.decorators import state_property
9
8
  from aiohomematic.model.hub.data_point import GenericSysvarDataPoint
9
+ from aiohomematic.property_decorators import state_property
10
10
 
11
11
 
12
12
  class SysvarDpBinarySensor(GenericSysvarDataPoint):
@@ -6,8 +6,8 @@ from __future__ import annotations
6
6
 
7
7
  from aiohomematic.const import DataPointCategory
8
8
  from aiohomematic.decorators import inspector
9
- from aiohomematic.model.decorators import state_property
10
9
  from aiohomematic.model.hub.data_point import GenericProgramDataPoint
10
+ from aiohomematic.property_decorators import state_property
11
11
 
12
12
 
13
13
  class ProgramDpButton(GenericProgramDataPoint):
@@ -22,7 +22,7 @@ class ProgramDpButton(GenericProgramDataPoint):
22
22
  """Return the availability of the device."""
23
23
  return self._is_active and self._central.available
24
24
 
25
- @inspector()
25
+ @inspector
26
26
  async def press(self) -> None:
27
27
  """Handle the button press."""
28
28
  await self.central.execute_program(pid=self.pid)
@@ -21,17 +21,16 @@ from aiohomematic.const import (
21
21
  )
22
22
  from aiohomematic.decorators import inspector
23
23
  from aiohomematic.model.data_point import CallbackDataPoint
24
- from aiohomematic.model.decorators import config_property, state_property
25
24
  from aiohomematic.model.device import Channel
26
25
  from aiohomematic.model.support import (
27
26
  PathData,
28
- PayloadMixin,
29
27
  ProgramPathData,
30
28
  SysvarPathData,
31
29
  generate_unique_id,
32
30
  get_hub_data_point_name_data,
33
31
  )
34
- from aiohomematic.support import parse_sys_var
32
+ from aiohomematic.property_decorators import config_property, state_property
33
+ from aiohomematic.support import PayloadMixin, parse_sys_var
35
34
 
36
35
 
37
36
  class GenericHubDataPoint(CallbackDataPoint, PayloadMixin):
@@ -207,10 +206,8 @@ class GenericSysvarDataPoint(GenericHubDataPoint):
207
206
  """Return the path data of the data_point."""
208
207
  return SysvarPathData(vid=self._vid)
209
208
 
210
- async def event(self, value: Any, received_at: datetime | None = None) -> None:
209
+ async def event(self, value: Any, received_at: datetime) -> None:
211
210
  """Handle event for which this data_point has subscribed."""
212
- if received_at is None:
213
- received_at = datetime.now()
214
211
  self.write_value(value=value, write_at=received_at)
215
212
 
216
213
  def _reset_temporary_value(self) -> None:
@@ -263,7 +260,7 @@ class GenericSysvarDataPoint(GenericHubDataPoint):
263
260
  value = float(new_value)
264
261
  return value
265
262
 
266
- @inspector()
263
+ @inspector
267
264
  async def send_variable(self, value: Any) -> None:
268
265
  """Set variable value on CCU/Homegear."""
269
266
  if client := self.central.primary_client:
@@ -22,7 +22,7 @@ class SysvarDpNumber(GenericSysvarDataPoint):
22
22
  _category = DataPointCategory.HUB_NUMBER
23
23
  _is_extended = True
24
24
 
25
- @inspector()
25
+ @inspector
26
26
  async def send_variable(self, value: float) -> None:
27
27
  """Set the value of the data_point."""
28
28
  if value is not None and self.max is not None and self.min is not None:
@@ -9,9 +9,9 @@ from typing import Final
9
9
 
10
10
  from aiohomematic.const import DataPointCategory
11
11
  from aiohomematic.decorators import inspector
12
- from aiohomematic.model.decorators import state_property
13
12
  from aiohomematic.model.hub.data_point import GenericSysvarDataPoint
14
13
  from aiohomematic.model.support import get_value_from_value_list
14
+ from aiohomematic.property_decorators import state_property
15
15
 
16
16
  _LOGGER: Final = logging.getLogger(__name__)
17
17
 
@@ -31,7 +31,7 @@ class SysvarDpSelect(GenericSysvarDataPoint):
31
31
  return value
32
32
  return None
33
33
 
34
- @inspector()
34
+ @inspector
35
35
  async def send_variable(self, value: int | str) -> None:
36
36
  """Set the value of the data_point."""
37
37
  # We allow setting the value via index as well, just in case.
@@ -8,9 +8,9 @@ import logging
8
8
  from typing import Any, Final
9
9
 
10
10
  from aiohomematic.const import DataPointCategory, SysvarType
11
- from aiohomematic.model.decorators import state_property
12
11
  from aiohomematic.model.hub.data_point import GenericSysvarDataPoint
13
12
  from aiohomematic.model.support import check_length_and_log, get_value_from_value_list
13
+ from aiohomematic.property_decorators import state_property
14
14
 
15
15
  _LOGGER: Final = logging.getLogger(__name__)
16
16
 
@@ -6,8 +6,8 @@ from __future__ import annotations
6
6
 
7
7
  from aiohomematic.const import DataPointCategory
8
8
  from aiohomematic.decorators import inspector
9
- from aiohomematic.model.decorators import state_property
10
9
  from aiohomematic.model.hub.data_point import GenericProgramDataPoint, GenericSysvarDataPoint
10
+ from aiohomematic.property_decorators import state_property
11
11
 
12
12
 
13
13
  class SysvarDpSwitch(GenericSysvarDataPoint):
@@ -31,13 +31,13 @@ class ProgramDpSwitch(GenericProgramDataPoint):
31
31
  """Get the value of the data_point."""
32
32
  return self._is_active
33
33
 
34
- @inspector()
34
+ @inspector
35
35
  async def turn_on(self) -> None:
36
36
  """Turn the program on."""
37
37
  await self.central.set_program_state(pid=self._pid, state=True)
38
38
  await self._central.fetch_program_data(scheduled=False)
39
39
 
40
- @inspector()
40
+ @inspector
41
41
  async def turn_off(self) -> None:
42
42
  """Turn the program off."""
43
43
  await self.central.set_program_state(pid=self._pid, state=False)
@@ -7,9 +7,9 @@ from __future__ import annotations
7
7
  from typing import cast
8
8
 
9
9
  from aiohomematic.const import DataPointCategory
10
- from aiohomematic.model.decorators import state_property
11
10
  from aiohomematic.model.hub.data_point import GenericSysvarDataPoint
12
11
  from aiohomematic.model.support import check_length_and_log
12
+ from aiohomematic.property_decorators import state_property
13
13
 
14
14
 
15
15
  class SysvarDpText(GenericSysvarDataPoint):