qolsys-controller 0.0.2__tar.gz → 0.0.5__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.
- qolsys_controller-0.0.5/.github/workflows/build.yml +36 -0
- qolsys_controller-0.0.5/.github/workflows/publish.yml +27 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/.gitignore +2 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/PKG-INFO +7 -3
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/README.md +6 -2
- qolsys_controller-0.0.5/bin/qolsys.py +75 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/example.py +19 -20
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/pyproject.toml +2 -2
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/controller.py +6 -8
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/db.py +62 -58
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table.py +24 -25
- qolsys_controller-0.0.5/qolsys_controller/database/table_alarmedsensor.py +46 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_automation.py +77 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_country_locale.py +60 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_dashboard_msgs.py +6 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_dimmerlight.py +57 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_doorlock.py +59 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_eu_event.py +5 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_heat_map.py +44 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_history.py +48 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_iqremotesettings.py +13 -12
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_iqrouter_network_config.py +5 -5
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_iqrouter_user_device.py +5 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_master_slave.py +71 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_partition.py +10 -10
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_powerg_device.py +5 -5
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_qolsyssettings.py +10 -10
- qolsys_controller-0.0.5/qolsys_controller/database/table_scene.py +55 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_sensor.py +121 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_smartsocket.py +5 -5
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_state.py +12 -11
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_tcc.py +6 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_thermostat.py +94 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_trouble_conditions.py +14 -13
- qolsys_controller-0.0.5/qolsys_controller/database/table_user.py +50 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_virtual_device.py +5 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_weather.py +48 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_zigbee_device.py +5 -5
- qolsys_controller-0.0.5/qolsys_controller/database/table_zwave_association_group.py +53 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_zwave_history.py +59 -0
- qolsys_controller-0.0.5/qolsys_controller/database/table_zwave_node.py +150 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/database/table_zwave_other.py +5 -5
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/enum.py +44 -41
- qolsys_controller-0.0.5/qolsys_controller/errors.py +37 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/mdns.py +3 -3
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/mqtt_command_queue.py +2 -3
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/observable.py +3 -2
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/panel.py +163 -161
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/partition.py +46 -43
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/pki.py +72 -65
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/plugin.py +5 -4
- qolsys_controller-0.0.5/qolsys_controller/plugin_c4.py +17 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/plugin_remote.py +237 -228
- qolsys_controller-0.0.5/qolsys_controller/settings.py +155 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/state.py +68 -65
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/task_manager.py +3 -3
- qolsys_controller-0.0.5/qolsys_controller/utils_mqtt.py +24 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zone.py +69 -68
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_device.py +46 -43
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_dimmer.py +28 -26
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_garagedoor.py +1 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_generic.py +2 -1
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_lock.py +28 -30
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_outlet.py +1 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/zwave_thermostat.py +58 -55
- qolsys_controller-0.0.2/config/pki/cc4b73865c89/cc4b73865c89.old_secure +0 -19
- qolsys_controller-0.0.2/config/pki/cc4b73865c89/cc4b73865c89.oldqolsys +0 -20
- qolsys_controller-0.0.2/config/users.conf +0 -10
- qolsys_controller-0.0.2/qolsys_controller/database/table_alarmedsensor.py +0 -45
- qolsys_controller-0.0.2/qolsys_controller/database/table_automation.py +0 -73
- qolsys_controller-0.0.2/qolsys_controller/database/table_country_locale.py +0 -57
- qolsys_controller-0.0.2/qolsys_controller/database/table_dimmerlight.py +0 -55
- qolsys_controller-0.0.2/qolsys_controller/database/table_doorlock.py +0 -57
- qolsys_controller-0.0.2/qolsys_controller/database/table_heat_map.py +0 -43
- qolsys_controller-0.0.2/qolsys_controller/database/table_history.py +0 -47
- qolsys_controller-0.0.2/qolsys_controller/database/table_master_slave.py +0 -68
- qolsys_controller-0.0.2/qolsys_controller/database/table_scene.py +0 -52
- qolsys_controller-0.0.2/qolsys_controller/database/table_sensor.py +0 -112
- qolsys_controller-0.0.2/qolsys_controller/database/table_thermostat.py +0 -87
- qolsys_controller-0.0.2/qolsys_controller/database/table_user.py +0 -49
- qolsys_controller-0.0.2/qolsys_controller/database/table_weather.py +0 -47
- qolsys_controller-0.0.2/qolsys_controller/database/table_zwave_association_group.py +0 -51
- qolsys_controller-0.0.2/qolsys_controller/database/table_zwave_history.py +0 -57
- qolsys_controller-0.0.2/qolsys_controller/database/table_zwave_node.py +0 -145
- qolsys_controller-0.0.2/qolsys_controller/errors.py +0 -37
- qolsys_controller-0.0.2/qolsys_controller/plugin_c4.py +0 -18
- qolsys_controller-0.0.2/qolsys_controller/settings.py +0 -59
- qolsys_controller-0.0.2/qolsys_controller/utils_mqtt.py +0 -21
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/Info_mqtt.md +0 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/LICENSE +0 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/info_pairing.md +0 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/info_qolsys.md +0 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/qolsys_controller/__init__.py +0 -0
- {qolsys_controller-0.0.2 → qolsys_controller-0.0.5}/requirements.txt +0 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
3
|
+
|
4
|
+
name: Build
|
5
|
+
|
6
|
+
on:
|
7
|
+
push:
|
8
|
+
branches: [ "main" ]
|
9
|
+
pull_request:
|
10
|
+
branches: [ "main" ]
|
11
|
+
|
12
|
+
permissions:
|
13
|
+
contents: read
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
build:
|
17
|
+
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v4
|
22
|
+
- name: Set up Python 3.12
|
23
|
+
uses: actions/setup-python@v3
|
24
|
+
with:
|
25
|
+
python-version: "3.12"
|
26
|
+
- name: Install dependencies
|
27
|
+
run: |
|
28
|
+
python -m pip install --upgrade pip
|
29
|
+
pip install flake8 pytest
|
30
|
+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
31
|
+
- name: Lint with flake8
|
32
|
+
run: |
|
33
|
+
# stop the build if there are Python syntax errors or undefined names
|
34
|
+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
35
|
+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
36
|
+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: Publish Python package to PyPI
|
2
|
+
|
3
|
+
on:
|
4
|
+
release:
|
5
|
+
types: [published]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
pypi-publish:
|
9
|
+
name: Upload release to PyPI
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
environment:
|
12
|
+
name: pypi
|
13
|
+
url: https://pypi.org/project/qolsys-controller/
|
14
|
+
permissions:
|
15
|
+
id-token: write # Required for PyPI Trusted Publishers
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v4
|
18
|
+
- name: Set up Python
|
19
|
+
uses: actions/setup-python@v5
|
20
|
+
with:
|
21
|
+
python-version: "3.12"
|
22
|
+
- name: Install build dependencies
|
23
|
+
run: python -m pip install build
|
24
|
+
- name: Build package
|
25
|
+
run: python -m build
|
26
|
+
- name: Publish package to PyPI
|
27
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qolsys-controller
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.5
|
4
4
|
Summary: A Python module that emulates a virtual IQ Remote device, enabling full local control of a Qolsys IQ Panel
|
5
5
|
Project-URL: Homepage, https://github.com/EHylands/QolsysController
|
6
6
|
Project-URL: Issues, https://github.com/EHylands/QolsysController/issues
|
@@ -14,7 +14,9 @@ Classifier: Topic :: Home Automation
|
|
14
14
|
Requires-Python: >=3.12
|
15
15
|
Description-Content-Type: text/markdown
|
16
16
|
|
17
|
-
#
|
17
|
+
# Qolsys Controller - qolsys-controller
|
18
|
+
|
19
|
+
[](https://github.com/EHylands/QolsysController/actions/workflows/python-app.yml)
|
18
20
|
|
19
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.
|
20
22
|
|
@@ -62,7 +64,9 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
62
64
|
|
63
65
|
## ⚠️ Certificate Warning
|
64
66
|
|
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.
|
67
|
+
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.
|
68
|
+
|
69
|
+
A new PKI, including a new private key, can be recreated under specific circumstances, though the precise conditions remain unknown at this time.
|
66
70
|
|
67
71
|
**Important:**
|
68
72
|
Immediately back up the following files from the `pki/` directory after initial pairing:
|
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# Qolsys Controller - qolsys-controller
|
2
|
+
|
3
|
+
[](https://github.com/EHylands/QolsysController/actions/workflows/python-app.yml)
|
2
4
|
|
3
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.
|
4
6
|
|
@@ -46,7 +48,9 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
46
48
|
|
47
49
|
## ⚠️ Certificate Warning
|
48
50
|
|
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.
|
51
|
+
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.
|
52
|
+
|
53
|
+
A new PKI, including a new private key, can be recreated under specific circumstances, though the precise conditions remain unknown at this time.
|
50
54
|
|
51
55
|
**Important:**
|
52
56
|
Immediately back up the following files from the `pki/` directory after initial pairing:
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
|
3
|
+
import argparse
|
4
|
+
import asyncio
|
5
|
+
import logging
|
6
|
+
import os
|
7
|
+
import sys
|
8
|
+
|
9
|
+
from qolsys_controller import qolsys_controller
|
10
|
+
from qolsys_controller.errors import QolsysMqttError, QolsysSqlError, QolsysSslError
|
11
|
+
|
12
|
+
|
13
|
+
async def main() -> None: # noqa: D103
|
14
|
+
|
15
|
+
cli_parser = argparse.ArgumentParser()
|
16
|
+
cli_parser.add_argument("--panel-ip", help="Qolsys Panel IP", default="")
|
17
|
+
cli_parser.add_argument("--plugin-ip", help="Plugin IP", default="")
|
18
|
+
cli_parser.add_argument("--config-dir", help="Configuration Directory", default="./config/")
|
19
|
+
cli_parser.add_argument("--pki-autodiscovery", help="Enable PKI Autodiscovery", action="store_true")
|
20
|
+
cli_parser.add_argument("--debug", help="Verbose MQTT Traffic", action="store_true")
|
21
|
+
|
22
|
+
args = cli_parser.parse_args()
|
23
|
+
|
24
|
+
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s - %(module)s: %(message)s")
|
25
|
+
LOGGER = logging.getLogger(__name__)
|
26
|
+
|
27
|
+
loop = asyncio.new_event_loop()
|
28
|
+
asyncio.set_event_loop(loop)
|
29
|
+
|
30
|
+
Panel = qolsys_controller()
|
31
|
+
|
32
|
+
# Select plugin
|
33
|
+
Panel.select_plugin("remote")
|
34
|
+
Panel.settings.config_directory = args.config_dir
|
35
|
+
Panel.plugin.settings.panel_ip = args.panel_ip
|
36
|
+
Panel.plugin.settings.plugin_ip = args.plugin_ip
|
37
|
+
Panel.plugin.settings.random_mac = ""
|
38
|
+
|
39
|
+
# Additionnal remote plugin config
|
40
|
+
Panel.plugin.check_user_code_on_disarm = False
|
41
|
+
Panel.plugin.log_mqtt_mesages = args.debug
|
42
|
+
Panel.plugin.auto_discover_pki = args.pki_autodiscovery
|
43
|
+
|
44
|
+
# Configure remote plugin
|
45
|
+
if not await Panel.plugin.config(start_pairing=True):
|
46
|
+
LOGGER.debug("Error Configuring remote plugin")
|
47
|
+
return
|
48
|
+
|
49
|
+
try:
|
50
|
+
await Panel.plugin.start_operation()
|
51
|
+
|
52
|
+
except QolsysMqttError:
|
53
|
+
LOGGER.debug("QolsysMqttError")
|
54
|
+
|
55
|
+
except QolsysSslError:
|
56
|
+
LOGGER.debug("QolsysSslError")
|
57
|
+
|
58
|
+
except QolsysSqlError:
|
59
|
+
LOGGER.debug("QolsysSqlError")
|
60
|
+
|
61
|
+
if not Panel.plugin.connected:
|
62
|
+
LOGGER.error("Panel not ready for operation")
|
63
|
+
return
|
64
|
+
|
65
|
+
LOGGER.debug("Qolsys Panel Ready for operation")
|
66
|
+
|
67
|
+
stop_event = asyncio.Event()
|
68
|
+
await stop_event.wait()
|
69
|
+
|
70
|
+
# Change to the "Selector" event loop if platform is Windows
|
71
|
+
if sys.platform.lower() == "win32" or os.name.lower() == "nt":
|
72
|
+
from asyncio import WindowsSelectorEventLoopPolicy, set_event_loop_policy
|
73
|
+
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
74
|
+
|
75
|
+
asyncio.run(main())
|
@@ -8,23 +8,25 @@ import sys
|
|
8
8
|
from qolsys_controller.controller import QolsysController
|
9
9
|
from qolsys_controller.errors import QolsysMqttError, QolsysSqlError, QolsysSslError
|
10
10
|
|
11
|
-
logging.basicConfig(level=logging.DEBUG,format="%(levelname)s - %(module)s: %(message)s")
|
11
|
+
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s - %(module)s: %(message)s")
|
12
12
|
LOGGER = logging.getLogger(__name__)
|
13
13
|
|
14
|
+
|
14
15
|
async def main() -> None: # noqa: D103
|
15
16
|
|
16
|
-
remote = QolsysController(
|
17
|
+
remote = QolsysController()
|
17
18
|
|
18
19
|
# Select plugin
|
19
20
|
remote.select_plugin("remote")
|
20
21
|
|
21
|
-
remote.plugin.settings.
|
22
|
+
remote.plugin.settings.config_directory = "./config/"
|
23
|
+
remote.plugin.settings.panel_ip = "192.168.10.220"
|
22
24
|
remote.plugin.settings.plugin_ip = "192.168.10.73"
|
23
|
-
remote.plugin.settings.random_mac = ""
|
25
|
+
remote.plugin.settings.random_mac = "" # Example: F2:16:3E:33:ED:20
|
24
26
|
|
25
27
|
# Additionnal remote plugin config
|
26
|
-
remote.plugin.check_user_code_on_disarm = False
|
27
|
-
remote.plugin.log_mqtt_mesages = False
|
28
|
+
remote.plugin.check_user_code_on_disarm = False # Check user code in user.conf file
|
29
|
+
remote.plugin.log_mqtt_mesages = False # Enable for MQTT debug purposes
|
28
30
|
remote.plugin.auto_discover_pki = True
|
29
31
|
|
30
32
|
# Configure remote plugin
|
@@ -36,13 +38,13 @@ async def main() -> None: # noqa: D103
|
|
36
38
|
await remote.plugin.start_operation()
|
37
39
|
|
38
40
|
except QolsysMqttError:
|
39
|
-
|
41
|
+
LOGGER.debug("QolsysMqttError")
|
40
42
|
|
41
43
|
except QolsysSslError:
|
42
|
-
|
44
|
+
LOGGER.debug("QolsysSslError")
|
43
45
|
|
44
46
|
except QolsysSqlError:
|
45
|
-
|
47
|
+
LOGGER.debug("QolsysSqlError")
|
46
48
|
|
47
49
|
if not remote.plugin.connected:
|
48
50
|
LOGGER.error("Panel not ready for operation")
|
@@ -56,9 +58,9 @@ async def main() -> None: # noqa: D103
|
|
56
58
|
# await asyncio.sleep(3)
|
57
59
|
# await remote.plugin.command_zwave_switch_multi_level(node_id=6,level=99)
|
58
60
|
|
59
|
-
|
60
|
-
#await asyncio.sleep(3)
|
61
|
-
#await remote.plugin.command_disarm(partition_id="0",
|
61
|
+
# DISARM
|
62
|
+
# await asyncio.sleep(3)
|
63
|
+
# await remote.plugin.command_disarm(partition_id="0",
|
62
64
|
# user_code="1111")
|
63
65
|
|
64
66
|
# ARM_STAY
|
@@ -68,24 +70,23 @@ async def main() -> None: # noqa: D103
|
|
68
70
|
user_code="1111",
|
69
71
|
exit_sounds=False,
|
70
72
|
instant_arm=False)
|
71
|
-
|
72
73
|
|
73
74
|
# DISARM
|
74
75
|
await asyncio.sleep(3)
|
75
76
|
await remote.plugin.command_disarm(partition_id="0",
|
76
77
|
user_code="1111")
|
77
78
|
|
78
|
-
|
79
79
|
# ARM_AWAY
|
80
|
-
#await asyncio.sleep(3)
|
81
|
-
#await remote.plugin.command_arm(partition_id=0,
|
80
|
+
# await asyncio.sleep(3)
|
81
|
+
# await remote.plugin.command_arm(partition_id=0,
|
82
82
|
# arming_type='ARM-AWAY',
|
83
83
|
# user_code='1111',
|
84
84
|
# exit_sounds=True,
|
85
85
|
# instant_arm=False)
|
86
86
|
|
87
|
-
|
88
|
-
|
87
|
+
# Use an asyncio.Event to keep the program running efficiently
|
88
|
+
stop_event = asyncio.Event()
|
89
|
+
await stop_event.wait()
|
89
90
|
|
90
91
|
# Change to the "Selector" event loop if platform is Windows
|
91
92
|
if sys.platform.lower() == "win32" or os.name.lower() == "nt":
|
@@ -93,5 +94,3 @@ if sys.platform.lower() == "win32" or os.name.lower() == "nt":
|
|
93
94
|
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
94
95
|
|
95
96
|
asyncio.run(main())
|
96
|
-
|
97
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "qolsys-controller"
|
3
|
-
version = "0.0.
|
3
|
+
version = "0.0.5"
|
4
4
|
authors = [
|
5
5
|
{ name="Eric Hylands", email="" },
|
6
6
|
]
|
@@ -31,5 +31,5 @@ line-length = 88
|
|
31
31
|
|
32
32
|
[tool.ruff.lint]
|
33
33
|
select = ['ALL']
|
34
|
-
ignore = ["E501","S608","S311","S104","D100","D101", "D102","D107", "FBT001", "N802","N806","PERF401"]
|
34
|
+
ignore = ["E501","S608","S311","S104","D100","D101", "D102","D107","ERA001", "FBT001","FBT002", "N802","N806","PERF401"]
|
35
35
|
|
@@ -9,16 +9,16 @@ from .state import QolsysState
|
|
9
9
|
|
10
10
|
LOGGER = logging.getLogger(__name__)
|
11
11
|
|
12
|
+
|
12
13
|
class QolsysController:
|
13
14
|
|
14
|
-
def __init__(self
|
15
|
+
def __init__(self) -> None:
|
15
16
|
|
16
17
|
# QolsysController Information
|
17
18
|
self.plugin = None
|
18
|
-
self._config_directory = config_directory
|
19
19
|
self._state = QolsysState()
|
20
|
-
self._panel = QolsysPanel(settings_directory=config_directory,state=self.state)
|
21
20
|
self._settings = QolsysSettings()
|
21
|
+
self._panel = QolsysPanel(settings=self.settings, state=self.state)
|
22
22
|
|
23
23
|
@property
|
24
24
|
def state(self) -> QolsysState:
|
@@ -32,21 +32,19 @@ class QolsysController:
|
|
32
32
|
def settings(self) -> QolsysSettings:
|
33
33
|
return self._settings
|
34
34
|
|
35
|
-
def select_plugin(self,plugin: str) -> None:
|
35
|
+
def select_plugin(self, plugin: str) -> None:
|
36
36
|
|
37
37
|
match plugin:
|
38
38
|
|
39
39
|
case "c4":
|
40
40
|
LOGGER.debug("C4 Plugin Selected")
|
41
|
-
self.plugin = QolsysPluginC4(self.state,self.panel,self.settings)
|
41
|
+
self.plugin = QolsysPluginC4(self.state, self.panel, self.settings)
|
42
42
|
return
|
43
43
|
|
44
44
|
case "remote":
|
45
45
|
LOGGER.debug("Remote Plugin Selected")
|
46
|
-
self.plugin = QolsysPluginRemote(self.state,self.panel,self.settings
|
46
|
+
self.plugin = QolsysPluginRemote(self.state, self.panel, self.settings)
|
47
47
|
return
|
48
48
|
|
49
49
|
case _:
|
50
50
|
LOGGER.debug("Unknow Plugin Selected")
|
51
|
-
|
52
|
-
|
@@ -36,44 +36,45 @@ from .table_zwave_other import QolsysTableZwaveOther
|
|
36
36
|
|
37
37
|
LOGGER = logging.getLogger(__name__)
|
38
38
|
|
39
|
+
|
39
40
|
class QolsysDB:
|
40
41
|
|
41
42
|
def __init__(self) -> None: # noqa: PLR0915
|
42
43
|
|
43
|
-
self._db:sqlite3.Connection = sqlite3.connect(":memory:")
|
44
|
-
self._cursor:sqlite3.Cursor = self._db.cursor()
|
45
|
-
|
46
|
-
self.table_alarmedsensor = QolsysTableAlarmedSensor(self.db,self.cursor)
|
47
|
-
self.table_automation = QolsysTableAutomation(self.db,self.cursor)
|
48
|
-
self.table_country_locale = QolsysTableCountryLocale(self.db,self.cursor)
|
49
|
-
self.table_dashboard_msgs = QolsysTableDashboardMsgs(self.db,self.cursor)
|
50
|
-
self.table_dimmer = QolsysTableDimmerLight(self.db,self.cursor)
|
51
|
-
self.table_doorlock = QolsysTableDoorLock(self.db,self.cursor)
|
52
|
-
self.table_eu_event = QolsysTableEuEvent(self.db,self.cursor)
|
53
|
-
self.table_heat_map = QolsysTableHeatMap(self.db,self.cursor)
|
54
|
-
self.table_history = QolsysTableHistory(self.db,self.cursor)
|
55
|
-
self.table_iqremotesettings = QolsysTableIqRemoteSettings(self.db,self.cursor)
|
56
|
-
self.table_iqrouter_network_config = QolsysTableIqRouterNetworkConfig(self.db,self.cursor)
|
57
|
-
self.table_iqrouter_user_device = QolsysTableIqRouterUserDevice(self.db,self.cursor)
|
58
|
-
self.table_master_slave = QolsysTableMasterSlave(self.db,self.cursor)
|
59
|
-
self.table_partition = QolsysTablePartition(self.db,self.cursor)
|
60
|
-
self.table_powerg_device = QolsysTablePowerGDevice(self.db,self.cursor)
|
61
|
-
self.table_sensor = QolsysTableSensor(self.db,self.cursor)
|
62
|
-
self.table_smartsocket = QolsysTableSmartSocket(self.db,self.cursor)
|
63
|
-
self.table_qolsyssettings = QolsysTableQolsysSettings(self.db,self.cursor)
|
64
|
-
self.table_scene = QolsysTableScene(self.db,self.cursor)
|
65
|
-
self.table_state = QolsysTableState(self.db,self.cursor)
|
66
|
-
self.table_tcc = QolsysTableTcc(self.db,self.cursor)
|
67
|
-
self.table_thermostat = QolsysTableThermostat(self.db,self.cursor)
|
68
|
-
self.table_trouble_conditions = QolsysTableTroubleConditions(self.db,self.cursor)
|
69
|
-
self.table_user = QolsysTableUser(self.db,self.cursor)
|
70
|
-
self.table_virtual_device = QolsysTableVirtualDevice(self.db,self.cursor)
|
71
|
-
self.table_weather = QolsysTableWeather(self.db,self.cursor)
|
72
|
-
self.table_zigbee_device = QolsysTableZigbeeDevice(self.db,self.cursor)
|
73
|
-
self.table_zwave_association_goup = QolsysTableZwaveAssociationGroup(self.db,self.cursor)
|
74
|
-
self.table_zwave_history = QolsysTableZwaveHistory(self.db,self.cursor)
|
75
|
-
self.table_zwave_node = QolsysTableZwaveNode(self.db,self.cursor)
|
76
|
-
self.table_zwave_other = QolsysTableZwaveOther(self.db,self.cursor)
|
44
|
+
self._db: sqlite3.Connection = sqlite3.connect(":memory:")
|
45
|
+
self._cursor: sqlite3.Cursor = self._db.cursor()
|
46
|
+
|
47
|
+
self.table_alarmedsensor = QolsysTableAlarmedSensor(self.db, self.cursor)
|
48
|
+
self.table_automation = QolsysTableAutomation(self.db, self.cursor)
|
49
|
+
self.table_country_locale = QolsysTableCountryLocale(self.db, self.cursor)
|
50
|
+
self.table_dashboard_msgs = QolsysTableDashboardMsgs(self.db, self.cursor)
|
51
|
+
self.table_dimmer = QolsysTableDimmerLight(self.db, self.cursor)
|
52
|
+
self.table_doorlock = QolsysTableDoorLock(self.db, self.cursor)
|
53
|
+
self.table_eu_event = QolsysTableEuEvent(self.db, self.cursor)
|
54
|
+
self.table_heat_map = QolsysTableHeatMap(self.db, self.cursor)
|
55
|
+
self.table_history = QolsysTableHistory(self.db, self.cursor)
|
56
|
+
self.table_iqremotesettings = QolsysTableIqRemoteSettings(self.db, self.cursor)
|
57
|
+
self.table_iqrouter_network_config = QolsysTableIqRouterNetworkConfig(self.db, self.cursor)
|
58
|
+
self.table_iqrouter_user_device = QolsysTableIqRouterUserDevice(self.db, self.cursor)
|
59
|
+
self.table_master_slave = QolsysTableMasterSlave(self.db, self.cursor)
|
60
|
+
self.table_partition = QolsysTablePartition(self.db, self.cursor)
|
61
|
+
self.table_powerg_device = QolsysTablePowerGDevice(self.db, self.cursor)
|
62
|
+
self.table_sensor = QolsysTableSensor(self.db, self.cursor)
|
63
|
+
self.table_smartsocket = QolsysTableSmartSocket(self.db, self.cursor)
|
64
|
+
self.table_qolsyssettings = QolsysTableQolsysSettings(self.db, self.cursor)
|
65
|
+
self.table_scene = QolsysTableScene(self.db, self.cursor)
|
66
|
+
self.table_state = QolsysTableState(self.db, self.cursor)
|
67
|
+
self.table_tcc = QolsysTableTcc(self.db, self.cursor)
|
68
|
+
self.table_thermostat = QolsysTableThermostat(self.db, self.cursor)
|
69
|
+
self.table_trouble_conditions = QolsysTableTroubleConditions(self.db, self.cursor)
|
70
|
+
self.table_user = QolsysTableUser(self.db, self.cursor)
|
71
|
+
self.table_virtual_device = QolsysTableVirtualDevice(self.db, self.cursor)
|
72
|
+
self.table_weather = QolsysTableWeather(self.db, self.cursor)
|
73
|
+
self.table_zigbee_device = QolsysTableZigbeeDevice(self.db, self.cursor)
|
74
|
+
self.table_zwave_association_goup = QolsysTableZwaveAssociationGroup(self.db, self.cursor)
|
75
|
+
self.table_zwave_history = QolsysTableZwaveHistory(self.db, self.cursor)
|
76
|
+
self.table_zwave_node = QolsysTableZwaveNode(self.db, self.cursor)
|
77
|
+
self.table_zwave_other = QolsysTableZwaveOther(self.db, self.cursor)
|
77
78
|
|
78
79
|
self._table_array = []
|
79
80
|
self._table_array.append(self.table_sensor)
|
@@ -143,108 +144,111 @@ class QolsysDB:
|
|
143
144
|
return self._cursor
|
144
145
|
|
145
146
|
def get_partitions(self) -> list[dict]:
|
146
|
-
self.cursor.execute(f"SELECT * FROM {self.table_partition.table} ORDER BY partition_id"
|
147
|
+
self.cursor.execute(f"SELECT * FROM {self.table_partition.table} ORDER BY partition_id")
|
147
148
|
self.db.commit()
|
148
149
|
|
149
150
|
partitions = []
|
150
151
|
columns = [description[0] for description in self.cursor.description]
|
151
|
-
for row in
|
152
|
+
for row in self.cursor.fetchall():
|
152
153
|
row_dict = dict(zip(columns, row, strict=True))
|
153
154
|
partitions.append(row_dict)
|
154
155
|
|
155
156
|
return partitions
|
156
157
|
|
157
158
|
def get_zwave_devices(self) -> list[dict]:
|
158
|
-
self.cursor.execute(f"SELECT * FROM {self.table_zwave_node.table} ORDER BY node_id"
|
159
|
+
self.cursor.execute(f"SELECT * FROM {self.table_zwave_node.table} ORDER BY node_id")
|
159
160
|
self.db.commit()
|
160
161
|
|
161
162
|
devices = []
|
162
163
|
columns = [description[0] for description in self.cursor.description]
|
163
|
-
for row in
|
164
|
+
for row in self.cursor.fetchall():
|
164
165
|
row_dict = dict(zip(columns, row, strict=True))
|
165
166
|
devices.append(row_dict)
|
166
167
|
|
167
168
|
return devices
|
168
169
|
|
169
170
|
def get_locks(self) -> list[dict]:
|
170
|
-
self.cursor.execute(f"SELECT * FROM {self.table_doorlock.table} ORDER BY node_id"
|
171
|
+
self.cursor.execute(f"SELECT * FROM {self.table_doorlock.table} ORDER BY node_id")
|
171
172
|
self.db.commit()
|
172
173
|
|
173
174
|
locks = []
|
174
175
|
columns = [description[0] for description in self.cursor.description]
|
175
|
-
for row in
|
176
|
+
for row in self.cursor.fetchall():
|
176
177
|
row_dict = dict(zip(columns, row, strict=True))
|
177
178
|
locks.append(row_dict)
|
178
179
|
|
179
180
|
return locks
|
180
181
|
|
181
182
|
def get_thermostats(self) -> list[dict]:
|
182
|
-
self.cursor.execute(f"SELECT * FROM {self.table_thermostat.table} ORDER BY node_id"
|
183
|
+
self.cursor.execute(f"SELECT * FROM {self.table_thermostat.table} ORDER BY node_id")
|
183
184
|
self.db.commit()
|
184
185
|
|
185
186
|
thermostats = []
|
186
187
|
columns = [description[0] for description in self.cursor.description]
|
187
|
-
for row in
|
188
|
+
for row in self.cursor.fetchall():
|
188
189
|
row_dict = dict(zip(columns, row, strict=True))
|
189
190
|
thermostats.append(row_dict)
|
190
191
|
|
191
192
|
return thermostats
|
192
193
|
|
193
194
|
def get_dimmers(self) -> list[dict]:
|
194
|
-
self.cursor.execute(f"SELECT * FROM {self.table_dimmer.table} ORDER BY node_id"
|
195
|
+
self.cursor.execute(f"SELECT * FROM {self.table_dimmer.table} ORDER BY node_id")
|
195
196
|
self.db.commit()
|
196
197
|
|
197
198
|
dimmers = []
|
198
199
|
columns = [description[0] for description in self.cursor.description]
|
199
|
-
for row in
|
200
|
+
for row in self.cursor.fetchall():
|
200
201
|
row_dict = dict(zip(columns, row, strict=True))
|
201
202
|
dimmers.append(row_dict)
|
202
203
|
|
203
204
|
return dimmers
|
204
205
|
|
205
206
|
def get_zones(self) -> list[dict]:
|
206
|
-
self.cursor.execute(f"SELECT * FROM {self.table_sensor.table} ORDER BY zoneid"
|
207
|
+
self.cursor.execute(f"SELECT * FROM {self.table_sensor.table} ORDER BY zoneid")
|
207
208
|
self.db.commit()
|
208
209
|
|
209
210
|
zones = []
|
210
211
|
columns = [description[0] for description in self.cursor.description]
|
211
|
-
for row in
|
212
|
+
for row in self.cursor.fetchall():
|
212
213
|
row_dict = dict(zip(columns, row, strict=True))
|
213
214
|
zones.append(row_dict)
|
214
215
|
|
215
216
|
return zones
|
216
217
|
|
217
|
-
def get_setting_panel(self,setting:str) -> str:
|
218
|
-
self.cursor.execute(f"SELECT value FROM {self.table_qolsyssettings.table}
|
218
|
+
def get_setting_panel(self, setting: str) -> str:
|
219
|
+
self.cursor.execute(f"""SELECT value FROM {self.table_qolsyssettings.table}
|
220
|
+
WHERE name = ? and partition_id = ? """, (setting, "0"))
|
219
221
|
row = self.cursor.fetchone()
|
220
222
|
|
221
223
|
if row is None:
|
222
|
-
LOGGER.debug("%s value not found",setting)
|
224
|
+
LOGGER.debug("%s value not found", setting)
|
223
225
|
return None
|
224
226
|
|
225
227
|
return row[0]
|
226
228
|
|
227
|
-
def get_setting_partition(self,setting:str,partition_id:str) -> str | None:
|
228
|
-
self.cursor.execute(f"SELECT value FROM {self.table_qolsyssettings.table}
|
229
|
+
def get_setting_partition(self, setting: str, partition_id: str) -> str | None:
|
230
|
+
self.cursor.execute(f"""SELECT value FROM {self.table_qolsyssettings.table}
|
231
|
+
WHERE name = ? and partition_id = ? """, (setting, partition_id))
|
229
232
|
row = self.cursor.fetchone()
|
230
233
|
|
231
234
|
if row is None:
|
232
|
-
LOGGER.debug("%s value not found",setting)
|
235
|
+
LOGGER.debug("%s value not found", setting)
|
233
236
|
return None
|
234
237
|
|
235
238
|
return row[0]
|
236
239
|
|
237
|
-
def get_state_partition(self,state:str,partition_id:str) -> str | None:
|
238
|
-
self.cursor.execute(
|
240
|
+
def get_state_partition(self, state: str, partition_id: str) -> str | None:
|
241
|
+
self.cursor.execute(
|
242
|
+
f"""SELECT value FROM {self.table_state.table} WHERE name = ? and partition_id = ? """, (state, partition_id))
|
239
243
|
row = self.cursor.fetchone()
|
240
244
|
|
241
245
|
if row is None:
|
242
|
-
LOGGER.debug("%s value not found",state)
|
246
|
+
LOGGER.debug("%s value not found", state)
|
243
247
|
return None
|
244
248
|
|
245
249
|
return row[0]
|
246
250
|
|
247
|
-
def get_alarm_type(self,partition_id:str) -> list[str]:
|
251
|
+
def get_alarm_type(self, partition_id: str) -> list[str]:
|
248
252
|
alarm_type = []
|
249
253
|
self.cursor.execute(f"SELECT sgroup FROM {self.table_alarmedsensor.table} WHERE partition_id = ? ", (partition_id))
|
250
254
|
rows = self.cursor.fetchall()
|
@@ -258,14 +262,14 @@ class QolsysDB:
|
|
258
262
|
for table in self._table_array:
|
259
263
|
table.clear()
|
260
264
|
|
261
|
-
def get_table(self,uri:str) -> QolsysTable | None:
|
265
|
+
def get_table(self, uri: str) -> QolsysTable | None:
|
262
266
|
for table in self._table_array:
|
263
267
|
if uri == table.uri:
|
264
268
|
return table
|
265
269
|
|
266
270
|
return None
|
267
271
|
|
268
|
-
def load_db(self,database:dict) -> None:
|
272
|
+
def load_db(self, database: dict) -> None:
|
269
273
|
|
270
274
|
self.clear_db()
|
271
275
|
|