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.
- qolsys_controller/adc_device.py +202 -0
- qolsys_controller/adc_service.py +139 -0
- qolsys_controller/adc_service_garagedoor.py +35 -0
- qolsys_controller/controller.py +245 -34
- qolsys_controller/database/db.py +60 -0
- qolsys_controller/database/table.py +1 -0
- qolsys_controller/database/table_alarmedsensor.py +2 -0
- qolsys_controller/database/table_history.py +2 -2
- qolsys_controller/database/table_smartsocket.py +12 -1
- qolsys_controller/database/table_thermostat.py +3 -0
- qolsys_controller/database/table_virtual_device.py +13 -1
- qolsys_controller/database/table_zwave_node.py +3 -0
- qolsys_controller/enum.py +5 -1
- qolsys_controller/enum_adc.py +28 -0
- qolsys_controller/enum_zwave.py +158 -29
- qolsys_controller/errors.py +5 -0
- qolsys_controller/mqtt_command.py +6 -0
- qolsys_controller/panel.py +109 -5
- qolsys_controller/partition.py +22 -2
- qolsys_controller/state.py +163 -1
- qolsys_controller/task_manager.py +4 -3
- qolsys_controller/zone.py +2 -1
- qolsys_controller/zwave_device.py +132 -4
- qolsys_controller/zwave_dimmer.py +3 -0
- qolsys_controller/zwave_energy_clamp.py +15 -0
- qolsys_controller/zwave_garagedoor.py +3 -0
- qolsys_controller/zwave_generic.py +3 -0
- qolsys_controller/zwave_lock.py +4 -0
- qolsys_controller/zwave_outlet.py +3 -0
- qolsys_controller/zwave_service_meter.py +192 -0
- qolsys_controller/zwave_service_multilevelsensor.py +119 -0
- qolsys_controller/zwave_thermometer.py +21 -0
- qolsys_controller/zwave_thermostat.py +150 -38
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/METADATA +1 -1
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/RECORD +37 -29
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/WHEEL +0 -0
- {qolsys_controller-0.0.62.dist-info → qolsys_controller-0.0.87.dist-info}/licenses/LICENSE +0 -0
qolsys_controller/controller.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
692
|
-
# Do local user code verification to arm
|
|
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
|
-
|
|
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, [
|
|
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, [
|
|
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, [
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
838
|
-
if not
|
|
839
|
-
LOGGER.error("
|
|
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
|
-
|
|
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, [
|
|
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
|
qolsys_controller/database/db.py
CHANGED
|
@@ -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()
|
|
@@ -27,9 +27,9 @@ class QolsysTableHistory(QolsysTable):
|
|
|
27
27
|
"feature1",
|
|
28
28
|
"feature2",
|
|
29
29
|
"device_id",
|
|
30
|
-
# "
|
|
30
|
+
# "history_bulk_insert",
|
|
31
31
|
"Partition",
|
|
32
|
-
# "
|
|
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 =
|
|
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 =
|
|
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()
|
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
|
-
|
|
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
|