qolsys-controller 0.0.62__py3-none-any.whl → 0.0.87__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 (37) hide show
  1. qolsys_controller/adc_device.py +202 -0
  2. qolsys_controller/adc_service.py +139 -0
  3. qolsys_controller/adc_service_garagedoor.py +35 -0
  4. qolsys_controller/controller.py +245 -34
  5. qolsys_controller/database/db.py +60 -0
  6. qolsys_controller/database/table.py +1 -0
  7. qolsys_controller/database/table_alarmedsensor.py +2 -0
  8. qolsys_controller/database/table_history.py +2 -2
  9. qolsys_controller/database/table_smartsocket.py +12 -1
  10. qolsys_controller/database/table_thermostat.py +3 -0
  11. qolsys_controller/database/table_virtual_device.py +13 -1
  12. qolsys_controller/database/table_zwave_node.py +3 -0
  13. qolsys_controller/enum.py +5 -1
  14. qolsys_controller/enum_adc.py +28 -0
  15. qolsys_controller/enum_zwave.py +158 -29
  16. qolsys_controller/errors.py +5 -0
  17. qolsys_controller/mqtt_command.py +6 -0
  18. qolsys_controller/panel.py +109 -5
  19. qolsys_controller/partition.py +22 -2
  20. qolsys_controller/state.py +163 -1
  21. qolsys_controller/task_manager.py +4 -3
  22. qolsys_controller/zone.py +2 -1
  23. qolsys_controller/zwave_device.py +132 -4
  24. qolsys_controller/zwave_dimmer.py +3 -0
  25. qolsys_controller/zwave_energy_clamp.py +15 -0
  26. qolsys_controller/zwave_garagedoor.py +3 -0
  27. qolsys_controller/zwave_generic.py +3 -0
  28. qolsys_controller/zwave_lock.py +4 -0
  29. qolsys_controller/zwave_outlet.py +3 -0
  30. qolsys_controller/zwave_service_meter.py +192 -0
  31. qolsys_controller/zwave_service_multilevelsensor.py +119 -0
  32. qolsys_controller/zwave_thermometer.py +21 -0
  33. qolsys_controller/zwave_thermostat.py +150 -38
  34. {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/METADATA +1 -1
  35. {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/RECORD +37 -29
  36. {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/WHEEL +0 -0
  37. {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,6 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import asyncio
5
- import base64
6
5
  import contextlib
7
6
  import json
8
7
  import logging
@@ -19,10 +18,11 @@ from qolsys_controller.mqtt_command import (
19
18
  MQTTCommand_Panel,
20
19
  MQTTCommand_ZWave,
21
20
  )
21
+ from qolsys_controller.zwave_thermostat import QolsysThermostat
22
22
 
23
23
  from .enum import PartitionAlarmState, PartitionArmingType, PartitionSystemStatus
24
- from .enum_zwave import ThermostatFanMode, ThermostatMode, ZwaveCommand, ZwaveDeviceClass
25
- from .errors import QolsysMqttError, QolsysSslError
24
+ from .enum_zwave import ThermostatFanMode, ThermostatMode, ThermostatSetpointMode, ZwaveCommandClass, ZwaveDeviceClass
25
+ from .errors import QolsysMqttError, QolsysSslError, QolsysUserCodeError
26
26
  from .mdns import QolsysMDNS
27
27
  from .mqtt_command_queue import QolsysMqttCommandQueue
28
28
  from .observable import QolsysObservable
@@ -53,6 +53,7 @@ class QolsysController:
53
53
  self.certificate_exchange_server: asyncio.Server | None = None
54
54
  self._task_manager = QolsysTaskManager()
55
55
  self._mqtt_command_queue = QolsysMqttCommandQueue()
56
+ self._zone_id: str = "1"
56
57
 
57
58
  # MQTT Client
58
59
  self.aiomqtt: aiomqtt.Client | None = None
@@ -201,14 +202,10 @@ class QolsysController:
201
202
  # Subscribe to MQTT commands send to panel by other devices
202
203
  await self.aiomqtt.subscribe("mastermeid", qos=self.settings.mqtt_qos)
203
204
 
204
- # Subscribe to all topics
205
- # await self.aiomqtt.subscribe("#", qos=self.settings.mqtt_qos)
206
-
207
205
  self._task_manager.run(self.mqtt_listen_task(), self._mqtt_task_listen_label)
208
206
  self._task_manager.run(self.mqtt_ping_task(), self._mqtt_task_ping_label)
209
207
 
210
208
  response_connect = await self.command_connect()
211
-
212
209
  self.panel.imei = response_connect.get("master_imei", "")
213
210
  self.panel.product_type = response_connect.get("primary_product_type", "")
214
211
 
@@ -285,14 +282,7 @@ class QolsysController:
285
282
  if message.topic.matches("ZWAVE_RESPONSE"): # noqa: SIM102
286
283
  if isinstance(message.payload, bytes):
287
284
  data = json.loads(message.payload.decode())
288
- zwave = data.get("ZWAVE_RESPONSE", "")
289
- decoded_payload = base64.b64decode(zwave.get("ZWAVE_PAYLOAD", "")).hex()
290
- LOGGER.debug(
291
- "Z-Wave Response: Node(%s) - Status(%s) - Payload(%s)",
292
- zwave.get("NODE_ID", ""),
293
- zwave.get("ZWAVE_COMMAND_STATUS", ""),
294
- decoded_payload,
295
- )
285
+ self.panel.parse_zwave_message(data)
296
286
 
297
287
  except aiomqtt.MqttError as err:
298
288
  self.connected = False
@@ -618,7 +608,7 @@ class QolsysController:
618
608
  user_id = self.panel.check_user(user_code)
619
609
  if user_id == -1:
620
610
  LOGGER.debug("MQTT: disarm command error - user_code error")
621
- return None
611
+ raise QolsysUserCodeError()
622
612
 
623
613
  async def get_mqtt_disarm_command(silent_disarming: bool) -> str:
624
614
  if partition.alarm_state == PartitionAlarmState.ALARM:
@@ -688,12 +678,12 @@ class QolsysController:
688
678
  LOGGER.debug("MQTT: arm command error - Unknow Partition")
689
679
  return None
690
680
 
691
- if self.panel.SECURE_ARMING == "true" and self.settings.check_user_code_on_arm:
692
- # Do local user code verification to arm if secure arming is enabled
681
+ if self.settings.check_user_code_on_arm:
682
+ # Do local user code verification to arm
693
683
  user_id = self.panel.check_user(user_code)
694
684
  if user_id == -1:
695
685
  LOGGER.debug("MQTT: arm command error - user_code error")
696
- return None
686
+ raise QolsysUserCodeError()
697
687
 
698
688
  exitSoundValue = "ON"
699
689
  if not exit_sounds:
@@ -758,6 +748,141 @@ class QolsysController:
758
748
  LOGGER.debug("MQTT: Receiving execute_scene command")
759
749
  return response
760
750
 
751
+ async def command_panel_virtual_device_action(self, device_id: str, state: int) -> dict[str, Any] | None:
752
+ LOGGER.debug("MQTT: Sending virtual_device command")
753
+
754
+ garage_door = self.state.adc_device(device_id)
755
+ if not garage_door:
756
+ LOGGER.error("Invalid Virtual Garage Door Id: %s", device_id)
757
+
758
+ device_list = {
759
+ "virtualDeviceList": [
760
+ {
761
+ "virtualDeviceId": device_id,
762
+ "virtualDeviceFunctionList": [
763
+ {
764
+ "vdFuncId": 1,
765
+ "vdFuncState": state,
766
+ "vdFuncBackendTimestamp": int(time.time() * 1000),
767
+ "vdFuncType": 1,
768
+ }
769
+ ],
770
+ }
771
+ ]
772
+ }
773
+
774
+ virtual_command = {
775
+ "operation_name": "send_virtual_device_description",
776
+ "virtual_device_operation": 4,
777
+ "virtual_device_description": json.dumps(device_list),
778
+ "operation_source": 0,
779
+ }
780
+
781
+ ipc_request = [
782
+ {
783
+ "dataType": "string",
784
+ "dataValue": json.dumps(virtual_command),
785
+ }
786
+ ]
787
+
788
+ LOGGER.debug("virtual command: %s", virtual_command)
789
+
790
+ command = MQTTCommand_Panel(self)
791
+ command.append_ipc_request(ipc_request)
792
+ response = await command.send_command()
793
+ LOGGER.debug("MQTT: Receiving virtual_device command: %s", response)
794
+ return response
795
+
796
+ async def command_panel_trigger_police(self, partition_id: str, silent: bool) -> dict[str, Any] | None:
797
+ LOGGER.debug("MQTT: Sending panel_trigger_police command")
798
+
799
+ partition = self.state.partition(partition_id)
800
+ if not partition:
801
+ LOGGER.debug("MQTT: command_panel_trigger_police Error - Unknow Partition: %s", partition_id)
802
+ return None
803
+
804
+ trigger_command = {
805
+ "operation_name": "generate_emergency",
806
+ "partitionID": int(partition_id),
807
+ "zoneID": int(self._zone_id),
808
+ "emergencyType": "Silent Police Emergency" if silent else "Police Emergency",
809
+ "operation_source": 1,
810
+ "macAddress": self.settings.random_mac,
811
+ }
812
+
813
+ ipc_request = [
814
+ {
815
+ "dataType": "string",
816
+ "dataValue": json.dumps(trigger_command),
817
+ }
818
+ ]
819
+
820
+ command = MQTTCommand_Panel(self)
821
+ command.append_ipc_request(ipc_request)
822
+ response = await command.send_command()
823
+ LOGGER.debug("MQTT: Receiving panel_trigger_police command")
824
+ return response
825
+
826
+ async def command_panel_trigger_auxilliary(self, partition_id: str, silent: bool) -> dict[str, Any] | None:
827
+ LOGGER.debug("MQTT: Sending panel_trigger_auxilliary command")
828
+
829
+ partition = self.state.partition(partition_id)
830
+ if not partition:
831
+ LOGGER.debug("MQTT: command_panel_trigger_auxilliary Error - Unknow Partition: %s", partition_id)
832
+ return None
833
+
834
+ trigger_command = {
835
+ "operation_name": "generate_emergency",
836
+ "partitionID": int(partition_id),
837
+ "zoneID": int(self._zone_id),
838
+ "emergencyType": "Silent Auxiliary Emergency" if silent else "Auxiliary Emergency",
839
+ "operation_source": 1,
840
+ "macAddress": self.settings.random_mac,
841
+ }
842
+
843
+ ipc_request = [
844
+ {
845
+ "dataType": "string",
846
+ "dataValue": json.dumps(trigger_command),
847
+ }
848
+ ]
849
+
850
+ command = MQTTCommand_Panel(self)
851
+ command.append_ipc_request(ipc_request)
852
+ response = await command.send_command()
853
+ LOGGER.debug("MQTT: Receiving panel_trigger_auxilliary command")
854
+ return response
855
+
856
+ async def command_panel_trigger_fire(self, partition_id: str) -> dict[str, Any] | None:
857
+ LOGGER.debug("MQTT: Sending panel_trigger_fire command")
858
+
859
+ partition = self.state.partition(partition_id)
860
+ if not partition:
861
+ LOGGER.debug("MQTT: command_panel_trigger_fire Error - Unknow Partition: %s", partition_id)
862
+ return None
863
+
864
+ trigger_command = {
865
+ "operation_name": "generate_emergency",
866
+ "partitionID": int(partition_id),
867
+ "zoneID": int(self._zone_id),
868
+ "emergencyType": "Fire Emergency",
869
+ "operation_source": 1,
870
+ "macAddress": self.settings.random_mac,
871
+ }
872
+
873
+ ipc_request = [
874
+ {
875
+ "dataType": "string",
876
+ "dataValue": json.dumps(trigger_command),
877
+ }
878
+ ]
879
+
880
+ command = MQTTCommand_Panel(self)
881
+ command.append_ipc_request(ipc_request)
882
+ response = await command.send_command()
883
+ LOGGER.debug("MQTT: Receiving panel_trigger_fire command")
884
+ return response
885
+
761
886
  async def command_zwave_switch_binary_set(self, node_id: str, status: bool) -> dict[str, Any] | None:
762
887
  LOGGER.debug("MQTT: Sending set_zwave_switch_binary command - Node(%s) - Status(%s)", node_id, status)
763
888
  zwave_node = self.state.zwave_device(node_id)
@@ -774,7 +899,7 @@ class QolsysController:
774
899
  if status:
775
900
  level = 255
776
901
 
777
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.SwitchBinary, 1, level])
902
+ command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.SwitchBinary, 1, level])
778
903
  response = await command.send_command()
779
904
  LOGGER.debug("MQTT: Receiving set_zwave_switch_binary command")
780
905
  return response
@@ -791,7 +916,7 @@ class QolsysController:
791
916
  LOGGER.error("switch_multilevel_set used on invalid %s", zwave_node.generic_device_type)
792
917
  return None
793
918
 
794
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.SwitchMultilevel, 1, level])
919
+ command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.SwitchMultilevel, 1, level])
795
920
  response = await command.send_command()
796
921
  LOGGER.debug("MQTT: Receiving set_zwave_multilevel_switch command")
797
922
  return response
@@ -809,37 +934,123 @@ class QolsysController:
809
934
  if locked:
810
935
  lock_mode = 255
811
936
 
812
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.DoorLock, 1, lock_mode])
937
+ command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.DoorLock, 1, lock_mode])
813
938
  response = await command.send_command()
814
939
  LOGGER.debug("MQTT: Receiving zwave_doorlock_set command")
815
940
  return response
816
941
 
817
942
  async def command_zwave_thermostat_setpoint_set(
818
- self, node_id: str, mode: ThermostatMode, setpoint: float
943
+ self, node_id: str, mode: ThermostatSetpointMode, setpoint: int
819
944
  ) -> dict[str, Any] | None:
820
- LOGGER.debug(
821
- "MQTT: Sending zwave_thermostat_setpoint_set - Node(%s) - Mode(%s) - Setpoint(%s)", node_id, mode, setpoint
822
- )
823
-
824
945
  zwave_node = self.state.zwave_device(node_id)
825
946
  if not zwave_node:
826
947
  LOGGER.error("thermostat_setpoint_set - Invalid node_id %s", node_id)
827
948
  return None
828
949
 
829
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.ThermostatSetPoint, 1, mode, int(setpoint)])
950
+ if not isinstance(zwave_node, QolsysThermostat):
951
+ LOGGER.error("thermostat_setpoint_set - Z-Wave node is not a thermostat %s", node_id)
952
+ return None
953
+
954
+ scale: int = 0
955
+ if zwave_node.thermostat_device_temp_unit == "F":
956
+ scale = 1
957
+
958
+ precision: int = 1
959
+ size: int = 2
960
+ pss = (precision << 5) | (scale << 3) | size
961
+ temp_int = int(round(setpoint * (10**precision)))
962
+ temp_bytes = temp_int.to_bytes(size, byteorder="big", signed=True)
963
+
964
+ setpointmode = ThermostatSetpointMode.HEATING
965
+ if mode == ThermostatSetpointMode.COOLING:
966
+ setpointmode = mode
967
+
968
+ # zwave_bytes: list[int] = [
969
+ # 0x43,
970
+ # 0x03, # SET
971
+ # mode.value,
972
+ # pss,
973
+ # ] + list(temp_bytes)
974
+
975
+ zwave_bytes2: list[int] = [
976
+ 0x43, # Thermostat Setpoint
977
+ 0x01, # SET
978
+ setpointmode.value,
979
+ pss,
980
+ ] + list(temp_bytes)
981
+
982
+ # zwave_bytes3: list[int] = [
983
+ # 0x43, # Thermostat Setpoint
984
+ # 0x03, # SET
985
+ # 0x03, # Furnace
986
+ # pss,
987
+ # ] + list(temp_bytes)
988
+
989
+ # zwave_bytes4: list[int] = [
990
+ # 0x43, # Thermostat Setpoint
991
+ # 0x01, # SET
992
+ # 0x03, # Furnace
993
+ # pss,
994
+ # ] + list(temp_bytes)
995
+
996
+ # LOGGER.debug(
997
+ # "MQTT: Sending zwave_thermostat_setpoint_set 0x03 - Node(%s) - Mode(%s) - Setpoint(%s): %s",
998
+ # node_id,
999
+ # mode.value,
1000
+ # setpoint,
1001
+ # zwave_bytes,
1002
+ # )
1003
+ # command = MQTTCommand_ZWave(self, node_id, zwave_bytes)
1004
+ # response = await command.send_command()
1005
+ # LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response)
1006
+
1007
+ LOGGER.debug(
1008
+ "MQTT: Sending zwave_thermostat_setpoint_set 0x01 - Node(%s) - Mode(%s) - Setpoint(%s): %s",
1009
+ node_id,
1010
+ mode.value,
1011
+ setpoint,
1012
+ zwave_bytes2,
1013
+ )
1014
+ command = MQTTCommand_ZWave(self, node_id, zwave_bytes2)
830
1015
  response = await command.send_command()
831
- LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command")
1016
+ LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response)
1017
+
1018
+ # LOGGER.debug(
1019
+ # "MQTT: Sending zwave_thermostat_setpoint_set 0x03 - Node(%s) - Mode(%s) - Setpoint(%s): %s",
1020
+ # node_id,
1021
+ # 0x03,
1022
+ # setpoint,
1023
+ # zwave_bytes3,
1024
+ # )
1025
+ # command = MQTTCommand_ZWave(self, node_id, zwave_bytes3)
1026
+ # response = await command.send_command()
1027
+ # LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response)
1028
+
1029
+ # LOGGER.debug(
1030
+ # "MQTT: Sending zwave_thermostat_setpoint_set 0x01 - Node(%s) - Mode(%s) - Setpoint(%s): %s",
1031
+ # node_id,
1032
+ # 0x03,
1033
+ # setpoint,
1034
+ # zwave_bytes4,
1035
+ # )
1036
+ # command = MQTTCommand_ZWave(self, node_id, zwave_bytes4)
1037
+ # response = await command.send_command()
1038
+ # LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response)
1039
+
832
1040
  return response
833
1041
 
834
1042
  async def command_zwave_thermostat_mode_set(self, node_id: str, mode: ThermostatMode) -> dict[str, Any] | None:
835
1043
  LOGGER.debug("MQTT: Sending zwave_thermostat_mode_set command - Node(%s) - Mode(%s)", node_id, mode)
836
1044
 
837
- zwave_node = self.state.zwave_device(node_id)
838
- if not zwave_node:
839
- LOGGER.error("thermostat_mode_set - Invalid node_id %s", node_id)
1045
+ thermostat = self.state.zwave_thermostat(node_id)
1046
+ if not thermostat:
1047
+ LOGGER.error("zwave_thermostat_mode_set - Invalid node_id %s", node_id)
840
1048
  return None
841
1049
 
842
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.ThermostatMode, 1, mode])
1050
+ if mode not in thermostat.available_thermostat_mode():
1051
+ LOGGER.error("thermostat_mode_set - Invalid mode %s", mode)
1052
+
1053
+ command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.ThermostatMode, 1, int(mode)])
843
1054
  response = await command.send_command()
844
1055
  LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command")
845
1056
  return response
@@ -852,7 +1063,7 @@ class QolsysController:
852
1063
  LOGGER.error("thermostat_fan_mode_set - Invalid node_id %s", node_id)
853
1064
  return None
854
1065
 
855
- command = MQTTCommand_ZWave(self, node_id, [ZwaveCommand.ThermostatFanMode, 1, fan_mode])
1066
+ command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.ThermostatFanMode, 1, fan_mode])
856
1067
  response = await command.send_command()
857
1068
  LOGGER.debug("MQTT: Receiving zwave_thermostat_fan_mode_set command")
858
1069
  return response
@@ -155,6 +155,42 @@ class QolsysDB:
155
155
  def cursor(self) -> sqlite3.Cursor:
156
156
  return self._cursor
157
157
 
158
+ def get_users(self) -> list[dict[str, str]]:
159
+ self.cursor.execute(f"SELECT * FROM {self.table_user.table} ORDER BY _id")
160
+ self.db.commit()
161
+
162
+ users = []
163
+ columns = [description[0] for description in self.cursor.description]
164
+ for row in self.cursor.fetchall():
165
+ row_dict = dict(zip(columns, row, strict=True))
166
+ users.append(row_dict)
167
+
168
+ return users
169
+
170
+ def get_master_slave(self) -> list[dict[str, str]]:
171
+ self.cursor.execute(f"SELECT * FROM {self.table_master_slave.table}")
172
+ self.db.commit()
173
+
174
+ masterslave = []
175
+ columns = [description[0] for description in self.cursor.description]
176
+ for row in self.cursor.fetchall():
177
+ row_dict = dict(zip(columns, row, strict=True))
178
+ masterslave.append(row_dict)
179
+
180
+ return masterslave
181
+
182
+ def get_iqremote_settings(self) -> list[dict[str, str]]:
183
+ self.cursor.execute(f"SELECT * FROM {self.table_iqremotesettings.table}")
184
+ self.db.commit()
185
+
186
+ iqremote_settings = []
187
+ columns = [description[0] for description in self.cursor.description]
188
+ for row in self.cursor.fetchall():
189
+ row_dict = dict(zip(columns, row, strict=True))
190
+ iqremote_settings.append(row_dict)
191
+
192
+ return iqremote_settings
193
+
158
194
  def get_scenes(self) -> list[dict[str, str]]:
159
195
  self.cursor.execute(f"SELECT * FROM {self.table_scene.table} ORDER BY scene_id")
160
196
  self.db.commit()
@@ -179,6 +215,18 @@ class QolsysDB:
179
215
 
180
216
  return partitions
181
217
 
218
+ def get_adc_devices(self) -> list[dict[str, str]]:
219
+ self.cursor.execute(f"SELECT * FROM {self.table_virtual_device.table} ORDER BY device_id")
220
+ self.db.commit()
221
+
222
+ devices = []
223
+ columns = [description[0] for description in self.cursor.description]
224
+ for row in self.cursor.fetchall():
225
+ row_dict = dict(zip(columns, row, strict=True))
226
+ devices.append(row_dict)
227
+
228
+ return devices
229
+
182
230
  def get_zwave_devices(self) -> list[dict[str, str]]:
183
231
  self.cursor.execute(f"SELECT * FROM {self.table_zwave_node.table} ORDER BY node_id")
184
232
  self.db.commit()
@@ -191,6 +239,18 @@ class QolsysDB:
191
239
 
192
240
  return devices
193
241
 
242
+ def get_zwave_other_devices(self) -> list[dict[str, str]]:
243
+ self.cursor.execute(f"SELECT * FROM {self.table_zwave_other.table} ORDER BY node_id")
244
+ self.db.commit()
245
+
246
+ devices = []
247
+ columns = [description[0] for description in self.cursor.description]
248
+ for row in self.cursor.fetchall():
249
+ row_dict = dict(zip(columns, row, strict=True))
250
+ devices.append(row_dict)
251
+
252
+ return devices
253
+
194
254
  def get_locks(self) -> list[dict[str, str]]:
195
255
  self.cursor.execute(f"SELECT * FROM {self.table_doorlock.table} ORDER BY node_id")
196
256
  self.db.commit()
@@ -79,6 +79,7 @@ class QolsysTable:
79
79
  LOGGER.warning("Please Report")
80
80
  return
81
81
 
82
+ # Select only known columns
82
83
  full_data = {col: data.get(col, "") for col in self._columns}
83
84
 
84
85
  new_columns = []
@@ -26,6 +26,8 @@ class QolsysTableAlarmedSensor(QolsysTable):
26
26
  "priority",
27
27
  "aseb_type",
28
28
  "alarm_time",
29
+ "version",
30
+ "opr",
29
31
  ]
30
32
 
31
33
  self._create_table()
@@ -27,9 +27,9 @@ class QolsysTableHistory(QolsysTable):
27
27
  "feature1",
28
28
  "feature2",
29
29
  "device_id",
30
- # "History Bulk Insert",
30
+ # "history_bulk_insert",
31
31
  "Partition",
32
- # "History Device Names List",
32
+ # "History_Device_Names_List",
33
33
  # "History Bypass Event",
34
34
  ]
35
35
 
@@ -12,10 +12,21 @@ class QolsysTableSmartSocket(QolsysTable):
12
12
  self._uri = "content://com.qolsys.qolsysprovider.SmartSocketsContentProvider/smartsocket"
13
13
  self._table = "smartsocket"
14
14
  self._abort_on_error = False
15
- self._implemented = False
15
+ self._implemented = True
16
16
 
17
17
  self._columns = [
18
18
  "_id",
19
+ "created_by",
20
+ "created_date",
21
+ "last_updated_date",
22
+ "node_id",
23
+ "paired_status",
24
+ "power_usage",
25
+ "status",
26
+ "updated_by",
27
+ "socket_id",
28
+ "socket_name",
29
+ "current_usagevoltage_usage",
19
30
  ]
20
31
 
21
32
  self._create_table()
@@ -40,6 +40,7 @@ class QolsysTableThermostat(QolsysTable):
40
40
  "thermostat_mode_updated_time",
41
41
  "fan_mode_updated_time",
42
42
  "set_point_mode_updated_time",
43
+ "setpoint_capabilites",
43
44
  "target_cool_temp_updated_time",
44
45
  "target_heat_temp_updated_time",
45
46
  "current_temp_updated_time",
@@ -47,6 +48,8 @@ class QolsysTableThermostat(QolsysTable):
47
48
  "endpoint",
48
49
  "paired_status",
49
50
  "configuration_parameter",
51
+ "operating_state",
52
+ "fan_state",
50
53
  ]
51
54
 
52
55
  self._create_table()
@@ -12,10 +12,22 @@ class QolsysTableVirtualDevice(QolsysTable):
12
12
  self._uri = "content://com.qolsys.qolsysprovider.VirtualDeviceContentProvider/virtual_device"
13
13
  self._table = "virtual_device"
14
14
  self._abort_on_error = False
15
- self._implemented = False
15
+ self._implemented = True
16
16
 
17
17
  self._columns = [
18
18
  "_id",
19
+ "version",
20
+ "opr",
21
+ "partition_id",
22
+ "device_id",
23
+ "name",
24
+ "type",
25
+ "func_list",
26
+ "create_time",
27
+ "created_by",
28
+ "update_time",
29
+ "updated_by",
30
+ "device_zone_list",
19
31
  ]
20
32
 
21
33
  self._create_table()
@@ -79,6 +79,9 @@ class QolsysTableZwaveNode(QolsysTable):
79
79
  "sound_switch_info",
80
80
  "long_range_nodeid",
81
81
  "hide_device_info",
82
+ "meter_capabilities",
83
+ "multisensor_capabilities",
84
+ "central_scene_supported",
82
85
  ]
83
86
 
84
87
  self._create_table()
qolsys_controller/enum.py CHANGED
@@ -44,6 +44,7 @@ class PartitionAlarmType(StrEnum):
44
44
  STAY_INSTANT_MOTION = "stayinstantmotion"
45
45
  STAY_DELAY_MOTION = "staydelaymotion"
46
46
  AWAY_DELAY_MOTION = "awaydelaymotion"
47
+ EMPTY = ""
47
48
 
48
49
 
49
50
  class ZoneStatus(StrEnum):
@@ -57,11 +58,13 @@ class ZoneStatus(StrEnum):
57
58
  NORMAL = "Normal"
58
59
  UNREACHABLE = "Unreachable"
59
60
  TAMPERED = "Tampered"
60
- SYNCHONIZING = "Synchonizing"
61
+ SYNCHRONIZING = "Synchronizing"
61
62
  CONNECTED = "connected"
62
63
  DISCONNECTED = "disconnected"
63
64
  FAILURE = "Failure"
64
65
  NOT_NETWORKED = "Not Networked"
66
+ DISARM = "Disarm"
67
+ ARM_AWAY = "Arm-Away"
65
68
 
66
69
 
67
70
  class DeviceCapability(StrEnum):
@@ -130,6 +133,7 @@ class ZoneSensorGroup(StrEnum):
130
133
  STAY_INSTANT_MOTION = "stayinstantmotion"
131
134
  STAY_DELAY_MOTION = "staydelaymotion"
132
135
  AWAY_DELAY_MOTION = "awaydelaymotion"
136
+ WATER = "WaterSensor"
133
137
 
134
138
  # TAKEOVER = "" #TBD
135
139
  # GARAGE_TILT_SAFETY = "" # TBD
@@ -0,0 +1,28 @@
1
+ from enum import Enum, IntEnum
2
+
3
+
4
+ class vdFuncType(IntEnum):
5
+ BINARY_ACTUATOR = 1
6
+ MULTISTATE_ACTUATOR = 2
7
+ LEVEL = 3
8
+ STATUS = 4
9
+ MOMENTARY_ACTION = 5
10
+ MODE_SELECTOR = 6
11
+ EVENT = 7
12
+
13
+
14
+ class vdFuncName(Enum):
15
+ OPEN_CLOSE = "Open/Close"
16
+ LOCK_UNLOCK = "Lock/Unlock"
17
+ ON_OFF = "On/Off"
18
+
19
+
20
+ class vdFuncLocalControl(IntEnum):
21
+ NONE = 0
22
+ STATUS_ONLY = 1
23
+ FULL_CONTROL = 2
24
+
25
+
26
+ class vdFuncState(IntEnum):
27
+ ON = 0
28
+ OFF = 1