qolsys-controller 0.0.81__tar.gz → 0.3.2__tar.gz
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-0.3.2/.github/dependabot.yml +11 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/PKG-INFO +1 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/pyproject.toml +1 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/adc_service_garagedoor.py +1 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/controller.py +137 -93
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/db.py +8 -8
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_sensor.py +2 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_smartsocket.py +12 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_user.py +1 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/enum.py +38 -25
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/enum_zwave.py +65 -23
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/mqtt_command.py +2 -1
- qolsys_controller-0.3.2/qolsys_controller/observable_v2.py +14 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/panel.py +47 -18
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/state.py +105 -24
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zone.py +74 -12
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_device.py +82 -8
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_dimmer.py +6 -10
- qolsys_controller-0.3.2/qolsys_controller/zwave_energy_clamp.py +19 -0
- qolsys_controller-0.3.2/qolsys_controller/zwave_extenal_siren.py +86 -0
- qolsys_controller-0.3.2/qolsys_controller/zwave_garagedoor.py +20 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_generic.py +6 -2
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_lock.py +15 -12
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_service_meter.py +1 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_service_multilevelsensor.py +9 -0
- qolsys_controller-0.3.2/qolsys_controller/zwave_smart_socket.py +20 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_thermometer.py +6 -2
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/zwave_thermostat.py +63 -9
- qolsys_controller-0.3.2/qolsys_controller/zwave_water_valve.py +83 -0
- qolsys_controller-0.3.2/requirements.txt +8 -0
- qolsys_controller-0.0.81/qolsys_controller/zwave_energy_clamp.py +0 -15
- qolsys_controller-0.0.81/qolsys_controller/zwave_garagedoor.py +0 -13
- qolsys_controller-0.0.81/qolsys_controller/zwave_outlet.py +0 -13
- qolsys_controller-0.0.81/requirements.txt +0 -8
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/.github/workflows/build.yml +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/.github/workflows/publish.yml +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/.gitignore +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/Info_mqtt.md +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/LICENSE +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/README.md +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/bin/qolsys.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/example.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/info_pairing.md +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/info_qolsys.md +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/mypy.ini +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/__init__.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/adc_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/adc_service.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_alarmedsensor.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_automation.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_country_locale.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_dashboard_msgs.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_dimmerlight.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_doorlock.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_eu_event.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_heat_map.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_history.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_iqremotesettings.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_iqrouter_network_config.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_iqrouter_user_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_master_slave.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_nest_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_output_rules.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_partition.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_pgm_outputs.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_powerg_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_qolsyssettings.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_scene.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_sensor_group.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_shades.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_state.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_tcc.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_thermostat.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_trouble_conditions.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_virtual_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_weather.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_zigbee_device.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_zwave_association_group.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_zwave_history.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_zwave_node.py +1 -1
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_zwave_other.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/enum_adc.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/errors.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/mdns.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/mqtt_command_queue.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/observable.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/partition.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/pki.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/scene.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/settings.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/task_manager.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/users.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/utils_mqtt.py +0 -0
- {qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/weather.py +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "pip" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qolsys-controller
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.2
|
|
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
|
|
@@ -21,7 +21,7 @@ from qolsys_controller.mqtt_command import (
|
|
|
21
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,
|
|
24
|
+
from .enum_zwave import ThermostatFanMode, ThermostatMode, ThermostatSetpointMode, ZwaveCommandClass
|
|
25
25
|
from .errors import QolsysMqttError, QolsysSslError, QolsysUserCodeError
|
|
26
26
|
from .mdns import QolsysMDNS
|
|
27
27
|
from .mqtt_command_queue import QolsysMqttCommandQueue
|
|
@@ -61,6 +61,7 @@ class QolsysController:
|
|
|
61
61
|
self._mqtt_task_listen_label: str = "mqtt_task_listen"
|
|
62
62
|
self._mqtt_task_connect_label: str = "mqtt_task_connect"
|
|
63
63
|
self._mqtt_task_ping_label: str = "mqtt_task_ping"
|
|
64
|
+
self._mqtt_task_zwave_meter_update_label: str = "mqtt_task_zwave_meter_update"
|
|
64
65
|
|
|
65
66
|
@property
|
|
66
67
|
def state(self) -> QolsysState:
|
|
@@ -152,32 +153,43 @@ class QolsysController:
|
|
|
152
153
|
self._task_manager.cancel(self._mqtt_task_listen_label)
|
|
153
154
|
self._task_manager.cancel(self._mqtt_task_ping_label)
|
|
154
155
|
self._task_manager.cancel(self._mqtt_task_config_label)
|
|
156
|
+
self._task_manager.cancel(self._mqtt_task_zwave_meter_update_label)
|
|
155
157
|
|
|
156
158
|
self.connected = False
|
|
157
159
|
self.connected_observer.notify()
|
|
158
160
|
|
|
159
161
|
async def mqtt_connect_task(self, reconnect: bool, run_forever: bool) -> None:
|
|
160
|
-
# Configure TLS
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
# Configure TLS context for MQTT connection
|
|
163
|
+
def create_tls_context(self: QolsysController) -> ssl.SSLContext:
|
|
164
|
+
ctx = ssl.create_default_context(
|
|
165
|
+
purpose=ssl.Purpose.SERVER_AUTH,
|
|
166
|
+
cafile=str(self._pki.qolsys_cer_file_path),
|
|
167
|
+
)
|
|
168
|
+
ctx.set_ciphers("DEFAULT:@SECLEVEL=0")
|
|
169
|
+
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
170
|
+
ctx.check_hostname = False
|
|
171
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
172
|
+
ctx.load_cert_chain(
|
|
173
|
+
certfile=str(self._pki.secure_file_path),
|
|
174
|
+
keyfile=str(self._pki.key_file_path),
|
|
175
|
+
)
|
|
176
|
+
return ctx
|
|
177
|
+
|
|
178
|
+
loop = asyncio.get_running_loop()
|
|
179
|
+
ctx = await loop.run_in_executor(None, create_tls_context, self)
|
|
169
180
|
|
|
170
181
|
LOGGER.debug("MQTT: Connecting ...")
|
|
171
182
|
|
|
172
183
|
self._task_manager.cancel(self._mqtt_task_listen_label)
|
|
173
184
|
self._task_manager.cancel(self._mqtt_task_ping_label)
|
|
185
|
+
self._task_manager.cancel(self._mqtt_task_zwave_meter_update_label)
|
|
174
186
|
|
|
175
187
|
while True:
|
|
176
188
|
try:
|
|
177
189
|
self.aiomqtt = aiomqtt.Client(
|
|
178
190
|
hostname=self.settings.panel_ip,
|
|
179
191
|
port=8883,
|
|
180
|
-
|
|
192
|
+
tls_context=ctx,
|
|
181
193
|
tls_insecure=True,
|
|
182
194
|
clean_session=True,
|
|
183
195
|
timeout=self.settings.mqtt_timeout,
|
|
@@ -214,11 +226,14 @@ class QolsysController:
|
|
|
214
226
|
|
|
215
227
|
response_database = await self.command_sync_database()
|
|
216
228
|
LOGGER.debug("MQTT: Updating State from syncdatabase")
|
|
217
|
-
self.panel.load_database(response_database.get("fulldbdata"))
|
|
229
|
+
await self.panel.load_database(response_database.get("fulldbdata"))
|
|
218
230
|
self.panel.dump()
|
|
219
231
|
self.state.dump()
|
|
220
232
|
|
|
221
233
|
self.connected = True
|
|
234
|
+
|
|
235
|
+
self._task_manager.run(self.mqtt_zwave_meter_update(), self._mqtt_task_zwave_meter_update_label)
|
|
236
|
+
|
|
222
237
|
self.connected_observer.notify()
|
|
223
238
|
|
|
224
239
|
if not run_forever:
|
|
@@ -259,6 +274,19 @@ class QolsysController:
|
|
|
259
274
|
|
|
260
275
|
await asyncio.sleep(self.settings.mqtt_ping)
|
|
261
276
|
|
|
277
|
+
async def mqtt_zwave_meter_update(self) -> None:
|
|
278
|
+
while True:
|
|
279
|
+
if self.aiomqtt is not None and self.connected:
|
|
280
|
+
LOGGER.debug("Updating Z-Wave Energy Clamps")
|
|
281
|
+
with contextlib.suppress(aiomqtt.MqttError):
|
|
282
|
+
for energy_clamp in self.state.zwave_meters:
|
|
283
|
+
for meter in energy_clamp.meter_endpoints:
|
|
284
|
+
zwave_command = MQTTCommand_ZWave(
|
|
285
|
+
self, energy_clamp.node_id, meter.endpoint, [ZwaveCommandClass.Meter, 0x01]
|
|
286
|
+
)
|
|
287
|
+
await zwave_command.send_command()
|
|
288
|
+
await asyncio.sleep(60)
|
|
289
|
+
|
|
262
290
|
async def mqtt_listen_task(self) -> None:
|
|
263
291
|
try:
|
|
264
292
|
async for message in self.aiomqtt.messages: # type: ignore[union-attr]
|
|
@@ -748,6 +776,70 @@ class QolsysController:
|
|
|
748
776
|
LOGGER.debug("MQTT: Receiving execute_scene command")
|
|
749
777
|
return response
|
|
750
778
|
|
|
779
|
+
async def command_panel_virtual_device_action(self, device_id: str, state: int) -> dict[str, Any] | None:
|
|
780
|
+
LOGGER.debug("MQTT: Sending virtual_device command")
|
|
781
|
+
|
|
782
|
+
garage_door = self.state.adc_device(device_id)
|
|
783
|
+
if not garage_door:
|
|
784
|
+
LOGGER.error("Invalid Virtual Garage Door Id: %s", device_id)
|
|
785
|
+
|
|
786
|
+
device_list = {
|
|
787
|
+
"virtualDeviceList": [
|
|
788
|
+
{
|
|
789
|
+
"virtualDeviceId": int(device_id),
|
|
790
|
+
"virtualDeviceFunctionList": [
|
|
791
|
+
{
|
|
792
|
+
"vdFuncId": 1,
|
|
793
|
+
"vdFuncState": state,
|
|
794
|
+
"vdFuncBackendTimestamp": int(time.time() * 1000),
|
|
795
|
+
"vdFuncType": 1,
|
|
796
|
+
}
|
|
797
|
+
],
|
|
798
|
+
}
|
|
799
|
+
]
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
virtual_command = {
|
|
803
|
+
"operation_name": "send_virtual_device_description",
|
|
804
|
+
"virtual_device_operation": 4,
|
|
805
|
+
"virtual_device_description": json.dumps(device_list),
|
|
806
|
+
"operation_source": 0,
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
virtual_command2 = {
|
|
810
|
+
"operation_name": "send_virtual_device_description",
|
|
811
|
+
"virtual_device_operation": 5,
|
|
812
|
+
"virtual_device_description": json.dumps(device_list),
|
|
813
|
+
"operation_source": 0,
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
ipc_request = [
|
|
817
|
+
{
|
|
818
|
+
"dataType": "string",
|
|
819
|
+
"dataValue": json.dumps(virtual_command),
|
|
820
|
+
}
|
|
821
|
+
]
|
|
822
|
+
|
|
823
|
+
ipc_request2 = [
|
|
824
|
+
{
|
|
825
|
+
"dataType": "string",
|
|
826
|
+
"dataValue": json.dumps(virtual_command2),
|
|
827
|
+
}
|
|
828
|
+
]
|
|
829
|
+
|
|
830
|
+
LOGGER.debug("virtual command: %s", virtual_command)
|
|
831
|
+
command = MQTTCommand_Panel(self)
|
|
832
|
+
command.append_ipc_request(ipc_request)
|
|
833
|
+
response = await command.send_command()
|
|
834
|
+
LOGGER.debug("MQTT: Receiving virtual_device command: %s", response)
|
|
835
|
+
|
|
836
|
+
LOGGER.debug("virtual command: %s", virtual_command2)
|
|
837
|
+
command2 = MQTTCommand_Panel(self)
|
|
838
|
+
command2.append_ipc_request(ipc_request2)
|
|
839
|
+
response2 = await command2.send_command()
|
|
840
|
+
LOGGER.debug("MQTT: Receiving virtual_device command: %s", response2)
|
|
841
|
+
return response
|
|
842
|
+
|
|
751
843
|
async def command_panel_trigger_police(self, partition_id: str, silent: bool) -> dict[str, Any] | None:
|
|
752
844
|
LOGGER.debug("MQTT: Sending panel_trigger_police command")
|
|
753
845
|
|
|
@@ -838,28 +930,28 @@ class QolsysController:
|
|
|
838
930
|
LOGGER.debug("MQTT: Receiving panel_trigger_fire command")
|
|
839
931
|
return response
|
|
840
932
|
|
|
841
|
-
async def command_zwave_switch_binary_set(self, node_id: str, status: bool) -> dict[str, Any] | None:
|
|
842
|
-
LOGGER.debug("MQTT: Sending
|
|
933
|
+
async def command_zwave_switch_binary_set(self, node_id: str, endpoint: str, status: bool) -> dict[str, Any] | None:
|
|
934
|
+
LOGGER.debug("MQTT: Sending set_zwave_switch_binar#y command - Node(%s) - Status(%s)", node_id, status)
|
|
843
935
|
zwave_node = self.state.zwave_device(node_id)
|
|
844
936
|
|
|
845
937
|
if not zwave_node:
|
|
846
938
|
LOGGER.error("switch_binary_set - Invalid node_id %s", node_id)
|
|
847
939
|
return None
|
|
848
940
|
|
|
849
|
-
if
|
|
850
|
-
LOGGER.error("
|
|
941
|
+
if ZwaveCommandClass.SwitchBinary not in zwave_node.command_class_list:
|
|
942
|
+
LOGGER.error("Z-Wave node does not support switch_binary_set")
|
|
851
943
|
return None
|
|
852
944
|
|
|
853
945
|
level = 0
|
|
854
946
|
if status:
|
|
855
947
|
level = 255
|
|
856
948
|
|
|
857
|
-
command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.SwitchBinary, 1, level])
|
|
949
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, [ZwaveCommandClass.SwitchBinary, 1, level])
|
|
858
950
|
response = await command.send_command()
|
|
859
951
|
LOGGER.debug("MQTT: Receiving set_zwave_switch_binary command")
|
|
860
952
|
return response
|
|
861
953
|
|
|
862
|
-
async def command_zwave_switch_multilevel_set(self, node_id: str, level: int) -> dict[str, Any] | None:
|
|
954
|
+
async def command_zwave_switch_multilevel_set(self, node_id: str, endpoint: str, level: int) -> dict[str, Any] | None:
|
|
863
955
|
LOGGER.debug("MQTT: Sending switch_multilevel_set command - Node(%s) - Level(%s)", node_id, level)
|
|
864
956
|
|
|
865
957
|
zwave_node = self.state.zwave_device(node_id)
|
|
@@ -867,16 +959,16 @@ class QolsysController:
|
|
|
867
959
|
LOGGER.error("switch_multilevel_set - Invalid node_id %s", node_id)
|
|
868
960
|
return None
|
|
869
961
|
|
|
870
|
-
if
|
|
871
|
-
LOGGER.error("
|
|
962
|
+
if ZwaveCommandClass.SwitchMultilevel not in zwave_node.command_class_list:
|
|
963
|
+
LOGGER.error("Z-Wave node does not support switch_multilevel_set")
|
|
872
964
|
return None
|
|
873
965
|
|
|
874
|
-
command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.SwitchMultilevel, 1, level])
|
|
966
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, [ZwaveCommandClass.SwitchMultilevel, 1, level])
|
|
875
967
|
response = await command.send_command()
|
|
876
968
|
LOGGER.debug("MQTT: Receiving set_zwave_multilevel_switch command")
|
|
877
969
|
return response
|
|
878
970
|
|
|
879
|
-
async def command_zwave_doorlock_set(self, node_id: str, locked: bool) -> dict[str, Any] | None:
|
|
971
|
+
async def command_zwave_doorlock_set(self, node_id: str, endpoint: str, locked: bool) -> dict[str, Any] | None:
|
|
880
972
|
LOGGER.debug("MQTT: Sending zwave_doorlock_set command - Node(%s) - Locked(%s)", node_id, locked)
|
|
881
973
|
|
|
882
974
|
zwave_node = self.state.zwave_device(node_id)
|
|
@@ -884,18 +976,22 @@ class QolsysController:
|
|
|
884
976
|
LOGGER.error("doorlock_set - Invalid node_id %s", node_id)
|
|
885
977
|
return None
|
|
886
978
|
|
|
979
|
+
if ZwaveCommandClass.DoorLock not in zwave_node.command_class_list:
|
|
980
|
+
LOGGER.error("Z-Wave node does not support zwave_doorlock_set")
|
|
981
|
+
return None
|
|
982
|
+
|
|
887
983
|
# 0 unlocked, 255 locked
|
|
888
984
|
lock_mode = 0
|
|
889
985
|
if locked:
|
|
890
986
|
lock_mode = 255
|
|
891
987
|
|
|
892
|
-
command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.DoorLock, 1, lock_mode])
|
|
988
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, [ZwaveCommandClass.DoorLock, 1, lock_mode])
|
|
893
989
|
response = await command.send_command()
|
|
894
990
|
LOGGER.debug("MQTT: Receiving zwave_doorlock_set command")
|
|
895
991
|
return response
|
|
896
992
|
|
|
897
993
|
async def command_zwave_thermostat_setpoint_set(
|
|
898
|
-
self, node_id: str, mode:
|
|
994
|
+
self, node_id: str, endpoint: str, mode: ThermostatSetpointMode, setpoint: int
|
|
899
995
|
) -> dict[str, Any] | None:
|
|
900
996
|
zwave_node = self.state.zwave_device(node_id)
|
|
901
997
|
if not zwave_node:
|
|
@@ -903,7 +999,7 @@ class QolsysController:
|
|
|
903
999
|
return None
|
|
904
1000
|
|
|
905
1001
|
if not isinstance(zwave_node, QolsysThermostat):
|
|
906
|
-
LOGGER.error("thermostat_setpoint_set - Z-
|
|
1002
|
+
LOGGER.error("thermostat_setpoint_set - Z-Wave node is not a thermostat %s", node_id)
|
|
907
1003
|
return None
|
|
908
1004
|
|
|
909
1005
|
scale: int = 0
|
|
@@ -916,85 +1012,32 @@ class QolsysController:
|
|
|
916
1012
|
temp_int = int(round(setpoint * (10**precision)))
|
|
917
1013
|
temp_bytes = temp_int.to_bytes(size, byteorder="big", signed=True)
|
|
918
1014
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
mode.value, # Heating
|
|
923
|
-
pss,
|
|
924
|
-
] + list(temp_bytes)
|
|
925
|
-
|
|
926
|
-
zwave_bytes2: list[int] = [
|
|
927
|
-
0x43, # Thermostat Setpoint
|
|
928
|
-
0x01, # SET
|
|
929
|
-
mode.value, # Heating
|
|
930
|
-
pss,
|
|
931
|
-
] + list(temp_bytes)
|
|
1015
|
+
setpointmode = ThermostatSetpointMode.HEATING
|
|
1016
|
+
if mode == ThermostatSetpointMode.COOLING:
|
|
1017
|
+
setpointmode = mode
|
|
932
1018
|
|
|
933
|
-
|
|
1019
|
+
zwave_bytes: list[int] = [
|
|
934
1020
|
0x43, # Thermostat Setpoint
|
|
935
1021
|
0x01, # SET
|
|
936
|
-
|
|
937
|
-
pss,
|
|
938
|
-
] + list(temp_bytes)
|
|
939
|
-
|
|
940
|
-
zwave_bytes4: list[int] = [
|
|
941
|
-
0x43, # Thermostat Setpoint
|
|
942
|
-
0x03, # SET
|
|
943
|
-
0x03, # Furnace
|
|
1022
|
+
setpointmode.value,
|
|
944
1023
|
pss,
|
|
945
1024
|
] + list(temp_bytes)
|
|
946
1025
|
|
|
947
1026
|
LOGGER.debug(
|
|
948
|
-
"MQTT: Sending zwave_thermostat_setpoint_set
|
|
1027
|
+
"MQTT: Sending zwave_thermostat_setpoint_set - Node(%s) - Mode(%s) - Setpoint(%s): %s",
|
|
949
1028
|
node_id,
|
|
950
|
-
mode,
|
|
1029
|
+
mode.value,
|
|
951
1030
|
setpoint,
|
|
952
1031
|
zwave_bytes,
|
|
953
1032
|
)
|
|
954
|
-
command = MQTTCommand_ZWave(self, node_id, zwave_bytes)
|
|
1033
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, zwave_bytes)
|
|
955
1034
|
response = await command.send_command()
|
|
956
1035
|
LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response)
|
|
957
|
-
|
|
958
|
-
await asyncio.sleep(3)
|
|
959
|
-
|
|
960
|
-
LOGGER.debug(
|
|
961
|
-
"MQTT: Sending zwave_thermostat_setpoint_set 0x01 - Node(%s) - Mode(%s) - Setpoint(%s): %s",
|
|
962
|
-
node_id,
|
|
963
|
-
mode,
|
|
964
|
-
setpoint,
|
|
965
|
-
zwave_bytes2,
|
|
966
|
-
)
|
|
967
|
-
command2 = MQTTCommand_ZWave(self, node_id, zwave_bytes2)
|
|
968
|
-
response2 = await command2.send_command()
|
|
969
|
-
LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response2)
|
|
970
|
-
|
|
971
|
-
await asyncio.sleep(3)
|
|
972
|
-
|
|
973
|
-
LOGGER.debug(
|
|
974
|
-
"MQTT: Sending zwave_thermostat_setpoint_set 0x01 - Node(%s) - Mode(0x03) - Setpoint(%s): %s",
|
|
975
|
-
node_id,
|
|
976
|
-
setpoint,
|
|
977
|
-
zwave_bytes3,
|
|
978
|
-
)
|
|
979
|
-
command2 = MQTTCommand_ZWave(self, node_id, zwave_bytes2)
|
|
980
|
-
response2 = await command2.send_command()
|
|
981
|
-
LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response2)
|
|
982
|
-
|
|
983
|
-
await asyncio.sleep(3)
|
|
984
|
-
|
|
985
|
-
LOGGER.debug(
|
|
986
|
-
"MQTT: Sending zwave_thermostat_setpoint_set 0x03 - Node(%s) - Mode(0x3) - Setpoint(%s): %s",
|
|
987
|
-
node_id,
|
|
988
|
-
setpoint,
|
|
989
|
-
zwave_bytes4,
|
|
990
|
-
)
|
|
991
|
-
command2 = MQTTCommand_ZWave(self, node_id, zwave_bytes2)
|
|
992
|
-
response2 = await command2.send_command()
|
|
993
|
-
LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command:%s", response2)
|
|
994
|
-
|
|
995
1036
|
return response
|
|
996
1037
|
|
|
997
|
-
async def command_zwave_thermostat_mode_set(
|
|
1038
|
+
async def command_zwave_thermostat_mode_set(
|
|
1039
|
+
self, node_id: str, endpoint: str, mode: ThermostatMode
|
|
1040
|
+
) -> dict[str, Any] | None:
|
|
998
1041
|
LOGGER.debug("MQTT: Sending zwave_thermostat_mode_set command - Node(%s) - Mode(%s)", node_id, mode)
|
|
999
1042
|
|
|
1000
1043
|
thermostat = self.state.zwave_thermostat(node_id)
|
|
@@ -1002,16 +1045,17 @@ class QolsysController:
|
|
|
1002
1045
|
LOGGER.error("zwave_thermostat_mode_set - Invalid node_id %s", node_id)
|
|
1003
1046
|
return None
|
|
1004
1047
|
|
|
1005
|
-
LOGGER.debug("thermostat_mode: %s", int(mode))
|
|
1006
1048
|
if mode not in thermostat.available_thermostat_mode():
|
|
1007
1049
|
LOGGER.error("thermostat_mode_set - Invalid mode %s", mode)
|
|
1008
1050
|
|
|
1009
|
-
command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.ThermostatMode, 1, int(mode)])
|
|
1051
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, [ZwaveCommandClass.ThermostatMode, 1, int(mode)])
|
|
1010
1052
|
response = await command.send_command()
|
|
1011
1053
|
LOGGER.debug("MQTT: Receiving zwave_thermostat_mode_set command")
|
|
1012
1054
|
return response
|
|
1013
1055
|
|
|
1014
|
-
async def command_zwave_thermostat_fan_mode_set(
|
|
1056
|
+
async def command_zwave_thermostat_fan_mode_set(
|
|
1057
|
+
self, node_id: str, endpoint: str, fan_mode: ThermostatFanMode
|
|
1058
|
+
) -> dict[str, Any] | None:
|
|
1015
1059
|
LOGGER.debug("MQTT: Sending zwave_thermostat_fan_mode_set command - Node(%s) - FanMode(%s)", node_id, fan_mode)
|
|
1016
1060
|
|
|
1017
1061
|
zwave_node = self.state.zwave_device(node_id)
|
|
@@ -1019,7 +1063,7 @@ class QolsysController:
|
|
|
1019
1063
|
LOGGER.error("thermostat_fan_mode_set - Invalid node_id %s", node_id)
|
|
1020
1064
|
return None
|
|
1021
1065
|
|
|
1022
|
-
command = MQTTCommand_ZWave(self, node_id, [ZwaveCommandClass.ThermostatFanMode, 1, fan_mode])
|
|
1066
|
+
command = MQTTCommand_ZWave(self, node_id, endpoint, [ZwaveCommandClass.ThermostatFanMode, 1, fan_mode])
|
|
1023
1067
|
response = await command.send_command()
|
|
1024
1068
|
LOGGER.debug("MQTT: Receiving zwave_thermostat_fan_mode_set command")
|
|
1025
1069
|
return response
|
|
@@ -216,7 +216,7 @@ class QolsysDB:
|
|
|
216
216
|
return partitions
|
|
217
217
|
|
|
218
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")
|
|
219
|
+
self.cursor.execute(f"SELECT * FROM {self.table_virtual_device.table} ORDER BY CAST(device_id AS INTEGER)")
|
|
220
220
|
self.db.commit()
|
|
221
221
|
|
|
222
222
|
devices = []
|
|
@@ -228,7 +228,7 @@ class QolsysDB:
|
|
|
228
228
|
return devices
|
|
229
229
|
|
|
230
230
|
def get_zwave_devices(self) -> list[dict[str, str]]:
|
|
231
|
-
self.cursor.execute(f"SELECT * FROM {self.table_zwave_node.table} ORDER BY node_id")
|
|
231
|
+
self.cursor.execute(f"SELECT * FROM {self.table_zwave_node.table} ORDER BY CAST(node_id AS INTEGER)")
|
|
232
232
|
self.db.commit()
|
|
233
233
|
|
|
234
234
|
devices = []
|
|
@@ -240,7 +240,7 @@ class QolsysDB:
|
|
|
240
240
|
return devices
|
|
241
241
|
|
|
242
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")
|
|
243
|
+
self.cursor.execute(f"SELECT * FROM {self.table_zwave_other.table} ORDER BY CAST(node_id AS INTEGER)")
|
|
244
244
|
self.db.commit()
|
|
245
245
|
|
|
246
246
|
devices = []
|
|
@@ -252,7 +252,7 @@ class QolsysDB:
|
|
|
252
252
|
return devices
|
|
253
253
|
|
|
254
254
|
def get_locks(self) -> list[dict[str, str]]:
|
|
255
|
-
self.cursor.execute(f"SELECT * FROM {self.table_doorlock.table} ORDER BY node_id")
|
|
255
|
+
self.cursor.execute(f"SELECT * FROM {self.table_doorlock.table} ORDER BY CAST(node_id AS INTEGER)")
|
|
256
256
|
self.db.commit()
|
|
257
257
|
|
|
258
258
|
locks = []
|
|
@@ -264,7 +264,7 @@ class QolsysDB:
|
|
|
264
264
|
return locks
|
|
265
265
|
|
|
266
266
|
def get_thermostats(self) -> list[dict[str, str]]:
|
|
267
|
-
self.cursor.execute(f"SELECT * FROM {self.table_thermostat.table} ORDER BY node_id")
|
|
267
|
+
self.cursor.execute(f"SELECT * FROM {self.table_thermostat.table} ORDER BY CAST(node_id AS INTEGER)")
|
|
268
268
|
self.db.commit()
|
|
269
269
|
|
|
270
270
|
thermostats = []
|
|
@@ -276,7 +276,7 @@ class QolsysDB:
|
|
|
276
276
|
return thermostats
|
|
277
277
|
|
|
278
278
|
def get_dimmers(self) -> list[dict[str, str]]:
|
|
279
|
-
self.cursor.execute(f"SELECT * FROM {self.table_dimmer.table} ORDER BY node_id")
|
|
279
|
+
self.cursor.execute(f"SELECT * FROM {self.table_dimmer.table} ORDER BY CAST(node_id AS INTEGER)")
|
|
280
280
|
self.db.commit()
|
|
281
281
|
|
|
282
282
|
dimmers = []
|
|
@@ -288,7 +288,7 @@ class QolsysDB:
|
|
|
288
288
|
return dimmers
|
|
289
289
|
|
|
290
290
|
def get_zones(self) -> list[dict[str, str]]:
|
|
291
|
-
self.cursor.execute(f"SELECT * FROM {self.table_sensor.table} ORDER BY zoneid")
|
|
291
|
+
self.cursor.execute(f"SELECT * FROM {self.table_sensor.table} ORDER BY CAST(zoneid AS INTEGER)")
|
|
292
292
|
self.db.commit()
|
|
293
293
|
|
|
294
294
|
zones = []
|
|
@@ -390,7 +390,7 @@ class QolsysDB:
|
|
|
390
390
|
|
|
391
391
|
return None
|
|
392
392
|
|
|
393
|
-
def load_db(self, database:
|
|
393
|
+
def load_db(self, database: Any | None) -> None:
|
|
394
394
|
self.clear_db()
|
|
395
395
|
|
|
396
396
|
if not database:
|
{qolsys_controller-0.0.81 → qolsys_controller-0.3.2}/qolsys_controller/database/table_smartsocket.py
RENAMED
|
@@ -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()
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
class QolsysEvent(StrEnum):
|
|
5
|
+
EVENT_PANEL_PARTITION_ADD = "EVENT_PANEL_PARTITION_ADD"
|
|
6
|
+
EVENT_PANEL_ZONE_ADD = "EVENT_PANEL_ZONE_ADD"
|
|
7
|
+
EVENT_PANEL_DOORBELL = "EVENT_PANEL_DOORBELL"
|
|
8
|
+
EVENT_PANEL_CHIME = "EVENT_PANEL_CHIME"
|
|
9
|
+
EVENT_ZWAVE_DEVICE_ADD = "EVENT_ZWAVE_MULTILEVELSENSOR_ADD"
|
|
10
|
+
EVENT_ZWAVE_MULTILEVELSENSOR_ADD = "EVENT_ZWAVE_MULTILEVELSENSOR_ADD"
|
|
11
|
+
EVENT_ZWAVE_METER_ADD = "EVENT_ZWAVE_METER_ADD"
|
|
12
|
+
|
|
13
|
+
|
|
4
14
|
class PartitionSystemStatus(StrEnum):
|
|
5
15
|
ARM_STAY = "ARM-STAY"
|
|
6
16
|
ARM_AWAY = "ARM-AWAY"
|
|
@@ -48,23 +58,24 @@ class PartitionAlarmType(StrEnum):
|
|
|
48
58
|
|
|
49
59
|
|
|
50
60
|
class ZoneStatus(StrEnum):
|
|
61
|
+
ACTIVE = "Active"
|
|
62
|
+
ACTIVATED = "Activated"
|
|
51
63
|
ALARMED = "Alarmed"
|
|
52
|
-
|
|
64
|
+
ARM_AWAY = "Arm-Away"
|
|
65
|
+
ARM_STAY = "Arm-Stay"
|
|
53
66
|
CLOSED = "Closed"
|
|
54
|
-
|
|
67
|
+
CONNECTED = "connected"
|
|
68
|
+
DISARM = "Disarm"
|
|
69
|
+
OPEN = "Open"
|
|
55
70
|
INACTIVE = "Inactive"
|
|
56
|
-
ACTIVATED = "Activated"
|
|
57
71
|
IDLE = "Idle"
|
|
58
72
|
NORMAL = "Normal"
|
|
59
73
|
UNREACHABLE = "Unreachable"
|
|
60
74
|
TAMPERED = "Tampered"
|
|
61
75
|
SYNCHRONIZING = "Synchronizing"
|
|
62
|
-
CONNECTED = "connected"
|
|
63
76
|
DISCONNECTED = "disconnected"
|
|
64
77
|
FAILURE = "Failure"
|
|
65
78
|
NOT_NETWORKED = "Not Networked"
|
|
66
|
-
DISARM = "Disarm"
|
|
67
|
-
ARM_AWAY = "Arm-Away"
|
|
68
79
|
|
|
69
80
|
|
|
70
81
|
class DeviceCapability(StrEnum):
|
|
@@ -72,37 +83,39 @@ class DeviceCapability(StrEnum):
|
|
|
72
83
|
WIFI = "WiFi"
|
|
73
84
|
POWERG = "POWERG"
|
|
74
85
|
ZWAVE = "Z-Wave"
|
|
86
|
+
S_LINE = "S-Line"
|
|
75
87
|
|
|
76
88
|
|
|
77
89
|
class ZoneSensorType(StrEnum):
|
|
78
|
-
|
|
90
|
+
AUXILIARY_PENDANT = "Auxiliary Pendant"
|
|
91
|
+
BLUETOOTH = "Bluetooth"
|
|
92
|
+
CO_DETECTOR = "CODetector"
|
|
79
93
|
DOORBELL = "Doorbell"
|
|
80
|
-
|
|
94
|
+
DOOR_WINDOW = "Door_Window"
|
|
95
|
+
DOOR_WINDOW_M = "Door_Window_M"
|
|
96
|
+
FREEZE = "Freeze"
|
|
81
97
|
GLASS_BREAK = "GlassBreak"
|
|
98
|
+
# HARDWIRE_TRANSLATOR = "" # TBD
|
|
99
|
+
HEAT = "Heat"
|
|
100
|
+
# HIGH_TEMPERATURE = "" # TBD
|
|
82
101
|
KEY_FOB = "KeyFob"
|
|
83
102
|
KEYPAD = "Keypad"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
MOTION = "Motion"
|
|
104
|
+
# OCCUPANCY = "" #TBD
|
|
105
|
+
PANEL_GLASS_BREAK = "Panel Glass Break"
|
|
106
|
+
PANEL_MOTION = "Panel Motion"
|
|
88
107
|
# WIRELESS_TRANSLATOR = "" #TBD
|
|
89
|
-
|
|
90
|
-
HEAT = "Heat"
|
|
91
|
-
WATER = "Water"
|
|
108
|
+
SIREN = "Siren"
|
|
92
109
|
SHOCK = "Shock"
|
|
93
|
-
|
|
94
|
-
TILT = "Tilt"
|
|
110
|
+
SMOKE_DETECTOR = "SmokeDetector"
|
|
95
111
|
SMOKE_M = "Smoke_M"
|
|
96
|
-
# DOOR_WINDOW_M = "" #TBD
|
|
97
|
-
# OCCUPANCY = "" #TBD
|
|
98
|
-
SIREN = "Siren"
|
|
99
|
-
# HIGH_TEMPERATURE = "" # TBD
|
|
100
|
-
PANEL_MOTION = "Panel Motion"
|
|
101
|
-
PANEL_GLASS_BREAK = "Panel Glass Break"
|
|
102
|
-
BLUETOOTH = "Bluetooth"
|
|
103
112
|
TAKEOVER_MODULE = "TakeoverModule"
|
|
104
|
-
TRANSLATOR = "Translator"
|
|
105
113
|
TAMPER = "Tamper Sensor"
|
|
114
|
+
TEMPERATURE = "Temperature"
|
|
115
|
+
TILT = "Tilt"
|
|
116
|
+
TRANSLATOR = "Translator"
|
|
117
|
+
UNKNOWN = "Unknown"
|
|
118
|
+
WATER = "Water"
|
|
106
119
|
|
|
107
120
|
|
|
108
121
|
class ZoneSensorGroup(StrEnum):
|