qbusmqttapi 0.1.0__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.
qbusmqttapi/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""QBUS MQTT API."""
|
qbusmqttapi/discovery.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""QBUS Discovery."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
_LOGGER = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
KEY_DEVICES = "devices"
|
|
10
|
+
|
|
11
|
+
KEY_DEVICE_FUNCTIONBLOCKS = "functionBlocks"
|
|
12
|
+
KEY_DEVICE_ID = "id"
|
|
13
|
+
KEY_DEVICE_IP = "ip"
|
|
14
|
+
KEY_DEVICE_MAC = "mac"
|
|
15
|
+
KEY_DEVICE_NAME = "name"
|
|
16
|
+
KEY_DEVICE_SERIAL_NR = "serialNr"
|
|
17
|
+
KEY_DEVICE_TYPE = "type"
|
|
18
|
+
|
|
19
|
+
KEY_OUTPUT_ID = "id"
|
|
20
|
+
KEY_OUTPUT_TYPE = "type"
|
|
21
|
+
KEY_OUTPUT_NAME = "name"
|
|
22
|
+
KEY_OUTPUT_REF_ID = "ref_id"
|
|
23
|
+
KEY_OUTPUT_PROPERTIES = "properties"
|
|
24
|
+
KEY_OUTPUT_ACTIONS = "actions"
|
|
25
|
+
|
|
26
|
+
KEY_CONTROLLER_CONNECTABLE = "connectable"
|
|
27
|
+
KEY_CONTROLLER_CONNECTED = "connected"
|
|
28
|
+
KEY_CONTROLLER_ID = "id"
|
|
29
|
+
KEY_CONTROLLER_STATE_PROPERTIES = "properties"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class QbusMqttOutput:
|
|
33
|
+
"""Class for parsing MQTT discovered outputs for Qbus Home Automation."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, dict: dict) -> None:
|
|
36
|
+
"""Initialize based on a json loaded dictionary."""
|
|
37
|
+
self._dict = dict
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def id(self) -> str:
|
|
41
|
+
"""Return the id."""
|
|
42
|
+
return self._dict.get(KEY_OUTPUT_ID) or ""
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def type(self) -> str:
|
|
46
|
+
"""Return the type."""
|
|
47
|
+
return self._dict.get(KEY_OUTPUT_TYPE) or ""
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def name(self) -> str:
|
|
51
|
+
"""Return the name."""
|
|
52
|
+
return self._dict.get(KEY_OUTPUT_NAME) or ""
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def ref_id(self) -> str:
|
|
56
|
+
"""Return the ref id."""
|
|
57
|
+
return self._dict.get(KEY_OUTPUT_REF_ID) or ""
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def properties(self) -> dict:
|
|
61
|
+
"""Return the properties."""
|
|
62
|
+
return self._dict.get(KEY_OUTPUT_PROPERTIES) or {}
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def actions(self) -> dict:
|
|
66
|
+
"""Return the actions."""
|
|
67
|
+
return self._dict.get(KEY_OUTPUT_ACTIONS) or {}
|
|
68
|
+
|
|
69
|
+
class QbusMqttDevice:
|
|
70
|
+
"""Class for parsing MQTT discovered devices for Qbus Home Automation."""
|
|
71
|
+
|
|
72
|
+
def __init__(self, dict: dict) -> None:
|
|
73
|
+
self._dict = dict
|
|
74
|
+
self._outputs: list[QbusMqttOutput] = []
|
|
75
|
+
self._connection_state: bool
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def id(self) -> str:
|
|
79
|
+
"""Return the id."""
|
|
80
|
+
return self._dict.get(KEY_DEVICE_ID) or ""
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def ip(self) -> str:
|
|
84
|
+
"""Return the ip address."""
|
|
85
|
+
return self._dict.get(KEY_DEVICE_IP) or ""
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def mac(self) -> str:
|
|
89
|
+
"""Return the ip address."""
|
|
90
|
+
return self._dict.get(KEY_DEVICE_MAC) or ""
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def name(self) -> str:
|
|
94
|
+
"""Return the ip address."""
|
|
95
|
+
return self._dict.get(KEY_DEVICE_NAME) or ""
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def serial_number(self) -> str:
|
|
99
|
+
"""Return the serial number."""
|
|
100
|
+
return self._dict.get(KEY_DEVICE_SERIAL_NR) or ""
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def type(self) -> str:
|
|
104
|
+
"""Return the mac address."""
|
|
105
|
+
return self._dict.get(KEY_DEVICE_TYPE) or ""
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def outputs(self) -> list[QbusMqttOutput]:
|
|
109
|
+
"""Return the outputs."""
|
|
110
|
+
|
|
111
|
+
outputs: list[QbusMqttOutput] = []
|
|
112
|
+
|
|
113
|
+
if self._dict.get(KEY_DEVICE_FUNCTIONBLOCKS):
|
|
114
|
+
outputs = [QbusMqttOutput(x) for x in self._dict[KEY_DEVICE_FUNCTIONBLOCKS]]
|
|
115
|
+
|
|
116
|
+
self._outputs = outputs
|
|
117
|
+
return self._outputs
|
|
118
|
+
|
|
119
|
+
class QbusMqttControllerStateProperties:
|
|
120
|
+
"""MQTT representation a Qbus controller its state properties."""
|
|
121
|
+
|
|
122
|
+
def __init__(self, dict: dict) -> None:
|
|
123
|
+
"""Initialize based on a json loaded dictionary."""
|
|
124
|
+
self._dict = dict
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def connectable(self) -> bool | None:
|
|
128
|
+
"""Return True if the controller is connectable."""
|
|
129
|
+
return self._dict.get(KEY_CONTROLLER_CONNECTABLE, None)
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def connected(self) -> bool | None:
|
|
133
|
+
"""Return True if the controller is connected."""
|
|
134
|
+
return self._dict.get(KEY_CONTROLLER_CONNECTED, None)
|
|
135
|
+
|
|
136
|
+
class QbusMqttControllerState:
|
|
137
|
+
"""MQTT representation a Qbus controller state."""
|
|
138
|
+
|
|
139
|
+
def __init__(self, dict: dict) -> None:
|
|
140
|
+
"""Initialize based on a json loaded dictionary."""
|
|
141
|
+
self._dict = dict
|
|
142
|
+
self._properties: QbusMqttControllerStateProperties | None = None
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def id(self) -> str | None:
|
|
146
|
+
"""Return the id."""
|
|
147
|
+
return self._dict.get(KEY_CONTROLLER_ID)
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def properties(self) -> QbusMqttControllerStateProperties | None:
|
|
151
|
+
"""Return the properties."""
|
|
152
|
+
|
|
153
|
+
if self._properties is not None:
|
|
154
|
+
return self._properties
|
|
155
|
+
|
|
156
|
+
properties: QbusMqttControllerStateProperties | None = None
|
|
157
|
+
|
|
158
|
+
if self._dict.get(KEY_CONTROLLER_STATE_PROPERTIES):
|
|
159
|
+
properties = QbusMqttControllerStateProperties(self._dict[KEY_CONTROLLER_STATE_PROPERTIES])
|
|
160
|
+
|
|
161
|
+
self._properties = properties
|
|
162
|
+
|
|
163
|
+
return self._properties
|
|
164
|
+
|
|
165
|
+
class QbusMqttOutputState:
|
|
166
|
+
"""MQTT representation a Qbus output state."""
|
|
167
|
+
|
|
168
|
+
def __init__(self, dict: dict) -> None:
|
|
169
|
+
"""Initialize based on a json loaded dictionary."""
|
|
170
|
+
self._dict = dict
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def id(self) -> str:
|
|
174
|
+
"""Return the id."""
|
|
175
|
+
return self._dict.get(KEY_OUTPUT_ID) or ""
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def type(self) -> str:
|
|
179
|
+
"""Return the type."""
|
|
180
|
+
return self._dict.get(KEY_OUTPUT_TYPE) or ""
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def properties(self) -> dict | None:
|
|
184
|
+
"""Return the properties."""
|
|
185
|
+
return self._dict.get(KEY_OUTPUT_PROPERTIES)
|
|
186
|
+
|
|
187
|
+
class QbusDiscovery:
|
|
188
|
+
"""Class for parsing MQTT discovery messages for Qbus Home Automation."""
|
|
189
|
+
|
|
190
|
+
def __init__(self, domain: str) -> None:
|
|
191
|
+
"""Initialize."""
|
|
192
|
+
self._domain = domain
|
|
193
|
+
self._devices = list[QbusMqttDevice] = []
|
|
194
|
+
self._hub_id = ""
|
|
195
|
+
self._device_id = ""
|
|
196
|
+
self._device_type = ""
|
|
197
|
+
self._device_desc = ""
|
|
198
|
+
self._name = ""
|
|
199
|
+
self._owner_id = ""
|
|
200
|
+
self._data_topic = ""
|
|
201
|
+
self._command_topic = ""
|
|
202
|
+
|
|
203
|
+
async def parse_discovery(self, discovery_topic: str, payload: str | bytes) -> bool:
|
|
204
|
+
"""Parse an MQTT discovery message and return True if successful."""
|
|
205
|
+
try:
|
|
206
|
+
json_data = json.loads(payload)
|
|
207
|
+
except ValueError:
|
|
208
|
+
_LOGGER.error(
|
|
209
|
+
"Invalid QBUS MQTT discovery payload on %s: %s",
|
|
210
|
+
discovery_topic,
|
|
211
|
+
payload,
|
|
212
|
+
)
|
|
213
|
+
return False
|
|
214
|
+
|
|
215
|
+
topic_elements = discovery_topic.split("/")
|
|
216
|
+
if not (
|
|
217
|
+
topic_elements[2].endswith("config")
|
|
218
|
+
):
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Discovery data must include the Qbus device type and name.
|
|
224
|
+
if (
|
|
225
|
+
KEY_DEVICES in json_data
|
|
226
|
+
):
|
|
227
|
+
self._devices = json_data[KEY_DEVICES]
|
|
228
|
+
else:
|
|
229
|
+
_LOGGER.error(
|
|
230
|
+
"Incomplete MQTT discovery payload on %s: %s", discovery_topic, payload
|
|
231
|
+
)
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def devices(self) -> list[QbusMqttDevice]:
|
|
236
|
+
"""Return the devices."""
|
|
237
|
+
|
|
238
|
+
devices: list[QbusMqttDevice] = []
|
|
239
|
+
|
|
240
|
+
if self._dict.get("devices"):
|
|
241
|
+
devices = [QbusMqttDevice(x) for x in self._dict["devices"]]
|
|
242
|
+
|
|
243
|
+
self._devices = devices
|
|
244
|
+
|
|
245
|
+
return self._devices
|
|
246
|
+
|
|
247
|
+
def get_device(self, serial: str) -> QbusMqttDevice | None:
|
|
248
|
+
"""Get the device by serial number."""
|
|
249
|
+
return next((x for x in self.devices if x.serial_number == serial), None)
|
|
250
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Qbus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: qbusmqttapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MQTT API for Qbus Home Automation
|
|
5
|
+
Author-email: Koen Schockaert <iot@qbus.be>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 Qbus
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/Qbus-iot/qbusmqttapi
|
|
29
|
+
Keywords: qbus,mqtt,api
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Programming Language :: Python
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Requires-Python: >=3.11
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
|
|
37
|
+
# qbusmqttapi
|
|
38
|
+
Python MQTT API for Qbus Home Automation
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
qbusmqttapi/__init__.py,sha256=gBSKnV4PNKfff3h3lTNMBJue8hkF-NBkFlJ-5bCMnIU,20
|
|
2
|
+
qbusmqttapi/discovery.py,sha256=mCSaQUbgGsFGXytD7Ix1ffz_Tzwx12Vh0M106gFvDNw,7491
|
|
3
|
+
qbusmqttapi-0.1.0.dist-info/LICENSE,sha256=tA9k_z4nwtQ7BPi69x8HyW8NKs6jgiXjYQKEvRSc34Y,1061
|
|
4
|
+
qbusmqttapi-0.1.0.dist-info/METADATA,sha256=vfMeryr2oGyZ3o6mvn3aMr2cTx0n2j7JUNHC1So-yvw,1790
|
|
5
|
+
qbusmqttapi-0.1.0.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
6
|
+
qbusmqttapi-0.1.0.dist-info/top_level.txt,sha256=4b327nGeDy12dfY_wCWnh-qQrOJVBoQBKAaKGvb52vY,12
|
|
7
|
+
qbusmqttapi-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
qbusmqttapi
|