qolsys-controller 0.0.38__py3-none-any.whl → 0.0.62__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of qolsys-controller might be problematic. Click here for more details.

Files changed (73) hide show
  1. qolsys_controller/controller.py +829 -20
  2. qolsys_controller/database/db.py +63 -25
  3. qolsys_controller/database/table.py +89 -60
  4. qolsys_controller/database/table_alarmedsensor.py +0 -2
  5. qolsys_controller/database/table_automation.py +0 -1
  6. qolsys_controller/database/table_country_locale.py +0 -1
  7. qolsys_controller/database/table_dashboard_msgs.py +1 -2
  8. qolsys_controller/database/table_dimmerlight.py +0 -1
  9. qolsys_controller/database/table_doorlock.py +1 -1
  10. qolsys_controller/database/table_eu_event.py +12 -4
  11. qolsys_controller/database/table_heat_map.py +0 -2
  12. qolsys_controller/database/table_history.py +4 -1
  13. qolsys_controller/database/table_iqremotesettings.py +0 -2
  14. qolsys_controller/database/table_iqrouter_network_config.py +0 -1
  15. qolsys_controller/database/table_iqrouter_user_device.py +0 -2
  16. qolsys_controller/database/table_master_slave.py +0 -1
  17. qolsys_controller/database/table_nest_device.py +0 -1
  18. qolsys_controller/database/table_output_rules.py +0 -1
  19. qolsys_controller/database/table_partition.py +0 -1
  20. qolsys_controller/database/table_pgm_outputs.py +0 -2
  21. qolsys_controller/database/table_powerg_device.py +25 -3
  22. qolsys_controller/database/table_qolsyssettings.py +0 -2
  23. qolsys_controller/database/table_scene.py +0 -2
  24. qolsys_controller/database/table_sensor.py +3 -2
  25. qolsys_controller/database/table_sensor_group.py +23 -0
  26. qolsys_controller/database/table_shades.py +0 -2
  27. qolsys_controller/database/table_smartsocket.py +0 -2
  28. qolsys_controller/database/table_state.py +0 -1
  29. qolsys_controller/database/table_tcc.py +0 -1
  30. qolsys_controller/database/table_thermostat.py +0 -1
  31. qolsys_controller/database/table_trouble_conditions.py +0 -2
  32. qolsys_controller/database/table_user.py +1 -2
  33. qolsys_controller/database/table_virtual_device.py +0 -2
  34. qolsys_controller/database/table_weather.py +0 -2
  35. qolsys_controller/database/table_zigbee_device.py +0 -1
  36. qolsys_controller/database/table_zwave_association_group.py +0 -1
  37. qolsys_controller/database/table_zwave_history.py +0 -1
  38. qolsys_controller/database/table_zwave_node.py +1 -1
  39. qolsys_controller/database/table_zwave_other.py +14 -2
  40. qolsys_controller/enum.py +44 -16
  41. qolsys_controller/enum_zwave.py +81 -36
  42. qolsys_controller/errors.py +9 -12
  43. qolsys_controller/mdns.py +7 -4
  44. qolsys_controller/mqtt_command.py +119 -0
  45. qolsys_controller/mqtt_command_queue.py +5 -4
  46. qolsys_controller/observable.py +2 -2
  47. qolsys_controller/panel.py +224 -143
  48. qolsys_controller/partition.py +129 -127
  49. qolsys_controller/pki.py +69 -97
  50. qolsys_controller/scene.py +30 -28
  51. qolsys_controller/settings.py +96 -50
  52. qolsys_controller/state.py +71 -33
  53. qolsys_controller/task_manager.py +8 -12
  54. qolsys_controller/users.py +25 -0
  55. qolsys_controller/utils_mqtt.py +8 -16
  56. qolsys_controller/weather.py +71 -0
  57. qolsys_controller/zone.py +307 -169
  58. qolsys_controller/zwave_device.py +108 -95
  59. qolsys_controller/zwave_dimmer.py +53 -50
  60. qolsys_controller/zwave_garagedoor.py +0 -1
  61. qolsys_controller/zwave_generic.py +2 -3
  62. qolsys_controller/zwave_lock.py +47 -44
  63. qolsys_controller/zwave_outlet.py +0 -1
  64. qolsys_controller/zwave_thermostat.py +112 -118
  65. qolsys_controller-0.0.62.dist-info/METADATA +89 -0
  66. qolsys_controller-0.0.62.dist-info/RECORD +69 -0
  67. {qolsys_controller-0.0.38.dist-info → qolsys_controller-0.0.62.dist-info}/WHEEL +1 -1
  68. qolsys_controller/plugin.py +0 -34
  69. qolsys_controller/plugin_c4.py +0 -17
  70. qolsys_controller/plugin_remote.py +0 -1298
  71. qolsys_controller-0.0.38.dist-info/METADATA +0 -93
  72. qolsys_controller-0.0.38.dist-info/RECORD +0 -68
  73. {qolsys_controller-0.0.38.dist-info → qolsys_controller-0.0.62.dist-info}/licenses/LICENSE +0 -0
@@ -6,36 +6,46 @@ LOGGER = logging.getLogger(__name__)
6
6
 
7
7
 
8
8
  class QolsysScene(QolsysObservable):
9
-
10
- def __init__(self, data: dict) -> None:
9
+ def __init__(self, data: dict[str, str]) -> None:
11
10
  super().__init__()
12
11
 
13
- self._scene_id = data.get("scene_id", "")
14
- self._name = data.get("name", "")
15
- self._icon = data.get("icon", "")
16
- self._color = data.get("color", "")
17
-
18
- def update(self, data: dict) -> None:
12
+ self._scene_id: str = data.get("scene_id", "")
13
+ self._name: str = data.get("name", "")
14
+ self._icon: str = data.get("icon", "")
15
+ self._color: str = data.get("color", "")
19
16
 
17
+ def update(self, data: dict[str, str]) -> None:
20
18
  scene_id_update = data.get("scene_id", "")
21
19
  if scene_id_update != self._scene_id:
22
- LOGGER.error("Updating Scene%s (%s) with Scene%s (different id)", self._scene_id, self.sensorname, scene_id_update)
20
+ LOGGER.error("Updating Scene%s (%s) with Scene%s (different id)", self._scene_id, self.name, scene_id_update)
23
21
  return
24
22
 
25
23
  self.start_batch_update()
26
24
 
27
25
  # Update name
28
26
  if "name" in data:
29
- self.sensorname = data.get("name")
27
+ self.sensorname = data.get("name", "")
30
28
 
31
29
  if "color" in data:
32
- self.color = data.get("color")
30
+ self.color = data.get("color", "")
33
31
 
34
32
  if "icon" in data:
35
- self.icon = data.get("icon")
33
+ self.icon = data.get("icon", "")
36
34
 
37
35
  self.end_batch_update()
38
36
 
37
+ def to_dict(self) -> dict[str, str]:
38
+ return {
39
+ "scene_id": self.scene_id,
40
+ "name": self.name,
41
+ "color": self.color,
42
+ "icon": self.icon,
43
+ }
44
+
45
+ # -----------------------------
46
+ # properties + setters
47
+ # -----------------------------
48
+
39
49
  @property
40
50
  def scene_id(self) -> str:
41
51
  return self._scene_id
@@ -44,36 +54,28 @@ class QolsysScene(QolsysObservable):
44
54
  def name(self) -> str:
45
55
  return self._name
46
56
 
47
- @property
48
- def icon(self) -> str:
49
- return self._icon
50
-
51
- @property
52
- def color(self) -> str:
53
- return self._color
54
-
55
57
  @name.setter
56
58
  def name(self, value: str) -> None:
57
59
  if self._name != value:
58
60
  self._name = value
59
61
  self.notify()
60
62
 
63
+ @property
64
+ def icon(self) -> str:
65
+ return self._icon
66
+
61
67
  @icon.setter
62
68
  def icon(self, value: str) -> None:
63
69
  if self._icon != value:
64
70
  self._icon = value
65
71
  self.notify()
66
72
 
73
+ @property
74
+ def color(self) -> str:
75
+ return self._color
76
+
67
77
  @color.setter
68
78
  def color(self, value: str) -> None:
69
79
  if self._color != value:
70
80
  self._color = value
71
81
  self.notify()
72
-
73
- def to_dict(self) -> dict:
74
- return {
75
- "scene_id": self.scene_id,
76
- "name": self.name,
77
- "color": self.color,
78
- "icon": self.icon,
79
- }
@@ -1,18 +1,24 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  from pathlib import Path
5
+ from typing import TYPE_CHECKING
3
6
 
4
7
  LOGGER = logging.getLogger(__name__)
5
8
 
9
+ if TYPE_CHECKING:
10
+ from .controller import QolsysController
6
11
 
7
- class QolsysSettings:
8
12
 
9
- def __init__(self) -> None:
13
+ class QolsysSettings:
14
+ def __init__(self, controller: QolsysController) -> None:
15
+ self._controller = controller
10
16
 
11
17
  # Plugin
12
- self._plugin_ip = ""
13
- self._random_mac = ""
14
- self._panel_mac = ""
15
- self._panel_ip = ""
18
+ self._plugin_ip: str = ""
19
+ self._random_mac: str = ""
20
+ self._panel_mac: str = ""
21
+ self._panel_ip: str = ""
16
22
 
17
23
  # Path
18
24
  self._config_directory: Path = Path()
@@ -22,16 +28,40 @@ class QolsysSettings:
22
28
 
23
29
  # Pki
24
30
  self._key_size: int = 2048
31
+ self._auto_discover_pki: bool = True
25
32
 
26
33
  # MQTT
27
34
  self._mqtt_timeout: int = 30
28
35
  self._mqtt_ping: int = 600
29
- self._mqtt_qos:int = 0
30
- self._mqtt_remote_client_id = ""
36
+ self._mqtt_qos: int = 0
37
+ self._mqtt_remote_client_id: str = ""
38
+ self._log_mqtt_message: bool = False
31
39
 
32
40
  # Operation
33
- self._motion_sensor_delay:bool = True
34
- self._motion_sensor_delay_sec:int = 310
41
+ self._motion_sensor_delay: bool = True
42
+ self._motion_sensor_delay_sec: int = 310
43
+ self._check_user_code_on_arm: bool = False
44
+ self._check_user_code_on_disarm: bool = True
45
+
46
+ def check_panel_ip(self) -> bool:
47
+ if self._panel_ip == "":
48
+ LOGGER.debug("Invalid Panel IP: %s", self._panel_ip)
49
+ return False
50
+
51
+ LOGGER.debug("Found Panel IP: %s", self._panel_ip)
52
+ return True
53
+
54
+ def check_plugin_ip(self) -> bool:
55
+ if self._plugin_ip == "":
56
+ LOGGER.debug("Invalid Plugin IP: %s", self._plugin_ip)
57
+ return False
58
+
59
+ LOGGER.debug("Found Plugin IP: %s", self._plugin_ip)
60
+ return True
61
+
62
+ # -----------------------------
63
+ # properties + setters
64
+ # -----------------------------
35
65
 
36
66
  @property
37
67
  def random_mac(self) -> str:
@@ -45,6 +75,10 @@ class QolsysSettings:
45
75
  def plugin_ip(self) -> str:
46
76
  return self._plugin_ip
47
77
 
78
+ @plugin_ip.setter
79
+ def plugin_ip(self, plugin_ip: str) -> None:
80
+ self._plugin_ip = plugin_ip
81
+
48
82
  @property
49
83
  def panel_mac(self) -> str:
50
84
  return self._panel_mac
@@ -57,36 +91,76 @@ class QolsysSettings:
57
91
  def panel_ip(self) -> str:
58
92
  return self._panel_ip
59
93
 
94
+ @panel_ip.setter
95
+ def panel_ip(self, panel_ip: str) -> None:
96
+ self._panel_ip = panel_ip
97
+
98
+ @property
99
+ def log_mqtt_mesages(self) -> bool:
100
+ return self._log_mqtt_messages
101
+
102
+ @log_mqtt_mesages.setter
103
+ def log_mqtt_mesages(self, log_mqtt_mesages: bool) -> None:
104
+ self._log_mqtt_messages = log_mqtt_mesages
105
+
106
+ @property
107
+ def check_user_code_on_disarm(self) -> bool:
108
+ return self._check_user_code_on_disarm
109
+
110
+ @check_user_code_on_disarm.setter
111
+ def check_user_code_on_disarm(self, check_user_code_on_disarm: bool) -> None:
112
+ self._check_user_code_on_disarm = check_user_code_on_disarm
113
+
114
+ @property
115
+ def check_user_code_on_arm(self) -> bool:
116
+ return self._check_user_code_on_arm
117
+
118
+ @check_user_code_on_arm.setter
119
+ def check_user_code_on_arm(self, check_user_code_on_arm: bool) -> None:
120
+ self._check_user_code_on_arm = check_user_code_on_arm
121
+
122
+ @property
123
+ def auto_discover_pki(self) -> bool:
124
+ return self._auto_discover_pki
125
+
126
+ @auto_discover_pki.setter
127
+ def auto_discover_pki(self, value: bool) -> None:
128
+ self._auto_discover_pki = value
129
+
60
130
  @property
61
131
  def mqtt_timeout(self) -> int:
62
132
  return self._mqtt_timeout
63
133
 
134
+ @mqtt_timeout.setter
135
+ def mqtt_timeout(self, value: int) -> None:
136
+ self._mqtt_timeout = value
137
+
64
138
  @property
65
139
  def mqtt_ping(self) -> int:
66
140
  return self._mqtt_ping
67
141
 
142
+ @mqtt_ping.setter
143
+ def mqtt_ping(self, value: int) -> None:
144
+ self._mqtt_ping = value
145
+
68
146
  @property
69
147
  def motion_sensor_delay(self) -> bool:
70
148
  return self._motion_sensor_delay
71
149
 
72
- @property
73
- def motion_sensor_delay_sec(self) -> int:
74
- return self._motion_sensor_delay_sec
75
-
76
150
  @motion_sensor_delay.setter
77
151
  def motion_sensor_delay(self, value: bool) -> None:
78
152
  self._motion_sensor_delay = value
79
153
 
80
- @panel_ip.setter
81
- def panel_ip(self, panel_ip: str) -> None:
82
- self._panel_ip = panel_ip
154
+ @property
155
+ def motion_sensor_delay_sec(self) -> int:
156
+ return self._motion_sensor_delay_sec
83
157
 
84
- @plugin_ip.setter
85
- def plugin_ip(self, plugin_ip: str) -> None:
86
- self._plugin_ip = plugin_ip
158
+ @motion_sensor_delay_sec.setter
159
+ def motion_sensor_delay_sec(self, value: int) -> None:
160
+ self._motion_sensor_delay_sec = value
87
161
 
88
162
  @property
89
- def config_directory(self) -> str:
163
+ def config_directory(self) -> Path:
90
164
  return self._config_directory
91
165
 
92
166
  @config_directory.setter
@@ -108,18 +182,6 @@ class QolsysSettings:
108
182
  def key_size(self) -> int:
109
183
  return self._key_size
110
184
 
111
- @mqtt_timeout.setter
112
- def mqtt_timeout(self, value: int) -> None:
113
- self._mqtt_timeout = value
114
-
115
- @mqtt_ping.setter
116
- def mqtt_ping(self, value: int) -> None:
117
- self._mqtt_ping = value
118
-
119
- @mqtt_ping.setter
120
- def mqtt_ping(self, ping:int) -> None:
121
- self._mqtt_ping = ping
122
-
123
185
  @property
124
186
  def mqtt_qos(self) -> int:
125
187
  return self._mqtt_qos
@@ -129,25 +191,9 @@ class QolsysSettings:
129
191
  return self._mqtt_remote_client_id
130
192
 
131
193
  @mqtt_remote_client_id.setter
132
- def mqtt_remote_client_id(self,client_id:str) -> None:
194
+ def mqtt_remote_client_id(self, client_id: str) -> None:
133
195
  self._mqtt_remote_client_id = client_id
134
196
 
135
- def check_panel_ip(self) -> bool:
136
- if self._panel_ip == "":
137
- LOGGER.debug("Invalid Panel IP: %s", self._panel_ip)
138
- return False
139
-
140
- LOGGER.debug("Found Panel IP: %s", self._panel_ip)
141
- return True
142
-
143
- def check_plugin_ip(self) -> bool:
144
- if self._plugin_ip == "":
145
- LOGGER.debug("Invalid Plugin IP: %s", self._plugin_ip)
146
- return False
147
-
148
- LOGGER.debug("Found Plugin IP: %s", self._plugin_ip)
149
- return True
150
-
151
197
  def check_config_directory(self, create: bool = True) -> bool: # noqa: PLR0911
152
198
  if not self.config_directory.is_dir():
153
199
  if not create:
@@ -1,9 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
4
+ from typing import TYPE_CHECKING
2
5
 
3
6
  from .observable import QolsysObservable
4
- from .partition import QolsysPartition
5
- from .scene import QolsysScene
6
- from .zone import QolsysZone
7
+ from .weather import QolsysWeather
7
8
  from .zwave_device import QolsysZWaveDevice
8
9
  from .zwave_dimmer import QolsysDimmer
9
10
  from .zwave_generic import QolsysGeneric
@@ -12,17 +13,23 @@ from .zwave_thermostat import QolsysThermostat
12
13
 
13
14
  LOGGER = logging.getLogger(__name__)
14
15
 
16
+ if TYPE_CHECKING:
17
+ from .controller import QolsysController
18
+ from .partition import QolsysPartition
19
+ from .scene import QolsysScene
20
+ from .zone import QolsysZone
21
+ from .zwave_device import QolsysZWaveDevice
15
22
 
16
- class QolsysState(QolsysObservable):
17
23
 
18
- def __init__(self) -> None:
24
+ class QolsysState(QolsysObservable):
25
+ def __init__(self, controller: QolsysController) -> None:
19
26
  super().__init__()
20
-
21
- self._partitions = []
22
- self._zones = []
23
- self._zwave_devices = []
24
- self._scenes = []
25
-
27
+ self._controller: QolsysController = controller
28
+ self._weather: QolsysWeather = QolsysWeather()
29
+ self._partitions: list[QolsysPartition] = []
30
+ self._zones: list[QolsysZone] = []
31
+ self._zwave_devices: list[QolsysZWaveDevice] = []
32
+ self._scenes: list[QolsysScene] = []
26
33
  self._state_partition_observer = QolsysObservable()
27
34
  self._state_zone_observer = QolsysObservable()
28
35
  self._state_zwave_observer = QolsysObservable()
@@ -44,6 +51,10 @@ class QolsysState(QolsysObservable):
44
51
  def scenes(self) -> list[QolsysScene]:
45
52
  return self._scenes
46
53
 
54
+ @property
55
+ def weather(self) -> QolsysWeather:
56
+ return self._weather
57
+
47
58
  @property
48
59
  def zwave_dimmers(self) -> list[QolsysDimmer]:
49
60
  dimmers = []
@@ -87,7 +98,7 @@ class QolsysState(QolsysObservable):
87
98
  def state_scene_observer(self) -> QolsysObservable:
88
99
  return self._state_scene_observer
89
100
 
90
- def partition(self, partition_id: str) -> QolsysPartition:
101
+ def partition(self, partition_id: str) -> QolsysPartition | None:
91
102
  for partition in self.partitions:
92
103
  if partition.id == partition_id:
93
104
  return partition
@@ -97,8 +108,11 @@ class QolsysState(QolsysObservable):
97
108
  def partition_add(self, new_partition: QolsysPartition) -> None:
98
109
  for partition in self.partitions:
99
110
  if new_partition.id == partition.id:
100
- LOGGER.debug("Adding Partition to State, Partition%s (%s) - Allready in Partitions List",
101
- new_partition.id, partition.name)
111
+ LOGGER.debug(
112
+ "Adding Partition to State, Partition%s (%s) - Allready in Partitions List",
113
+ new_partition.id,
114
+ partition.name,
115
+ )
102
116
  return
103
117
 
104
118
  self.partitions.append(new_partition)
@@ -115,7 +129,7 @@ class QolsysState(QolsysObservable):
115
129
  self.partitions.remove(partition)
116
130
  self.state_partition_observer.notify()
117
131
 
118
- def scene(self, scene_id: str) -> QolsysScene:
132
+ def scene(self, scene_id: str) -> QolsysScene | None:
119
133
  for scene in self.scenes:
120
134
  if scene.scene_id == scene_id:
121
135
  return scene
@@ -125,7 +139,7 @@ class QolsysState(QolsysObservable):
125
139
  def scene_add(self, new_scene: QolsysScene) -> None:
126
140
  for scene in self.scenes:
127
141
  if new_scene.scene_id == scene.scene_id:
128
- LOGGER.debug("Adding Scene to State, Scene%s (%s) - Allready in Scene List", new_scene.scene_id, scene.name )
142
+ LOGGER.debug("Adding Scene to State, Scene%s (%s) - Allready in Scene List", new_scene.scene_id, scene.name)
129
143
  return
130
144
 
131
145
  self.scenes.append(new_scene)
@@ -143,16 +157,24 @@ class QolsysState(QolsysObservable):
143
157
  self.scenes.remove(scene)
144
158
  self.state_scene_observer.notify()
145
159
 
146
- def zone(self, zone_id: str) -> QolsysZone:
160
+ def zone(self, zone_id: str) -> QolsysZone | None:
147
161
  for zone in self.zones:
148
162
  if zone.zone_id == zone_id:
149
163
  return zone
150
164
  return None
151
165
 
166
+ def zone_from_short_id(self, short_id: int) -> QolsysZone | None:
167
+ for zone in self.zones:
168
+ if zone.shortID == str(short_id):
169
+ return zone
170
+ return None
171
+
152
172
  def zone_add(self, new_zone: QolsysZone) -> None:
153
173
  for zone in self.zones:
154
174
  if new_zone.zone_id == zone.zone_id:
155
- LOGGER.debug("Adding Zone to State, zone%s (%s) - Allready in Zone List", new_zone.zone_id, self.sensorname)
175
+ LOGGER.debug(
176
+ "Adding Zone to State, zone%s (%s) - Allready in Zone List", new_zone.zone_id, new_zone.sensorname
177
+ )
156
178
  return
157
179
 
158
180
  self.zones.append(new_zone)
@@ -169,7 +191,7 @@ class QolsysState(QolsysObservable):
169
191
  self.zones.remove(zone)
170
192
  self.state_zone_observer.notify()
171
193
 
172
- def zwave_device(self, node_id: str) -> QolsysZWaveDevice:
194
+ def zwave_device(self, node_id: str) -> QolsysZWaveDevice | None:
173
195
  for zwave_device in self.zwave_devices:
174
196
  if zwave_device.node_id == node_id:
175
197
  return zwave_device
@@ -179,8 +201,9 @@ class QolsysState(QolsysObservable):
179
201
  def zwave_add(self, new_zwave: QolsysZWaveDevice) -> None:
180
202
  for zwave_device in self.zwave_devices:
181
203
  if new_zwave.node_id == zwave_device.node_id:
182
- LOGGER.debug("Adding ZWave to State, ZWave%s (%s) - Allready in ZWave List",
183
- new_zwave.node_id, zwave_device.node_name)
204
+ LOGGER.debug(
205
+ "Adding ZWave to State, ZWave%s (%s) - Allready in ZWave List", new_zwave.node_id, zwave_device.node_name
206
+ )
184
207
  return
185
208
 
186
209
  self.zwave_devices.append(new_zwave)
@@ -198,7 +221,6 @@ class QolsysState(QolsysObservable):
198
221
  self.state_zwave_observer.notify()
199
222
 
200
223
  def sync_zwave_devices_data(self, db_zwaves: list[QolsysZWaveDevice]) -> None: # noqa: PLR0912
201
-
202
224
  db_zwave_list = []
203
225
  for db_zwave in db_zwaves:
204
226
  db_zwave_list.append(db_zwave.node_id)
@@ -223,13 +245,13 @@ class QolsysState(QolsysObservable):
223
245
  # Update Thermostat
224
246
  if isinstance(state_zwave, QolsysThermostat) and isinstance(db_zwave, QolsysThermostat):
225
247
  state_zwave.update_base(db_zwave.to_dict_base())
226
- state_zwave.update_thermostat(db_zwave.to_dict_thermostat)
248
+ state_zwave.update_thermostat(db_zwave.to_dict_thermostat())
227
249
  break
228
250
 
229
251
  # Update Lock
230
252
  if isinstance(state_zwave, QolsysLock) and isinstance(db_zwave, QolsysLock):
231
253
  state_zwave.update_base(db_zwave.to_dict_base())
232
- state_zwave.update_lock(db_zwave.to_dict_lock)
254
+ state_zwave.update_lock(db_zwave.to_dict_lock())
233
255
  break
234
256
 
235
257
  # Generic Z-Wave Device
@@ -237,10 +259,6 @@ class QolsysState(QolsysObservable):
237
259
  state_zwave.update_base(db_zwave.to_dict_base())
238
260
  break
239
261
 
240
- # zwave node_id has changed of node_type, delete and add again
241
- # self.zwave_delete(int(state_zwave.node_id))
242
- # self.zwave_add(db_zwave)
243
-
244
262
  # Add new zwave device
245
263
  for db_zwave in db_zwaves:
246
264
  if db_zwave.node_id not in state_zwave_list:
@@ -250,9 +268,13 @@ class QolsysState(QolsysObservable):
250
268
  # Delete zwave device
251
269
  for state_zwave in self.zwave_devices:
252
270
  if state_zwave.node_id not in db_zwave_list:
253
- LOGGER.debug("sync_data - delete ZWave%s", state_zwave.none_id)
271
+ LOGGER.debug("sync_data - delete ZWave%s", state_zwave.node_id)
254
272
  self.zwave_delete(state_zwave.node_id)
255
273
 
274
+ def sync_weather_data(self, db_weather: QolsysWeather) -> None:
275
+ LOGGER.debug("sync_data - update Weather")
276
+ self._weather.update(db_weather.forecasts)
277
+
256
278
  def sync_scenes_data(self, db_scenes: list[QolsysScene]) -> None:
257
279
  db_scene_list = []
258
280
  for db_scene in db_scenes:
@@ -299,6 +321,7 @@ class QolsysState(QolsysObservable):
299
321
  if state_zone.zone_id == db_zone.zone_id:
300
322
  LOGGER.debug("sync_data - update Zone%s", state_zone.zone_id)
301
323
  state_zone.update(db_zone.to_dict())
324
+ state_zone.update_powerg(db_zone.to_powerg_dict())
302
325
 
303
326
  # Delete zones
304
327
  for state_zone in self.zones:
@@ -344,8 +367,8 @@ class QolsysState(QolsysObservable):
344
367
  LOGGER.debug("sync_data - Add Partition%s", db_partition.id)
345
368
  self.partition_add(db_partition)
346
369
 
347
- def dump(self) -> None: # noqa: PLR0915
348
- LOGGER.debug("*** Information ***")
370
+ def dump(self) -> None: # noqa: PLR0912, PLR0915
371
+ LOGGER.debug("*** Device Information ***")
349
372
 
350
373
  for partition in self.partitions:
351
374
  pid = partition.id
@@ -371,6 +394,12 @@ class QolsysState(QolsysObservable):
371
394
  LOGGER.debug("Zone%s (%s) - latestdBm: %s", zid, name, zone.latestdBm)
372
395
  LOGGER.debug("Zone%s (%s) - averagedBm: %s", zid, name, zone.averagedBm)
373
396
 
397
+ if zone.is_powerg_temperature_enabled():
398
+ LOGGER.debug("Zone%s (%s) - powerg_temperature: %s", zid, name, zone.powerg_temperature)
399
+
400
+ if zone.is_powerg_light_enabled():
401
+ LOGGER.debug("Zone%s (%s) - powerg_light: %s", zid, name, zone.powerg_light)
402
+
374
403
  for zwave in self.zwave_devices:
375
404
  if isinstance(zwave, QolsysDimmer):
376
405
  nid = zwave.node_id
@@ -398,7 +427,7 @@ class QolsysState(QolsysObservable):
398
427
  if isinstance(zwave, QolsysLock):
399
428
  zid = zwave.lock_node_id
400
429
  name = zwave.lock_name
401
- LOGGER.debug("Lock%s (%s) - current_temp: %s", zid, name, zwave.lock_status)
430
+ LOGGER.debug("Lock%s (%s) - lock_status: %s", zid, name, zwave.lock_status)
402
431
  continue
403
432
 
404
433
  if isinstance(zwave, QolsysGeneric):
@@ -413,4 +442,13 @@ class QolsysState(QolsysObservable):
413
442
  for scene in self.scenes:
414
443
  sid = scene.scene_id
415
444
  name = scene.name
416
- LOGGER.debug("Scene%s (%s)",sid, name)
445
+ LOGGER.debug("Scene%s (%s)", sid, name)
446
+
447
+ for forecast in self.weather.forecasts:
448
+ LOGGER.debug(
449
+ "Weather - %s - High: %s, Low:%s, Condition: %s",
450
+ forecast.day_of_week[0:3],
451
+ forecast.high_temp,
452
+ forecast.low_temp,
453
+ forecast.condition,
454
+ )
@@ -7,32 +7,31 @@ LOGGER = logging.getLogger(__name__)
7
7
 
8
8
  class QolsysTaskManager:
9
9
  def __init__(self) -> None:
10
- self._tasks = set()
10
+ self._tasks: set[asyncio.Task] = set() # type: ignore[type-arg]
11
11
 
12
- def run(self, coro: Coroutine, label: str) -> asyncio.Task:
12
+ def run(self, coro: Coroutine, label: str) -> asyncio.Task: # type: ignore[type-arg]
13
13
  task = asyncio.create_task(coro, name=label)
14
14
  self._tasks.add(task)
15
15
 
16
- def _done_callback(task: asyncio.Task) -> None:
17
-
16
+ def _done_callback(task: asyncio.Task) -> None: # type: ignore[type-arg]
18
17
  try:
19
18
  task.result()
20
19
 
21
20
  except asyncio.CancelledError:
22
- LOGGER.debug("Task Cancelled: %s",task.get_name())
21
+ LOGGER.debug("Task Cancelled: %s", task.get_name())
23
22
 
24
23
  except Exception as e: # noqa: BLE001
25
- LOGGER.debug("[Callback] Task failed with: %s",e)
24
+ LOGGER.debug("[Callback] Task failed with: %s", e)
26
25
 
27
26
  self._tasks.discard(task)
28
27
 
29
28
  task.add_done_callback(_done_callback)
30
29
  return task
31
30
 
32
- def get_task(self, label:str) -> asyncio.Task | None:
31
+ def get_task(self, label: str) -> asyncio.Task | None: # type: ignore[type-arg]
33
32
  for task in self._tasks:
34
- if task.get_name() == label:
35
- return task
33
+ if task.get_name() == label:
34
+ return task
36
35
  return None
37
36
 
38
37
  def cancel(self, label: str) -> None:
@@ -49,9 +48,6 @@ class QolsysTaskManager:
49
48
  if self._tasks:
50
49
  await asyncio.gather(*self._tasks, return_exceptions=True)
51
50
 
52
- def pending(self) -> None:
53
- return {t for t in self._tasks if not t.done()}
54
-
55
51
  def dump(self) -> None:
56
52
  for task in self._tasks:
57
53
  LOGGER.debug("Task: %s, Done: %s, Cancelled: %s", task.get_name(), task.done(), task.cancelled())
@@ -0,0 +1,25 @@
1
+ import logging
2
+
3
+ LOGGER = logging.getLogger(__name__)
4
+
5
+
6
+ class QolsysUser:
7
+ def __init__(self) -> None:
8
+ self._id: int = 0
9
+ self._user_code = ""
10
+
11
+ @property
12
+ def id(self) -> int:
13
+ return self._id
14
+
15
+ @id.setter
16
+ def id(self, value: int) -> None:
17
+ self._id = value
18
+
19
+ @property
20
+ def user_code(self) -> str:
21
+ return self._user_code
22
+
23
+ @user_code.setter
24
+ def user_code(self, value: str) -> None:
25
+ self._user_code = value
@@ -1,24 +1,16 @@
1
1
  import logging
2
2
  import random
3
- import re
4
3
 
5
4
  LOGGER = logging.getLogger(__name__)
6
5
 
7
6
 
8
- def fix_json_string(json_string):
9
- def replace_escape(match):
10
- hex_value = match.group(1)
11
- decimal_value = int(hex_value, 16)
12
- return f"\\u{decimal_value:04x}"
13
-
14
- return re.sub(r"\\x([0-9a-fA-F]{2})", replace_escape, json_string)
15
-
16
-
17
- def generate_random_mac() -> str:
7
+ def generate_random_mac() -> str: # noqa: D103
18
8
  mac = [
19
- 0xf2, 0x16, 0x3e,
20
- random.randint(0x00, 0x7f),
21
- random.randint(0x00, 0xff),
22
- random.randint(0x00, 0xff),
9
+ 0xF2,
10
+ 0x16,
11
+ 0x3E,
12
+ random.randint(0x00, 0x7F),
13
+ random.randint(0x00, 0xFF),
14
+ random.randint(0x00, 0xFF),
23
15
  ]
24
- return ":".join(map(lambda x: "%02x" % x, mac))
16
+ return ":".join(map(lambda x: "%02x" % x, mac)) # noqa: C417, UP031