aiohomematic 2025.8.6__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 (77) hide show
  1. aiohomematic/__init__.py +47 -0
  2. aiohomematic/async_support.py +146 -0
  3. aiohomematic/caches/__init__.py +10 -0
  4. aiohomematic/caches/dynamic.py +554 -0
  5. aiohomematic/caches/persistent.py +459 -0
  6. aiohomematic/caches/visibility.py +774 -0
  7. aiohomematic/central/__init__.py +2034 -0
  8. aiohomematic/central/decorators.py +110 -0
  9. aiohomematic/central/xml_rpc_server.py +267 -0
  10. aiohomematic/client/__init__.py +1746 -0
  11. aiohomematic/client/json_rpc.py +1193 -0
  12. aiohomematic/client/xml_rpc.py +222 -0
  13. aiohomematic/const.py +795 -0
  14. aiohomematic/context.py +8 -0
  15. aiohomematic/converter.py +82 -0
  16. aiohomematic/decorators.py +188 -0
  17. aiohomematic/exceptions.py +145 -0
  18. aiohomematic/hmcli.py +159 -0
  19. aiohomematic/model/__init__.py +137 -0
  20. aiohomematic/model/calculated/__init__.py +65 -0
  21. aiohomematic/model/calculated/climate.py +230 -0
  22. aiohomematic/model/calculated/data_point.py +319 -0
  23. aiohomematic/model/calculated/operating_voltage_level.py +311 -0
  24. aiohomematic/model/calculated/support.py +174 -0
  25. aiohomematic/model/custom/__init__.py +175 -0
  26. aiohomematic/model/custom/climate.py +1334 -0
  27. aiohomematic/model/custom/const.py +146 -0
  28. aiohomematic/model/custom/cover.py +741 -0
  29. aiohomematic/model/custom/data_point.py +318 -0
  30. aiohomematic/model/custom/definition.py +861 -0
  31. aiohomematic/model/custom/light.py +1092 -0
  32. aiohomematic/model/custom/lock.py +389 -0
  33. aiohomematic/model/custom/siren.py +268 -0
  34. aiohomematic/model/custom/support.py +40 -0
  35. aiohomematic/model/custom/switch.py +172 -0
  36. aiohomematic/model/custom/valve.py +112 -0
  37. aiohomematic/model/data_point.py +1109 -0
  38. aiohomematic/model/decorators.py +173 -0
  39. aiohomematic/model/device.py +1347 -0
  40. aiohomematic/model/event.py +210 -0
  41. aiohomematic/model/generic/__init__.py +211 -0
  42. aiohomematic/model/generic/action.py +32 -0
  43. aiohomematic/model/generic/binary_sensor.py +28 -0
  44. aiohomematic/model/generic/button.py +25 -0
  45. aiohomematic/model/generic/data_point.py +162 -0
  46. aiohomematic/model/generic/number.py +73 -0
  47. aiohomematic/model/generic/select.py +36 -0
  48. aiohomematic/model/generic/sensor.py +72 -0
  49. aiohomematic/model/generic/switch.py +52 -0
  50. aiohomematic/model/generic/text.py +27 -0
  51. aiohomematic/model/hub/__init__.py +334 -0
  52. aiohomematic/model/hub/binary_sensor.py +22 -0
  53. aiohomematic/model/hub/button.py +26 -0
  54. aiohomematic/model/hub/data_point.py +332 -0
  55. aiohomematic/model/hub/number.py +37 -0
  56. aiohomematic/model/hub/select.py +47 -0
  57. aiohomematic/model/hub/sensor.py +35 -0
  58. aiohomematic/model/hub/switch.py +42 -0
  59. aiohomematic/model/hub/text.py +28 -0
  60. aiohomematic/model/support.py +599 -0
  61. aiohomematic/model/update.py +136 -0
  62. aiohomematic/py.typed +0 -0
  63. aiohomematic/rega_scripts/fetch_all_device_data.fn +75 -0
  64. aiohomematic/rega_scripts/get_program_descriptions.fn +30 -0
  65. aiohomematic/rega_scripts/get_serial.fn +44 -0
  66. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +30 -0
  67. aiohomematic/rega_scripts/set_program_state.fn +12 -0
  68. aiohomematic/rega_scripts/set_system_variable.fn +15 -0
  69. aiohomematic/support.py +482 -0
  70. aiohomematic/validator.py +65 -0
  71. aiohomematic-2025.8.6.dist-info/METADATA +69 -0
  72. aiohomematic-2025.8.6.dist-info/RECORD +77 -0
  73. aiohomematic-2025.8.6.dist-info/WHEEL +5 -0
  74. aiohomematic-2025.8.6.dist-info/licenses/LICENSE +21 -0
  75. aiohomematic-2025.8.6.dist-info/top_level.txt +2 -0
  76. aiohomematic_support/__init__.py +1 -0
  77. aiohomematic_support/client_local.py +349 -0
@@ -0,0 +1,173 @@
1
+ """Decorators for data points used within aiohomematic."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Mapping
6
+ from datetime import datetime
7
+ from enum import Enum
8
+ from typing import Any, ParamSpec, TypeVar, cast
9
+
10
+ __all__ = [
11
+ "config_property",
12
+ "get_public_attributes_for_config_property",
13
+ "get_public_attributes_for_info_property",
14
+ "get_public_attributes_for_state_property",
15
+ "info_property",
16
+ "state_property",
17
+ ]
18
+
19
+ P = ParamSpec("P")
20
+ T = TypeVar("T")
21
+ R = TypeVar("R")
22
+
23
+
24
+ # pylint: disable=invalid-name
25
+ class generic_property[GETTER, SETTER](property):
26
+ """Generic property implementation."""
27
+
28
+ fget: Callable[[Any], GETTER] | None
29
+ fset: Callable[[Any, SETTER], None] | None
30
+ fdel: Callable[[Any], None] | None
31
+
32
+ def __init__(
33
+ self,
34
+ fget: Callable[[Any], GETTER] | None = None,
35
+ fset: Callable[[Any, SETTER], None] | None = None,
36
+ fdel: Callable[[Any], None] | None = None,
37
+ doc: str | None = None,
38
+ ) -> None:
39
+ """Init the generic property."""
40
+ super().__init__(fget, fset, fdel, doc)
41
+ if doc is None and fget is not None:
42
+ doc = fget.__doc__
43
+ self.__doc__ = doc
44
+
45
+ def getter(self, fget: Callable[[Any], GETTER], /) -> generic_property:
46
+ """Return generic getter."""
47
+ return type(self)(fget, self.fset, self.fdel, self.__doc__) # pragma: no cover
48
+
49
+ def setter(self, fset: Callable[[Any, SETTER], None], /) -> generic_property:
50
+ """Return generic setter."""
51
+ return type(self)(self.fget, fset, self.fdel, self.__doc__)
52
+
53
+ def deleter(self, fdel: Callable[[Any], None], /) -> generic_property:
54
+ """Return generic deleter."""
55
+ return type(self)(self.fget, self.fset, fdel, self.__doc__)
56
+
57
+ def __get__(self, obj: Any, gtype: type | None = None, /) -> GETTER: # type: ignore[override]
58
+ """Return the attribute."""
59
+ if obj is None:
60
+ return self # type: ignore[return-value]
61
+ if self.fget is None:
62
+ raise AttributeError("unreadable attribute") # pragma: no cover
63
+ return self.fget(obj)
64
+
65
+ def __set__(self, obj: Any, value: Any, /) -> None:
66
+ """Set the attribute."""
67
+ if self.fset is None:
68
+ raise AttributeError("can't set attribute") # pragma: no cover
69
+ self.fset(obj, value)
70
+
71
+ def __delete__(self, obj: Any, /) -> None:
72
+ """Delete the attribute."""
73
+ if self.fdel is None:
74
+ raise AttributeError("can't delete attribute") # pragma: no cover
75
+ self.fdel(obj)
76
+
77
+
78
+ # pylint: disable=invalid-name
79
+ class config_property[GETTER, SETTER](generic_property[GETTER, SETTER]):
80
+ """Decorate to mark own config properties."""
81
+
82
+
83
+ # pylint: disable=invalid-name
84
+ class info_property[GETTER, SETTER](generic_property[GETTER, SETTER]):
85
+ """Decorate to mark own info properties."""
86
+
87
+
88
+ # pylint: disable=invalid-name
89
+ class state_property[GETTER, SETTER](generic_property[GETTER, SETTER]):
90
+ """Decorate to mark own value properties."""
91
+
92
+
93
+ # Cache for per-class attribute names by decorator to avoid repeated dir() scans
94
+ # Keyed by (class, decorator class); value is a tuple of attribute names
95
+ _PUBLIC_ATTR_CACHE: dict[tuple[type, type], tuple[str, ...]] = {}
96
+
97
+
98
+ def _get_public_attributes_by_class_decorator(data_object: Any, class_decorator: type) -> Mapping[str, Any]:
99
+ """
100
+ Return the object attributes by decorator.
101
+
102
+ This caches the attribute names per (class, decorator) to reduce overhead
103
+ from repeated dir()/getattr() scans. Values are not cached as they are
104
+ instance-dependent and may change over time.
105
+ """
106
+ cls = data_object.__class__
107
+ cache_key = (cls, class_decorator)
108
+
109
+ if (names := _PUBLIC_ATTR_CACHE.get(cache_key)) is None:
110
+ names = tuple(y for y in dir(cls) if not y.startswith("_") and isinstance(getattr(cls, y), class_decorator))
111
+ _PUBLIC_ATTR_CACHE[cache_key] = names
112
+
113
+ return {name: _get_text_value(getattr(data_object, name)) for name in names}
114
+
115
+
116
+ def _get_text_value(value: Any) -> Any:
117
+ """Convert value to text."""
118
+ if isinstance(value, (list, tuple, set)):
119
+ return tuple(_get_text_value(v) for v in value)
120
+ if isinstance(value, Enum):
121
+ return str(value)
122
+ if isinstance(value, datetime):
123
+ return datetime.timestamp(value)
124
+ return value
125
+
126
+
127
+ def get_public_attributes_for_config_property(data_object: Any) -> Mapping[str, Any]:
128
+ """Return the object attributes by decorator config_property."""
129
+ return _get_public_attributes_by_class_decorator(data_object=data_object, class_decorator=config_property)
130
+
131
+
132
+ def get_public_attributes_for_info_property(data_object: Any) -> Mapping[str, Any]:
133
+ """Return the object attributes by decorator info_property."""
134
+ return _get_public_attributes_by_class_decorator(data_object=data_object, class_decorator=info_property)
135
+
136
+
137
+ def get_public_attributes_for_state_property(data_object: Any) -> Mapping[str, Any]:
138
+ """Return the object attributes by decorator state_property."""
139
+ return _get_public_attributes_by_class_decorator(data_object=data_object, class_decorator=state_property)
140
+
141
+
142
+ # pylint: disable=invalid-name
143
+ class cached_slot_property[T, R]:
144
+ """A property-like descriptor that caches the computed value in a slot attribute. Designed to work with classes that use __slots__ and do not define __dict__."""
145
+
146
+ def __init__(self, func: Callable[[T], R]) -> None:
147
+ """Init the cached property."""
148
+ self._func = func # The function to compute the value
149
+ self._cache_attr = f"_cached_{func.__name__}" # Default name of the cache attribute
150
+ self._name = func.__name__
151
+
152
+ def __get__(self, instance: T | None, owner: type | None = None) -> R:
153
+ """Return the cached value if it exists. Otherwise, compute it using the function and cache it."""
154
+ if instance is None:
155
+ # Accessed from class, return the descriptor itself
156
+ return cast(R, self)
157
+
158
+ # If the cached value is not set yet, compute and store it
159
+ if not hasattr(instance, self._cache_attr):
160
+ value = self._func(instance)
161
+ setattr(instance, self._cache_attr, value)
162
+
163
+ # Return the cached value
164
+ return cast(R, getattr(instance, self._cache_attr))
165
+
166
+ def __set__(self, instance: T, value: Any) -> None:
167
+ """Raise an error to prevent manual assignment to the property."""
168
+ raise AttributeError(f"Can't set read-only cached property '{self._name}'")
169
+
170
+ def __delete__(self, instance: T) -> None:
171
+ """Delete the cached value so it can be recomputed on next access."""
172
+ if hasattr(instance, self._cache_attr):
173
+ delattr(instance, self._cache_attr)