qolsys-controller 0.0.62__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 +245 -34
- qolsys_controller/database/db.py +60 -0
- qolsys_controller/database/table.py +1 -0
- qolsys_controller/database/table_alarmedsensor.py +2 -0
- qolsys_controller/database/table_history.py +2 -2
- qolsys_controller/database/table_smartsocket.py +12 -1
- qolsys_controller/database/table_thermostat.py +3 -0
- qolsys_controller/database/table_virtual_device.py +13 -1
- qolsys_controller/database/table_zwave_node.py +3 -0
- qolsys_controller/enum.py +5 -1
- qolsys_controller/enum_adc.py +28 -0
- qolsys_controller/enum_zwave.py +158 -29
- qolsys_controller/errors.py +5 -0
- qolsys_controller/mqtt_command.py +6 -0
- qolsys_controller/panel.py +109 -5
- qolsys_controller/partition.py +22 -2
- qolsys_controller/state.py +163 -1
- qolsys_controller/task_manager.py +4 -3
- qolsys_controller/zone.py +2 -1
- qolsys_controller/zwave_device.py +132 -4
- qolsys_controller/zwave_dimmer.py +3 -0
- qolsys_controller/zwave_energy_clamp.py +15 -0
- qolsys_controller/zwave_garagedoor.py +3 -0
- qolsys_controller/zwave_generic.py +3 -0
- qolsys_controller/zwave_lock.py +4 -0
- qolsys_controller/zwave_outlet.py +3 -0
- 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 +150 -38
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/METADATA +1 -1
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/RECORD +37 -29
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/WHEEL +0 -0
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/licenses/LICENSE +0 -0
qolsys_controller/state.py
CHANGED
|
@@ -3,6 +3,12 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
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
|
|
10
|
+
|
|
11
|
+
from .adc_device import QolsysAdcDevice
|
|
6
12
|
from .observable import QolsysObservable
|
|
7
13
|
from .weather import QolsysWeather
|
|
8
14
|
from .zwave_device import QolsysZWaveDevice
|
|
@@ -28,11 +34,14 @@ class QolsysState(QolsysObservable):
|
|
|
28
34
|
self._weather: QolsysWeather = QolsysWeather()
|
|
29
35
|
self._partitions: list[QolsysPartition] = []
|
|
30
36
|
self._zones: list[QolsysZone] = []
|
|
37
|
+
self._adc_devices: list[QolsysAdcDevice] = []
|
|
31
38
|
self._zwave_devices: list[QolsysZWaveDevice] = []
|
|
32
39
|
self._scenes: list[QolsysScene] = []
|
|
40
|
+
|
|
33
41
|
self._state_partition_observer = QolsysObservable()
|
|
34
42
|
self._state_zone_observer = QolsysObservable()
|
|
35
43
|
self._state_zwave_observer = QolsysObservable()
|
|
44
|
+
self._state_adc_observer = QolsysObservable()
|
|
36
45
|
self._state_scene_observer = QolsysObservable()
|
|
37
46
|
|
|
38
47
|
@property
|
|
@@ -43,6 +52,10 @@ class QolsysState(QolsysObservable):
|
|
|
43
52
|
def zwave_devices(self) -> list[QolsysZWaveDevice]:
|
|
44
53
|
return self._zwave_devices
|
|
45
54
|
|
|
55
|
+
@property
|
|
56
|
+
def adc_devices(self) -> list[QolsysAdcDevice]:
|
|
57
|
+
return self._adc_devices
|
|
58
|
+
|
|
46
59
|
@property
|
|
47
60
|
def zones(self) -> list[QolsysZone]:
|
|
48
61
|
return self._zones
|
|
@@ -79,9 +92,28 @@ class QolsysState(QolsysObservable):
|
|
|
79
92
|
for device in self.zwave_devices:
|
|
80
93
|
if isinstance(device, QolsysThermostat):
|
|
81
94
|
thermostats.append(device)
|
|
82
|
-
|
|
83
95
|
return thermostats
|
|
84
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
|
+
|
|
85
117
|
@property
|
|
86
118
|
def state_partition_observer(self) -> QolsysObservable:
|
|
87
119
|
return self._state_partition_observer
|
|
@@ -98,6 +130,10 @@ class QolsysState(QolsysObservable):
|
|
|
98
130
|
def state_scene_observer(self) -> QolsysObservable:
|
|
99
131
|
return self._state_scene_observer
|
|
100
132
|
|
|
133
|
+
@property
|
|
134
|
+
def state_adc_observer(self) -> QolsysObservable:
|
|
135
|
+
return self._state_adc_observer
|
|
136
|
+
|
|
101
137
|
def partition(self, partition_id: str) -> QolsysPartition | None:
|
|
102
138
|
for partition in self.partitions:
|
|
103
139
|
if partition.id == partition_id:
|
|
@@ -195,7 +231,12 @@ class QolsysState(QolsysObservable):
|
|
|
195
231
|
for zwave_device in self.zwave_devices:
|
|
196
232
|
if zwave_device.node_id == node_id:
|
|
197
233
|
return zwave_device
|
|
234
|
+
return None
|
|
198
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
|
|
199
240
|
return None
|
|
200
241
|
|
|
201
242
|
def zwave_add(self, new_zwave: QolsysZWaveDevice) -> None:
|
|
@@ -220,6 +261,61 @@ class QolsysState(QolsysObservable):
|
|
|
220
261
|
self.zwave_devices.remove(zwave)
|
|
221
262
|
self.state_zwave_observer.notify()
|
|
222
263
|
|
|
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
|
|
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
|
+
|
|
223
319
|
def sync_zwave_devices_data(self, db_zwaves: list[QolsysZWaveDevice]) -> None: # noqa: PLR0912
|
|
224
320
|
db_zwave_list = []
|
|
225
321
|
for db_zwave in db_zwaves:
|
|
@@ -254,6 +350,11 @@ class QolsysState(QolsysObservable):
|
|
|
254
350
|
state_zwave.update_lock(db_zwave.to_dict_lock())
|
|
255
351
|
break
|
|
256
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())
|
|
356
|
+
break
|
|
357
|
+
|
|
257
358
|
# Generic Z-Wave Device
|
|
258
359
|
if isinstance(state_zwave, QolsysGeneric) and isinstance(db_zwave, QolsysGeneric):
|
|
259
360
|
state_zwave.update_base(db_zwave.to_dict_base())
|
|
@@ -370,6 +471,29 @@ class QolsysState(QolsysObservable):
|
|
|
370
471
|
def dump(self) -> None: # noqa: PLR0912, PLR0915
|
|
371
472
|
LOGGER.debug("*** Device Information ***")
|
|
372
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
|
+
)
|
|
496
|
+
|
|
373
497
|
for partition in self.partitions:
|
|
374
498
|
pid = partition.id
|
|
375
499
|
name = partition.name
|
|
@@ -410,6 +534,8 @@ class QolsysState(QolsysObservable):
|
|
|
410
534
|
LOGGER.debug("Dimmer%s (%s) - node_status: %s", nid, name, zwave.node_status)
|
|
411
535
|
LOGGER.debug("Dimmer%s (%s) - battery_level: %s", nid, name, zwave.node_battery_level)
|
|
412
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)
|
|
413
539
|
continue
|
|
414
540
|
|
|
415
541
|
if isinstance(zwave, QolsysThermostat):
|
|
@@ -422,12 +548,32 @@ class QolsysState(QolsysObservable):
|
|
|
422
548
|
LOGGER.debug("Thermostat%s (%s) - target_cool_temp: %s", zid, name, zwave.thermostat_target_cool_temp)
|
|
423
549
|
LOGGER.debug("Thermostat%s (%s) - target_heat_temp: %s", zid, name, zwave.thermostat_target_heat_temp)
|
|
424
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)
|
|
425
553
|
continue
|
|
426
554
|
|
|
427
555
|
if isinstance(zwave, QolsysLock):
|
|
428
556
|
zid = zwave.lock_node_id
|
|
429
557
|
name = zwave.lock_name
|
|
430
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)
|
|
431
577
|
continue
|
|
432
578
|
|
|
433
579
|
if isinstance(zwave, QolsysGeneric):
|
|
@@ -437,8 +583,24 @@ class QolsysState(QolsysObservable):
|
|
|
437
583
|
LOGGER.debug("Generic%s (%s) - status: %s", zid, name, zwave.node_status)
|
|
438
584
|
LOGGER.debug("Generic%s (%s) - battery_level: %s", zid, name, zwave.node_battery_level)
|
|
439
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)
|
|
440
588
|
continue
|
|
441
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
|
+
|
|
442
604
|
for scene in self.scenes:
|
|
443
605
|
sid = scene.scene_id
|
|
444
606
|
name = scene.name
|
|
@@ -20,10 +20,11 @@ class QolsysTaskManager:
|
|
|
20
20
|
except asyncio.CancelledError:
|
|
21
21
|
LOGGER.debug("Task Cancelled: %s", task.get_name())
|
|
22
22
|
|
|
23
|
-
except Exception
|
|
24
|
-
LOGGER.
|
|
23
|
+
except Exception: # noqa: BLE001
|
|
24
|
+
LOGGER.exception("[Callback] Task failed: %s", task.get_name())
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
finally:
|
|
27
|
+
self._tasks.discard(task)
|
|
27
28
|
|
|
28
29
|
task.add_done_callback(_done_callback)
|
|
29
30
|
return task
|
qolsys_controller/zone.py
CHANGED
|
@@ -391,7 +391,8 @@ class QolsysZone(QolsysObservable):
|
|
|
391
391
|
@property
|
|
392
392
|
def powerg_temperature(self) -> float | None:
|
|
393
393
|
try:
|
|
394
|
-
|
|
394
|
+
temp = float(self._powerg_temperature)
|
|
395
|
+
return round(temp, 1)
|
|
395
396
|
except ValueError:
|
|
396
397
|
return None
|
|
397
398
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
|
|
3
|
-
from .
|
|
4
|
+
from qolsys_controller.zwave_service_meter import QolsysZwaveServiceMeter
|
|
5
|
+
from qolsys_controller.zwave_service_multilevelsensor import QolsysZwaveMultilevelSensor, QolsysZwaveServiceMultilevelSensor
|
|
6
|
+
|
|
7
|
+
from .enum_zwave import ZwaveDeviceClass, ZWaveMultilevelSensorScale
|
|
4
8
|
from .observable import QolsysObservable
|
|
5
9
|
|
|
6
10
|
LOGGER = logging.getLogger(__name__)
|
|
@@ -35,6 +39,19 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
35
39
|
self._is_device_hidden: str = zwave_dict.get("is_device_hidden", "")
|
|
36
40
|
self._last_updated_date: str = zwave_dict.get("last_updated_date", "")
|
|
37
41
|
self._command_class_list: str = zwave_dict.get("command_class_list", "")
|
|
42
|
+
self._meter_capabilities: str = ""
|
|
43
|
+
self._multisensor_capabilities: str = ""
|
|
44
|
+
self._notification_capabilities = zwave_dict.get("notification_capabilities", "")
|
|
45
|
+
self._multi_channel_details = zwave_dict.get("multi_channel_details", "")
|
|
46
|
+
|
|
47
|
+
# Set Meter and MutilevelSensor Services if available
|
|
48
|
+
self._meter_endpoints: list[QolsysZwaveServiceMeter] = []
|
|
49
|
+
self._multilevelsensor_endpoints: list[QolsysZwaveServiceMultilevelSensor] = []
|
|
50
|
+
self.meter_capabilities = zwave_dict.get("meter_capabilities", "")
|
|
51
|
+
self.multisensor_capabilities = zwave_dict.get("multisensor_capabilities", "")
|
|
52
|
+
|
|
53
|
+
def update_raw(self, payload: bytes) -> None:
|
|
54
|
+
LOGGER.debug("Raw Update (node%s) - payload: %s", self.node_id, payload.hex())
|
|
38
55
|
|
|
39
56
|
def update_base(self, data: dict[str, str]) -> None: # noqa: C901, PLR0912, PLR0915
|
|
40
57
|
# Check if we are updating same node_id
|
|
@@ -98,6 +115,14 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
98
115
|
self._last_updated_date = data.get("last_updated_date", "")
|
|
99
116
|
if "command_class_list" in data:
|
|
100
117
|
self._last_updated_date = data.get("command_class_list", "")
|
|
118
|
+
if "multisensor_capabilities" in data:
|
|
119
|
+
self.multisensor_capabilities = data.get("multisensor_capabilities", "")
|
|
120
|
+
if "meter_capabilities" in data:
|
|
121
|
+
self.meter_capabilities = data.get("meter_capabilities", "")
|
|
122
|
+
if "notification_capabilities" in data:
|
|
123
|
+
self._notification_capabilities = data.get("notification_capabilities", "")
|
|
124
|
+
if "multi_channel_details" in data:
|
|
125
|
+
self._multi_channel_details = data.get("multi_channel_details", "")
|
|
101
126
|
|
|
102
127
|
self.end_batch_update()
|
|
103
128
|
|
|
@@ -136,8 +161,82 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
136
161
|
self.notify()
|
|
137
162
|
|
|
138
163
|
@property
|
|
139
|
-
def
|
|
140
|
-
return self.
|
|
164
|
+
def meter_capabilities(self) -> str:
|
|
165
|
+
return self._meter_capabilities
|
|
166
|
+
|
|
167
|
+
@meter_capabilities.setter
|
|
168
|
+
def meter_capabilities(self, value: str) -> None:
|
|
169
|
+
if self._meter_capabilities != value:
|
|
170
|
+
self._meter_capabilities = value
|
|
171
|
+
|
|
172
|
+
# Update Meter Service
|
|
173
|
+
try:
|
|
174
|
+
meter_services = json.loads(value)
|
|
175
|
+
for endpoint, service in meter_services.items():
|
|
176
|
+
# Check if we already have this meter service
|
|
177
|
+
meter_endpoint = None
|
|
178
|
+
for meter in self._meter_endpoints:
|
|
179
|
+
if meter.endpoint == endpoint:
|
|
180
|
+
meter_endpoint = meter
|
|
181
|
+
meter_endpoint.update_iq2medi(service)
|
|
182
|
+
break
|
|
183
|
+
|
|
184
|
+
# Create new meter service if not found
|
|
185
|
+
if meter_endpoint is None:
|
|
186
|
+
LOGGER.debug("ZWave%s (%s) - Adding new meter endpoint: %s", self.node_id, self.node_name, endpoint)
|
|
187
|
+
meter_endpoint = QolsysZwaveServiceMeter(self, endpoint, service)
|
|
188
|
+
self._meter_endpoints.append(meter_endpoint)
|
|
189
|
+
|
|
190
|
+
except json.JSONDecodeError:
|
|
191
|
+
LOGGER.error("ZWave%s (%s) - Error parsing meter_capabilities:%s", self.node_id, self.node_name, value)
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def multisensor_capabilities(self) -> str:
|
|
196
|
+
return self._multisensor_capabilities
|
|
197
|
+
|
|
198
|
+
@multisensor_capabilities.setter
|
|
199
|
+
def multisensor_capabilities(self, value: str) -> None:
|
|
200
|
+
if self._multisensor_capabilities != value:
|
|
201
|
+
self._multisensor_capabilities = value
|
|
202
|
+
|
|
203
|
+
# Update Multilevel Sensor Service
|
|
204
|
+
try:
|
|
205
|
+
sensor_services = json.loads(value)
|
|
206
|
+
for endpoint, service in sensor_services.items():
|
|
207
|
+
# Check if we already have this meter service
|
|
208
|
+
sensor_endpoint = None
|
|
209
|
+
for sensor in self._multilevelsensor_endpoints:
|
|
210
|
+
if sensor.endpoint == endpoint:
|
|
211
|
+
sensor_endpoint = sensor
|
|
212
|
+
sensor_endpoint.update_iq2medi(service)
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
# Create new meter service if not found
|
|
216
|
+
if sensor_endpoint is None:
|
|
217
|
+
LOGGER.debug(
|
|
218
|
+
"ZWave%s (%s) - Adding new multilevelsensor endpoint: %s", self.node_id, self.node_name, endpoint
|
|
219
|
+
)
|
|
220
|
+
sensor_endpoint = QolsysZwaveServiceMultilevelSensor(self, endpoint, service)
|
|
221
|
+
self.multilevelsensor_endpoints.append(sensor_endpoint)
|
|
222
|
+
|
|
223
|
+
except json.JSONDecodeError:
|
|
224
|
+
LOGGER.error(
|
|
225
|
+
"ZWave%s (%s) - Error parsing multilevelsensor_capabilities:%s", self.node_id, self.node_name, value
|
|
226
|
+
)
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def node_battery_level_value(self) -> int | None:
|
|
231
|
+
try:
|
|
232
|
+
value = int(self._node_battery_level_value)
|
|
233
|
+
if value >= 0 and value <= 100:
|
|
234
|
+
return value
|
|
235
|
+
else:
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
except ValueError:
|
|
239
|
+
return None
|
|
141
240
|
|
|
142
241
|
@node_battery_level_value.setter
|
|
143
242
|
def node_battery_level_value(self, value: str) -> None:
|
|
@@ -190,6 +289,14 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
190
289
|
self._partition_id = value
|
|
191
290
|
self.notify()
|
|
192
291
|
|
|
292
|
+
@property
|
|
293
|
+
def meter_endpoints(self) -> list[QolsysZwaveServiceMeter]:
|
|
294
|
+
return self._meter_endpoints
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def multilevelsensor_endpoints(self) -> list[QolsysZwaveServiceMultilevelSensor]:
|
|
298
|
+
return self._multilevelsensor_endpoints
|
|
299
|
+
|
|
193
300
|
@property
|
|
194
301
|
def generic_device_type(self) -> ZwaveDeviceClass:
|
|
195
302
|
try:
|
|
@@ -197,6 +304,23 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
197
304
|
except ValueError:
|
|
198
305
|
return ZwaveDeviceClass.Unknown
|
|
199
306
|
|
|
307
|
+
def is_battery_enabled(self) -> bool:
|
|
308
|
+
return self.node_battery_level_value is not None
|
|
309
|
+
|
|
310
|
+
def is_service_meter_enabled(self) -> bool:
|
|
311
|
+
return self._meter_endpoints != []
|
|
312
|
+
|
|
313
|
+
def is_service_multilevelsensor_enabled(self) -> bool:
|
|
314
|
+
return self._multilevelsensor_endpoints != []
|
|
315
|
+
|
|
316
|
+
def multilevelsensor_value(self, scale: ZWaveMultilevelSensorScale) -> list[QolsysZwaveMultilevelSensor]:
|
|
317
|
+
result: list[QolsysZwaveMultilevelSensor] = []
|
|
318
|
+
for endpoint in self.multilevelsensor_endpoints:
|
|
319
|
+
sensor = endpoint.get_sensor(scale)
|
|
320
|
+
if sensor is not None:
|
|
321
|
+
result.append(sensor)
|
|
322
|
+
return result
|
|
323
|
+
|
|
200
324
|
def to_dict_base(self) -> dict[str, str]:
|
|
201
325
|
return {
|
|
202
326
|
"_id": self._id,
|
|
@@ -206,7 +330,7 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
206
330
|
"node_status": self.node_status,
|
|
207
331
|
"partition_id": self._partition_id,
|
|
208
332
|
"node_battery_level": self.node_battery_level,
|
|
209
|
-
"node_battery_level_value": self.
|
|
333
|
+
"node_battery_level_value": self._node_battery_level_value,
|
|
210
334
|
"paired_status": self.paired_status,
|
|
211
335
|
"node_secure_cmd_cls": self._node_secure_cmd_cls,
|
|
212
336
|
"is_node_listening_node": self._is_node_listening_node,
|
|
@@ -224,4 +348,8 @@ class QolsysZWaveDevice(QolsysObservable):
|
|
|
224
348
|
"is_device_hidden": self._is_device_hidden,
|
|
225
349
|
"last_updated_date": self._last_updated_date,
|
|
226
350
|
"command_class_list": self._command_class_list,
|
|
351
|
+
"multisensor_capabilities": self.multisensor_capabilities,
|
|
352
|
+
"meter_capabilities": self.meter_capabilities,
|
|
353
|
+
"notification_capabilities": self._notification_capabilities,
|
|
354
|
+
"multi_channel_details": self._multi_channel_details,
|
|
227
355
|
}
|
|
@@ -69,6 +69,9 @@ class QolsysDimmer(QolsysZWaveDevice):
|
|
|
69
69
|
self._dimmer_level = value
|
|
70
70
|
self.notify()
|
|
71
71
|
|
|
72
|
+
def update_raw(self, payload: bytes) -> None:
|
|
73
|
+
pass
|
|
74
|
+
|
|
72
75
|
def update_dimmer(self, content_values: dict[str, str]) -> None: # noqa: PLR0912
|
|
73
76
|
# Check if we are updating same none_id
|
|
74
77
|
node_id_update = content_values.get("node_id", "")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .zwave_device import QolsysZWaveDevice
|
|
4
|
+
|
|
5
|
+
LOGGER = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QolsysEnergyClamp(QolsysZWaveDevice):
|
|
9
|
+
def __init__(self, zwave_dict: dict[str, str]) -> None:
|
|
10
|
+
super().__init__(zwave_dict)
|
|
11
|
+
|
|
12
|
+
# Energy clamp only enables meter seter in base zwave_device class
|
|
13
|
+
|
|
14
|
+
def update_raw(self, payload: bytes) -> None:
|
|
15
|
+
pass
|
|
@@ -8,3 +8,6 @@ LOGGER = logging.getLogger(__name__)
|
|
|
8
8
|
class QolsysGeneric(QolsysZWaveDevice):
|
|
9
9
|
def __init__(self, zwave_dict: dict[str, str]) -> None:
|
|
10
10
|
super().__init__(zwave_dict)
|
|
11
|
+
|
|
12
|
+
def update_raw(self, payload: bytes) -> None:
|
|
13
|
+
LOGGER.debug("Raw Update (node%s) - payload: %s", self.node_id, payload.hex())
|
qolsys_controller/zwave_lock.py
CHANGED
|
@@ -69,6 +69,9 @@ class QolsysLock(QolsysZWaveDevice):
|
|
|
69
69
|
self._lock_paired_status = value
|
|
70
70
|
self.notify()
|
|
71
71
|
|
|
72
|
+
def update_raw(self, payload: bytes) -> None:
|
|
73
|
+
pass
|
|
74
|
+
|
|
72
75
|
def update_lock(self, data: dict[str, str]) -> None: # noqa: PLR0912
|
|
73
76
|
# Check if we are updating same zoneid
|
|
74
77
|
node_id_update = data.get("node_id", "")
|
|
@@ -118,6 +121,7 @@ class QolsysLock(QolsysZWaveDevice):
|
|
|
118
121
|
"opr": self._lock_opr,
|
|
119
122
|
"partition_id": self._lock_partition_id,
|
|
120
123
|
"doorlock_name": self.lock_name,
|
|
124
|
+
"node_id": self.lock_node_id,
|
|
121
125
|
"status": self.lock_status,
|
|
122
126
|
"created_by": self._lock_created_by,
|
|
123
127
|
"created_date": self._lock_created_date,
|