qolsys-controller 0.0.56__tar.gz → 0.0.82__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 (98) hide show
  1. qolsys_controller-0.0.82/.github/workflows/build.yml +30 -0
  2. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/PKG-INFO +3 -3
  3. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/README.md +2 -2
  4. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/bin/qolsys.py +16 -15
  5. qolsys_controller-0.0.82/example.py +78 -0
  6. qolsys_controller-0.0.82/mypy.ini +6 -0
  7. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/pyproject.toml +6 -4
  8. qolsys_controller-0.0.82/qolsys_controller/adc_device.py +202 -0
  9. qolsys_controller-0.0.82/qolsys_controller/adc_service.py +139 -0
  10. qolsys_controller-0.0.82/qolsys_controller/adc_service_garagedoor.py +35 -0
  11. qolsys_controller-0.0.82/qolsys_controller/controller.py +966 -0
  12. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/db.py +97 -30
  13. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table.py +79 -53
  14. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_alarmedsensor.py +2 -2
  15. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_automation.py +0 -1
  16. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_country_locale.py +0 -1
  17. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_dashboard_msgs.py +0 -2
  18. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_dimmerlight.py +0 -1
  19. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_doorlock.py +0 -1
  20. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_eu_event.py +1 -2
  21. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_heat_map.py +0 -2
  22. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_history.py +4 -1
  23. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_iqremotesettings.py +0 -2
  24. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_iqrouter_network_config.py +0 -1
  25. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_iqrouter_user_device.py +0 -2
  26. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_master_slave.py +0 -1
  27. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_nest_device.py +0 -1
  28. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_output_rules.py +0 -1
  29. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_partition.py +0 -1
  30. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_pgm_outputs.py +0 -2
  31. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_powerg_device.py +0 -2
  32. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_qolsyssettings.py +0 -2
  33. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_scene.py +0 -2
  34. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_sensor.py +2 -2
  35. qolsys_controller-0.0.82/qolsys_controller/database/table_sensor_group.py +23 -0
  36. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_shades.py +0 -2
  37. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_smartsocket.py +0 -2
  38. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_state.py +0 -1
  39. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_tcc.py +0 -1
  40. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_thermostat.py +3 -1
  41. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_trouble_conditions.py +0 -2
  42. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_user.py +0 -2
  43. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_virtual_device.py +13 -3
  44. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_weather.py +0 -2
  45. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_zigbee_device.py +0 -1
  46. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_zwave_association_group.py +0 -1
  47. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_zwave_history.py +0 -1
  48. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_zwave_node.py +3 -1
  49. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/database/table_zwave_other.py +0 -1
  50. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/enum.py +35 -12
  51. qolsys_controller-0.0.82/qolsys_controller/enum_adc.py +28 -0
  52. qolsys_controller-0.0.82/qolsys_controller/enum_zwave.py +211 -0
  53. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/errors.py +14 -12
  54. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/mdns.py +0 -1
  55. qolsys_controller-0.0.82/qolsys_controller/mqtt_command.py +125 -0
  56. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/mqtt_command_queue.py +5 -4
  57. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/observable.py +2 -2
  58. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/panel.py +233 -95
  59. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/partition.py +149 -127
  60. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/pki.py +69 -97
  61. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/scene.py +30 -28
  62. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/settings.py +78 -41
  63. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/state.py +200 -32
  64. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/task_manager.py +11 -14
  65. qolsys_controller-0.0.82/qolsys_controller/users.py +25 -0
  66. qolsys_controller-0.0.82/qolsys_controller/utils_mqtt.py +16 -0
  67. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/weather.py +8 -11
  68. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/zone.py +177 -163
  69. qolsys_controller-0.0.82/qolsys_controller/zwave_device.py +347 -0
  70. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/zwave_dimmer.py +55 -49
  71. qolsys_controller-0.0.82/qolsys_controller/zwave_energy_clamp.py +15 -0
  72. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/zwave_garagedoor.py +3 -1
  73. qolsys_controller-0.0.82/qolsys_controller/zwave_generic.py +13 -0
  74. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/zwave_lock.py +51 -44
  75. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/qolsys_controller/zwave_outlet.py +3 -1
  76. qolsys_controller-0.0.82/qolsys_controller/zwave_service_meter.py +192 -0
  77. qolsys_controller-0.0.82/qolsys_controller/zwave_service_multilevelsensor.py +119 -0
  78. qolsys_controller-0.0.82/qolsys_controller/zwave_thermometer.py +21 -0
  79. qolsys_controller-0.0.82/qolsys_controller/zwave_thermostat.py +412 -0
  80. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/requirements.txt +2 -1
  81. qolsys_controller-0.0.56/.github/workflows/build.yml +0 -36
  82. qolsys_controller-0.0.56/example.py +0 -109
  83. qolsys_controller-0.0.56/qolsys_controller/controller.py +0 -61
  84. qolsys_controller-0.0.56/qolsys_controller/enum_zwave.py +0 -36
  85. qolsys_controller-0.0.56/qolsys_controller/plugin.py +0 -24
  86. qolsys_controller-0.0.56/qolsys_controller/plugin_c4.py +0 -17
  87. qolsys_controller-0.0.56/qolsys_controller/plugin_remote.py +0 -1293
  88. qolsys_controller-0.0.56/qolsys_controller/utils_mqtt.py +0 -24
  89. qolsys_controller-0.0.56/qolsys_controller/zwave_device.py +0 -214
  90. qolsys_controller-0.0.56/qolsys_controller/zwave_generic.py +0 -11
  91. qolsys_controller-0.0.56/qolsys_controller/zwave_thermostat.py +0 -306
  92. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/.github/workflows/publish.yml +0 -0
  93. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/.gitignore +0 -0
  94. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/Info_mqtt.md +0 -0
  95. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/LICENSE +0 -0
  96. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/info_pairing.md +0 -0
  97. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/info_qolsys.md +0 -0
  98. {qolsys_controller-0.0.56 → qolsys_controller-0.0.82}/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.0.56
3
+ Version: 0.0.82
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** | Light Status and Level Control | ✅ |
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** | Light Status and Level Control | ✅ |
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.plugin.settings.panel_ip = args.panel_ip
36
- Panel.plugin.settings.plugin_ip = args.plugin_ip
37
- Panel.plugin.settings.random_mac = ""
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.plugin.check_user_code_on_disarm = False
41
- Panel.plugin.log_mqtt_mesages = args.debug
42
- Panel.plugin.auto_discover_pki = args.pki_autodiscovery
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.plugin.config(start_pairing=True):
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.plugin.start_operation()
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.plugin.connected:
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 WindowsSelectorEventLoopPolicy, set_event_loop_policy
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())
@@ -0,0 +1,6 @@
1
+ [mypy]
2
+ python_version = 3.12
3
+ warn_unused_configs = True
4
+ disallow_untyped_defs = True
5
+ ignore_missing_imports = True
6
+ strict = True
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qolsys-controller"
3
- version = "0.0.56"
3
+ version = "0.0.82"
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 = 100
30
+ line-length = 127
31
+ target-version = "py312"
32
+
31
33
 
32
34
  [tool.ruff.lint]
33
- select = ['ALL']
34
- ignore = ["E501","S608","S311","S104","D100","D101", "D102","D107","ERA001", "FBT001","FBT002", "N802","N806","PERF401"]
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