qolsys-controller 0.0.16__py3-none-any.whl → 0.0.19__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.
Files changed (50) hide show
  1. qolsys_controller/database/db.py +12 -3
  2. qolsys_controller/database/table.py +44 -16
  3. qolsys_controller/database/table_alarmedsensor.py +3 -16
  4. qolsys_controller/database/table_automation.py +2 -33
  5. qolsys_controller/database/table_country_locale.py +1 -24
  6. qolsys_controller/database/table_dashboard_msgs.py +2 -18
  7. qolsys_controller/database/table_dimmerlight.py +2 -23
  8. qolsys_controller/database/table_doorlock.py +1 -23
  9. qolsys_controller/database/table_eu_event.py +2 -5
  10. qolsys_controller/database/table_heat_map.py +1 -14
  11. qolsys_controller/database/table_history.py +2 -17
  12. qolsys_controller/database/table_iqremotesettings.py +1 -13
  13. qolsys_controller/database/table_iqrouter_network_config.py +1 -6
  14. qolsys_controller/database/table_iqrouter_user_device.py +2 -6
  15. qolsys_controller/database/table_master_slave.py +1 -30
  16. qolsys_controller/database/table_nest_device.py +1 -6
  17. qolsys_controller/database/table_output_rules.py +1 -6
  18. qolsys_controller/database/table_partition.py +1 -11
  19. qolsys_controller/database/table_pgm_outputs.py +2 -6
  20. qolsys_controller/database/table_powerg_device.py +2 -6
  21. qolsys_controller/database/table_qolsyssettings.py +2 -11
  22. qolsys_controller/database/table_scene.py +2 -21
  23. qolsys_controller/database/table_sensor.py +1 -58
  24. qolsys_controller/database/table_shades.py +1 -5
  25. qolsys_controller/database/table_smartsocket.py +1 -5
  26. qolsys_controller/database/table_state.py +1 -13
  27. qolsys_controller/database/table_tcc.py +1 -8
  28. qolsys_controller/database/table_thermostat.py +1 -42
  29. qolsys_controller/database/table_trouble_conditions.py +1 -14
  30. qolsys_controller/database/table_user.py +12 -17
  31. qolsys_controller/database/table_virtual_device.py +1 -5
  32. qolsys_controller/database/table_weather.py +2 -17
  33. qolsys_controller/database/table_zigbee_device.py +1 -6
  34. qolsys_controller/database/table_zwave_association_group.py +1 -20
  35. qolsys_controller/database/table_zwave_history.py +1 -23
  36. qolsys_controller/database/table_zwave_node.py +8 -74
  37. qolsys_controller/database/table_zwave_other.py +1 -6
  38. qolsys_controller/enum_zwave.py +37 -0
  39. qolsys_controller/panel.py +21 -0
  40. qolsys_controller/plugin_remote.py +261 -8
  41. qolsys_controller/scene.py +79 -0
  42. qolsys_controller/settings.py +5 -0
  43. qolsys_controller/state.py +72 -0
  44. qolsys_controller/zone.py +1 -1
  45. qolsys_controller/zwave_thermostat.py +55 -0
  46. {qolsys_controller-0.0.16.dist-info → qolsys_controller-0.0.19.dist-info}/METADATA +2 -1
  47. qolsys_controller-0.0.19.dist-info/RECORD +68 -0
  48. qolsys_controller-0.0.16.dist-info/RECORD +0 -66
  49. {qolsys_controller-0.0.16.dist-info → qolsys_controller-0.0.19.dist-info}/WHEEL +0 -0
  50. {qolsys_controller-0.0.16.dist-info → qolsys_controller-0.0.19.dist-info}/licenses/LICENSE +0 -0
@@ -9,6 +9,7 @@ import uuid
9
9
  import aiomqtt
10
10
 
11
11
  from .enum import PartitionAlarmState, PartitionSystemStatus
12
+ from .enum_zwave import ThermostatFanMode, ThermostatMode
12
13
  from .errors import QolsysMqttError, QolsysSslError
13
14
  from .mdns import QolsysMDNS
14
15
  from .mqtt_command_queue import QolsysMqttCommandQueue
@@ -197,15 +198,15 @@ class QolsysPluginRemote(QolsysPlugin):
197
198
  await self.aiomqtt.subscribe("iq2meid")
198
199
 
199
200
  # Subscribte to MQTT commands response
200
- await self.aiomqtt.subscribe("response_" + self.settings.random_mac, qos=0)
201
+ await self.aiomqtt.subscribe("response_" + self.settings.random_mac, qos=self.settings.mqtt_qos)
201
202
 
202
203
  # Only log mastermeid traffic for debug purposes
203
204
  if self.log_mqtt_mesages:
204
205
  # Subscribe to MQTT commands send to panel by other devices
205
- await self.aiomqtt.subscribe("mastermeid", qos=0)
206
+ await self.aiomqtt.subscribe("mastermeid", qos=self.settings.mqtt_qos)
206
207
 
207
208
  # Subscribe to all topics
208
- #await self.aiomqtt.subscribe("#", qos=0)
209
+ await self.aiomqtt.subscribe("#", qos=self.settings.mqtt_qos)
209
210
 
210
211
  # Start mqtt_listent_task and mqtt_ping_task
211
212
  self._task_manager.cancel(self._mqtt_task_listen_label)
@@ -455,7 +456,7 @@ class QolsysPluginRemote(QolsysPlugin):
455
456
  LOGGER.error("MQTT Client not configured")
456
457
  raise QolsysMqttError
457
458
 
458
- await self.aiomqtt.publish(topic=topic, payload=json.dumps(json_payload), qos=0)
459
+ await self.aiomqtt.publish(topic=topic, payload=json.dumps(json_payload), qos=self.settings.mqtt_qos)
459
460
  return await self._mqtt_command_queue.wait_for_response(request_id)
460
461
 
461
462
  async def command_connect(self) -> dict:
@@ -816,7 +817,6 @@ class QolsysPluginRemote(QolsysPlugin):
816
817
  mqtt_disarm_command = await get_mqtt_disarm_command(silent_disarming)
817
818
  LOGGER.debug("MQTT: Sending disarm command - check_user_code:%s", self.check_user_code_on_disarm)
818
819
 
819
-
820
820
  disarm_command = {
821
821
  "operation_name": mqtt_disarm_command,
822
822
  "userID": user_id,
@@ -851,8 +851,161 @@ class QolsysPluginRemote(QolsysPlugin):
851
851
 
852
852
  return True
853
853
 
854
- async def command_zwave_switch_multi_level(self, node_id: int, level: int) -> None:
854
+ async def command_zwave_thermostat_setpoint_set(self, node_id: int, mode:ThermostatMode, setpoint:float) -> None:
855
+ # Command 67
856
+ LOGGER.debug("MQTT: Sending zwave_thermostat_setpoint_set command: EXPERIMENTAL")
857
+ LOGGER.debug("MQTT: Sending zwave_thermostat_setpoint_set command")
858
+ ipcRequest = [{
859
+ "dataType": "int",
860
+ "dataValue": node_id,
861
+ },
862
+ {
863
+ "dataType": "int",
864
+ "dataValue": 0,
865
+ },
866
+ {
867
+ "dataType": "byteArray",
868
+ "dataValue": [67,1,mode,setpoint],
869
+ },
870
+ {
871
+ "dataType": "int",
872
+ "dataValue": 0,
873
+ },
874
+ {
875
+ "dataType": "int",
876
+ "dataValue": 106,
877
+ },
878
+ {
879
+ "dataType": "byteArray",
880
+ "dataValue": [0],
881
+ },
882
+ ]
883
+
884
+ topic = "mastermeid"
885
+ eventName = "ipcCall"
886
+ ipcServiceName = "qzwaveservice"
887
+ ipcInterfaceName = "android.os.IQZwaveService"
888
+ ipcTransactionID = 47
889
+ requestID = str(uuid.uuid4())
890
+ remoteMacAddress = self.settings.random_mac
891
+ responseTopic = "response_" + self.settings.random_mac
892
+
893
+ payload = {"eventName": eventName,
894
+ "ipcServiceName": ipcServiceName,
895
+ "ipcInterfaceName": ipcInterfaceName,
896
+ "ipcTransactionID": ipcTransactionID,
897
+ "ipcRequest": ipcRequest,
898
+ "requestID": requestID,
899
+ "responseTopic": responseTopic,
900
+ "remoteMacAddress": remoteMacAddress}
901
+
902
+ await self.send_command(topic, payload, requestID)
903
+ LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command")
904
+
905
+ async def command_zwave_thermostat_mode_set(self, node_id: int, mode:ThermostatMode) -> None:
906
+ # Command 64
907
+ LOGGER.debug("MQTT: Sending zwave_thermostat_mode_set command: EXPERIMENTAL")
908
+ LOGGER.debug("MQTT: Sending zwave_thermostat_mode_set command")
909
+ ipcRequest = [{
910
+ "dataType": "int",
911
+ "dataValue": node_id,
912
+ },
913
+ {
914
+ "dataType": "int",
915
+ "dataValue": 0,
916
+ },
917
+ {
918
+ "dataType": "byteArray",
919
+ "dataValue": [64,1,mode],
920
+ },
921
+ {
922
+ "dataType": "int",
923
+ "dataValue": 0,
924
+ },
925
+ {
926
+ "dataType": "int",
927
+ "dataValue": 106,
928
+ },
929
+ {
930
+ "dataType": "byteArray",
931
+ "dataValue": [0],
932
+ },
933
+ ]
934
+
935
+ topic = "mastermeid"
936
+ eventName = "ipcCall"
937
+ ipcServiceName = "qzwaveservice"
938
+ ipcInterfaceName = "android.os.IQZwaveService"
939
+ ipcTransactionID = 47
940
+ requestID = str(uuid.uuid4())
941
+ remoteMacAddress = self.settings.random_mac
942
+ responseTopic = "response_" + self.settings.random_mac
943
+
944
+ payload = {"eventName": eventName,
945
+ "ipcServiceName": ipcServiceName,
946
+ "ipcInterfaceName": ipcInterfaceName,
947
+ "ipcTransactionID": ipcTransactionID,
948
+ "ipcRequest": ipcRequest,
949
+ "requestID": requestID,
950
+ "responseTopic": responseTopic,
951
+ "remoteMacAddress": remoteMacAddress}
952
+
953
+ await self.send_command(topic, payload, requestID)
954
+ LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command")
955
+
956
+ async def command_zwave_thermostat_fan_mode_set(self, node_id: int, fan_mode:ThermostatFanMode) -> None:
957
+ # Command 68
958
+ LOGGER.debug("MQTT: Sending zwave_thermostat_fan_mode_set command: EXPERIMENTAL")
959
+ LOGGER.debug("MQTT: Sending zwave_thermostat_fan_mode_set command")
960
+ ipcRequest = [{
961
+ "dataType": "int",
962
+ "dataValue": node_id,
963
+ },
964
+ {
965
+ "dataType": "int",
966
+ "dataValue": 0,
967
+ },
968
+ {
969
+ "dataType": "byteArray",
970
+ "dataValue": [68,1,fan_mode],
971
+ },
972
+ {
973
+ "dataType": "int",
974
+ "dataValue": 0,
975
+ },
976
+ {
977
+ "dataType": "int",
978
+ "dataValue": 106,
979
+ },
980
+ {
981
+ "dataType": "byteArray",
982
+ "dataValue": [0],
983
+ },
984
+ ]
985
+
986
+ topic = "mastermeid"
987
+ eventName = "ipcCall"
988
+ ipcServiceName = "qzwaveservice"
989
+ ipcInterfaceName = "android.os.IQZwaveService"
990
+ ipcTransactionID = 47
991
+ requestID = str(uuid.uuid4())
992
+ remoteMacAddress = self.settings.random_mac
993
+ responseTopic = "response_" + self.settings.random_mac
994
+
995
+ payload = {"eventName": eventName,
996
+ "ipcServiceName": ipcServiceName,
997
+ "ipcInterfaceName": ipcInterfaceName,
998
+ "ipcTransactionID": ipcTransactionID,
999
+ "ipcRequest": ipcRequest,
1000
+ "requestID": requestID,
1001
+ "responseTopic": responseTopic,
1002
+ "remoteMacAddress": remoteMacAddress}
1003
+
1004
+ await self.send_command(topic, payload, requestID)
1005
+ LOGGER.debug("MQTT: Receiving zwave_thermostat_fan_mode_set command")
855
1006
 
1007
+ async def command_zwave_switch_multi_level(self, node_id: int, level: int) -> None:
1008
+ LOGGER.debug("MQTT: Sending zwave_switch_multi_level command")
856
1009
  ipcRequest = [{
857
1010
  "dataType": "int", # Node ID
858
1011
  "dataValue": node_id,
@@ -862,8 +1015,9 @@ class QolsysPluginRemote(QolsysPlugin):
862
1015
  "dataValue": 0,
863
1016
  },
864
1017
  {
865
- "dataType": "byteArray", # ZWAVE MULTILEVELSWITCH COMMAND
866
- "dataValue": [38, 1, level],
1018
+ # [38,1,level] ZWAVE MULTILEVELSWITCH SET (level 255 to set to previous state)
1019
+ "dataType": "byteArray",
1020
+ "dataValue": [38,1,level],
867
1021
  },
868
1022
  {
869
1023
  "dataType": "int", # ?
@@ -898,6 +1052,62 @@ class QolsysPluginRemote(QolsysPlugin):
898
1052
  "remoteMacAddress": remoteMacAddress}
899
1053
 
900
1054
  await self.send_command(topic, payload, requestID)
1055
+ LOGGER.debug("MQTT: Receiving zwave_switch_multi_level command")
1056
+
1057
+ async def command_zwave_switch_binary(self, node_id: int, status:bool) -> None:
1058
+ LOGGER.debug("MQTT:Sending zwave_switch_binary command")
1059
+
1060
+ level = 0
1061
+ if status:
1062
+ level = 99
1063
+
1064
+ ipcRequest = [{
1065
+ "dataType": "int",
1066
+ "dataValue": node_id,
1067
+ },
1068
+ {
1069
+ "dataType": "int",
1070
+ "dataValue": 0,
1071
+ },
1072
+ {
1073
+ "dataType": "byteArray",
1074
+ "dataValue": [37,1,level],
1075
+ },
1076
+ {
1077
+ "dataType": "int",
1078
+ "dataValue": 0,
1079
+ },
1080
+ {
1081
+ "dataType": "int",
1082
+ "dataValue": 106,
1083
+ },
1084
+ {
1085
+ "dataType": "byteArray",
1086
+ "dataValue": [0],
1087
+ },
1088
+ ]
1089
+
1090
+ topic = "mastermeid"
1091
+ eventName = "ipcCall"
1092
+ ipcServiceName = "qzwaveservice"
1093
+ ipcInterfaceName = "android.os.IQZwaveService"
1094
+ ipcTransactionID = 47
1095
+ requestID = str(uuid.uuid4())
1096
+ remoteMacAddress = self.settings.random_mac
1097
+ responseTopic = "response_" + self.settings.random_mac
1098
+
1099
+ payload = {"eventName": eventName,
1100
+ "ipcServiceName": ipcServiceName,
1101
+ "ipcInterfaceName": ipcInterfaceName,
1102
+ "ipcTransactionID": ipcTransactionID,
1103
+ "ipcRequest": ipcRequest,
1104
+ "requestID": requestID,
1105
+ "responseTopic": responseTopic,
1106
+ "remoteMacAddress": remoteMacAddress}
1107
+
1108
+ await self.send_command(topic, payload, requestID)
1109
+ LOGGER.debug("MQTT:Receiving zwave_switch_binary command")
1110
+
901
1111
 
902
1112
  async def command_arm(self, partition_id: str, arming_type: str, user_code: str = "", exit_sounds: bool = False,
903
1113
  instant_arm: bool = False) -> bool:
@@ -979,3 +1189,46 @@ class QolsysPluginRemote(QolsysPlugin):
979
1189
  await self.send_command(topic, payload, requestID)
980
1190
 
981
1191
  return True
1192
+
1193
+ async def command_execute_scene(self,scene_id:str) -> bool:
1194
+ LOGGER.debug("MQTT: Sending execute_scene command")
1195
+
1196
+ scene = self.state.scene(scene_id)
1197
+ if not scene:
1198
+ LOGGER.debug("MQTT: command_execute_scene Erro - Unknow Scene: %s", scene_id)
1199
+ return False
1200
+
1201
+ scene_command = {
1202
+ "operation_name": "execute_scene",
1203
+ "scene_id": scene.scene_id,
1204
+ "operation_source": 1,
1205
+ "macAddress": self.settings.random_mac,
1206
+ }
1207
+
1208
+ topic = "mastermeid"
1209
+ eventName = "ipcCall"
1210
+ ipcServiceName = "qinternalservice"
1211
+ ipcInterfaceName = "android.os.IQInternalService"
1212
+ ipcTransactionID = 7
1213
+ requestID = str(uuid.uuid4())
1214
+ remoteMacAddress = self.settings.random_mac
1215
+ responseTopic = "response_" + self.settings.random_mac
1216
+
1217
+ payload = {
1218
+ "eventName": eventName,
1219
+ "ipcServiceName": ipcServiceName,
1220
+ "ipcInterfaceName": ipcInterfaceName,
1221
+ "ipcTransactionID": ipcTransactionID,
1222
+ "ipcRequest": [{
1223
+ "dataType": "string",
1224
+ "dataValue": json.dumps(scene_command),
1225
+ }],
1226
+ "requestID": requestID,
1227
+ "responseTopic": responseTopic,
1228
+ "remoteMacAddress": remoteMacAddress,
1229
+ }
1230
+
1231
+ await self.send_command(topic, payload, requestID)
1232
+ LOGGER.debug("MQTT: Receiving execute_scene command")
1233
+
1234
+ return False
@@ -0,0 +1,79 @@
1
+ import logging
2
+
3
+ from .observable import QolsysObservable
4
+
5
+ LOGGER = logging.getLogger(__name__)
6
+
7
+
8
+ class QolsysScene(QolsysObservable):
9
+
10
+ def __init__(self, data: dict) -> None:
11
+ super().__init__()
12
+
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:
19
+
20
+ scene_id_update = data.get("scene_id", "")
21
+ 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)
23
+ return
24
+
25
+ self.start_batch_update()
26
+
27
+ # Update name
28
+ if "name" in data:
29
+ self.sensorname = data.get("name")
30
+
31
+ if "color" in data:
32
+ self.color = data.get("color")
33
+
34
+ if "icon" in data:
35
+ self.icon = data.get("icon")
36
+
37
+ self.end_batch_update()
38
+
39
+ @property
40
+ def scene_id(self) -> str:
41
+ return self._scene_id
42
+
43
+ @property
44
+ def name(self) -> str:
45
+ return self._name
46
+
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
+ @name.setter
56
+ def name(self, value: str) -> None:
57
+ if self._name != value:
58
+ self._name = value
59
+ self.notify()
60
+
61
+ @icon.setter
62
+ def icon(self, value: str) -> None:
63
+ if self._icon != value:
64
+ self._icon = value
65
+ self.notify()
66
+
67
+ @color.setter
68
+ def color(self, value: str) -> None:
69
+ if self._color != value:
70
+ self._color = value
71
+ 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
+ }
@@ -25,6 +25,7 @@ class QolsysSettings:
25
25
  # MQTT
26
26
  self._mqtt_timeout: int = 30
27
27
  self._mqtt_ping: int = 600
28
+ self._mqtt_qos:int = 0
28
29
  self._mqtt_remote_client_id = ""
29
30
 
30
31
  @property
@@ -94,6 +95,10 @@ class QolsysSettings:
94
95
  def mqtt_ping(self, ping:int) -> None:
95
96
  self._mqtt_ping = ping
96
97
 
98
+ @property
99
+ def mqtt_qos(self) -> int:
100
+ return self._mqtt_qos
101
+
97
102
  @property
98
103
  def mqtt_remote_client_id(self) -> str:
99
104
  return self._mqtt_remote_client_id
@@ -2,6 +2,7 @@ import logging
2
2
 
3
3
  from .observable import QolsysObservable
4
4
  from .partition import QolsysPartition
5
+ from .scene import QolsysScene
5
6
  from .zone import QolsysZone
6
7
  from .zwave_device import QolsysZWaveDevice
7
8
  from .zwave_dimmer import QolsysDimmer
@@ -20,10 +21,12 @@ class QolsysState(QolsysObservable):
20
21
  self._partitions = []
21
22
  self._zones = []
22
23
  self._zwave_devices = []
24
+ self._scenes = []
23
25
 
24
26
  self._state_partition_observer = QolsysObservable()
25
27
  self._state_zone_observer = QolsysObservable()
26
28
  self._state_zwave_observer = QolsysObservable()
29
+ self._state_scene_observer = QolsysObservable()
27
30
 
28
31
  @property
29
32
  def partitions(self) -> list[QolsysPartition]:
@@ -37,6 +40,10 @@ class QolsysState(QolsysObservable):
37
40
  def zones(self) -> list[QolsysZone]:
38
41
  return self._zones
39
42
 
43
+ @property
44
+ def scenes(self) -> list[QolsysScene]:
45
+ return self._scenes
46
+
40
47
  @property
41
48
  def zwave_dimmers(self) -> list[QolsysDimmer]:
42
49
  dimmers = []
@@ -76,6 +83,10 @@ class QolsysState(QolsysObservable):
76
83
  def state_zwave_observer(self) -> QolsysObservable:
77
84
  return self._state_zwave_observer
78
85
 
86
+ @property
87
+ def state_scene_observer(self) -> QolsysObservable:
88
+ return self._state_scene_observer
89
+
79
90
  def partition(self, partition_id: str) -> QolsysPartition:
80
91
  for partition in self.partitions:
81
92
  if partition.id == partition_id:
@@ -103,6 +114,32 @@ class QolsysState(QolsysObservable):
103
114
  self.partitions.remove(partition)
104
115
  self.state_partition_observer.notify()
105
116
 
117
+ def scene(self, scene_id: str) -> QolsysScene:
118
+ for scene in self.scenes:
119
+ if scene.scene_id == scene_id:
120
+ return scene
121
+
122
+ return None
123
+
124
+ def scene_add(self, new_scene: QolsysScene) -> None:
125
+ for scene in self.scenes:
126
+ if new_scene.scene_id == scene.scene_id:
127
+ LOGGER.debug("Adding Scene to State, Scene%s (%s) - Allready in Scene List", new_scene.scene_id, scene.name )
128
+ return
129
+
130
+ self.scenes.append(new_scene)
131
+ self.state_scene_observer.notify()
132
+
133
+ def scene_delete(self, scene_id: str) -> None:
134
+ scene = self.scene(scene_id)
135
+
136
+ if scene is None:
137
+ LOGGER.debug("Deleting Scene from State, Scene%s not found", scene_id)
138
+ return
139
+
140
+ self.scenes.remove(scene)
141
+ self.state_scene_observer.notify()
142
+
106
143
  def zone(self, zone_id: str) -> QolsysZone:
107
144
  for zone in self.zones:
108
145
  if zone.zone_id == zone_id:
@@ -212,6 +249,36 @@ class QolsysState(QolsysObservable):
212
249
  LOGGER.debug("sync_data - delete ZWave%s", state_zwave.none_id)
213
250
  self.zwave_delete(int(state_zwave.node_id))
214
251
 
252
+ def sync_scenes_data(self, db_scenes: list[QolsysScene]) -> None:
253
+ db_scene_list = []
254
+ for db_scene in db_scenes:
255
+ db_scene_list.append(db_scene.scene_id)
256
+
257
+ state_scene_list = []
258
+ for state_scene in self.scenes:
259
+ state_scene_list.append(state_scene.scene_id)
260
+
261
+ # Update existing scenes
262
+ for state_scene in self.scenes:
263
+ if state_scene.scene_id in db_scene_list:
264
+ for db_scene in db_scenes:
265
+ if state_scene.scene_id == db_scene.scene_id:
266
+ LOGGER.debug("sync_data - update Scene%s", state_scene.scene_id)
267
+ state_scene.update(db_scene.to_dict())
268
+ break
269
+
270
+ # Delete scenes
271
+ for state_scene in self.scenes:
272
+ if state_scene.scene_id not in db_scene_list:
273
+ LOGGER.debug("sync_data - delete Scene%s", state_scene.scene_id)
274
+ self.scene_delete(int(state_scene.scene_id))
275
+
276
+ # Add new scene
277
+ for db_scene in db_scenes:
278
+ if db_scene.scene_id not in state_scene_list:
279
+ LOGGER.debug("sync_data - add Scene%s", db_scene.scene_id)
280
+ self.scene_add(db_scene)
281
+
215
282
  def sync_zones_data(self, db_zones: list[QolsysZone]) -> None: # noqa: C901
216
283
  db_zone_list = []
217
284
  for db_zone in db_zones:
@@ -338,3 +405,8 @@ class QolsysState(QolsysObservable):
338
405
  LOGGER.debug("Generic%s (%s) - battery_level: %s", zid, name, zwave.node_battery_level)
339
406
  LOGGER.debug("Generic%s (%s) - battery_level_vale: %s", zid, name, zwave.node_battery_level_value)
340
407
  continue
408
+
409
+ for scene in self.scenes:
410
+ sid = scene.scene_id
411
+ name = scene.name
412
+ LOGGER.debug("Scene%s (%s)",sid, name)
qolsys_controller/zone.py CHANGED
@@ -245,7 +245,7 @@ class QolsysZone(QolsysObservable):
245
245
  @time.setter
246
246
  def time(self, value: str) -> None:
247
247
  if self._time != value:
248
- LOGGER.debug("Zone%s (%s) - time: %s", self.zone_id, self.sensorname, value)
248
+ #LOGGER.debug("Zone%s (%s) - time: %s", self.zone_id, self.sensorname, value)
249
249
  self._time = value
250
250
  self.notify()
251
251
 
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
 
3
+ from .enum_zwave import ThermostatFanMode, ThermostatMode
3
4
  from .zwave_device import QolsysZWaveDevice
4
5
 
5
6
  LOGGER = logging.getLogger(__name__)
@@ -249,3 +250,57 @@ class QolsysThermostat(QolsysZWaveDevice):
249
250
  "endpoint": self._thermostat_endpoint,
250
251
  "configuration_parameter": self._thermostat_configuration_parameter,
251
252
  }
253
+
254
+ def thermostat_mode(self) -> ThermostatMode:
255
+ thermostat_mode = int(self._thermostat_mode)
256
+ for mode in ThermostatMode:
257
+ if thermostat_mode == mode:
258
+ return mode
259
+ return None
260
+
261
+ def available_thermostat_mode(self) -> list[ThermostatMode]:
262
+
263
+ int_list = [int(x) for x in self._thermostat_mode_bitmask.split(",")]
264
+ byte_array = bytes(int_list)
265
+ bitmask = int.from_bytes(byte_array, byteorder="little")
266
+
267
+ mode_array = []
268
+ for mode in ThermostatMode:
269
+ if mode.value & bitmask:
270
+ mode_array.append(mode)
271
+
272
+ return mode_array
273
+
274
+ def thermostat_fan_mode(self) -> ThermostatFanMode:
275
+ thermostat_fan_mode = int(self._thermostat_fan_mode)
276
+ for mode in ThermostatMode:
277
+ if thermostat_fan_mode == mode:
278
+ return mode
279
+ return None
280
+
281
+ def available_thermostat_fan_mode(self) -> list[ThermostatFanMode]:
282
+
283
+ int_list = [int(x) for x in self._thermostat_fan_mode_bitmask.split(",")]
284
+ byte_array = bytes(int_list)
285
+ bitmask = int.from_bytes(byte_array, byteorder="little")
286
+
287
+ fan_mode_array = []
288
+ for mode in ThermostatFanMode:
289
+ if mode.value & bitmask:
290
+ fan_mode_array.append(mode)
291
+
292
+ return fan_mode_array
293
+
294
+ def available_thermostat_set_point_mode(self) -> list[ThermostatMode]:
295
+
296
+ int_list = [int(x) for x in self._thermostat_set_point_mode_bitmask.split(",")]
297
+ byte_array = bytes(int_list)
298
+ bitmask = int.from_bytes(byte_array, byteorder="little")
299
+
300
+ set_point_mode_array = []
301
+ for mode in ThermostatMode:
302
+ if mode.value & bitmask:
303
+ set_point_mode_array.append(mode)
304
+
305
+ return set_point_mode_array
306
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qolsys-controller
3
- Version: 0.0.16
3
+ Version: 0.0.19
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
@@ -35,6 +35,7 @@ A Python module that emulates a virtual IQ Remote device, enabling full **local
35
35
  | **Partitions** | Arming status | ✅ |
36
36
  | | Set Exit sounds | ✅ |
37
37
  | | Home Instant arming | ✅ |
38
+ | | Home Silent Disarm | ✅ |
38
39
  | | Alarm state and type | ✅ |
39
40
  | | Disarm pictures | 🛠️ WIP |
40
41
  |---|---|---|