qolsys-controller 0.0.44__py3-none-any.whl → 0.0.87__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 qolsys-controller might be problematic. Click here for more details.
- qolsys_controller/adc_device.py +202 -0
- qolsys_controller/adc_service.py +139 -0
- qolsys_controller/adc_service_garagedoor.py +35 -0
- qolsys_controller/controller.py +1040 -20
- qolsys_controller/database/db.py +108 -29
- qolsys_controller/database/table.py +90 -60
- qolsys_controller/database/table_alarmedsensor.py +2 -2
- qolsys_controller/database/table_automation.py +0 -1
- qolsys_controller/database/table_country_locale.py +0 -1
- qolsys_controller/database/table_dashboard_msgs.py +1 -2
- qolsys_controller/database/table_dimmerlight.py +0 -1
- qolsys_controller/database/table_doorlock.py +0 -1
- qolsys_controller/database/table_eu_event.py +1 -2
- qolsys_controller/database/table_heat_map.py +0 -2
- qolsys_controller/database/table_history.py +4 -1
- qolsys_controller/database/table_iqremotesettings.py +0 -2
- qolsys_controller/database/table_iqrouter_network_config.py +0 -1
- qolsys_controller/database/table_iqrouter_user_device.py +0 -2
- qolsys_controller/database/table_master_slave.py +0 -1
- qolsys_controller/database/table_nest_device.py +0 -1
- qolsys_controller/database/table_output_rules.py +0 -1
- qolsys_controller/database/table_partition.py +0 -1
- qolsys_controller/database/table_pgm_outputs.py +0 -2
- qolsys_controller/database/table_powerg_device.py +0 -2
- qolsys_controller/database/table_qolsyssettings.py +0 -2
- qolsys_controller/database/table_scene.py +0 -2
- qolsys_controller/database/table_sensor.py +2 -2
- qolsys_controller/database/table_sensor_group.py +23 -0
- qolsys_controller/database/table_shades.py +0 -2
- qolsys_controller/database/table_smartsocket.py +12 -3
- qolsys_controller/database/table_state.py +0 -1
- qolsys_controller/database/table_tcc.py +0 -1
- qolsys_controller/database/table_thermostat.py +3 -1
- qolsys_controller/database/table_trouble_conditions.py +0 -2
- qolsys_controller/database/table_user.py +0 -2
- qolsys_controller/database/table_virtual_device.py +13 -3
- qolsys_controller/database/table_weather.py +0 -2
- qolsys_controller/database/table_zigbee_device.py +0 -1
- qolsys_controller/database/table_zwave_association_group.py +0 -1
- qolsys_controller/database/table_zwave_history.py +0 -1
- qolsys_controller/database/table_zwave_node.py +3 -1
- qolsys_controller/database/table_zwave_other.py +0 -1
- qolsys_controller/enum.py +42 -13
- qolsys_controller/enum_adc.py +28 -0
- qolsys_controller/enum_zwave.py +210 -36
- qolsys_controller/errors.py +14 -12
- qolsys_controller/mdns.py +7 -4
- qolsys_controller/mqtt_command.py +125 -0
- qolsys_controller/mqtt_command_queue.py +5 -4
- qolsys_controller/observable.py +2 -2
- qolsys_controller/panel.py +304 -156
- qolsys_controller/partition.py +149 -127
- qolsys_controller/pki.py +69 -97
- qolsys_controller/scene.py +30 -28
- qolsys_controller/settings.py +96 -50
- qolsys_controller/state.py +221 -34
- qolsys_controller/task_manager.py +11 -14
- qolsys_controller/users.py +25 -0
- qolsys_controller/utils_mqtt.py +8 -16
- qolsys_controller/weather.py +71 -0
- qolsys_controller/zone.py +243 -214
- qolsys_controller/zwave_device.py +234 -93
- qolsys_controller/zwave_dimmer.py +55 -49
- qolsys_controller/zwave_energy_clamp.py +15 -0
- qolsys_controller/zwave_garagedoor.py +3 -1
- qolsys_controller/zwave_generic.py +5 -3
- qolsys_controller/zwave_lock.py +51 -44
- qolsys_controller/zwave_outlet.py +3 -1
- qolsys_controller/zwave_service_meter.py +192 -0
- qolsys_controller/zwave_service_multilevelsensor.py +119 -0
- qolsys_controller/zwave_thermometer.py +21 -0
- qolsys_controller/zwave_thermostat.py +249 -143
- qolsys_controller-0.0.87.dist-info/METADATA +89 -0
- qolsys_controller-0.0.87.dist-info/RECORD +77 -0
- {qolsys_controller-0.0.44.dist-info → qolsys_controller-0.0.87.dist-info}/WHEEL +1 -1
- qolsys_controller/plugin.py +0 -34
- qolsys_controller/plugin_c4.py +0 -17
- qolsys_controller/plugin_remote.py +0 -1298
- qolsys_controller-0.0.44.dist-info/METADATA +0 -93
- qolsys_controller-0.0.44.dist-info/RECORD +0 -68
- {qolsys_controller-0.0.44.dist-info → qolsys_controller-0.0.87.dist-info}/licenses/LICENSE +0 -0
qolsys_controller/state.py
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from qolsys_controller.adc_service import QolsysAdcService
|
|
7
|
+
from qolsys_controller.adc_service_garagedoor import QolsysAdcGarageDoorService
|
|
8
|
+
from qolsys_controller.zwave_energy_clamp import QolsysEnergyClamp
|
|
9
|
+
from qolsys_controller.zwave_thermometer import QolsysThermometer
|
|
2
10
|
|
|
11
|
+
from .adc_device import QolsysAdcDevice
|
|
3
12
|
from .observable import QolsysObservable
|
|
4
|
-
from .
|
|
5
|
-
from .scene import QolsysScene
|
|
6
|
-
from .zone import QolsysZone
|
|
13
|
+
from .weather import QolsysWeather
|
|
7
14
|
from .zwave_device import QolsysZWaveDevice
|
|
8
15
|
from .zwave_dimmer import QolsysDimmer
|
|
9
16
|
from .zwave_generic import QolsysGeneric
|
|
@@ -12,20 +19,29 @@ from .zwave_thermostat import QolsysThermostat
|
|
|
12
19
|
|
|
13
20
|
LOGGER = logging.getLogger(__name__)
|
|
14
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from .controller import QolsysController
|
|
24
|
+
from .partition import QolsysPartition
|
|
25
|
+
from .scene import QolsysScene
|
|
26
|
+
from .zone import QolsysZone
|
|
27
|
+
from .zwave_device import QolsysZWaveDevice
|
|
15
28
|
|
|
16
|
-
class QolsysState(QolsysObservable):
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
class QolsysState(QolsysObservable):
|
|
31
|
+
def __init__(self, controller: QolsysController) -> None:
|
|
19
32
|
super().__init__()
|
|
20
|
-
|
|
21
|
-
self.
|
|
22
|
-
self.
|
|
23
|
-
self.
|
|
24
|
-
self.
|
|
33
|
+
self._controller: QolsysController = controller
|
|
34
|
+
self._weather: QolsysWeather = QolsysWeather()
|
|
35
|
+
self._partitions: list[QolsysPartition] = []
|
|
36
|
+
self._zones: list[QolsysZone] = []
|
|
37
|
+
self._adc_devices: list[QolsysAdcDevice] = []
|
|
38
|
+
self._zwave_devices: list[QolsysZWaveDevice] = []
|
|
39
|
+
self._scenes: list[QolsysScene] = []
|
|
25
40
|
|
|
26
41
|
self._state_partition_observer = QolsysObservable()
|
|
27
42
|
self._state_zone_observer = QolsysObservable()
|
|
28
43
|
self._state_zwave_observer = QolsysObservable()
|
|
44
|
+
self._state_adc_observer = QolsysObservable()
|
|
29
45
|
self._state_scene_observer = QolsysObservable()
|
|
30
46
|
|
|
31
47
|
@property
|
|
@@ -36,6 +52,10 @@ class QolsysState(QolsysObservable):
|
|
|
36
52
|
def zwave_devices(self) -> list[QolsysZWaveDevice]:
|
|
37
53
|
return self._zwave_devices
|
|
38
54
|
|
|
55
|
+
@property
|
|
56
|
+
def adc_devices(self) -> list[QolsysAdcDevice]:
|
|
57
|
+
return self._adc_devices
|
|
58
|
+
|
|
39
59
|
@property
|
|
40
60
|
def zones(self) -> list[QolsysZone]:
|
|
41
61
|
return self._zones
|
|
@@ -44,6 +64,10 @@ class QolsysState(QolsysObservable):
|
|
|
44
64
|
def scenes(self) -> list[QolsysScene]:
|
|
45
65
|
return self._scenes
|
|
46
66
|
|
|
67
|
+
@property
|
|
68
|
+
def weather(self) -> QolsysWeather:
|
|
69
|
+
return self._weather
|
|
70
|
+
|
|
47
71
|
@property
|
|
48
72
|
def zwave_dimmers(self) -> list[QolsysDimmer]:
|
|
49
73
|
dimmers = []
|
|
@@ -68,9 +92,28 @@ class QolsysState(QolsysObservable):
|
|
|
68
92
|
for device in self.zwave_devices:
|
|
69
93
|
if isinstance(device, QolsysThermostat):
|
|
70
94
|
thermostats.append(device)
|
|
71
|
-
|
|
72
95
|
return thermostats
|
|
73
96
|
|
|
97
|
+
@property
|
|
98
|
+
def zwave_meters(self) -> list[QolsysEnergyClamp]:
|
|
99
|
+
meters = []
|
|
100
|
+
for device in self.zwave_devices:
|
|
101
|
+
if isinstance(device, QolsysEnergyClamp):
|
|
102
|
+
meters.append(device)
|
|
103
|
+
return meters
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def zwave_thermometers(self) -> list[QolsysThermometer]:
|
|
107
|
+
thermometer = []
|
|
108
|
+
for device in self.zwave_devices:
|
|
109
|
+
if isinstance(device, QolsysThermometer):
|
|
110
|
+
thermometer.append(device)
|
|
111
|
+
return thermometer
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def zwave_other_devices(self) -> list[dict[str, str]]:
|
|
115
|
+
return self._controller.panel.db.get_zwave_other_devices()
|
|
116
|
+
|
|
74
117
|
@property
|
|
75
118
|
def state_partition_observer(self) -> QolsysObservable:
|
|
76
119
|
return self._state_partition_observer
|
|
@@ -87,7 +130,11 @@ class QolsysState(QolsysObservable):
|
|
|
87
130
|
def state_scene_observer(self) -> QolsysObservable:
|
|
88
131
|
return self._state_scene_observer
|
|
89
132
|
|
|
90
|
-
|
|
133
|
+
@property
|
|
134
|
+
def state_adc_observer(self) -> QolsysObservable:
|
|
135
|
+
return self._state_adc_observer
|
|
136
|
+
|
|
137
|
+
def partition(self, partition_id: str) -> QolsysPartition | None:
|
|
91
138
|
for partition in self.partitions:
|
|
92
139
|
if partition.id == partition_id:
|
|
93
140
|
return partition
|
|
@@ -97,8 +144,11 @@ class QolsysState(QolsysObservable):
|
|
|
97
144
|
def partition_add(self, new_partition: QolsysPartition) -> None:
|
|
98
145
|
for partition in self.partitions:
|
|
99
146
|
if new_partition.id == partition.id:
|
|
100
|
-
LOGGER.debug(
|
|
101
|
-
|
|
147
|
+
LOGGER.debug(
|
|
148
|
+
"Adding Partition to State, Partition%s (%s) - Allready in Partitions List",
|
|
149
|
+
new_partition.id,
|
|
150
|
+
partition.name,
|
|
151
|
+
)
|
|
102
152
|
return
|
|
103
153
|
|
|
104
154
|
self.partitions.append(new_partition)
|
|
@@ -115,7 +165,7 @@ class QolsysState(QolsysObservable):
|
|
|
115
165
|
self.partitions.remove(partition)
|
|
116
166
|
self.state_partition_observer.notify()
|
|
117
167
|
|
|
118
|
-
def scene(self, scene_id: str) -> QolsysScene:
|
|
168
|
+
def scene(self, scene_id: str) -> QolsysScene | None:
|
|
119
169
|
for scene in self.scenes:
|
|
120
170
|
if scene.scene_id == scene_id:
|
|
121
171
|
return scene
|
|
@@ -125,7 +175,7 @@ class QolsysState(QolsysObservable):
|
|
|
125
175
|
def scene_add(self, new_scene: QolsysScene) -> None:
|
|
126
176
|
for scene in self.scenes:
|
|
127
177
|
if new_scene.scene_id == scene.scene_id:
|
|
128
|
-
LOGGER.debug("Adding Scene to State, Scene%s (%s) - Allready in Scene List", new_scene.scene_id, scene.name
|
|
178
|
+
LOGGER.debug("Adding Scene to State, Scene%s (%s) - Allready in Scene List", new_scene.scene_id, scene.name)
|
|
129
179
|
return
|
|
130
180
|
|
|
131
181
|
self.scenes.append(new_scene)
|
|
@@ -143,7 +193,7 @@ class QolsysState(QolsysObservable):
|
|
|
143
193
|
self.scenes.remove(scene)
|
|
144
194
|
self.state_scene_observer.notify()
|
|
145
195
|
|
|
146
|
-
def zone(self, zone_id: str) -> QolsysZone:
|
|
196
|
+
def zone(self, zone_id: str) -> QolsysZone | None:
|
|
147
197
|
for zone in self.zones:
|
|
148
198
|
if zone.zone_id == zone_id:
|
|
149
199
|
return zone
|
|
@@ -151,14 +201,16 @@ class QolsysState(QolsysObservable):
|
|
|
151
201
|
|
|
152
202
|
def zone_from_short_id(self, short_id: int) -> QolsysZone | None:
|
|
153
203
|
for zone in self.zones:
|
|
154
|
-
if zone.shortID == short_id:
|
|
204
|
+
if zone.shortID == str(short_id):
|
|
155
205
|
return zone
|
|
156
206
|
return None
|
|
157
207
|
|
|
158
208
|
def zone_add(self, new_zone: QolsysZone) -> None:
|
|
159
209
|
for zone in self.zones:
|
|
160
210
|
if new_zone.zone_id == zone.zone_id:
|
|
161
|
-
LOGGER.debug(
|
|
211
|
+
LOGGER.debug(
|
|
212
|
+
"Adding Zone to State, zone%s (%s) - Allready in Zone List", new_zone.zone_id, new_zone.sensorname
|
|
213
|
+
)
|
|
162
214
|
return
|
|
163
215
|
|
|
164
216
|
self.zones.append(new_zone)
|
|
@@ -175,18 +227,24 @@ class QolsysState(QolsysObservable):
|
|
|
175
227
|
self.zones.remove(zone)
|
|
176
228
|
self.state_zone_observer.notify()
|
|
177
229
|
|
|
178
|
-
def zwave_device(self, node_id: str) -> QolsysZWaveDevice:
|
|
230
|
+
def zwave_device(self, node_id: str) -> QolsysZWaveDevice | None:
|
|
179
231
|
for zwave_device in self.zwave_devices:
|
|
180
232
|
if zwave_device.node_id == node_id:
|
|
181
233
|
return zwave_device
|
|
234
|
+
return None
|
|
182
235
|
|
|
236
|
+
def zwave_thermostat(self, node_id: str) -> QolsysThermostat | None:
|
|
237
|
+
thermostat = self.zwave_device(node_id)
|
|
238
|
+
if isinstance(thermostat, QolsysThermostat):
|
|
239
|
+
return thermostat
|
|
183
240
|
return None
|
|
184
241
|
|
|
185
242
|
def zwave_add(self, new_zwave: QolsysZWaveDevice) -> None:
|
|
186
243
|
for zwave_device in self.zwave_devices:
|
|
187
244
|
if new_zwave.node_id == zwave_device.node_id:
|
|
188
|
-
LOGGER.debug(
|
|
189
|
-
|
|
245
|
+
LOGGER.debug(
|
|
246
|
+
"Adding ZWave to State, ZWave%s (%s) - Allready in ZWave List", new_zwave.node_id, zwave_device.node_name
|
|
247
|
+
)
|
|
190
248
|
return
|
|
191
249
|
|
|
192
250
|
self.zwave_devices.append(new_zwave)
|
|
@@ -203,8 +261,62 @@ class QolsysState(QolsysObservable):
|
|
|
203
261
|
self.zwave_devices.remove(zwave)
|
|
204
262
|
self.state_zwave_observer.notify()
|
|
205
263
|
|
|
206
|
-
def
|
|
264
|
+
def adc_device(self, device_id: str) -> QolsysAdcDevice | None:
|
|
265
|
+
for adc_device in self.adc_devices:
|
|
266
|
+
if adc_device.device_id == device_id:
|
|
267
|
+
return adc_device
|
|
268
|
+
return None
|
|
207
269
|
|
|
270
|
+
def adc_add(self, new_adc: QolsysAdcDevice) -> None:
|
|
271
|
+
for adc_device in self.adc_devices:
|
|
272
|
+
if new_adc.device_id == adc_device.device_id:
|
|
273
|
+
LOGGER.debug("Adding ADC to State, ADC%s (%s) - Allready in ADC List", new_adc.device_id, new_adc.name)
|
|
274
|
+
return
|
|
275
|
+
|
|
276
|
+
self.adc_devices.append(new_adc)
|
|
277
|
+
self.adc_devices.sort(key=lambda x: x.device_id, reverse=False)
|
|
278
|
+
self.state_adc_observer.notify()
|
|
279
|
+
|
|
280
|
+
def adc_delete(self, device_id: str) -> None:
|
|
281
|
+
adc = self.adc_device(device_id)
|
|
282
|
+
|
|
283
|
+
if adc is None:
|
|
284
|
+
LOGGER.debug("Deleting ADC from State, ADC%s not found", device_id)
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
self.adc_devices.remove(adc)
|
|
288
|
+
self.state_adc_observer.notify()
|
|
289
|
+
|
|
290
|
+
def sync_adc_devices_data(self, db_adcs: list[QolsysAdcDevice]) -> None:
|
|
291
|
+
db_adc_list = []
|
|
292
|
+
for db_adc in db_adcs:
|
|
293
|
+
db_adc_list.append(db_adc.device_id)
|
|
294
|
+
|
|
295
|
+
state_adc_list = []
|
|
296
|
+
for state_adc in self.adc_devices:
|
|
297
|
+
state_adc_list.append(state_adc.device_id)
|
|
298
|
+
|
|
299
|
+
# Update existing ADC devices
|
|
300
|
+
for state_adc in self.adc_devices:
|
|
301
|
+
if state_adc.device_id in db_adc_list:
|
|
302
|
+
for db_adc in db_adcs:
|
|
303
|
+
if state_adc.device_id == db_adc.device_id:
|
|
304
|
+
LOGGER.debug("sync_data - update ADC%s", state_adc.device_id)
|
|
305
|
+
state_adc.update_adc_device(db_adc.to_dict_adc())
|
|
306
|
+
|
|
307
|
+
# Add new ADC devices
|
|
308
|
+
for db_adc in db_adcs:
|
|
309
|
+
if db_adc.device_id not in state_adc_list:
|
|
310
|
+
LOGGER.debug("sync_data - add ADC%s", db_adc.device_id)
|
|
311
|
+
self.adc_add(db_adc)
|
|
312
|
+
|
|
313
|
+
# Delete ADC device
|
|
314
|
+
for state_adc in self.adc_devices:
|
|
315
|
+
if state_adc.device_id not in db_adc_list:
|
|
316
|
+
LOGGER.debug("sync_data - delete ADC%s", state_adc.device_id)
|
|
317
|
+
self.adc_delete(state_adc.device_id)
|
|
318
|
+
|
|
319
|
+
def sync_zwave_devices_data(self, db_zwaves: list[QolsysZWaveDevice]) -> None: # noqa: PLR0912
|
|
208
320
|
db_zwave_list = []
|
|
209
321
|
for db_zwave in db_zwaves:
|
|
210
322
|
db_zwave_list.append(db_zwave.node_id)
|
|
@@ -229,13 +341,18 @@ class QolsysState(QolsysObservable):
|
|
|
229
341
|
# Update Thermostat
|
|
230
342
|
if isinstance(state_zwave, QolsysThermostat) and isinstance(db_zwave, QolsysThermostat):
|
|
231
343
|
state_zwave.update_base(db_zwave.to_dict_base())
|
|
232
|
-
state_zwave.update_thermostat(db_zwave.to_dict_thermostat)
|
|
344
|
+
state_zwave.update_thermostat(db_zwave.to_dict_thermostat())
|
|
233
345
|
break
|
|
234
346
|
|
|
235
347
|
# Update Lock
|
|
236
348
|
if isinstance(state_zwave, QolsysLock) and isinstance(db_zwave, QolsysLock):
|
|
237
349
|
state_zwave.update_base(db_zwave.to_dict_base())
|
|
238
|
-
state_zwave.update_lock(db_zwave.to_dict_lock)
|
|
350
|
+
state_zwave.update_lock(db_zwave.to_dict_lock())
|
|
351
|
+
break
|
|
352
|
+
|
|
353
|
+
# Update Energy Clamp
|
|
354
|
+
if isinstance(state_zwave, QolsysEnergyClamp) and isinstance(db_zwave, QolsysEnergyClamp):
|
|
355
|
+
state_zwave.update_base(db_zwave.to_dict_base())
|
|
239
356
|
break
|
|
240
357
|
|
|
241
358
|
# Generic Z-Wave Device
|
|
@@ -243,10 +360,6 @@ class QolsysState(QolsysObservable):
|
|
|
243
360
|
state_zwave.update_base(db_zwave.to_dict_base())
|
|
244
361
|
break
|
|
245
362
|
|
|
246
|
-
# zwave node_id has changed of node_type, delete and add again
|
|
247
|
-
# self.zwave_delete(int(state_zwave.node_id))
|
|
248
|
-
# self.zwave_add(db_zwave)
|
|
249
|
-
|
|
250
363
|
# Add new zwave device
|
|
251
364
|
for db_zwave in db_zwaves:
|
|
252
365
|
if db_zwave.node_id not in state_zwave_list:
|
|
@@ -256,9 +369,13 @@ class QolsysState(QolsysObservable):
|
|
|
256
369
|
# Delete zwave device
|
|
257
370
|
for state_zwave in self.zwave_devices:
|
|
258
371
|
if state_zwave.node_id not in db_zwave_list:
|
|
259
|
-
LOGGER.debug("sync_data - delete ZWave%s", state_zwave.
|
|
372
|
+
LOGGER.debug("sync_data - delete ZWave%s", state_zwave.node_id)
|
|
260
373
|
self.zwave_delete(state_zwave.node_id)
|
|
261
374
|
|
|
375
|
+
def sync_weather_data(self, db_weather: QolsysWeather) -> None:
|
|
376
|
+
LOGGER.debug("sync_data - update Weather")
|
|
377
|
+
self._weather.update(db_weather.forecasts)
|
|
378
|
+
|
|
262
379
|
def sync_scenes_data(self, db_scenes: list[QolsysScene]) -> None:
|
|
263
380
|
db_scene_list = []
|
|
264
381
|
for db_scene in db_scenes:
|
|
@@ -351,8 +468,31 @@ class QolsysState(QolsysObservable):
|
|
|
351
468
|
LOGGER.debug("sync_data - Add Partition%s", db_partition.id)
|
|
352
469
|
self.partition_add(db_partition)
|
|
353
470
|
|
|
354
|
-
def dump(self) -> None: # noqa: PLR0915
|
|
355
|
-
LOGGER.debug("*** Information ***")
|
|
471
|
+
def dump(self) -> None: # noqa: PLR0912, PLR0915
|
|
472
|
+
LOGGER.debug("*** Device Information ***")
|
|
473
|
+
|
|
474
|
+
def dump_meter(self: QolsysState, device: QolsysZWaveDevice) -> None:
|
|
475
|
+
for endpoint in device.meter_endpoints:
|
|
476
|
+
for meter_sensor in endpoint.sensors:
|
|
477
|
+
LOGGER.debug(
|
|
478
|
+
" Meter%s Endpoint%s - %s - value: %.2f (%s)",
|
|
479
|
+
device.node_id,
|
|
480
|
+
endpoint.endpoint,
|
|
481
|
+
endpoint._meter_type.name,
|
|
482
|
+
meter_sensor.value,
|
|
483
|
+
meter_sensor.scale.name,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
def dump_multilevelsensor(self: QolsysState, device: QolsysZWaveDevice) -> None:
|
|
487
|
+
for endpoint in device.multilevelsensor_endpoints:
|
|
488
|
+
for sensor in endpoint.sensors:
|
|
489
|
+
LOGGER.debug(
|
|
490
|
+
" Multilevelsensor%s Endpoint%s - value: %.2f (%s)",
|
|
491
|
+
device.node_id,
|
|
492
|
+
endpoint.endpoint,
|
|
493
|
+
sensor.value,
|
|
494
|
+
sensor.unit.name,
|
|
495
|
+
)
|
|
356
496
|
|
|
357
497
|
for partition in self.partitions:
|
|
358
498
|
pid = partition.id
|
|
@@ -394,6 +534,8 @@ class QolsysState(QolsysObservable):
|
|
|
394
534
|
LOGGER.debug("Dimmer%s (%s) - node_status: %s", nid, name, zwave.node_status)
|
|
395
535
|
LOGGER.debug("Dimmer%s (%s) - battery_level: %s", nid, name, zwave.node_battery_level)
|
|
396
536
|
LOGGER.debug("Dimmer%s (%s) - battery_level_value: %s", nid, name, zwave.node_battery_level_value)
|
|
537
|
+
dump_meter(self, zwave)
|
|
538
|
+
dump_multilevelsensor(self, zwave)
|
|
397
539
|
continue
|
|
398
540
|
|
|
399
541
|
if isinstance(zwave, QolsysThermostat):
|
|
@@ -406,12 +548,32 @@ class QolsysState(QolsysObservable):
|
|
|
406
548
|
LOGGER.debug("Thermostat%s (%s) - target_cool_temp: %s", zid, name, zwave.thermostat_target_cool_temp)
|
|
407
549
|
LOGGER.debug("Thermostat%s (%s) - target_heat_temp: %s", zid, name, zwave.thermostat_target_heat_temp)
|
|
408
550
|
LOGGER.debug("Thermostat%s (%s) - set_point_mode: %s", zid, name, zwave.thermostat_set_point_mode)
|
|
551
|
+
dump_meter(self, zwave)
|
|
552
|
+
dump_multilevelsensor(self, zwave)
|
|
409
553
|
continue
|
|
410
554
|
|
|
411
555
|
if isinstance(zwave, QolsysLock):
|
|
412
556
|
zid = zwave.lock_node_id
|
|
413
557
|
name = zwave.lock_name
|
|
414
|
-
LOGGER.debug("Lock%s (%s) -
|
|
558
|
+
LOGGER.debug("Lock%s (%s) - lock_status: %s", zid, name, zwave.lock_status)
|
|
559
|
+
dump_meter(self, zwave)
|
|
560
|
+
dump_multilevelsensor(self, zwave)
|
|
561
|
+
continue
|
|
562
|
+
|
|
563
|
+
if isinstance(zwave, QolsysEnergyClamp):
|
|
564
|
+
nid = zwave.node_id
|
|
565
|
+
name = zwave.node_name
|
|
566
|
+
LOGGER.debug("EnergyClamp%s (%s)", nid, name)
|
|
567
|
+
dump_meter(self, zwave)
|
|
568
|
+
dump_multilevelsensor(self, zwave)
|
|
569
|
+
continue
|
|
570
|
+
|
|
571
|
+
if isinstance(zwave, QolsysThermometer):
|
|
572
|
+
nid = zwave.node_id
|
|
573
|
+
name = zwave.node_name
|
|
574
|
+
LOGGER.debug("Thermometer%s (%s)", nid, name)
|
|
575
|
+
dump_meter(self, zwave)
|
|
576
|
+
dump_multilevelsensor(self, zwave)
|
|
415
577
|
continue
|
|
416
578
|
|
|
417
579
|
if isinstance(zwave, QolsysGeneric):
|
|
@@ -421,9 +583,34 @@ class QolsysState(QolsysObservable):
|
|
|
421
583
|
LOGGER.debug("Generic%s (%s) - status: %s", zid, name, zwave.node_status)
|
|
422
584
|
LOGGER.debug("Generic%s (%s) - battery_level: %s", zid, name, zwave.node_battery_level)
|
|
423
585
|
LOGGER.debug("Generic%s (%s) - battery_level_vale: %s", zid, name, zwave.node_battery_level_value)
|
|
586
|
+
dump_meter(self, zwave)
|
|
587
|
+
dump_multilevelsensor(self, zwave)
|
|
424
588
|
continue
|
|
425
589
|
|
|
590
|
+
LOGGER.debug("Other Z-Wave devices information")
|
|
591
|
+
LOGGER.debug(self.zwave_other_devices)
|
|
592
|
+
|
|
593
|
+
for adc in self.adc_devices:
|
|
594
|
+
for service in adc.services:
|
|
595
|
+
if isinstance(service, QolsysAdcGarageDoorService):
|
|
596
|
+
LOGGER.debug(
|
|
597
|
+
"ADC%s GarageDoor%s (%s) - state: %s", adc.device_id, service.id, adc.name, service.func_state
|
|
598
|
+
)
|
|
599
|
+
continue
|
|
600
|
+
|
|
601
|
+
if isinstance(service, QolsysAdcService):
|
|
602
|
+
LOGGER.debug("ADC%s Service%s (%s) - state: %s", adc.device_id, service.id, adc.name, service.func_state)
|
|
603
|
+
|
|
426
604
|
for scene in self.scenes:
|
|
427
605
|
sid = scene.scene_id
|
|
428
606
|
name = scene.name
|
|
429
|
-
LOGGER.debug("Scene%s (%s)",sid, name)
|
|
607
|
+
LOGGER.debug("Scene%s (%s)", sid, name)
|
|
608
|
+
|
|
609
|
+
for forecast in self.weather.forecasts:
|
|
610
|
+
LOGGER.debug(
|
|
611
|
+
"Weather - %s - High: %s, Low:%s, Condition: %s",
|
|
612
|
+
forecast.day_of_week[0:3],
|
|
613
|
+
forecast.high_temp,
|
|
614
|
+
forecast.low_temp,
|
|
615
|
+
forecast.condition,
|
|
616
|
+
)
|
|
@@ -7,32 +7,32 @@ LOGGER = logging.getLogger(__name__)
|
|
|
7
7
|
|
|
8
8
|
class QolsysTaskManager:
|
|
9
9
|
def __init__(self) -> None:
|
|
10
|
-
self._tasks = set()
|
|
10
|
+
self._tasks: set[asyncio.Task] = set() # type: ignore[type-arg]
|
|
11
11
|
|
|
12
|
-
def run(self, coro: Coroutine, label: str) -> asyncio.Task:
|
|
12
|
+
def run(self, coro: Coroutine, label: str) -> asyncio.Task: # type: ignore[type-arg]
|
|
13
13
|
task = asyncio.create_task(coro, name=label)
|
|
14
14
|
self._tasks.add(task)
|
|
15
15
|
|
|
16
|
-
def _done_callback(task: asyncio.Task) -> None:
|
|
17
|
-
|
|
16
|
+
def _done_callback(task: asyncio.Task) -> None: # type: ignore[type-arg]
|
|
18
17
|
try:
|
|
19
18
|
task.result()
|
|
20
19
|
|
|
21
20
|
except asyncio.CancelledError:
|
|
22
|
-
LOGGER.debug("Task Cancelled: %s",task.get_name())
|
|
21
|
+
LOGGER.debug("Task Cancelled: %s", task.get_name())
|
|
23
22
|
|
|
24
|
-
except Exception
|
|
25
|
-
LOGGER.
|
|
23
|
+
except Exception: # noqa: BLE001
|
|
24
|
+
LOGGER.exception("[Callback] Task failed: %s", task.get_name())
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
finally:
|
|
27
|
+
self._tasks.discard(task)
|
|
28
28
|
|
|
29
29
|
task.add_done_callback(_done_callback)
|
|
30
30
|
return task
|
|
31
31
|
|
|
32
|
-
def get_task(self, label:str) -> asyncio.Task | None:
|
|
32
|
+
def get_task(self, label: str) -> asyncio.Task | None: # type: ignore[type-arg]
|
|
33
33
|
for task in self._tasks:
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
if task.get_name() == label:
|
|
35
|
+
return task
|
|
36
36
|
return None
|
|
37
37
|
|
|
38
38
|
def cancel(self, label: str) -> None:
|
|
@@ -49,9 +49,6 @@ class QolsysTaskManager:
|
|
|
49
49
|
if self._tasks:
|
|
50
50
|
await asyncio.gather(*self._tasks, return_exceptions=True)
|
|
51
51
|
|
|
52
|
-
def pending(self) -> None:
|
|
53
|
-
return {t for t in self._tasks if not t.done()}
|
|
54
|
-
|
|
55
52
|
def dump(self) -> None:
|
|
56
53
|
for task in self._tasks:
|
|
57
54
|
LOGGER.debug("Task: %s, Done: %s, Cancelled: %s", task.get_name(), task.done(), task.cancelled())
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
LOGGER = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class QolsysUser:
|
|
7
|
+
def __init__(self) -> None:
|
|
8
|
+
self._id: int = 0
|
|
9
|
+
self._user_code = ""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def id(self) -> int:
|
|
13
|
+
return self._id
|
|
14
|
+
|
|
15
|
+
@id.setter
|
|
16
|
+
def id(self, value: int) -> None:
|
|
17
|
+
self._id = value
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def user_code(self) -> str:
|
|
21
|
+
return self._user_code
|
|
22
|
+
|
|
23
|
+
@user_code.setter
|
|
24
|
+
def user_code(self, value: str) -> None:
|
|
25
|
+
self._user_code = value
|
qolsys_controller/utils_mqtt.py
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import random
|
|
3
|
-
import re
|
|
4
3
|
|
|
5
4
|
LOGGER = logging.getLogger(__name__)
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
def
|
|
9
|
-
def replace_escape(match):
|
|
10
|
-
hex_value = match.group(1)
|
|
11
|
-
decimal_value = int(hex_value, 16)
|
|
12
|
-
return f"\\u{decimal_value:04x}"
|
|
13
|
-
|
|
14
|
-
return re.sub(r"\\x([0-9a-fA-F]{2})", replace_escape, json_string)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def generate_random_mac() -> str:
|
|
7
|
+
def generate_random_mac() -> str: # noqa: D103
|
|
18
8
|
mac = [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
random.randint(0x00,
|
|
9
|
+
0xF2,
|
|
10
|
+
0x16,
|
|
11
|
+
0x3E,
|
|
12
|
+
random.randint(0x00, 0x7F),
|
|
13
|
+
random.randint(0x00, 0xFF),
|
|
14
|
+
random.randint(0x00, 0xFF),
|
|
23
15
|
]
|
|
24
|
-
return ":".join(map(lambda x: "%02x" % x, mac))
|
|
16
|
+
return ":".join(map(lambda x: "%02x" % x, mac)) # noqa: C417, UP031
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .observable import QolsysObservable
|
|
4
|
+
|
|
5
|
+
LOGGER = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QolsysForecast:
|
|
9
|
+
def __init__(self, data: dict[str, str]) -> None:
|
|
10
|
+
self._high_temp: str = data.get("high_temp", "")
|
|
11
|
+
self._low_temp: str = data.get("low_temp", "")
|
|
12
|
+
self._day_of_week: str = data.get("day_of_week", "")
|
|
13
|
+
self._condition: str = data.get("condition", "")
|
|
14
|
+
self._icon: str = data.get("icon", "")
|
|
15
|
+
self._precipitation: str = data.get("precipitation", "")
|
|
16
|
+
self._current_weather_date: str = data.get("current_weather_date", "")
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def high_temp(self) -> float | None:
|
|
20
|
+
try:
|
|
21
|
+
return float(self._high_temp)
|
|
22
|
+
except ValueError:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def low_temp(self) -> float | None:
|
|
27
|
+
try:
|
|
28
|
+
return float(self._low_temp)
|
|
29
|
+
except ValueError:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def day_of_week(self) -> str:
|
|
34
|
+
return self._day_of_week
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def condition(self) -> str:
|
|
38
|
+
return self._condition
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def precipitation(self) -> int | None:
|
|
42
|
+
try:
|
|
43
|
+
return int(self._precipitation)
|
|
44
|
+
except ValueError:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def current_weather_date(self) -> str:
|
|
49
|
+
return self._current_weather_date
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class QolsysWeather(QolsysObservable):
|
|
53
|
+
def __init__(self) -> None:
|
|
54
|
+
super().__init__()
|
|
55
|
+
self._forecasts: list[QolsysForecast] = []
|
|
56
|
+
|
|
57
|
+
def current_weather(self) -> QolsysForecast | None:
|
|
58
|
+
if self._forecasts:
|
|
59
|
+
return self._forecasts[0]
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def update(self, data: list[QolsysForecast]) -> None:
|
|
63
|
+
self._forecasts.clear()
|
|
64
|
+
for forecast_data in data:
|
|
65
|
+
self._forecasts.append(forecast_data)
|
|
66
|
+
|
|
67
|
+
self.notify()
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def forecasts(self) -> list[QolsysForecast]:
|
|
71
|
+
return self._forecasts
|