qolsys-controller 0.0.19__tar.gz → 0.0.56__tar.gz

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 (83) hide show
  1. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/.github/workflows/publish.yml +1 -0
  2. qolsys_controller-0.0.56/PKG-INFO +89 -0
  3. qolsys_controller-0.0.56/README.md +73 -0
  4. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/example.py +18 -12
  5. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/pyproject.toml +4 -2
  6. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/controller.py +18 -7
  7. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/db.py +31 -0
  8. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table.py +39 -16
  9. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_dashboard_msgs.py +1 -0
  10. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_dimmerlight.py +1 -1
  11. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_doorlock.py +3 -1
  12. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_eu_event.py +11 -2
  13. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_master_slave.py +1 -0
  14. qolsys_controller-0.0.56/qolsys_controller/database/table_powerg_device.py +47 -0
  15. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_qolsyssettings.py +1 -1
  16. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_sensor.py +4 -0
  17. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_user.py +1 -0
  18. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_weather.py +1 -1
  19. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_zwave_node.py +2 -1
  20. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_zwave_other.py +14 -1
  21. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/enum.py +23 -8
  22. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/enum_zwave.py +0 -1
  23. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/mdns.py +7 -3
  24. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/panel.py +120 -65
  25. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/partition.py +15 -2
  26. qolsys_controller-0.0.56/qolsys_controller/plugin.py +24 -0
  27. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/plugin_c4.py +1 -1
  28. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/plugin_remote.py +242 -183
  29. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/scene.py +1 -1
  30. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/settings.py +53 -19
  31. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/state.py +55 -19
  32. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/task_manager.py +18 -1
  33. qolsys_controller-0.0.56/qolsys_controller/weather.py +74 -0
  34. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zone.py +191 -38
  35. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_device.py +1 -1
  36. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_lock.py +2 -2
  37. qolsys_controller-0.0.56/requirements.txt +7 -0
  38. qolsys_controller-0.0.19/PKG-INFO +0 -92
  39. qolsys_controller-0.0.19/README.md +0 -76
  40. qolsys_controller-0.0.19/qolsys_controller/database/table_powerg_device.py +0 -23
  41. qolsys_controller-0.0.19/qolsys_controller/plugin.py +0 -34
  42. qolsys_controller-0.0.19/requirements.txt +0 -3
  43. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/.github/workflows/build.yml +0 -0
  44. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/.gitignore +0 -0
  45. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/Info_mqtt.md +0 -0
  46. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/LICENSE +0 -0
  47. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/bin/qolsys.py +0 -0
  48. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/info_pairing.md +0 -0
  49. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/info_qolsys.md +0 -0
  50. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/__init__.py +0 -0
  51. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_alarmedsensor.py +0 -0
  52. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_automation.py +0 -0
  53. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_country_locale.py +0 -0
  54. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_heat_map.py +0 -0
  55. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_history.py +0 -0
  56. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_iqremotesettings.py +0 -0
  57. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_iqrouter_network_config.py +0 -0
  58. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_iqrouter_user_device.py +0 -0
  59. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_nest_device.py +0 -0
  60. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_output_rules.py +0 -0
  61. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_partition.py +0 -0
  62. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_pgm_outputs.py +0 -0
  63. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_scene.py +0 -0
  64. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_shades.py +0 -0
  65. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_smartsocket.py +0 -0
  66. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_state.py +0 -0
  67. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_tcc.py +0 -0
  68. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_thermostat.py +0 -0
  69. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_trouble_conditions.py +0 -0
  70. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_virtual_device.py +0 -0
  71. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_zigbee_device.py +0 -0
  72. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_zwave_association_group.py +0 -0
  73. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/database/table_zwave_history.py +0 -0
  74. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/errors.py +0 -0
  75. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/mqtt_command_queue.py +0 -0
  76. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/observable.py +0 -0
  77. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/pki.py +0 -0
  78. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/utils_mqtt.py +0 -0
  79. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_dimmer.py +0 -0
  80. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_garagedoor.py +0 -0
  81. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_generic.py +0 -0
  82. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_outlet.py +0 -0
  83. {qolsys_controller-0.0.19 → qolsys_controller-0.0.56}/qolsys_controller/zwave_thermostat.py +0 -0
@@ -1,6 +1,7 @@
1
1
  name: Publish Python package to PyPI
2
2
 
3
3
  on:
4
+ workflow_dispatch:
4
5
  release:
5
6
  types: [published]
6
7
 
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.4
2
+ Name: qolsys-controller
3
+ Version: 0.0.56
4
+ Summary: A Python module that emulates a virtual IQ Remote device, enabling full local control of a Qolsys IQ Panel
5
+ Project-URL: Homepage, https://github.com/EHylands/QolsysController
6
+ Project-URL: Issues, https://github.com/EHylands/QolsysController/issues
7
+ Project-URL: Repository, https://github.com/EHylands/QolsysController.git
8
+ Author: Eric Hylands
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Home Automation
14
+ Requires-Python: >=3.12
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Qolsys Controller - qolsys-controller
18
+
19
+ [![Build](https://github.com/EHylands/QolsysController/actions/workflows/build.yml/badge.svg)](https://github.com/EHylands/QolsysController/actions/workflows/build.yml)
20
+
21
+ A Python module that emulates a virtual IQ Remote device, enabling full **local control** of a Qolsys IQ Panel over MQTT — no cloud access required.
22
+
23
+ ## QolsysController
24
+ - ✅ Connects directly to the **Qolsys Panel's local MQTT server as an IQ Remote**
25
+ - 🔐 Pairs by only using **Installer Code** (same procedure as standard IQ Remote pairing)
26
+ - 🔢 Supports **4-digit user codes**
27
+ - ⚠️ Uses a **custom local usercode database** — panel's internal user code verification process is not yet supported
28
+
29
+ ## ✨ Functionality Highlights
30
+
31
+ | Category | Feature | Status |
32
+ |------------------------|--------------------------------------|--------|
33
+ | **Panel** | Diagnostic Sensors | ✅ |
34
+ | | Panel Scenes | ✅ |
35
+ | | Weather Forecast | ✅ |
36
+ | | (Alarm.com Weather to Panel) | |
37
+ | **Partition** | Arming Status | ✅ |
38
+ | | Alarm State | ✅ |
39
+ | | Home Instant Arming | ✅ |
40
+ | | Home Silent Disarming (Firmware 4.6.1)| ✅ |
41
+ | | Set Exit Sounds | ✅ |
42
+ | | Set Entry Delay | ✅ |
43
+ | | Disarm Photos | 🛠️ |
44
+ | | TTS | 🛠️ |
45
+ | **Zones** | Sensor Status | ✅ |
46
+ | | Tamper State | ✅ |
47
+ | | Battery Level | ✅ |
48
+ | | Temperature (supported PowerG device)| ✅ |
49
+ | | Light (supported PowerG device) | ✅ |
50
+ | | Average dBm | ✅ |
51
+ | | Latest dBm | ✅ |
52
+ | **Z-Wave Devices** | Battery Level | ✅ |
53
+ | | Node Status | ✅ |
54
+ | | Control Generic Devices | TBD |
55
+ | **Z-Wave Dimmers** | Light Status and Level Control | ✅ |
56
+ | **Z-Wave Door Locks** | Lock, Unlock | ✅ |
57
+ | **Z-Wave Thermostats** | Read device status | ✅ |
58
+ | | Write device status | ✅ |
59
+ | **Z-Wave Garage Doors**| | 🛠️ |
60
+ | **Z-Wave Outlets** | | 🛠️ |
61
+
62
+
63
+ ## ⚠️ Certificate Warning
64
+
65
+ During pairing, the main panel issues **only one signed client certificate** per virtual IQ Remote. If any key files are lost or deleted, re-pairing may become impossible.
66
+
67
+ A new PKI, including a new private key, can be recreated under specific circumstances, though the precise conditions remain unknown at this time.
68
+
69
+ **Important:**
70
+ Immediately back up the following files from the `pki/` directory after initial pairing:
71
+
72
+ - `.key` (private key)
73
+ - `.cer` (certificate)
74
+ - `.csr` (certificate signing request)
75
+ - `.secure` (signed client certificate)
76
+ - `.qolsys` (Qolsys Panel public certificate)
77
+
78
+ Store these files securely.
79
+
80
+ ## 📦 Installation
81
+
82
+ ```bash
83
+ git clone https://github.com/EHylands/QolsysController.git
84
+ cd qolsys_controller
85
+ pip3.12 install -r requirements.txt
86
+
87
+ # Change panel_ip and plugin_in in main.py file
88
+ python3.12 example.py
89
+ ```
@@ -0,0 +1,73 @@
1
+ # Qolsys Controller - qolsys-controller
2
+
3
+ [![Build](https://github.com/EHylands/QolsysController/actions/workflows/build.yml/badge.svg)](https://github.com/EHylands/QolsysController/actions/workflows/build.yml)
4
+
5
+ A Python module that emulates a virtual IQ Remote device, enabling full **local control** of a Qolsys IQ Panel over MQTT — no cloud access required.
6
+
7
+ ## QolsysController
8
+ - ✅ Connects directly to the **Qolsys Panel's local MQTT server as an IQ Remote**
9
+ - 🔐 Pairs by only using **Installer Code** (same procedure as standard IQ Remote pairing)
10
+ - 🔢 Supports **4-digit user codes**
11
+ - ⚠️ Uses a **custom local usercode database** — panel's internal user code verification process is not yet supported
12
+
13
+ ## ✨ Functionality Highlights
14
+
15
+ | Category | Feature | Status |
16
+ |------------------------|--------------------------------------|--------|
17
+ | **Panel** | Diagnostic Sensors | ✅ |
18
+ | | Panel Scenes | ✅ |
19
+ | | Weather Forecast | ✅ |
20
+ | | (Alarm.com Weather to Panel) | |
21
+ | **Partition** | Arming Status | ✅ |
22
+ | | Alarm State | ✅ |
23
+ | | Home Instant Arming | ✅ |
24
+ | | Home Silent Disarming (Firmware 4.6.1)| ✅ |
25
+ | | Set Exit Sounds | ✅ |
26
+ | | Set Entry Delay | ✅ |
27
+ | | Disarm Photos | 🛠️ |
28
+ | | TTS | 🛠️ |
29
+ | **Zones** | Sensor Status | ✅ |
30
+ | | Tamper State | ✅ |
31
+ | | Battery Level | ✅ |
32
+ | | Temperature (supported PowerG device)| ✅ |
33
+ | | Light (supported PowerG device) | ✅ |
34
+ | | Average dBm | ✅ |
35
+ | | Latest dBm | ✅ |
36
+ | **Z-Wave Devices** | Battery Level | ✅ |
37
+ | | Node Status | ✅ |
38
+ | | Control Generic Devices | TBD |
39
+ | **Z-Wave Dimmers** | Light Status and Level Control | ✅ |
40
+ | **Z-Wave Door Locks** | Lock, Unlock | ✅ |
41
+ | **Z-Wave Thermostats** | Read device status | ✅ |
42
+ | | Write device status | ✅ |
43
+ | **Z-Wave Garage Doors**| | 🛠️ |
44
+ | **Z-Wave Outlets** | | 🛠️ |
45
+
46
+
47
+ ## ⚠️ Certificate Warning
48
+
49
+ During pairing, the main panel issues **only one signed client certificate** per virtual IQ Remote. If any key files are lost or deleted, re-pairing may become impossible.
50
+
51
+ A new PKI, including a new private key, can be recreated under specific circumstances, though the precise conditions remain unknown at this time.
52
+
53
+ **Important:**
54
+ Immediately back up the following files from the `pki/` directory after initial pairing:
55
+
56
+ - `.key` (private key)
57
+ - `.cer` (certificate)
58
+ - `.csr` (certificate signing request)
59
+ - `.secure` (signed client certificate)
60
+ - `.qolsys` (Qolsys Panel public certificate)
61
+
62
+ Store these files securely.
63
+
64
+ ## 📦 Installation
65
+
66
+ ```bash
67
+ git clone https://github.com/EHylands/QolsysController.git
68
+ cd qolsys_controller
69
+ pip3.12 install -r requirements.txt
70
+
71
+ # Change panel_ip and plugin_in in main.py file
72
+ python3.12 example.py
73
+ ```
@@ -55,8 +55,7 @@ async def main() -> None: # noqa: D103
55
55
  #await asyncio.sleep(5)
56
56
 
57
57
  #await remote.plugin.stop_operation()
58
-
59
- LOGGER.debug("Qolsys Panel - Stopped")
58
+ #LOGGER.debug("Qolsys Panel - Stopped")
60
59
 
61
60
  # Change Z-Wave dimmer
62
61
  # node_id: z-wane device id
@@ -65,17 +64,18 @@ async def main() -> None: # noqa: D103
65
64
  # await remote.plugin.command_zwave_switch_multi_level(node_id=6,level=99)
66
65
 
67
66
  # DISARM
68
- # await asyncio.sleep(3)
69
- # await remote.plugin.command_disarm(partition_id="0",
67
+ #await asyncio.sleep(3)
68
+ #await remote.plugin.command_disarm(partition_id="0",
70
69
  # user_code="1111")
71
70
 
72
71
  # ARM_STAY
73
- await asyncio.sleep(3)
74
- await remote.plugin.command_arm(partition_id="0",
75
- arming_type="ARM-STAY",
76
- user_code="1111",
77
- exit_sounds=False,
78
- instant_arm=True)
72
+ #await asyncio.sleep(3)
73
+ #await remote.plugin.command_arm(partition_id="0",
74
+ # arming_type="ARM-STAY",
75
+ # user_code="1111",
76
+ # exit_sounds=False,
77
+ # instant_arm=True,
78
+ # entry_delay=False)
79
79
 
80
80
 
81
81
  # ARM_AWAY
@@ -87,9 +87,15 @@ async def main() -> None: # noqa: D103
87
87
  # instant_arm=True)
88
88
 
89
89
  # DISARM
90
- await asyncio.sleep(5)
91
- await remote.plugin.command_disarm(partition_id="0", user_code="1111", silent_disarming=True)
90
+ #await asyncio.sleep(5)
91
+ #await remote.plugin.command_disarm(partition_id="0", user_code="1111", silent_disarming=True)
92
92
 
93
+ #await asyncio.sleep(5)
94
+ #await remote.plugin.command_execute_scene(scene_id="3")
95
+
96
+ #await asyncio.sleep(5)
97
+ #await remote.plugin.command_zwave_switch_multi_level(6,80)
98
+ #await remote.plugin.command_zwave_doorlock_set(node_id="7",locked=True)
93
99
 
94
100
  # Use an asyncio.Event to keep the program running efficiently
95
101
  stop_event = asyncio.Event()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qolsys-controller"
3
- version = "0.0.19"
3
+ version = "0.0.56"
4
4
  authors = [
5
5
  { name="Eric Hylands", email="" },
6
6
  ]
@@ -27,9 +27,11 @@ build-backend = "hatchling.build"
27
27
  packages = ["qolsys_controller/"]
28
28
 
29
29
  [tool.ruff]
30
- line-length = 88
30
+ line-length = 100
31
31
 
32
32
  [tool.ruff.lint]
33
33
  select = ['ALL']
34
34
  ignore = ["E501","S608","S311","S104","D100","D101", "D102","D107","ERA001", "FBT001","FBT002", "N802","N806","PERF401"]
35
35
 
36
+ [tool.ruff.lint.mccabe]
37
+ max-complexity = 25
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
2
4
  import logging
5
+ from typing import TYPE_CHECKING
6
+
7
+ from qolsys_controller.plugin import QolsysPlugin
3
8
 
4
9
  from .panel import QolsysPanel
5
10
  from .plugin_c4 import QolsysPluginC4
@@ -9,21 +14,27 @@ from .state import QolsysState
9
14
 
10
15
  LOGGER = logging.getLogger(__name__)
11
16
 
17
+ if TYPE_CHECKING:
18
+ from .plugin import QolsysPlugin
12
19
 
13
20
  class QolsysController:
14
21
 
15
22
  def __init__(self) -> None:
16
23
 
17
24
  # QolsysController Information
18
- self.plugin = None
19
- self._state = QolsysState()
20
- self._settings = QolsysSettings()
21
- self._panel = QolsysPanel(settings=self.settings, state=self.state)
25
+ self._plugin: QolsysPlugin | None = None
26
+ self._state = QolsysState(self)
27
+ self._settings = QolsysSettings(self)
28
+ self._panel = QolsysPanel(self)
22
29
 
23
30
  @property
24
31
  def state(self) -> QolsysState:
25
32
  return self._state
26
33
 
34
+ @property
35
+ def plugin(self) -> QolsysPlugin:
36
+ return self._plugin
37
+
27
38
  @property
28
39
  def panel(self) -> QolsysPanel:
29
40
  return self._panel
@@ -38,13 +49,13 @@ class QolsysController:
38
49
 
39
50
  case "c4":
40
51
  LOGGER.debug("C4 Plugin Selected")
41
- self.plugin = QolsysPluginC4(self.state, self.panel, self.settings)
52
+ self._plugin = QolsysPluginC4(self)
42
53
  return
43
54
 
44
55
  case "remote":
45
56
  LOGGER.debug("Remote Plugin Selected")
46
- self.plugin = QolsysPluginRemote(self.state, self.panel, self.settings)
57
+ self._plugin = QolsysPluginRemote(self)
47
58
  return
48
59
 
49
60
  case _:
50
- LOGGER.debug("Unknow Plugin Selected")
61
+ LOGGER.error("Unknow Plugin Selected")
@@ -237,6 +237,37 @@ class QolsysDB:
237
237
 
238
238
  return zones
239
239
 
240
+ def get_weather(self) -> list[dict]:
241
+ self.cursor.execute(f"SELECT * FROM {self.table_weather.table} ORDER BY _id")
242
+ self.db.commit()
243
+
244
+ weather_list = []
245
+ columns = [description[0] for description in self.cursor.description]
246
+ for row in self.cursor.fetchall():
247
+ row_dict = dict(zip(columns, row, strict=True))
248
+ weather_list.append(row_dict)
249
+
250
+ return weather_list
251
+
252
+ def get_powerg(self, short_id: str) -> dict:
253
+ try:
254
+ self.cursor.execute(f"SELECT * FROM {self.table_powerg_device.table} WHERE shortID = ?",(short_id,))
255
+ self.db.commit()
256
+
257
+ row = self.cursor.fetchone()
258
+
259
+ if row is None:
260
+ LOGGER.debug("%s value not found", short_id)
261
+ return None
262
+
263
+ columns = [description[0] for description in self.cursor.description]
264
+ return dict(zip(columns, row, strict=True))
265
+
266
+ except sqlite3.Error:
267
+ LOGGER.exception("Error getting PowerG device info for shortID %s", short_id)
268
+ return None
269
+
270
+
240
271
  def get_setting_panel(self, setting: str) -> str:
241
272
  self.cursor.execute(f"""SELECT value FROM {self.table_qolsyssettings.table}
242
273
  WHERE name = ? and partition_id = ? """, (setting, "0"))
@@ -68,6 +68,7 @@ class QolsysTable:
68
68
  raise error from err
69
69
 
70
70
  def insert(self, data: dict) -> None:
71
+
71
72
  try:
72
73
  if not self._implemented and data is not None:
73
74
  LOGGER.warning("New Table format: %s", self.uri)
@@ -92,6 +93,7 @@ class QolsysTable:
92
93
 
93
94
  col_str = ", ".join(full_data.keys())
94
95
  placeholder_str = ", ".join([f":{key}" for key in full_data])
96
+
95
97
  query = f"INSERT OR IGNORE INTO {self.table} ({col_str}) VALUES ({placeholder_str})"
96
98
  self._cursor.execute(query, full_data)
97
99
  self._db.commit()
@@ -106,25 +108,43 @@ class QolsysTable:
106
108
  if self._abort_on_error:
107
109
  raise error from err
108
110
 
109
- def update(self, selection: str, selection_argument: str, content_value: str) -> None:
111
+ def update(self, selection: str | None, selection_argument: list | str | None, content_value: str | None) -> None:
110
112
  # selection: 'zone_id=?, parition_id=?'
111
113
  # Firmware 4.4.1: selection_argument: '[3,1]'
112
114
  # Firmware 4.6.1: selection_argument: ['3','1']
113
115
  # contentValues:{"partition_id":"0","sensorgroup":"safetymotion","sensorstatus":"Idle"}"
114
116
 
115
- # New Values to update in table
116
- db_value = ",".join([f"{key}='{value}'" for key, value in content_value.items()])
117
-
118
- # Selection Argument
119
- # Panel send selection_argument as list in Firmware 4.6.1
120
- if(type(selection_argument) is not list):
121
- #Firmware 4.4.1, seletion_argument is sent as a string
117
+ # Firmware 4.4.1: seletion_argument is sent as a string and needs to be converted to an array
118
+ if(type(selection_argument) is str):
122
119
  selection_argument = selection_argument.strip("[]")
123
120
  selection_argument = [item.strip() for item in selection_argument.split(",")]
124
121
 
125
122
  try:
126
- query = f"UPDATE {self.table} SET {db_value} WHERE {selection}"
127
- self._cursor.execute(query, selection_argument)
123
+ full_data = {}
124
+ new_columns = []
125
+
126
+ for key, value in content_value.items():
127
+ if key in self._columns:
128
+ full_data[key] = value
129
+ else:
130
+ new_columns.append(key)
131
+
132
+ db_value = ",".join([f"{key}='{value}'" for key, value in full_data.items()])
133
+
134
+ # Warn if new column found in iq2meid database
135
+ if new_columns:
136
+ LOGGER.warning("New column found in iq2meid database")
137
+ LOGGER.warning("Table: %s", self.table)
138
+ LOGGER.warning("New Columns: %s", new_columns)
139
+ LOGGER.warning("Please Report")
140
+
141
+ if selection:
142
+ query = f"UPDATE {self.table} SET {db_value} WHERE {selection}"
143
+ self._cursor.execute(query, selection_argument)
144
+ else:
145
+ query = f"UPDATE {self.table} SET {db_value}"
146
+ self._cursor.execute(query)
147
+
128
148
  self._db.commit()
129
149
 
130
150
  except sqlite3.Error as err:
@@ -140,20 +160,23 @@ class QolsysTable:
140
160
  if self._abort_on_error:
141
161
  raise error from err
142
162
 
143
- def delete(self, selection: str, selection_argument: str) -> None:
163
+ def delete(self, selection: str | None, selection_argument: list | str | None) -> None:
144
164
  # selection: 'zone_id=?, parition_id=?'
145
165
  # Firmware 4.4.1: selection_argument: '[3,1]'
146
166
  # Firmware 4.6.1: selection_argument: ['3','1']
147
167
 
148
- # Selection Argument
149
- if(type(selection_argument) is not list):
150
- #Firmware 4.4.1, seletion_argument is sent as a string
168
+ # Firmware 4.4.1: seletion_argument is sent as a string and needs to be converted to an array
169
+ if(type(selection_argument) is str):
151
170
  selection_argument = selection_argument.strip("[]")
152
171
  selection_argument = [item.strip() for item in selection_argument.split(",")]
153
172
 
154
173
  try:
155
- query = f"DELETE FROM {self.table} WHERE {selection}"
156
- self._cursor.execute(query, selection_argument)
174
+ if selection:
175
+ query = f"DELETE FROM {self.table} WHERE {selection}"
176
+ self._cursor.execute(query, selection_argument)
177
+ else:
178
+ self.clear()
179
+
157
180
  self._db.commit()
158
181
 
159
182
  except sqlite3.Error as err:
@@ -29,6 +29,7 @@ class QolsysTableDashboardMsgs(QolsysTable):
29
29
  "end_time",
30
30
  "read",
31
31
  "mime_type",
32
+ "type",
32
33
  ]
33
34
 
34
35
  self._create_table()
@@ -12,7 +12,7 @@ class QolsysTableDimmerLight(QolsysTable):
12
12
  super().__init__(db, cursor)
13
13
  self._uri = "content://com.qolsys.qolsysprovider.DimmerLightsContentProvider/dimmerlight"
14
14
  self._table = "dimmerlight"
15
- self._abort_on_error = True
15
+ self._abort_on_error = False
16
16
  self._implemented = True
17
17
 
18
18
  self._columns = [
@@ -12,11 +12,12 @@ class QolsysTableDoorLock(QolsysTable):
12
12
  super().__init__(db, cursor)
13
13
  self._uri = "content://com.qolsys.qolsysprovider.DoorLocksContentProvider/doorlock"
14
14
  self._table = "doorlock"
15
- self._abort_on_error = True
15
+ self._abort_on_error = False
16
16
  self._implemented = True
17
17
 
18
18
  self._columns = [
19
19
  "_id",
20
+ "capabilities",
20
21
  "version",
21
22
  "opr",
22
23
  "partition_id",
@@ -32,6 +33,7 @@ class QolsysTableDoorLock(QolsysTable):
32
33
  "panel_arming",
33
34
  "endpoint",
34
35
  "paired_status",
36
+ "configuration",
35
37
  ]
36
38
 
37
39
  self._create_table()
@@ -13,12 +13,21 @@ class QolsysTableEuEvent(QolsysTable):
13
13
  self._uri = "content://com.qolsys.qolsysprovider.EUEventContentProvider/eu_event"
14
14
  self._table = "eu_event"
15
15
  self._abort_on_error = False
16
- self._implemented = False
16
+ self._implemented = True
17
17
 
18
18
 
19
19
  self._columns = [
20
20
  "_id",
21
+ "version",
22
+ "opr",
23
+ "partition_id",
24
+ "history_id",
25
+ "device_id",
26
+ "device",
27
+ "events",
28
+ "time",
29
+ "ack",
30
+ "type",
21
31
  ]
22
32
 
23
33
  self._create_table()
24
-
@@ -39,6 +39,7 @@ class QolsysTableMasterSlave(QolsysTable):
39
39
  "dhcpInfo",
40
40
  "topology",
41
41
  "reboot_reason",
42
+ "field_remote_camera_streaming",
42
43
  ]
43
44
 
44
45
  self._create_table()
@@ -0,0 +1,47 @@
1
+ import logging # noqa: INP001
2
+ import sqlite3
3
+
4
+ from .table import QolsysTable
5
+
6
+ LOGGER = logging.getLogger(__name__)
7
+
8
+
9
+ class QolsysTablePowerGDevice(QolsysTable):
10
+
11
+ def __init__(self, db: sqlite3.Connection, cursor: sqlite3.Cursor) -> None:
12
+ super().__init__(db, cursor)
13
+ self._uri = "content://com.qolsys.qolsysprovider.PowerGDeviceContentProvider/powerg_device"
14
+ self._table = "powerg_device"
15
+ self._abort_on_error = False
16
+ self._implemented = True
17
+
18
+
19
+ self._columns = [
20
+ "_id",
21
+ "avg_link_quality",
22
+ "battery_voltage",
23
+ "capabilities",
24
+ "dealer_code",
25
+ "extras",
26
+ "firmware_version",
27
+ "led",
28
+ "light",
29
+ "link_quality",
30
+ "link_status",
31
+ "longID",
32
+ "manufacturing_id",
33
+ "notification_period",
34
+ "opr",
35
+ "parent_node",
36
+ "partition_id",
37
+ "radio_id",
38
+ "radio_version",
39
+ "shortID",
40
+ "status_data",
41
+ "supported_type",
42
+ "temperature",
43
+ "version",
44
+ "writeable_capabilities",
45
+ ]
46
+
47
+ self._create_table()
@@ -12,7 +12,7 @@ class QolsysTableQolsysSettings(QolsysTable):
12
12
  super().__init__(db, cursor)
13
13
  self._uri = "content://com.qolsys.qolsysprovider.QolsysSettingsProvider/qolsyssettings"
14
14
  self._table = "qolsyssettings"
15
- self._abort_on_error = True
15
+ self._abort_on_error = False
16
16
  self._implemented = True
17
17
 
18
18
 
@@ -40,6 +40,9 @@ class QolsysTableSensor(QolsysTable):
40
40
  "zone_supervised",
41
41
  "zone_two_way_voice_enabled",
42
42
  "zone_reporting_enabled",
43
+ "zone_feature1",
44
+ "zone_feature2",
45
+ "zone_feature3",
43
46
  "battery_status",
44
47
  "created_date",
45
48
  "created_by",
@@ -59,6 +62,7 @@ class QolsysTableSensor(QolsysTable):
59
62
  "latestdBm",
60
63
  "averagedBm",
61
64
  "serial_number",
65
+ "secondary_panel_mac_address",
62
66
  "extras",
63
67
  "allowspeaker",
64
68
  ]
@@ -39,6 +39,7 @@ class QolsysTableUser(QolsysTable):
39
39
  "start_date",
40
40
  "tag_flag",
41
41
  "check_in_time",
42
+ "user_feature1",
42
43
  ]
43
44
 
44
45
  self._create_table()
@@ -12,7 +12,7 @@ class QolsysTableWeather(QolsysTable):
12
12
  super().__init__(db, cursor)
13
13
  self._uri = "content://com.qolsys.qolsysprovider.ForecastWeatherContentProvider/weather"
14
14
  self._table = "weather"
15
- self._abort_on_error = True
15
+ self._abort_on_error = False
16
16
  self._implemented = True
17
17
 
18
18
  self._columns = [
@@ -12,7 +12,7 @@ class QolsysTableZwaveNode(QolsysTable):
12
12
  super().__init__(db, cursor)
13
13
  self._uri = "content://com.qolsys.qolsysprovider.ZwaveContentProvider/zwave_node"
14
14
  self._table = "zwave_node"
15
- self._abort_on_error = True
15
+ self._abort_on_error = False
16
16
  self._implemented = True
17
17
 
18
18
  self._columns = [
@@ -57,6 +57,7 @@ class QolsysTableZwaveNode(QolsysTable):
57
57
  "last_rediscover_time",
58
58
  "neighbour_info",
59
59
  "last_node_test_time",
60
+ "notification_capabilities",
60
61
  "endpoint",
61
62
  "endpoint_details",
62
63
  "device_wakeup_time",
@@ -13,10 +13,23 @@ class QolsysTableZwaveOther(QolsysTable):
13
13
  self._uri = "content://com.qolsys.qolsysprovider.ZwaveOtherDeviceContentProvider/zwave_other"
14
14
  self._table = "zwave_other"
15
15
  self._abort_on_error = False
16
- self._implemented = False
16
+ self._implemented = True
17
17
 
18
18
  self._columns = [
19
19
  "_id",
20
+ "created_date",
21
+ "device_name",
22
+ "device_params_1",
23
+ "device_params_2",
24
+ "endpoint",
25
+ "last_updated_date",
26
+ "node_id",
27
+ "node_type",
28
+ "opr",
29
+ "paired_status",
30
+ "partition_id",
31
+ "status",
32
+ "version",
20
33
  ]
21
34
 
22
35
  self._create_table()