qolsys-controller 0.0.56__tar.gz → 0.2.9__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.
- qolsys_controller-0.2.9/.github/workflows/build.yml +30 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/PKG-INFO +3 -3
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/README.md +2 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/bin/qolsys.py +16 -15
- qolsys_controller-0.2.9/example.py +78 -0
- qolsys_controller-0.2.9/mypy.ini +6 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/pyproject.toml +6 -4
- qolsys_controller-0.2.9/qolsys_controller/adc_device.py +202 -0
- qolsys_controller-0.2.9/qolsys_controller/adc_service.py +139 -0
- qolsys_controller-0.2.9/qolsys_controller/adc_service_garagedoor.py +35 -0
- qolsys_controller-0.2.9/qolsys_controller/controller.py +1023 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/db.py +102 -35
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table.py +79 -53
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_alarmedsensor.py +2 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_automation.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_country_locale.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_dashboard_msgs.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_dimmerlight.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_doorlock.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_eu_event.py +1 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_heat_map.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_history.py +4 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_iqremotesettings.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_iqrouter_network_config.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_iqrouter_user_device.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_master_slave.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_nest_device.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_output_rules.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_partition.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_pgm_outputs.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_powerg_device.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_qolsyssettings.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_scene.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_sensor.py +4 -2
- qolsys_controller-0.2.9/qolsys_controller/database/table_sensor_group.py +23 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_shades.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_smartsocket.py +12 -3
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_state.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_tcc.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_thermostat.py +3 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_trouble_conditions.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_user.py +1 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_virtual_device.py +13 -3
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_weather.py +0 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_zigbee_device.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_zwave_association_group.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_zwave_history.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_zwave_node.py +4 -2
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/database/table_zwave_other.py +0 -1
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/enum.py +62 -26
- qolsys_controller-0.2.9/qolsys_controller/enum_adc.py +28 -0
- qolsys_controller-0.2.9/qolsys_controller/enum_zwave.py +227 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/errors.py +14 -12
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/mdns.py +0 -1
- qolsys_controller-0.2.9/qolsys_controller/mqtt_command.py +125 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/mqtt_command_queue.py +5 -4
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/observable.py +2 -2
- qolsys_controller-0.2.9/qolsys_controller/observable_v2.py +14 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/panel.py +271 -102
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/partition.py +149 -127
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/pki.py +69 -97
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/scene.py +30 -28
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/settings.py +78 -41
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/state.py +262 -39
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/task_manager.py +11 -14
- qolsys_controller-0.2.9/qolsys_controller/users.py +25 -0
- qolsys_controller-0.2.9/qolsys_controller/utils_mqtt.py +16 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/weather.py +8 -11
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/zone.py +237 -162
- qolsys_controller-0.2.9/qolsys_controller/zwave_device.py +401 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/zwave_dimmer.py +61 -51
- qolsys_controller-0.2.9/qolsys_controller/zwave_energy_clamp.py +19 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_extenal_siren.py +20 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_garagedoor.py +20 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_generic.py +17 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/zwave_lock.py +57 -46
- qolsys_controller-0.2.9/qolsys_controller/zwave_service_meter.py +192 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_service_multilevelsensor.py +128 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_smart_socket.py +20 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_thermometer.py +25 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_thermostat.py +450 -0
- qolsys_controller-0.2.9/qolsys_controller/zwave_water_valve.py +20 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/requirements.txt +4 -3
- qolsys_controller-0.0.56/.github/workflows/build.yml +0 -36
- qolsys_controller-0.0.56/example.py +0 -109
- qolsys_controller-0.0.56/qolsys_controller/controller.py +0 -61
- qolsys_controller-0.0.56/qolsys_controller/enum_zwave.py +0 -36
- qolsys_controller-0.0.56/qolsys_controller/plugin.py +0 -24
- qolsys_controller-0.0.56/qolsys_controller/plugin_c4.py +0 -17
- qolsys_controller-0.0.56/qolsys_controller/plugin_remote.py +0 -1293
- qolsys_controller-0.0.56/qolsys_controller/utils_mqtt.py +0 -24
- qolsys_controller-0.0.56/qolsys_controller/zwave_device.py +0 -214
- qolsys_controller-0.0.56/qolsys_controller/zwave_garagedoor.py +0 -11
- qolsys_controller-0.0.56/qolsys_controller/zwave_generic.py +0 -11
- qolsys_controller-0.0.56/qolsys_controller/zwave_outlet.py +0 -11
- qolsys_controller-0.0.56/qolsys_controller/zwave_thermostat.py +0 -306
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/.github/workflows/publish.yml +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/.gitignore +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/Info_mqtt.md +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/LICENSE +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/info_pairing.md +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/info_qolsys.md +0 -0
- {qolsys_controller-0.0.56 → qolsys_controller-0.2.9}/qolsys_controller/__init__.py +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
lint_and_typecheck:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: |
|
|
20
|
+
pip install -r requirements.txt
|
|
21
|
+
pip install ruff mypy
|
|
22
|
+
|
|
23
|
+
- name: Ruff lint
|
|
24
|
+
run: ruff check .
|
|
25
|
+
|
|
26
|
+
- name: Ruff format check
|
|
27
|
+
run: ruff format --check .
|
|
28
|
+
|
|
29
|
+
- name: Mypy type checking
|
|
30
|
+
run: mypy .
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qolsys-controller
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.9
|
|
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
|
|
@@ -40,7 +40,6 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
|
40
40
|
| | Home Silent Disarming (Firmware 4.6.1)| ✅ |
|
|
41
41
|
| | Set Exit Sounds | ✅ |
|
|
42
42
|
| | Set Entry Delay | ✅ |
|
|
43
|
-
| | Disarm Photos | 🛠️ |
|
|
44
43
|
| | TTS | 🛠️ |
|
|
45
44
|
| **Zones** | Sensor Status | ✅ |
|
|
46
45
|
| | Tamper State | ✅ |
|
|
@@ -52,7 +51,8 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
|
52
51
|
| **Z-Wave Devices** | Battery Level | ✅ |
|
|
53
52
|
| | Node Status | ✅ |
|
|
54
53
|
| | Control Generic Devices | TBD |
|
|
55
|
-
| **Z-Wave Dimmers** |
|
|
54
|
+
| **Z-Wave Dimmers** | Binary Switch | ✅ |
|
|
55
|
+
| | Multi Level Dimmer | ✅ |
|
|
56
56
|
| **Z-Wave Door Locks** | Lock, Unlock | ✅ |
|
|
57
57
|
| **Z-Wave Thermostats** | Read device status | ✅ |
|
|
58
58
|
| | Write device status | ✅ |
|
|
@@ -24,7 +24,6 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
|
24
24
|
| | Home Silent Disarming (Firmware 4.6.1)| ✅ |
|
|
25
25
|
| | Set Exit Sounds | ✅ |
|
|
26
26
|
| | Set Entry Delay | ✅ |
|
|
27
|
-
| | Disarm Photos | 🛠️ |
|
|
28
27
|
| | TTS | 🛠️ |
|
|
29
28
|
| **Zones** | Sensor Status | ✅ |
|
|
30
29
|
| | Tamper State | ✅ |
|
|
@@ -36,7 +35,8 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
|
|
|
36
35
|
| **Z-Wave Devices** | Battery Level | ✅ |
|
|
37
36
|
| | Node Status | ✅ |
|
|
38
37
|
| | Control Generic Devices | TBD |
|
|
39
|
-
| **Z-Wave Dimmers** |
|
|
38
|
+
| **Z-Wave Dimmers** | Binary Switch | ✅ |
|
|
39
|
+
| | Multi Level Dimmer | ✅ |
|
|
40
40
|
| **Z-Wave Door Locks** | Lock, Unlock | ✅ |
|
|
41
41
|
| **Z-Wave Thermostats** | Read device status | ✅ |
|
|
42
42
|
| | Write device status | ✅ |
|
|
@@ -6,12 +6,11 @@ import logging
|
|
|
6
6
|
import os
|
|
7
7
|
import sys
|
|
8
8
|
|
|
9
|
-
from qolsys_controller import qolsys_controller
|
|
9
|
+
from qolsys_controller import qolsys_controller # type: ignore[attr-defined]
|
|
10
10
|
from qolsys_controller.errors import QolsysMqttError, QolsysSqlError, QolsysSslError
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
async def main() -> None: # noqa: D103
|
|
14
|
-
|
|
15
14
|
cli_parser = argparse.ArgumentParser()
|
|
16
15
|
cli_parser.add_argument("--panel-ip", help="Qolsys Panel IP", default="")
|
|
17
16
|
cli_parser.add_argument("--plugin-ip", help="Plugin IP", default="")
|
|
@@ -28,26 +27,23 @@ async def main() -> None: # noqa: D103
|
|
|
28
27
|
asyncio.set_event_loop(loop)
|
|
29
28
|
|
|
30
29
|
Panel = qolsys_controller()
|
|
31
|
-
|
|
32
|
-
# Select plugin
|
|
33
|
-
Panel.select_plugin("remote")
|
|
34
30
|
Panel.settings.config_directory = args.config_dir
|
|
35
|
-
Panel.
|
|
36
|
-
Panel.
|
|
37
|
-
Panel.
|
|
31
|
+
Panel.settings.panel_ip = args.panel_ip
|
|
32
|
+
Panel.settings.plugin_ip = args.plugin_ip
|
|
33
|
+
Panel.settings.random_mac = ""
|
|
38
34
|
|
|
39
35
|
# Additionnal remote plugin config
|
|
40
|
-
Panel.
|
|
41
|
-
Panel.
|
|
42
|
-
Panel.
|
|
36
|
+
Panel.settings.check_user_code_on_disarm = False
|
|
37
|
+
Panel.settings.log_mqtt_mesages = args.debug
|
|
38
|
+
Panel.settings.auto_discover_pki = args.pki_autodiscovery
|
|
43
39
|
|
|
44
40
|
# Configure remote plugin
|
|
45
|
-
if not await Panel.
|
|
41
|
+
if not await Panel.config(start_pairing=True):
|
|
46
42
|
LOGGER.debug("Error Configuring remote plugin")
|
|
47
43
|
return
|
|
48
44
|
|
|
49
45
|
try:
|
|
50
|
-
await Panel.
|
|
46
|
+
await Panel.start_operation()
|
|
51
47
|
|
|
52
48
|
except QolsysMqttError:
|
|
53
49
|
LOGGER.debug("QolsysMqttError")
|
|
@@ -58,7 +54,7 @@ async def main() -> None: # noqa: D103
|
|
|
58
54
|
except QolsysSqlError:
|
|
59
55
|
LOGGER.debug("QolsysSqlError")
|
|
60
56
|
|
|
61
|
-
if not Panel.
|
|
57
|
+
if not Panel.connected:
|
|
62
58
|
LOGGER.error("Panel not ready for operation")
|
|
63
59
|
return
|
|
64
60
|
|
|
@@ -67,9 +63,14 @@ async def main() -> None: # noqa: D103
|
|
|
67
63
|
stop_event = asyncio.Event()
|
|
68
64
|
await stop_event.wait()
|
|
69
65
|
|
|
66
|
+
|
|
70
67
|
# Change to the "Selector" event loop if platform is Windows
|
|
71
68
|
if sys.platform.lower() == "win32" or os.name.lower() == "nt":
|
|
72
|
-
from asyncio import
|
|
69
|
+
from asyncio import ( # type: ignore[attr-defined]
|
|
70
|
+
WindowsSelectorEventLoopPolicy,
|
|
71
|
+
set_event_loop_policy,
|
|
72
|
+
)
|
|
73
|
+
|
|
73
74
|
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
|
74
75
|
|
|
75
76
|
asyncio.run(main())
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from qolsys_controller.controller import QolsysController
|
|
9
|
+
from qolsys_controller.errors import QolsysMqttError, QolsysSqlError, QolsysSslError
|
|
10
|
+
|
|
11
|
+
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s - %(module)s: %(message)s")
|
|
12
|
+
LOGGER = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def main() -> None: # noqa: D103
|
|
16
|
+
remote = QolsysController()
|
|
17
|
+
remote.settings.config_directory = "./config/"
|
|
18
|
+
remote.settings.panel_ip = "****"
|
|
19
|
+
remote.settings.plugin_ip = "****"
|
|
20
|
+
remote.settings.random_mac = "" # Example: F2:16:3E:33:ED:20
|
|
21
|
+
|
|
22
|
+
# Additionnal remote plugin config
|
|
23
|
+
remote.settings.check_user_code_on_disarm = False # Check user code in user.conf file
|
|
24
|
+
remote.settings.log_mqtt_mesages = False # Enable for MQTT debug purposes
|
|
25
|
+
remote.settings.auto_discover_pki = True
|
|
26
|
+
|
|
27
|
+
# Configure remote plugin
|
|
28
|
+
if not await remote.config(start_pairing=True):
|
|
29
|
+
LOGGER.debug("Error Configuring remote plugin")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
await remote.start_operation()
|
|
34
|
+
|
|
35
|
+
except QolsysMqttError:
|
|
36
|
+
LOGGER.debug("QolsysMqttError")
|
|
37
|
+
|
|
38
|
+
except QolsysSslError:
|
|
39
|
+
LOGGER.debug("QolsysSslError")
|
|
40
|
+
|
|
41
|
+
except QolsysSqlError:
|
|
42
|
+
LOGGER.debug("QolsysSqlError")
|
|
43
|
+
|
|
44
|
+
if not remote.connected:
|
|
45
|
+
LOGGER.error("Panel not ready for operation")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
LOGGER.debug("Qolsys Panel Ready for operation")
|
|
49
|
+
|
|
50
|
+
await asyncio.sleep(5)
|
|
51
|
+
# await remote.command_zwave_switch_multi_level(node_id="6",level=99)
|
|
52
|
+
# await remote.command_zwave_switch_binary_set(node_id="8", status=True)
|
|
53
|
+
# await remote.plugin.command_arm(
|
|
54
|
+
# partition_id='0',
|
|
55
|
+
# arming_type=PartitionArmingType:ARM_NIGHT,
|
|
56
|
+
# user_code="1111",
|
|
57
|
+
# exit_sounds=False,
|
|
58
|
+
# instant_arm=True)
|
|
59
|
+
# await remote.command_disarm(partition_id="0", user_code="1111")
|
|
60
|
+
# await remote.command_panel_execute_scene(scene_id="3")
|
|
61
|
+
# await remote.command_zwave_doorlock_set(node_id="7",locked=True)
|
|
62
|
+
# await remote.stop_operation()
|
|
63
|
+
|
|
64
|
+
# Use an asyncio.Event to keep the program running efficiently
|
|
65
|
+
stop_event = asyncio.Event()
|
|
66
|
+
await stop_event.wait()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Change to the "Selector" event loop if platform is Windows
|
|
70
|
+
if sys.platform.lower() == "win32" or os.name.lower() == "nt":
|
|
71
|
+
from asyncio import ( # type: ignore[attr-defined]
|
|
72
|
+
WindowsSelectorEventLoopPolicy,
|
|
73
|
+
set_event_loop_policy,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
|
77
|
+
|
|
78
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qolsys-controller"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.9"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="Eric Hylands", email="" },
|
|
6
6
|
]
|
|
@@ -27,11 +27,13 @@ build-backend = "hatchling.build"
|
|
|
27
27
|
packages = ["qolsys_controller/"]
|
|
28
28
|
|
|
29
29
|
[tool.ruff]
|
|
30
|
-
line-length =
|
|
30
|
+
line-length = 127
|
|
31
|
+
target-version = "py312"
|
|
32
|
+
|
|
31
33
|
|
|
32
34
|
[tool.ruff.lint]
|
|
33
|
-
select = [
|
|
34
|
-
ignore = ["E501"
|
|
35
|
+
select = ["E", "F", "W", "I"]
|
|
36
|
+
ignore = ["E501"]
|
|
35
37
|
|
|
36
38
|
[tool.ruff.lint.mccabe]
|
|
37
39
|
max-complexity = 25
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from .adc_service import QolsysAdcService
|
|
6
|
+
from .adc_service_garagedoor import QolsysAdcGarageDoorService
|
|
7
|
+
from .enum_adc import vdFuncLocalControl, vdFuncName, vdFuncState, vdFuncType
|
|
8
|
+
from .observable import QolsysObservable
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .adc_service import QolsysAdcService
|
|
12
|
+
|
|
13
|
+
LOGGER = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class QolsysAdcDevice(QolsysObservable):
|
|
17
|
+
def __init__(self, adc_dict: dict[str, str]) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
self._services: list[QolsysAdcService] = []
|
|
21
|
+
|
|
22
|
+
self._id: str = adc_dict.get("_id", "")
|
|
23
|
+
self._partition_id: str = adc_dict.get("partition_id", "")
|
|
24
|
+
self._device_id: str = adc_dict.get("device_id", "")
|
|
25
|
+
self._name: str = adc_dict.get("name", "")
|
|
26
|
+
self._type: str = adc_dict.get("type", "")
|
|
27
|
+
self._create_time: str = adc_dict.get("create_time", "")
|
|
28
|
+
self._created_by: str = adc_dict.get("created_by", "")
|
|
29
|
+
self._update_time: str = adc_dict.get("update_time", "")
|
|
30
|
+
self._updated_by: str = adc_dict.get("updated_by", "")
|
|
31
|
+
self._device_zone_list: str = adc_dict.get("device_zone_list", "")
|
|
32
|
+
self._func_list = ""
|
|
33
|
+
self.func_list = adc_dict.get("func_list", "")
|
|
34
|
+
|
|
35
|
+
def update_adc_device(self, data: dict[str, str]) -> None:
|
|
36
|
+
# Check if we are updating same device_id
|
|
37
|
+
device_id_update = data.get("device_id", "")
|
|
38
|
+
if device_id_update != self._device_id:
|
|
39
|
+
LOGGER.error(
|
|
40
|
+
"Updating ADC%s (%s) with ADC%s (different device_id)",
|
|
41
|
+
self._device_id,
|
|
42
|
+
self._name,
|
|
43
|
+
device_id_update,
|
|
44
|
+
)
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
self.start_batch_update()
|
|
48
|
+
|
|
49
|
+
if "partition_id" in data:
|
|
50
|
+
self.partition_id = data.get("partition_id", "")
|
|
51
|
+
|
|
52
|
+
if "name" in data:
|
|
53
|
+
self.name = data.get("name", "")
|
|
54
|
+
|
|
55
|
+
if "type" in data:
|
|
56
|
+
self.type = data.get("type", "")
|
|
57
|
+
|
|
58
|
+
self.end_batch_update()
|
|
59
|
+
|
|
60
|
+
if "func_list" in data:
|
|
61
|
+
self.func_list = data.get("func_list", "")
|
|
62
|
+
|
|
63
|
+
def get_adc_service(self, id: int) -> QolsysAdcService | None:
|
|
64
|
+
for service in self._services:
|
|
65
|
+
if service.id == id:
|
|
66
|
+
return service
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
def add_adc_service(
|
|
70
|
+
self,
|
|
71
|
+
id: int,
|
|
72
|
+
local_control: vdFuncLocalControl,
|
|
73
|
+
func_name: vdFuncName,
|
|
74
|
+
func_type: vdFuncType,
|
|
75
|
+
func_state: vdFuncState,
|
|
76
|
+
timestamp: str,
|
|
77
|
+
) -> None:
|
|
78
|
+
# Garage Door
|
|
79
|
+
if func_name == vdFuncName.OPEN_CLOSE and func_type == vdFuncType.BINARY_ACTUATOR:
|
|
80
|
+
LOGGER.debug("ADC%s (%s) - Adding garage door service", self.device_id, self.name)
|
|
81
|
+
self._services.append(
|
|
82
|
+
QolsysAdcGarageDoorService(self, id, func_name, local_control, func_type, func_state, timestamp)
|
|
83
|
+
)
|
|
84
|
+
self.notify()
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
# Add generic service if other services have beed identified
|
|
88
|
+
LOGGER.debug("ADC%s (%s) - Adding generic service", self.device_id, self.name)
|
|
89
|
+
self._services.append(QolsysAdcService(self, id, func_name, local_control, func_type, func_state, timestamp))
|
|
90
|
+
self.notify()
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
# -----------------------------
|
|
94
|
+
# properties + setters
|
|
95
|
+
# -----------------------------
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def device_id(self) -> str:
|
|
99
|
+
return self._device_id
|
|
100
|
+
|
|
101
|
+
@device_id.setter
|
|
102
|
+
def device_id(self, value: str) -> None:
|
|
103
|
+
self._device_id = value
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def services(self) -> list[QolsysAdcService]:
|
|
107
|
+
return self._services
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def partition_id(self) -> str:
|
|
111
|
+
return self._partition_id
|
|
112
|
+
|
|
113
|
+
@partition_id.setter
|
|
114
|
+
def partition_id(self, value: str) -> None:
|
|
115
|
+
if self._partition_id != value:
|
|
116
|
+
LOGGER.debug("ADC%s (%s) - partition_id: %s", self.device_id, self.name, value)
|
|
117
|
+
self._partition_id = value
|
|
118
|
+
self.notify()
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def name(self) -> str:
|
|
122
|
+
return self._name
|
|
123
|
+
|
|
124
|
+
@name.setter
|
|
125
|
+
def name(self, value: str) -> None:
|
|
126
|
+
if self._name != value:
|
|
127
|
+
LOGGER.debug("ADC%s (%s) - name: %s", self.device_id, self.name, value)
|
|
128
|
+
self._name = value
|
|
129
|
+
self.notify()
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def type(self) -> str:
|
|
133
|
+
return self._type
|
|
134
|
+
|
|
135
|
+
@type.setter
|
|
136
|
+
def type(self, value: str) -> None:
|
|
137
|
+
if self._type != value:
|
|
138
|
+
LOGGER.debug("ADC%s (%s) - type: %s", self.device_id, self.name, value)
|
|
139
|
+
self._type = value
|
|
140
|
+
self.notify()
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def func_list(self) -> str:
|
|
144
|
+
return self._func_list
|
|
145
|
+
|
|
146
|
+
@func_list.setter
|
|
147
|
+
def func_list(self, value: str) -> None:
|
|
148
|
+
if self._func_list != value:
|
|
149
|
+
LOGGER.debug("ADC%s (%s) - func_list: %s", self.device_id, self.name, value)
|
|
150
|
+
self._func_list = value
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
json_func_list = json.loads(self._func_list)
|
|
154
|
+
new_service_id: list[int] = []
|
|
155
|
+
self.start_batch_update()
|
|
156
|
+
|
|
157
|
+
for function in json_func_list:
|
|
158
|
+
try:
|
|
159
|
+
id = function.get("vdFuncId")
|
|
160
|
+
local_control = vdFuncLocalControl(function.get("vdFuncLocalControl"))
|
|
161
|
+
func_name = vdFuncName(function.get("vdFuncName"))
|
|
162
|
+
func_type = vdFuncType(function.get("vdFuncType"))
|
|
163
|
+
func_state = vdFuncState(function.get("vdFuncState"))
|
|
164
|
+
timestamp = function.get("vdFuncBackendTimestamp")
|
|
165
|
+
new_service_id.append(id)
|
|
166
|
+
|
|
167
|
+
service = self.get_adc_service(id)
|
|
168
|
+
if service is not None:
|
|
169
|
+
service.update_adc_service(func_name, local_control, func_type, func_state, timestamp)
|
|
170
|
+
|
|
171
|
+
if service is None:
|
|
172
|
+
self.add_adc_service(id, local_control, func_name, func_type, func_state, timestamp)
|
|
173
|
+
|
|
174
|
+
except ValueError as e:
|
|
175
|
+
LOGGER.error("Error converting value:", e)
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
# Check if service have been removed
|
|
179
|
+
for service in self._services:
|
|
180
|
+
if service.id not in new_service_id:
|
|
181
|
+
self._services.remove(service)
|
|
182
|
+
self.notify()
|
|
183
|
+
|
|
184
|
+
self.end_batch_update()
|
|
185
|
+
|
|
186
|
+
except json.JSONDecodeError as e:
|
|
187
|
+
LOGGER.error("ADC%s - Error parsing JSON:", self.device_id, e)
|
|
188
|
+
|
|
189
|
+
def to_dict_adc(self) -> dict[str, str]:
|
|
190
|
+
return {
|
|
191
|
+
"_id": self._id,
|
|
192
|
+
"partition_id": self.partition_id,
|
|
193
|
+
"device_id": self.device_id,
|
|
194
|
+
"name": self.name,
|
|
195
|
+
"type": self.type,
|
|
196
|
+
"func_list": self.func_list,
|
|
197
|
+
"create_time": self._create_time,
|
|
198
|
+
"created_by": self._created_by,
|
|
199
|
+
"update_time": self._update_time,
|
|
200
|
+
"updated_by": self._updated_by,
|
|
201
|
+
"device_zone_list": self._device_zone_list,
|
|
202
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from .enum_adc import vdFuncLocalControl, vdFuncName, vdFuncState, vdFuncType
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .adc_device import QolsysAdcDevice
|
|
8
|
+
|
|
9
|
+
LOGGER = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class QolsysAdcService:
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
parent_device: "QolsysAdcDevice",
|
|
16
|
+
id: int,
|
|
17
|
+
func_name: vdFuncName,
|
|
18
|
+
local_control: vdFuncLocalControl,
|
|
19
|
+
func_type: vdFuncType,
|
|
20
|
+
func_state: vdFuncState,
|
|
21
|
+
timestamp: str,
|
|
22
|
+
) -> None:
|
|
23
|
+
super().__init__()
|
|
24
|
+
self._parent_device: QolsysAdcDevice = parent_device
|
|
25
|
+
self._id: int = id
|
|
26
|
+
self._func_name: vdFuncName = func_name
|
|
27
|
+
self._local_control: vdFuncLocalControl = local_control
|
|
28
|
+
self._func_type: vdFuncType = func_type
|
|
29
|
+
self._func_state: vdFuncState = func_state
|
|
30
|
+
self._timestamp: str = timestamp
|
|
31
|
+
|
|
32
|
+
def update_adc_service(
|
|
33
|
+
self,
|
|
34
|
+
func_name: vdFuncName,
|
|
35
|
+
local_control: vdFuncLocalControl,
|
|
36
|
+
func_type: vdFuncType,
|
|
37
|
+
func_state: vdFuncState,
|
|
38
|
+
timestamp: str,
|
|
39
|
+
) -> None:
|
|
40
|
+
self.name = func_name
|
|
41
|
+
self.local_control = local_control
|
|
42
|
+
self.func_type = func_type
|
|
43
|
+
self.func_state = func_state
|
|
44
|
+
self.timestamp = timestamp
|
|
45
|
+
|
|
46
|
+
# -----------------------------
|
|
47
|
+
# properties + setters
|
|
48
|
+
# -----------------------------
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def id(self) -> int:
|
|
52
|
+
return self._id
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def func_name(self) -> vdFuncName:
|
|
56
|
+
return self._func_name
|
|
57
|
+
|
|
58
|
+
@func_name.setter
|
|
59
|
+
def func_name(self, value: vdFuncName) -> None:
|
|
60
|
+
if value != self._func_name:
|
|
61
|
+
self._func_name = value
|
|
62
|
+
LOGGER.debug(
|
|
63
|
+
"ADC%s (%s) - Func%s - func_name:%s",
|
|
64
|
+
self._parent_device.device_id,
|
|
65
|
+
self._parent_device.name,
|
|
66
|
+
self.id,
|
|
67
|
+
self.func_name,
|
|
68
|
+
)
|
|
69
|
+
LOGGER.debug("Warning - Changing func_name will change device type - Not supported")
|
|
70
|
+
self._parent_device.notify()
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def local_control(self) -> vdFuncLocalControl:
|
|
74
|
+
return self._local_control
|
|
75
|
+
|
|
76
|
+
@local_control.setter
|
|
77
|
+
def local_control(self, value: vdFuncLocalControl) -> None:
|
|
78
|
+
if value != self.local_control:
|
|
79
|
+
self._local_control = value
|
|
80
|
+
LOGGER.debug(
|
|
81
|
+
"ADC%s (%s) - Func%s - local_control:%s",
|
|
82
|
+
self._parent_device.device_id,
|
|
83
|
+
self._parent_device.name,
|
|
84
|
+
self.id,
|
|
85
|
+
self.local_control,
|
|
86
|
+
)
|
|
87
|
+
self._parent_device.notify()
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def func_type(self) -> vdFuncType:
|
|
91
|
+
return self._func_type
|
|
92
|
+
|
|
93
|
+
@func_type.setter
|
|
94
|
+
def func_type(self, value: vdFuncType) -> None:
|
|
95
|
+
if value != self._func_type:
|
|
96
|
+
self._func_type = value
|
|
97
|
+
LOGGER.debug(
|
|
98
|
+
"ADC%s (%s) - Func%s - func_type:%s",
|
|
99
|
+
self._parent_device.device_id,
|
|
100
|
+
self._parent_device.name,
|
|
101
|
+
self.id,
|
|
102
|
+
self.func_type,
|
|
103
|
+
)
|
|
104
|
+
LOGGER.debug("Warning - Changing func_type will change device type - Not supported")
|
|
105
|
+
self._parent_device.notify()
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def func_state(self) -> vdFuncState:
|
|
109
|
+
return self._func_state
|
|
110
|
+
|
|
111
|
+
@func_state.setter
|
|
112
|
+
def func_state(self, value: vdFuncState) -> None:
|
|
113
|
+
if value != self._func_state:
|
|
114
|
+
self._func_state = value
|
|
115
|
+
LOGGER.debug(
|
|
116
|
+
"ADC%s (%s) - Func%s - func_state:%s",
|
|
117
|
+
self._parent_device.device_id,
|
|
118
|
+
self._parent_device.name,
|
|
119
|
+
self.id,
|
|
120
|
+
self.func_state,
|
|
121
|
+
)
|
|
122
|
+
self._parent_device.notify()
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def timestamp(self) -> str:
|
|
126
|
+
return self._timestamp
|
|
127
|
+
|
|
128
|
+
@timestamp.setter
|
|
129
|
+
def timestamp(self, value: str) -> None:
|
|
130
|
+
if value != self._timestamp:
|
|
131
|
+
self._timestamp = value
|
|
132
|
+
LOGGER.debug(
|
|
133
|
+
"ADC%s (%s) - Func%s - timestamp:%s",
|
|
134
|
+
self._parent_device.device_id,
|
|
135
|
+
self._parent_device.name,
|
|
136
|
+
self.id,
|
|
137
|
+
self.timestamp,
|
|
138
|
+
)
|
|
139
|
+
self._parent_device.notify()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from .adc_service import QolsysAdcService
|
|
5
|
+
from .enum_adc import vdFuncLocalControl, vdFuncName, vdFuncState, vdFuncType
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .adc_device import QolsysAdcDevice
|
|
9
|
+
|
|
10
|
+
LOGGER = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class QolsysAdcGarageDoorService(QolsysAdcService):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
parent_device: "QolsysAdcDevice",
|
|
17
|
+
id: int,
|
|
18
|
+
func_name: vdFuncName,
|
|
19
|
+
local_control: vdFuncLocalControl,
|
|
20
|
+
func_type: vdFuncType,
|
|
21
|
+
func_state: vdFuncState,
|
|
22
|
+
timestamp: str,
|
|
23
|
+
) -> None:
|
|
24
|
+
super().__init__(
|
|
25
|
+
parent_device,
|
|
26
|
+
id,
|
|
27
|
+
func_name,
|
|
28
|
+
local_control,
|
|
29
|
+
func_type,
|
|
30
|
+
func_state,
|
|
31
|
+
timestamp,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def is_open(self) -> bool:
|
|
35
|
+
return self.func_state == vdFuncState.ON
|