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.

Files changed (81) hide show
  1. qolsys_controller/adc_device.py +202 -0
  2. qolsys_controller/adc_service.py +139 -0
  3. qolsys_controller/adc_service_garagedoor.py +35 -0
  4. qolsys_controller/controller.py +1040 -20
  5. qolsys_controller/database/db.py +108 -29
  6. qolsys_controller/database/table.py +90 -60
  7. qolsys_controller/database/table_alarmedsensor.py +2 -2
  8. qolsys_controller/database/table_automation.py +0 -1
  9. qolsys_controller/database/table_country_locale.py +0 -1
  10. qolsys_controller/database/table_dashboard_msgs.py +1 -2
  11. qolsys_controller/database/table_dimmerlight.py +0 -1
  12. qolsys_controller/database/table_doorlock.py +0 -1
  13. qolsys_controller/database/table_eu_event.py +1 -2
  14. qolsys_controller/database/table_heat_map.py +0 -2
  15. qolsys_controller/database/table_history.py +4 -1
  16. qolsys_controller/database/table_iqremotesettings.py +0 -2
  17. qolsys_controller/database/table_iqrouter_network_config.py +0 -1
  18. qolsys_controller/database/table_iqrouter_user_device.py +0 -2
  19. qolsys_controller/database/table_master_slave.py +0 -1
  20. qolsys_controller/database/table_nest_device.py +0 -1
  21. qolsys_controller/database/table_output_rules.py +0 -1
  22. qolsys_controller/database/table_partition.py +0 -1
  23. qolsys_controller/database/table_pgm_outputs.py +0 -2
  24. qolsys_controller/database/table_powerg_device.py +0 -2
  25. qolsys_controller/database/table_qolsyssettings.py +0 -2
  26. qolsys_controller/database/table_scene.py +0 -2
  27. qolsys_controller/database/table_sensor.py +2 -2
  28. qolsys_controller/database/table_sensor_group.py +23 -0
  29. qolsys_controller/database/table_shades.py +0 -2
  30. qolsys_controller/database/table_smartsocket.py +12 -3
  31. qolsys_controller/database/table_state.py +0 -1
  32. qolsys_controller/database/table_tcc.py +0 -1
  33. qolsys_controller/database/table_thermostat.py +3 -1
  34. qolsys_controller/database/table_trouble_conditions.py +0 -2
  35. qolsys_controller/database/table_user.py +0 -2
  36. qolsys_controller/database/table_virtual_device.py +13 -3
  37. qolsys_controller/database/table_weather.py +0 -2
  38. qolsys_controller/database/table_zigbee_device.py +0 -1
  39. qolsys_controller/database/table_zwave_association_group.py +0 -1
  40. qolsys_controller/database/table_zwave_history.py +0 -1
  41. qolsys_controller/database/table_zwave_node.py +3 -1
  42. qolsys_controller/database/table_zwave_other.py +0 -1
  43. qolsys_controller/enum.py +42 -13
  44. qolsys_controller/enum_adc.py +28 -0
  45. qolsys_controller/enum_zwave.py +210 -36
  46. qolsys_controller/errors.py +14 -12
  47. qolsys_controller/mdns.py +7 -4
  48. qolsys_controller/mqtt_command.py +125 -0
  49. qolsys_controller/mqtt_command_queue.py +5 -4
  50. qolsys_controller/observable.py +2 -2
  51. qolsys_controller/panel.py +304 -156
  52. qolsys_controller/partition.py +149 -127
  53. qolsys_controller/pki.py +69 -97
  54. qolsys_controller/scene.py +30 -28
  55. qolsys_controller/settings.py +96 -50
  56. qolsys_controller/state.py +221 -34
  57. qolsys_controller/task_manager.py +11 -14
  58. qolsys_controller/users.py +25 -0
  59. qolsys_controller/utils_mqtt.py +8 -16
  60. qolsys_controller/weather.py +71 -0
  61. qolsys_controller/zone.py +243 -214
  62. qolsys_controller/zwave_device.py +234 -93
  63. qolsys_controller/zwave_dimmer.py +55 -49
  64. qolsys_controller/zwave_energy_clamp.py +15 -0
  65. qolsys_controller/zwave_garagedoor.py +3 -1
  66. qolsys_controller/zwave_generic.py +5 -3
  67. qolsys_controller/zwave_lock.py +51 -44
  68. qolsys_controller/zwave_outlet.py +3 -1
  69. qolsys_controller/zwave_service_meter.py +192 -0
  70. qolsys_controller/zwave_service_multilevelsensor.py +119 -0
  71. qolsys_controller/zwave_thermometer.py +21 -0
  72. qolsys_controller/zwave_thermostat.py +249 -143
  73. qolsys_controller-0.0.87.dist-info/METADATA +89 -0
  74. qolsys_controller-0.0.87.dist-info/RECORD +77 -0
  75. {qolsys_controller-0.0.44.dist-info → qolsys_controller-0.0.87.dist-info}/WHEEL +1 -1
  76. qolsys_controller/plugin.py +0 -34
  77. qolsys_controller/plugin_c4.py +0 -17
  78. qolsys_controller/plugin_remote.py +0 -1298
  79. qolsys_controller-0.0.44.dist-info/METADATA +0 -93
  80. qolsys_controller-0.0.44.dist-info/RECORD +0 -68
  81. {qolsys_controller-0.0.44.dist-info → qolsys_controller-0.0.87.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,13 @@
1
- from hmac import new
1
+ from __future__ import annotations
2
+
3
+ import base64
2
4
  import json
3
5
  import logging
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from qolsys_controller.adc_device import QolsysAdcDevice
9
+ from qolsys_controller.zwave_energy_clamp import QolsysEnergyClamp
10
+ from qolsys_controller.zwave_thermometer import QolsysThermometer
4
11
 
5
12
  from .database.db import QolsysDB
6
13
  from .enum import (
@@ -11,10 +18,9 @@ from .enum import (
11
18
  from .observable import QolsysObservable
12
19
  from .partition import QolsysPartition
13
20
  from .scene import QolsysScene
14
- from .settings import QolsysSettings
15
- from .state import QolsysState
21
+ from .users import QolsysUser
22
+ from .weather import QolsysForecast, QolsysWeather
16
23
  from .zone import QolsysZone
17
- from .zwave_device import QolsysZWaveDevice
18
24
  from .zwave_dimmer import QolsysDimmer
19
25
  from .zwave_generic import QolsysGeneric
20
26
  from .zwave_lock import QolsysLock
@@ -22,12 +28,14 @@ from .zwave_thermostat import QolsysThermostat
22
28
 
23
29
  LOGGER = logging.getLogger(__name__)
24
30
 
31
+ if TYPE_CHECKING:
32
+ from .controller import QolsysController
33
+ from .zwave_device import QolsysZWaveDevice
25
34
 
26
- class QolsysPanel(QolsysObservable):
27
- def __init__(self, settings: QolsysSettings, state: QolsysState) -> None:
28
35
 
29
- self._state = state
30
- self._settings = settings
36
+ class QolsysPanel(QolsysObservable):
37
+ def __init__(self, controller: QolsysController) -> None:
38
+ self._controller = controller
31
39
  self._db = QolsysDB()
32
40
 
33
41
  # Partition settings
@@ -37,73 +45,108 @@ class QolsysPanel(QolsysObservable):
37
45
  # Panel settings
38
46
  self.settings_panel_observer = QolsysObservable()
39
47
  self.settings_panel = [
40
- "PANEL_TAMPER_STATE", "AC_STATUS", "BATTERY_STATUS", "FAIL_TO_COMMUNICATE", "SECURE_ARMING", "AUTO_BYPASS",
41
- "AUTO_STAY", "AUTO_ARM_STAY", "AUTO_EXIT_EXTENSION", "FINAL_EXIT_DOOR_ARMING", "NO_ARM_LOW_BATTERY",
42
- "TEMPFORMAT", "LANGUAGE", "COUNTRY", "SYSTEM_TIME", "GSM_CONNECTION_STATUS", "GSM_SIGNAL_STRENGTH",
43
- "ANDROID_VERSION", "HARDWARE_VERSION", "TIMER_NORMAL_ENTRY_DELAY", "TIMER_NORMAL_EXIT_DELAY",
44
- "TIMER_LONG_ENTRY_DELAY", "TIMER_LONG_EXIT_DELAY", "ZWAVE_CONTROLLER", "ZWAVE_CARD", "POLICE_PANIC_ENABLED",
45
- "FIRE_PANIC_ENABLED", "AUXILIARY_PANIC_ENABLED", "NIGHTMODE_SETTINGS", "NIGHT_SETTINGS_STATE", "PARTITIONS",
46
- "SIX_DIGIT_USER_CODE", "SHOW_SECURITY_SENSORS", "SYSTEM_LOGGED_IN_USER", "PANEL_SCENES_SETTING", "CONTROL_4",
47
- "ZWAVE_FIRM_WARE_VERSION", "FINAL_EXIT_DOOR_ARMING", "NO_ARM_LOW_BATTERY", "MAC_ADDRESS",
48
+ "PANEL_TAMPER_STATE",
49
+ "AC_STATUS",
50
+ "BATTERY_STATUS",
51
+ "FAIL_TO_COMMUNICATE",
52
+ "SECURE_ARMING",
53
+ "AUTO_BYPASS",
54
+ "AUTO_STAY",
55
+ "AUTO_ARM_STAY",
56
+ "AUTO_EXIT_EXTENSION",
57
+ "FINAL_EXIT_DOOR_ARMING",
58
+ "NO_ARM_LOW_BATTERY",
59
+ "TEMPFORMAT",
60
+ "LANGUAGE",
61
+ "COUNTRY",
62
+ "SYSTEM_TIME",
63
+ "GSM_CONNECTION_STATUS",
64
+ "GSM_SIGNAL_STRENGTH",
65
+ "ANDROID_VERSION",
66
+ "HARDWARE_VERSION",
67
+ "TIMER_NORMAL_ENTRY_DELAY",
68
+ "TIMER_NORMAL_EXIT_DELAY",
69
+ "TIMER_LONG_ENTRY_DELAY",
70
+ "TIMER_LONG_EXIT_DELAY",
71
+ "ZWAVE_CONTROLLER",
72
+ "ZWAVE_CARD",
73
+ "POLICE_PANIC_ENABLED",
74
+ "FIRE_PANIC_ENABLED",
75
+ "AUXILIARY_PANIC_ENABLED",
76
+ "NIGHTMODE_SETTINGS",
77
+ "NIGHT_SETTINGS_STATE",
78
+ "PARTITIONS",
79
+ "SIX_DIGIT_USER_CODE",
80
+ "SHOW_SECURITY_SENSORS",
81
+ "SYSTEM_LOGGED_IN_USER",
82
+ "PANEL_SCENES_SETTING",
83
+ "CONTROL_4",
84
+ "ZWAVE_FIRM_WARE_VERSION",
85
+ "FINAL_EXIT_DOOR_ARMING",
86
+ "NO_ARM_LOW_BATTERY",
87
+ "MAC_ADDRESS",
48
88
  "LAST_UPDATE_IQ_REMOTE_PATCH_CKECKSUM_N",
49
89
  ]
50
90
 
51
- self._PANEL_TAMPER_STATE = ""
52
- self._AC_STATUS = ""
53
- self._BATTERY_STATUS = ""
54
- self._FAIL_TO_COMMUNICATE = ""
55
- self._SECURE_ARMING = ""
56
- self._AUTO_BYPASS = ""
57
- self._AUTO_STAY = ""
58
- self._AUTO_ARM_STAY = ""
59
- self._AUTO_EXIT_EXTENSION = ""
60
- self._FINAL_EXIT_DOOR_ARMING = ""
61
- self._NO_ARM_LOW_BATTERY = ""
62
- self._TEMPFORMAT = ""
63
- self._LANGUAGE = ""
64
- self._COUNTRY = ""
65
- self._SYSTEM_TIME = ""
66
- self._GSM_CONNECTION_STATUS = ""
67
- self._GSM_SIGNAL_STRENGTH = ""
68
- self._ANDROID_VERSION = ""
69
- self._HARDWARE_VERSION = ""
70
- self._TIMER_NORMAL_ENTRY_DELAY = ""
71
- self._TIMER_NORMAL_EXIT_DELAY = ""
72
- self._TIMER_LONG_ENTRY_DELAY = ""
73
- self._TIMER_LONG_EXIT_DELAY = ""
74
- self._ZWAVE_FIRM_WARE_VERSION = ""
75
- self._ZWAVE_CONTROLLER = ""
76
- self._ZWAVE_CARD = ""
77
- self._POLICE_PANIC_ENABLED = ""
78
- self._FIRE_PANIC_ENABLED = ""
79
- self._AUXILIARY_PANIC_ENABfLED = ""
80
- self._NIGHTMODE_SETTINGS = ""
81
- self._NIGHT_SETTINGS_STATE = ""
82
- self._PARTITIONS = ""
83
- self._SIX_DIGIT_USER_CODE = ""
84
- self._SHOW_SECURITY_SENSORS = ""
85
- self._CONTROL_4 = ""
86
- self._MAC_ADDRESS = ""
87
- self._SYSTEM_LOGGED_IN_USER = ""
88
- self._PANEL_SCENES_SETTING = ""
89
- self._LAST_UPDATE_IQ_REMOTE_PATCH_CKECKSUM_N = ""
90
-
91
- self._users = []
92
- self._unique_id = ""
93
-
94
- self._imei = ""
95
- self._product_type = ""
91
+ self._PANEL_TAMPER_STATE: str = ""
92
+ self._AC_STATUS: str = ""
93
+ self._BATTERY_STATUS: str = ""
94
+ self._FAIL_TO_COMMUNICATE: str = ""
95
+ self._SECURE_ARMING: str = ""
96
+ self._AUTO_BYPASS: str = ""
97
+ self._AUTO_STAY: str = ""
98
+ self._AUTO_ARM_STAY: str = ""
99
+ self._AUTO_EXIT_EXTENSION: str = ""
100
+ self._FINAL_EXIT_DOOR_ARMING: str = ""
101
+ self._NO_ARM_LOW_BATTERY: str = ""
102
+ self._TEMPFORMAT: str = ""
103
+ self._LANGUAGE: str = ""
104
+ self._COUNTRY: str = ""
105
+ self._SYSTEM_TIME: str = ""
106
+ self._GSM_CONNECTION_STATUS: str = ""
107
+ self._GSM_SIGNAL_STRENGTH: str = ""
108
+ self._ANDROID_VERSION: str = ""
109
+ self._HARDWARE_VERSION: str = ""
110
+ self._TIMER_NORMAL_ENTRY_DELAY: str = ""
111
+ self._TIMER_NORMAL_EXIT_DELAY: str = ""
112
+ self._TIMER_LONG_ENTRY_DELAY: str = ""
113
+ self._TIMER_LONG_EXIT_DELAY: str = ""
114
+ self._ZWAVE_FIRM_WARE_VERSION: str = ""
115
+ self._ZWAVE_CONTROLLER: str = ""
116
+ self._ZWAVE_CARD: str = ""
117
+ self._POLICE_PANIC_ENABLED: str = ""
118
+ self._FIRE_PANIC_ENABLED: str = ""
119
+ self._AUXILIARY_PANIC_ENABfLED: str = ""
120
+ self._NIGHTMODE_SETTINGS: str = ""
121
+ self._NIGHT_SETTINGS_STATE: str = ""
122
+ self._PARTITIONS: str = ""
123
+ self._SIX_DIGIT_USER_CODE: str = ""
124
+ self._SHOW_SECURITY_SENSORS: str = ""
125
+ self._CONTROL_4: str = ""
126
+ self._MAC_ADDRESS: str = ""
127
+ self._SYSTEM_LOGGED_IN_USER: str = ""
128
+ self._PANEL_SCENES_SETTING: str = ""
129
+ self._LAST_UPDATE_IQ_REMOTE_PATCH_CKECKSUM_N: str = ""
130
+
131
+ self._users: list[QolsysUser] = []
132
+ self._unique_id: str = ""
133
+
134
+ self._imei: str = ""
135
+ self._product_type: str = ""
96
136
 
97
137
  def read_users_file(self) -> bool:
98
138
  # Loading user_code data from users.conf file if exists
99
- if self._settings.users_file_path.is_file():
139
+ if self._controller.settings.users_file_path.is_file():
100
140
  try:
101
- path = self._settings.users_file_path
141
+ path = self._controller.settings.users_file_path
102
142
  with path.open("r", encoding="utf-8") as file:
103
143
  try:
104
144
  users = json.load(file)
105
145
  for user in users:
106
- self._users.append(user)
146
+ qolsys_user = QolsysUser()
147
+ qolsys_user.id = user.get("id")
148
+ qolsys_user.user_code = user.get("user_code")
149
+ self._users.append(qolsys_user)
107
150
 
108
151
  except json.JSONDecodeError:
109
152
  LOGGER.exception("users.conf file json error")
@@ -343,22 +386,66 @@ class QolsysPanel(QolsysObservable):
343
386
  self._PANEL_SCENES_SETTING = self.db.get_setting_panel("PANEL_SCENES_SETTING")
344
387
  return self.PANEL_SCENES_SETTING
345
388
 
346
- def load_database(self, database: dict) -> None:
389
+ def load_database(self, database: list[dict[str, Any]]) -> None:
347
390
  self.db.load_db(database)
348
- self._state.sync_partitions_data(self.get_partitions_from_db())
349
- self._state.sync_zones_data(self.get_zones_from_db())
350
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
351
- self._state.sync_scenes_data(self.get_scenes_from_db())
391
+ self._controller.state.sync_partitions_data(self.get_partitions_from_db())
392
+ self._controller.state.sync_zones_data(self.get_zones_from_db())
393
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
394
+ self._controller.state.sync_adc_devices_data(self.get_adc_devices_from_db())
395
+ self._controller.state.sync_scenes_data(self.get_scenes_from_db())
396
+ self._controller.state.sync_weather_data(self.get_weather_from_db())
397
+
398
+ # Validate all local user match a Qolsys Panel user
399
+ qolsys_users = self.db.get_users()
400
+ qolsys_user_list = []
401
+ for qolsys_user in qolsys_users:
402
+ try:
403
+ userid = int(qolsys_user.get("userid", ""))
404
+ except ValueError:
405
+ LOGGER.error("Invalid userid in panel database: %s", qolsys_user.get("userid", ""))
406
+ userid = -1
407
+
408
+ qolsys_user_list.append(userid)
409
+
410
+ for local_user in self._users:
411
+ if local_user.id not in qolsys_user_list:
412
+ LOGGER.error("ID %s from users.conf file not found in panel database", local_user.id)
413
+
414
+ # Check associated zone_id in iqremotesettins table
415
+ LOGGER.debug("Checking iqremotesettings table for zone_id matching panel MAC address")
416
+ iqremote_settings_list = self.db.get_iqremote_settings()
417
+ for iqremote in iqremote_settings_list:
418
+ if (
419
+ self._controller.settings.random_mac.replace(":", "").lower()
420
+ == iqremote.get("mac_address", "").replace(":", "").lower()
421
+ ):
422
+ self._controller._zone_id = iqremote.get("zone_id", "")
423
+ LOGGER.debug("Found matching zone_id: %s", self._controller._zone_id)
424
+ break
425
+
426
+ # Parse Z-Wave message
427
+ def parse_zwave_message(self, data: dict[str, Any]) -> None:
428
+ zwave = data.get("ZWAVE_RESPONSE", "")
429
+ payload = base64.b64decode(zwave.get("ZWAVE_PAYLOAD", "")).hex()
430
+ # LOGGER.debug(
431
+ # "Z-Wave Response: Node(%s) - Status(%s) - Payload(%s)",
432
+ # zwave.get("NODE_ID", ""),
433
+ # zwave.get("ZWAVE_COMMAND_STATUS", ""),
434
+ # payload,
435
+ # )
436
+
437
+ node_id: str = str(zwave.get("NODE_ID", 0))
438
+ node = self._controller.state.zwave_device(node_id)
439
+ if node is not None:
440
+ node.update_raw(bytes.fromhex(payload))
352
441
 
353
442
  # Parse panel update to database
354
- def parse_iq2meid_message(self, data: dict) -> bool: # noqa: C901, PLR0912, PLR0915
355
-
443
+ def parse_iq2meid_message(self, data: dict[str, Any]) -> None: # noqa: C901, PLR0912, PLR0915
356
444
  eventName = data.get("eventName")
357
- dbOperation = data.get("dbOperation","")
445
+ dbOperation = data.get("dbOperation", "")
358
446
  uri = data.get("uri")
359
447
 
360
448
  match eventName:
361
-
362
449
  case "stopScreenCapture":
363
450
  pass
364
451
 
@@ -366,16 +453,13 @@ class QolsysPanel(QolsysObservable):
366
453
  LOGGER.info("Main Panel Disconnect")
367
454
 
368
455
  case "dbChanged":
369
-
370
456
  match dbOperation:
371
-
372
457
  case "update":
373
- content_values = data.get("contentValues")
458
+ content_values = data.get("contentValues", "")
374
459
  selection = data.get("selection")
375
460
  selection_argument = data.get("selectionArgs")
376
461
 
377
462
  match uri:
378
-
379
463
  # Update Settings Content Provider
380
464
  case self.db.table_qolsyssettings.uri:
381
465
  name = content_values.get("name", "")
@@ -391,7 +475,7 @@ class QolsysPanel(QolsysObservable):
391
475
  # Update Partition setting - Send notification if setting has changed
392
476
  if name in self.settings_partition:
393
477
  partition_id = content_values.get("partition_id", "")
394
- partition = self._state.partition(partition_id)
478
+ partition = self._controller.state.partition(partition_id)
395
479
  if partition is not None:
396
480
  match name:
397
481
  case "SYSTEM_STATUS":
@@ -407,7 +491,7 @@ class QolsysPanel(QolsysObservable):
407
491
  case self.db.table_sensor.uri:
408
492
  self.db.table_sensor.update(selection, selection_argument, content_values)
409
493
  zoneid = content_values.get("zoneid", "")
410
- zone = self._state.zone(zone_id=zoneid)
494
+ zone = self._controller.state.zone(zone_id=zoneid)
411
495
  if zone is not None:
412
496
  zone.update(content_values)
413
497
 
@@ -419,7 +503,7 @@ class QolsysPanel(QolsysObservable):
419
503
  self.db.table_state.update(selection, selection_argument, content_values)
420
504
 
421
505
  if name in self.state_partition:
422
- partition = self._state.partition(partition_id)
506
+ partition = self._controller.state.partition(partition_id)
423
507
  if partition is not None:
424
508
  match name:
425
509
  case "ALARM_STATE":
@@ -428,36 +512,32 @@ class QolsysPanel(QolsysObservable):
428
512
  # Update heat_map
429
513
  case self.db.table_heat_map.uri:
430
514
  self.db.table_heat_map.update(selection, selection_argument, content_values)
431
- # No action needed
432
515
 
433
516
  # Update master_slave
434
517
  case self.db.table_master_slave.uri:
435
518
  self.db.table_master_slave.update(selection, selection_argument, content_values)
436
- # No action needed
437
519
 
438
520
  # Update dashboard_msgs
439
521
  case self.db.table_dashboard_msgs.uri:
440
522
  self.db.table_dashboard_msgs.update(selection, selection_argument, content_values)
441
- # No action needed
442
523
 
443
524
  # Update PartitionContentProvider
444
525
  case self.db.table_partition.uri:
445
526
  self.db.table_partition.update(selection, selection_argument, content_values)
446
527
  partition_id = content_values.get("partition_id", "")
447
- partition = self._state.partition(partition_id)
528
+ partition = self._controller.state.partition(partition_id)
448
529
  if partition is not None:
449
530
  partition.update_partition(content_values)
450
531
 
451
532
  # Update History Content Provider
452
533
  case self.db.table_history.uri:
453
534
  self.db.table_history.update(selection, selection_argument, content_values)
454
- # No action needed
455
535
 
456
536
  # Update DimmerLightsContentProvider
457
537
  case self.db.table_dimmer.uri:
458
538
  self.db.table_dimmer.update(selection, selection_argument, content_values)
459
539
  node_id = content_values.get("node_id", "")
460
- node = self._state.zwave_device(node_id)
540
+ node = self._controller.state.zwave_device(node_id)
461
541
  if node is not None and isinstance(node, QolsysDimmer):
462
542
  node.update_dimmer(content_values)
463
543
 
@@ -465,7 +545,7 @@ class QolsysPanel(QolsysObservable):
465
545
  case self.db.table_thermostat.uri:
466
546
  self.db.table_thermostat.update(selection, selection_argument, content_values)
467
547
  node_id = content_values.get("node_id", "")
468
- node = self._state.zwave_device(node_id)
548
+ node = self._controller.state.zwave_device(node_id)
469
549
  if node is not None and isinstance(node, QolsysThermostat):
470
550
  node.update_thermostat(content_values)
471
551
 
@@ -473,7 +553,7 @@ class QolsysPanel(QolsysObservable):
473
553
  case self.db.table_doorlock.uri:
474
554
  self.db.table_doorlock.update(selection, selection_argument, content_values)
475
555
  node_id = content_values.get("node_id", "")
476
- node = self._state.zwave_device(node_id)
556
+ node = self._controller.state.zwave_device(node_id)
477
557
  if node is not None and isinstance(node, QolsysLock):
478
558
  node.update_lock(content_values)
479
559
 
@@ -481,19 +561,17 @@ class QolsysPanel(QolsysObservable):
481
561
  case self.db.table_zwave_node.uri:
482
562
  self.db.table_zwave_node.update(selection, selection_argument, content_values)
483
563
  node_id = content_values.get("node_id", "")
484
- node = self._state.zwave_device(node_id)
564
+ node = self._controller.state.zwave_device(node_id)
485
565
  if node is not None:
486
566
  node.update_base(content_values)
487
567
 
488
568
  # Update Z-Wave History Content Provier
489
569
  case self.db.table_zwave_history.uri:
490
570
  self.db.table_zwave_history.update(selection, selection_argument, content_values)
491
- # No action needed
492
571
 
493
572
  # Update AutomationDeviceContentProvider
494
573
  case self.db.table_automation.uri:
495
574
  self.db.table_automation.update(selection, selection_argument, content_values)
496
- # No action needed
497
575
 
498
576
  # Update Alarmed Sensor Content Provider
499
577
  case self.db.table_alarmedsensor.uri:
@@ -502,35 +580,56 @@ class QolsysPanel(QolsysObservable):
502
580
  # Update IQ Remote Settings Content Provider
503
581
  case self.db.table_iqremotesettings.uri:
504
582
  self.db.table_iqremotesettings.update(selection, selection_argument, content_values)
505
- # No action needed
506
583
 
507
584
  # Update Scene Content Provider
508
585
  case self.db.table_scene.uri:
509
586
  self.db.table_scene.update(selection, selection_argument, content_values)
510
587
  scene_id = content_values.get("scene_id", "")
511
- scene = self._state.scene(scene_id)
512
- if scene is not None and isinstance(node, QolsysScene):
588
+ scene = self._controller.state.scene(scene_id)
589
+ if scene is not None and isinstance(scene, QolsysScene):
513
590
  scene.update(content_values)
514
591
 
515
592
  # Update Trouble Conditions
516
593
  case self.db.table_trouble_conditions.uri:
517
- self.db.table_trouble_conditions.update(selection,selection_argument,content_values)
518
- # No action needed
594
+ self.db.table_trouble_conditions.update(selection, selection_argument, content_values)
519
595
 
520
596
  # Update EU_EVENT:
521
597
  case self.db.table_eu_event.uri:
522
- self.db.table_eu_event.update(selection,selection_argument,content_values)
523
- # No action needed
598
+ self.db.table_eu_event.update(selection, selection_argument, content_values)
524
599
 
525
600
  # Update PowerG Device
526
601
  case self.db.table_powerg_device.uri:
527
- self.db.table_powerg_device.update(selection,selection_argument,content_values)
602
+ self.db.table_powerg_device.update(selection, selection_argument, content_values)
528
603
  short_id = content_values.get("shortID", "")
529
- zone = self._state.zone_from_short_id(short_id)
604
+ zone = self._controller.state.zone_from_short_id(short_id)
530
605
  if zone is not None:
531
- LOGGER.debug("iq2meid updating powerg device for zoneid(%s):%s", zone.zone_id,content_values)
532
606
  zone.update_powerg(content_values)
533
607
 
608
+ # Update Weather
609
+ case self.db.table_weather.uri:
610
+ self.db.table_weather.update(selection, selection_argument, content_values)
611
+ self._controller.state.sync_weather_data(self.get_weather_from_db())
612
+
613
+ # Update Zwave Association Group
614
+ case self.db.table_zwave_association_goup.uri:
615
+ self.db.table_zwave_association_goup.update(selection, selection_argument, content_values)
616
+
617
+ # Update Zwave Other
618
+ case self.db.table_zwave_other.uri:
619
+ self.db.table_zwave_other.update(selection, selection_argument, content_values)
620
+
621
+ # Country Locale
622
+ case self.db.table_country_locale.uri:
623
+ self.db.table_country_locale.update(selection, selection_argument, content_values)
624
+
625
+ # Virtual device
626
+ case self.db.table_virtual_device.uri:
627
+ self.db.table_virtual_device.update(selection, selection_argument, content_values)
628
+ adc_id = content_values.get("device_id", "")
629
+ adc_device = self._controller.state.adc_device(adc_id)
630
+ if adc_device is not None:
631
+ adc_device.update_adc_device(content_values)
632
+
534
633
  case _:
535
634
  LOGGER.debug("iq2meid updating unknow uri:%s", uri)
536
635
  LOGGER.debug(data)
@@ -540,87 +639,89 @@ class QolsysPanel(QolsysObservable):
540
639
  selection_argument = data.get("selectionArgs")
541
640
 
542
641
  match uri:
543
-
544
642
  case self.db.table_sensor.uri:
545
643
  self.db.table_sensor.delete(selection, selection_argument)
546
- self._state.sync_zones_data(self.get_zones_from_db())
547
- # Notify delete zone
644
+ self._controller.state.sync_zones_data(self.get_zones_from_db())
548
645
 
549
646
  case self.db.table_iqremotesettings.uri:
550
647
  self.db.table_iqremotesettings.delete(selection, selection_argument)
551
- # No action needed
552
648
 
553
649
  case self.db.table_state.uri:
554
650
  self.db.table_state.delete(selection, selection_argument)
555
- # No action needed
556
651
 
557
652
  case self.db.table_master_slave.uri:
558
653
  self.db.table_master_slave.delete(selection, selection_argument)
559
- # No action needed
560
654
 
561
655
  case self.db.table_qolsyssettings.uri:
562
656
  self.db.table_qolsyssettings.delete(selection, selection_argument)
563
- # No action needed
564
657
 
565
658
  case self.db.table_alarmedsensor.uri:
566
659
  self.db.table_alarmedsensor.delete(selection, selection_argument)
567
- self._state.sync_partitions_data(self.get_partitions_from_db())
660
+ self._controller.state.sync_partitions_data(self.get_partitions_from_db())
568
661
 
569
662
  case self.db.table_history.uri:
570
663
  self.db.table_history.delete(selection, selection_argument)
571
- # No action needed
572
664
 
573
665
  case self.db.table_zwave_history.uri:
574
666
  self.db.table_zwave_history.delete(selection, selection_argument)
575
- # No action needed
576
667
 
577
668
  case self.db.table_doorlock.uri:
578
669
  self.db.table_doorlock.delete(selection, selection_argument)
579
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
670
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
580
671
 
581
672
  case self.db.table_dimmer.uri:
582
673
  self.db.table_dimmer.delete(selection, selection_argument)
583
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
674
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
584
675
 
585
676
  case self.db.table_thermostat.uri:
586
677
  self.db.table_thermostat.delete(selection, selection_argument)
587
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
678
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
588
679
 
589
680
  case self.db.table_zwave_node.uri:
590
681
  self.db.table_zwave_node.delete(selection, selection_argument)
591
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
682
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
592
683
 
593
684
  case self.db.table_automation.uri:
594
685
  self.db.table_automation.delete(selection, selection_argument)
595
- # No action needed
596
686
 
597
687
  case self.db.table_partition.uri:
598
688
  self.db.table_partition.delete(selection, selection_argument)
599
- self._state.sync_partitions_data(self.get_partitions_from_db())
689
+ self._controller.state.sync_partitions_data(self.get_partitions_from_db())
600
690
 
601
691
  case self.db.table_user.uri:
602
692
  self.db.table_user.delete(selection, selection_argument)
603
- # No action needed
604
693
 
605
694
  case self.db.table_dashboard_msgs.uri:
606
695
  self.db.table_dashboard_msgs.delete(selection, selection_argument)
607
- # No action needed
608
696
 
609
697
  case self.db.table_eu_event.uri:
610
- self.db.table_eu_event.delete(selection,selection_argument)
698
+ self.db.table_eu_event.delete(selection, selection_argument)
611
699
 
612
700
  case self.db.table_powerg_device.uri:
613
- self.db.table_powerg_device.delete(selection,selection_argument)
701
+ self.db.table_powerg_device.delete(selection, selection_argument)
702
+
703
+ case self.db.table_weather.uri:
704
+ self.db.table_weather.delete(selection, selection_argument)
705
+ self._controller.state.sync_weather_data(self.get_weather_from_db())
706
+
707
+ case self.db.table_zwave_association_goup.uri:
708
+ self.db.table_zwave_association_goup.delete(selection, selection_argument)
709
+
710
+ case self.db.table_virtual_device.uri:
711
+ self.db.table_virtual_device.delete(selection, selection_argument)
712
+ self._controller.state.sync_adc_devices_data(self.get_adc_devices_from_db())
713
+
714
+ case self.db.table_zwave_other.uri:
715
+ self.db.table_zwave_other.delete(selection, selection_argument)
614
716
 
615
717
  case _:
616
718
  LOGGER.debug("iq2meid deleting unknown uri:%s", uri)
617
719
  LOGGER.debug(data)
618
720
 
619
721
  case "insert":
620
- content_values = data.get("contentValues")
722
+ content_values = data.get("contentValues", {})
621
723
 
622
724
  match uri:
623
-
624
725
  # Inser State Content Provider
625
726
  case self.db.table_state.uri:
626
727
  self.db.table_state.insert(data=content_values)
@@ -629,16 +730,16 @@ class QolsysPanel(QolsysObservable):
629
730
  new_value = content_values.get("value", "")
630
731
  if name in self.state_partition:
631
732
  partition_id = content_values.get("partition_id", "")
632
- partition = self._state.partition(partition_id)
733
+ partition = self._controller.state.partition(partition_id)
633
734
  if partition is not None:
634
735
  match name:
635
736
  case "ALARM_STATE":
636
737
  partition.alarm_state = PartitionAlarmState(new_value)
637
738
 
638
739
  # Inser Partition Content Provider
639
- case self.db.table_partition:
740
+ case self.db.table_partition.uri:
640
741
  self.db.table_partition.insert(data=content_values)
641
- self._state.sync_partitions_data(self.get_partitions_from_db())
742
+ self._controller.state.sync_partitions_data(self.get_partitions_from_db())
642
743
 
643
744
  # Insert Settings Content Provider
644
745
  case self.db.table_qolsyssettings.uri:
@@ -649,7 +750,7 @@ class QolsysPanel(QolsysObservable):
649
750
  new_value = content_values.get("value", "")
650
751
  if name in self.settings_partition:
651
752
  partition_id = content_values.get("partition_id", "")
652
- partition = self._state.partition(partition_id)
753
+ partition = self._controller.state.partition(partition_id)
653
754
  if partition is not None:
654
755
  match name:
655
756
  case "SYSTEM_STATUS":
@@ -679,62 +780,56 @@ class QolsysPanel(QolsysObservable):
679
780
  # Sensor Content Provider
680
781
  case self.db.table_sensor.uri:
681
782
  self.db.table_sensor.insert(data=content_values)
682
- self._state.sync_zones_data(self.get_zones_from_db())
783
+ self._controller.state.sync_zones_data(self.get_zones_from_db())
683
784
 
684
785
  # Door Lock Content Provider
685
786
  case self.db.table_doorlock.uri:
686
787
  self.db.table_doorlock.insert(data=content_values)
687
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
788
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
688
789
 
689
790
  # Dimmer Content Provider
690
791
  case self.db.table_dimmer.uri:
691
792
  self.db.table_dimmer.insert(data=content_values)
692
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
793
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
693
794
 
694
795
  # Thermostat Content Provider
695
796
  case self.db.table_thermostat.uri:
696
797
  self.db.table_thermostat.insert(data=content_values)
697
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
798
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
698
799
 
699
800
  # ZWave Node Content Provider
700
801
  case self.db.table_zwave_node.uri:
701
802
  self.db.table_zwave_node.insert(data=content_values)
702
- self._state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
803
+ self._controller.state.sync_zwave_devices_data(self.get_zwave_devices_from_db())
703
804
 
704
805
  # HistoryContentProvider
705
806
  case self.db.table_history.uri:
706
807
  self.db.table_history.insert(data=content_values)
707
- # No action needed
708
808
 
709
809
  # AlarmedSensorProvider
710
810
  case self.db.table_alarmedsensor.uri:
711
-
712
811
  partition_id = content_values.get("partition_id", "")
713
812
  self.db.table_alarmedsensor.insert(data=content_values)
714
813
 
715
- partition = self._state.partition(partition_id)
814
+ partition = self._controller.state.partition(partition_id)
716
815
  if partition is not None:
717
816
  partition.append_alarm_type([PartitionAlarmType(content_values.get("sgroup", ""))])
718
817
 
719
818
  # IQRemoteSettingsProvider
720
819
  case self.db.table_iqremotesettings.uri:
721
820
  self.db.table_iqremotesettings.insert(data=content_values)
722
- # No action needed
723
821
 
724
822
  # HeatMapContentProvider
725
823
  case self.db.table_heat_map.uri:
726
824
  self.db.table_heat_map.insert(data=content_values)
727
- # No action needed
728
825
 
729
826
  # ZDeviceHistoryContentProvider
730
827
  case self.db.table_zwave_history.uri:
731
828
  self.db.table_zwave_history.insert(data=content_values)
732
- # No action needed
733
829
 
734
830
  # Dashboard Message Content Provider
735
831
  case self.db.table_dashboard_msgs.uri:
736
832
  self.db.table_dashboard_msgs.insert(data=content_values)
737
- # No action needed
738
833
 
739
834
  # EU_EVENT
740
835
  case self.db.table_eu_event.uri:
@@ -744,6 +839,26 @@ class QolsysPanel(QolsysObservable):
744
839
  case self.db.table_powerg_device.uri:
745
840
  self.db.table_powerg_device.insert(data=content_values)
746
841
 
842
+ # Weather
843
+ case self.db.table_weather.uri:
844
+ self.db.table_weather.insert(data=content_values)
845
+ self._controller.state.sync_weather_data(self.get_weather_from_db())
846
+
847
+ # ZWave Association Group
848
+ case self.db.table_zwave_association_goup.uri:
849
+ self.db.table_zwave_association_goup.insert(data=content_values)
850
+
851
+ # Zwave Other
852
+ case self.db.table_zwave_other.uri:
853
+ self.db.table_zwave_other.insert(data=content_values)
854
+ LOGGER.debug("New Z-Wave Other information")
855
+ LOGGER.debug(content_values)
856
+
857
+ # Virtual Device
858
+ case self.db.table_virtual_device.uri:
859
+ self.db.table_virtual_device.insert(data=content_values)
860
+ self._controller.state.sync_adc_devices_data(self.get_adc_devices_from_db())
861
+
747
862
  case _:
748
863
  LOGGER.debug("iq2meid inserting unknow uri:%s", uri)
749
864
  LOGGER.debug(data)
@@ -757,24 +872,45 @@ class QolsysPanel(QolsysObservable):
757
872
 
758
873
  def check_user(self, user_code: str) -> int:
759
874
  for user in self._users:
760
- if user["user_code"] == user_code:
761
- return user["id"]
875
+ if user.user_code == user_code:
876
+ return user.id
762
877
 
763
878
  # No valid user code found
764
879
  return -1
765
880
 
881
+ def get_adc_devices_from_db(self) -> list[QolsysAdcDevice]:
882
+ adc_devices: list[QolsysAdcDevice] = []
883
+ devices_list = self.db.get_adc_devices()
884
+
885
+ for device in devices_list:
886
+ adc_devices.append(QolsysAdcDevice(device))
887
+
888
+ return adc_devices
889
+
766
890
  def get_zwave_devices_from_db(self) -> list[QolsysZWaveDevice]:
767
- devices = []
891
+ devices: list[QolsysZWaveDevice] = []
768
892
  devices_list = self.db.get_zwave_devices()
769
893
  dimmers_list = self.db.get_dimmers()
770
894
  thermostats_list = self.db.get_thermostats()
771
895
  locks_list = self.db.get_locks()
772
896
 
773
897
  for device in devices_list:
774
-
775
898
  device_added = False
776
-
777
899
  zwave_node_id = device.get("node_id", "")
900
+
901
+ # Check if z-wave device is an Energy Clamp
902
+ if device.get("node_type", "") == "Energy Clamp":
903
+ LOGGER.debug(device)
904
+ qolsys_meter_device = QolsysEnergyClamp(device)
905
+ devices.append(qolsys_meter_device)
906
+ device_added = True
907
+
908
+ # Check if z-wave device is a thermometer
909
+ if device.get("node_type", "") == "Thermometer":
910
+ qolsys_thermometer = QolsysThermometer(device)
911
+ devices.append(qolsys_thermometer)
912
+ device_added = True
913
+
778
914
  # Check if z-wave device is a Dimmer
779
915
  for d in dimmers_list:
780
916
  dimmer_node_id = d.get("node_id", "")
@@ -821,7 +957,7 @@ class QolsysPanel(QolsysObservable):
821
957
 
822
958
  def get_scenes_from_db(self) -> list[QolsysScene]:
823
959
  scenes = []
824
- scenes_list: list[dict] = self.db.get_scenes()
960
+ scenes_list: list[dict[str, str]] = self.db.get_scenes()
825
961
 
826
962
  # Create scenes array
827
963
  for scene_info in scenes_list:
@@ -829,17 +965,30 @@ class QolsysPanel(QolsysObservable):
829
965
 
830
966
  return scenes
831
967
 
968
+ def get_weather_from_db(self) -> QolsysWeather:
969
+ weather = QolsysWeather()
970
+ forecast_dic_list: list[dict[str, str]] = self.db.get_weather()
971
+
972
+ forecast_obj_list = []
973
+ for forecast in forecast_dic_list:
974
+ forecast_obj_list.append(QolsysForecast(forecast))
975
+
976
+ # Create weather array
977
+ weather.update(forecast_obj_list)
978
+
979
+ return weather
980
+
832
981
  def get_zones_from_db(self) -> list[QolsysZone]:
833
982
  zones = []
834
- zones_list: list[dict] = self.db.get_zones()
983
+ zones_list: list[dict[str, str]] = self.db.get_zones()
835
984
 
836
985
  # Create sensors array
837
986
  for zone_info in zones_list:
838
- new_zone = QolsysZone(zone_info,self._settings)
987
+ new_zone = QolsysZone(zone_info, self._controller.settings)
839
988
 
840
989
  if new_zone.current_capability == "POWERG":
841
990
  LOGGER.debug("Loading PowerG device info for zone %s", new_zone.zone_id)
842
- powerg_dict = self.db.get_powerg(short_id= new_zone.shortID)
991
+ powerg_dict = self.db.get_powerg(short_id=new_zone.shortID)
843
992
  LOGGER.debug("PowerG device info: %s", powerg_dict)
844
993
  if powerg_dict is not None:
845
994
  new_zone.update_powerg(powerg_dict)
@@ -849,13 +998,11 @@ class QolsysPanel(QolsysObservable):
849
998
  return zones
850
999
 
851
1000
  def get_partitions_from_db(self) -> list[QolsysPartition]:
852
-
853
1001
  partitions = []
854
- partition_list: list[dict] = self.db.get_partitions()
1002
+ partition_list: list[dict[str, str]] = self.db.get_partitions()
855
1003
 
856
1004
  # Create partitions array
857
1005
  for partition_dict in partition_list:
858
-
859
1006
  partition_id = partition_dict["partition_id"]
860
1007
 
861
1008
  settings_dict = {
@@ -867,10 +1014,7 @@ class QolsysPanel(QolsysObservable):
867
1014
 
868
1015
  alarm_type = []
869
1016
  for alarm in self.db.get_alarm_type(partition_id):
870
- if alarm == "":
871
- alarm_type.append(PartitionAlarmType("Police Emergency"))
872
- else:
873
- alarm_type.append(PartitionAlarmType(alarm))
1017
+ alarm_type.append(PartitionAlarmType(alarm))
874
1018
 
875
1019
  alarm_state = PartitionAlarmState(self.db.get_state_partition("ALARM_STATE", partition_id) or "UNKNOWN")
876
1020
 
@@ -921,4 +1065,8 @@ class QolsysPanel(QolsysObservable):
921
1065
 
922
1066
  LOGGER.debug("Users list:")
923
1067
  for user in self._users:
924
- LOGGER.debug("User: %s", user["id"])
1068
+ LOGGER.debug("User: %s", user.id)
1069
+
1070
+ LOGGER.debug("*** Plugin Information ***")
1071
+ LOGGER.debug("Motion Delay Enabled: %s", self._controller.settings.motion_sensor_delay)
1072
+ LOGGER.debug("Motion Delay Value: %s", self._controller.settings.motion_sensor_delay_sec)