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
|
@@ -52,7 +52,7 @@ def callback_backend_system(system_event: BackendSystemEvent) -> Callable:
|
|
|
52
52
|
central = unit.get_central(interface_id=str(args[1]))
|
|
53
53
|
if central:
|
|
54
54
|
central.looper.create_task(
|
|
55
|
-
_exec_backend_system_callback(*args, **kwargs),
|
|
55
|
+
target=_exec_backend_system_callback(*args, **kwargs),
|
|
56
56
|
name="wrapper_backend_system_callback",
|
|
57
57
|
)
|
|
58
58
|
except Exception as exc:
|
|
@@ -123,7 +123,7 @@ def callback_event[**P, R](func: Callable[P, R]) -> Callable:
|
|
|
123
123
|
unit = args[0]
|
|
124
124
|
if isinstance(unit, hmcu.CentralUnit):
|
|
125
125
|
unit.looper.create_task(
|
|
126
|
-
_async_wrap_sync(_exec_event_callback, *args, **kwargs),
|
|
126
|
+
target=_async_wrap_sync(_exec_event_callback, *args, **kwargs),
|
|
127
127
|
name="wrapper_event_callback",
|
|
128
128
|
)
|
|
129
129
|
return
|
|
@@ -27,15 +27,18 @@ _LOGGER: Final = logging.getLogger(__name__)
|
|
|
27
27
|
class RPCFunctions:
|
|
28
28
|
"""The XML-RPC functions the backend will expect."""
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
# Disable kw-only linter for this class since XML-RPC signatures are positional by protocol
|
|
31
|
+
__kwonly_check__ = False
|
|
32
|
+
|
|
33
|
+
def __init__(self, *, xml_rpc_server: XmlRpcServer) -> None:
|
|
31
34
|
"""Init RPCFunctions."""
|
|
32
35
|
self._xml_rpc_server: Final = xml_rpc_server
|
|
33
36
|
|
|
34
|
-
def event(self, interface_id: str, channel_address: str, parameter: str, value: Any) -> None:
|
|
37
|
+
def event(self, interface_id: str, channel_address: str, parameter: str, value: Any, /) -> None:
|
|
35
38
|
"""If a device emits some sort event, we will handle it here."""
|
|
36
|
-
if central := self.get_central(interface_id):
|
|
39
|
+
if central := self.get_central(interface_id=interface_id):
|
|
37
40
|
central.looper.create_task(
|
|
38
|
-
central.data_point_event(
|
|
41
|
+
target=central.data_point_event(
|
|
39
42
|
interface_id=interface_id,
|
|
40
43
|
channel_address=channel_address,
|
|
41
44
|
parameter=parameter,
|
|
@@ -45,7 +48,7 @@ class RPCFunctions:
|
|
|
45
48
|
)
|
|
46
49
|
|
|
47
50
|
@callback_backend_system(system_event=BackendSystemEvent.ERROR)
|
|
48
|
-
def error(self, interface_id: str, error_code: str, msg: str) -> None:
|
|
51
|
+
def error(self, interface_id: str, error_code: str, msg: str, /) -> None:
|
|
49
52
|
"""When some error occurs the backend will send its error message here."""
|
|
50
53
|
# Structured boundary log (warning level). XML-RPC server received error notification.
|
|
51
54
|
try:
|
|
@@ -66,32 +69,34 @@ class RPCFunctions:
|
|
|
66
69
|
str(msg),
|
|
67
70
|
)
|
|
68
71
|
|
|
69
|
-
def listDevices(self, interface_id: str) -> list[dict[str, Any]]:
|
|
72
|
+
def listDevices(self, interface_id: str, /) -> list[dict[str, Any]]:
|
|
70
73
|
"""Return already existing devices to the backend."""
|
|
71
|
-
if central := self.get_central(interface_id):
|
|
74
|
+
if central := self.get_central(interface_id=interface_id):
|
|
72
75
|
return [dict(device_description) for device_description in central.list_devices(interface_id=interface_id)]
|
|
73
76
|
return []
|
|
74
77
|
|
|
75
|
-
def newDevices(self, interface_id: str, device_descriptions: list[dict[str, Any]]) -> None:
|
|
78
|
+
def newDevices(self, interface_id: str, device_descriptions: list[dict[str, Any]], /) -> None:
|
|
76
79
|
"""Add new devices send from the backend."""
|
|
77
80
|
central: hmcu.CentralUnit | None
|
|
78
|
-
if central := self.get_central(interface_id):
|
|
81
|
+
if central := self.get_central(interface_id=interface_id):
|
|
79
82
|
central.looper.create_task(
|
|
80
|
-
central.add_new_devices(
|
|
83
|
+
target=central.add_new_devices(
|
|
84
|
+
interface_id=interface_id, device_descriptions=tuple(device_descriptions)
|
|
85
|
+
),
|
|
81
86
|
name=f"newDevices-{interface_id}",
|
|
82
87
|
)
|
|
83
88
|
|
|
84
|
-
def deleteDevices(self, interface_id: str, addresses: list[str]) -> None:
|
|
89
|
+
def deleteDevices(self, interface_id: str, addresses: list[str], /) -> None:
|
|
85
90
|
"""Delete devices send from the backend."""
|
|
86
91
|
central: hmcu.CentralUnit | None
|
|
87
|
-
if central := self.get_central(interface_id):
|
|
92
|
+
if central := self.get_central(interface_id=interface_id):
|
|
88
93
|
central.looper.create_task(
|
|
89
|
-
central.delete_devices(interface_id=interface_id, addresses=tuple(addresses)),
|
|
94
|
+
target=central.delete_devices(interface_id=interface_id, addresses=tuple(addresses)),
|
|
90
95
|
name=f"deleteDevices-{interface_id}",
|
|
91
96
|
)
|
|
92
97
|
|
|
93
98
|
@callback_backend_system(system_event=BackendSystemEvent.UPDATE_DEVICE)
|
|
94
|
-
def updateDevice(self, interface_id: str, address: str, hint: int) -> None:
|
|
99
|
+
def updateDevice(self, interface_id: str, address: str, hint: int, /) -> None:
|
|
95
100
|
"""
|
|
96
101
|
Update a device.
|
|
97
102
|
|
|
@@ -106,7 +111,7 @@ class RPCFunctions:
|
|
|
106
111
|
)
|
|
107
112
|
|
|
108
113
|
@callback_backend_system(system_event=BackendSystemEvent.REPLACE_DEVICE)
|
|
109
|
-
def replaceDevice(self, interface_id: str, old_device_address: str, new_device_address: str) -> None:
|
|
114
|
+
def replaceDevice(self, interface_id: str, old_device_address: str, new_device_address: str, /) -> None:
|
|
110
115
|
"""Replace a device. Probably irrelevant for us."""
|
|
111
116
|
_LOGGER.debug(
|
|
112
117
|
"REPLACEDEVICE: interface_id = %s, oldDeviceAddress = %s, newDeviceAddress = %s",
|
|
@@ -116,7 +121,7 @@ class RPCFunctions:
|
|
|
116
121
|
)
|
|
117
122
|
|
|
118
123
|
@callback_backend_system(system_event=BackendSystemEvent.RE_ADDED_DEVICE)
|
|
119
|
-
def readdedDevice(self, interface_id: str, addresses: list[str]) -> None:
|
|
124
|
+
def readdedDevice(self, interface_id: str, addresses: list[str], /) -> None:
|
|
120
125
|
"""
|
|
121
126
|
Re-Add device from the backend.
|
|
122
127
|
|
|
@@ -130,9 +135,9 @@ class RPCFunctions:
|
|
|
130
135
|
str(addresses),
|
|
131
136
|
)
|
|
132
137
|
|
|
133
|
-
def get_central(self, interface_id: str) -> hmcu.CentralUnit | None:
|
|
138
|
+
def get_central(self, *, interface_id: str) -> hmcu.CentralUnit | None:
|
|
134
139
|
"""Return the central by interface_id."""
|
|
135
|
-
return self._xml_rpc_server.get_central(interface_id)
|
|
140
|
+
return self._xml_rpc_server.get_central(interface_id=interface_id)
|
|
136
141
|
|
|
137
142
|
|
|
138
143
|
# Restrict to specific paths.
|
|
@@ -159,7 +164,9 @@ class AioHomematicXMLRPCServer(SimpleXMLRPCServer):
|
|
|
159
164
|
system_listMethods(self, interface_id: str.
|
|
160
165
|
"""
|
|
161
166
|
|
|
162
|
-
|
|
167
|
+
__kwonly_check__ = False
|
|
168
|
+
|
|
169
|
+
def system_listMethods(self, interface_id: str | None = None, /) -> list[str]:
|
|
163
170
|
"""Return a list of the methods supported by the server."""
|
|
164
171
|
return SimpleXMLRPCServer.system_listMethods(self)
|
|
165
172
|
|
|
@@ -172,6 +179,7 @@ class XmlRpcServer(threading.Thread):
|
|
|
172
179
|
|
|
173
180
|
def __init__(
|
|
174
181
|
self,
|
|
182
|
+
*,
|
|
175
183
|
ip_addr: str,
|
|
176
184
|
port: int,
|
|
177
185
|
) -> None:
|
|
@@ -192,10 +200,10 @@ class XmlRpcServer(threading.Thread):
|
|
|
192
200
|
)
|
|
193
201
|
self._simple_xml_rpc_server.register_introspection_functions()
|
|
194
202
|
self._simple_xml_rpc_server.register_multicall_functions()
|
|
195
|
-
self._simple_xml_rpc_server.register_instance(RPCFunctions(self), allow_dotted_names=True)
|
|
203
|
+
self._simple_xml_rpc_server.register_instance(RPCFunctions(xml_rpc_server=self), allow_dotted_names=True)
|
|
196
204
|
self._centrals: Final[dict[str, hmcu.CentralUnit]] = {}
|
|
197
205
|
|
|
198
|
-
def __new__(cls, ip_addr: str, port: int) -> XmlRpcServer: # noqa: PYI034
|
|
206
|
+
def __new__(cls, ip_addr: str, port: int) -> XmlRpcServer: # noqa: PYI034 # kwonly: disable
|
|
199
207
|
"""Create new XmlRPC server."""
|
|
200
208
|
if (xml_rpc := cls._instances.get((ip_addr, port))) is None:
|
|
201
209
|
_LOGGER.debug("Creating XmlRpc server")
|
|
@@ -240,17 +248,17 @@ class XmlRpcServer(threading.Thread):
|
|
|
240
248
|
"""Return if thread is active."""
|
|
241
249
|
return self._started.is_set() is True # type: ignore[attr-defined]
|
|
242
250
|
|
|
243
|
-
def add_central(self, central: hmcu.CentralUnit) -> None:
|
|
251
|
+
def add_central(self, *, central: hmcu.CentralUnit) -> None:
|
|
244
252
|
"""Register a central in the XmlRPC-Server."""
|
|
245
253
|
if not self._centrals.get(central.name):
|
|
246
254
|
self._centrals[central.name] = central
|
|
247
255
|
|
|
248
|
-
def remove_central(self, central: hmcu.CentralUnit) -> None:
|
|
256
|
+
def remove_central(self, *, central: hmcu.CentralUnit) -> None:
|
|
249
257
|
"""Unregister a central from XmlRPC-Server."""
|
|
250
258
|
if self._centrals.get(central.name):
|
|
251
259
|
del self._centrals[central.name]
|
|
252
260
|
|
|
253
|
-
def get_central(self, interface_id: str) -> hmcu.CentralUnit | None:
|
|
261
|
+
def get_central(self, *, interface_id: str) -> hmcu.CentralUnit | None:
|
|
254
262
|
"""Return a central by interface_id."""
|
|
255
263
|
for central in self._centrals.values():
|
|
256
264
|
if central.has_client(interface_id=interface_id):
|
|
@@ -263,7 +271,7 @@ class XmlRpcServer(threading.Thread):
|
|
|
263
271
|
return len(self._centrals) == 0
|
|
264
272
|
|
|
265
273
|
|
|
266
|
-
def create_xml_rpc_server(ip_addr: str = IP_ANY_V4, port: int = PORT_ANY) -> XmlRpcServer:
|
|
274
|
+
def create_xml_rpc_server(*, ip_addr: str = IP_ANY_V4, port: int = PORT_ANY) -> XmlRpcServer:
|
|
267
275
|
"""Register the xml rpc server."""
|
|
268
276
|
xml_rpc = XmlRpcServer(ip_addr=ip_addr, port=port)
|
|
269
277
|
if not xml_rpc.started:
|