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.
- qolsys_controller/database/db.py +12 -3
- qolsys_controller/database/table.py +44 -16
- qolsys_controller/database/table_alarmedsensor.py +3 -16
- qolsys_controller/database/table_automation.py +2 -33
- qolsys_controller/database/table_country_locale.py +1 -24
- qolsys_controller/database/table_dashboard_msgs.py +2 -18
- qolsys_controller/database/table_dimmerlight.py +2 -23
- qolsys_controller/database/table_doorlock.py +1 -23
- qolsys_controller/database/table_eu_event.py +2 -5
- qolsys_controller/database/table_heat_map.py +1 -14
- qolsys_controller/database/table_history.py +2 -17
- qolsys_controller/database/table_iqremotesettings.py +1 -13
- qolsys_controller/database/table_iqrouter_network_config.py +1 -6
- qolsys_controller/database/table_iqrouter_user_device.py +2 -6
- qolsys_controller/database/table_master_slave.py +1 -30
- qolsys_controller/database/table_nest_device.py +1 -6
- qolsys_controller/database/table_output_rules.py +1 -6
- qolsys_controller/database/table_partition.py +1 -11
- qolsys_controller/database/table_pgm_outputs.py +2 -6
- qolsys_controller/database/table_powerg_device.py +2 -6
- qolsys_controller/database/table_qolsyssettings.py +2 -11
- qolsys_controller/database/table_scene.py +2 -21
- qolsys_controller/database/table_sensor.py +1 -58
- qolsys_controller/database/table_shades.py +1 -5
- qolsys_controller/database/table_smartsocket.py +1 -5
- qolsys_controller/database/table_state.py +1 -13
- qolsys_controller/database/table_tcc.py +1 -8
- qolsys_controller/database/table_thermostat.py +1 -42
- qolsys_controller/database/table_trouble_conditions.py +1 -14
- qolsys_controller/database/table_user.py +12 -17
- qolsys_controller/database/table_virtual_device.py +1 -5
- qolsys_controller/database/table_weather.py +2 -17
- qolsys_controller/database/table_zigbee_device.py +1 -6
- qolsys_controller/database/table_zwave_association_group.py +1 -20
- qolsys_controller/database/table_zwave_history.py +1 -23
- qolsys_controller/database/table_zwave_node.py +8 -74
- qolsys_controller/database/table_zwave_other.py +1 -6
- qolsys_controller/enum_zwave.py +37 -0
- qolsys_controller/panel.py +21 -0
- qolsys_controller/plugin_remote.py +261 -8
- qolsys_controller/scene.py +79 -0
- qolsys_controller/settings.py +5 -0
- qolsys_controller/state.py +72 -0
- qolsys_controller/zone.py +1 -1
- qolsys_controller/zwave_thermostat.py +55 -0
- {qolsys_controller-0.0.16.dist-info → qolsys_controller-0.0.19.dist-info}/METADATA +2 -1
- qolsys_controller-0.0.19.dist-info/RECORD +68 -0
- qolsys_controller-0.0.16.dist-info/RECORD +0 -66
- {qolsys_controller-0.0.16.dist-info → qolsys_controller-0.0.19.dist-info}/WHEEL +0 -0
- {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=
|
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=
|
206
|
+
await self.aiomqtt.subscribe("mastermeid", qos=self.settings.mqtt_qos)
|
206
207
|
|
207
208
|
# Subscribe to all topics
|
208
|
-
|
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=
|
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
|
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
|
-
|
866
|
-
"
|
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
|
+
}
|
qolsys_controller/settings.py
CHANGED
@@ -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
|
qolsys_controller/state.py
CHANGED
@@ -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.
|
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
|
|---|---|---|
|