qolsys-controller 0.0.2__py3-none-any.whl → 0.0.4__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 (62) hide show
  1. qolsys_controller/controller.py +6 -8
  2. qolsys_controller/database/db.py +62 -58
  3. qolsys_controller/database/table.py +24 -25
  4. qolsys_controller/database/table_alarmedsensor.py +15 -14
  5. qolsys_controller/database/table_automation.py +32 -28
  6. qolsys_controller/database/table_country_locale.py +23 -20
  7. qolsys_controller/database/table_dashboard_msgs.py +6 -5
  8. qolsys_controller/database/table_dimmerlight.py +22 -20
  9. qolsys_controller/database/table_doorlock.py +22 -20
  10. qolsys_controller/database/table_eu_event.py +5 -5
  11. qolsys_controller/database/table_heat_map.py +14 -13
  12. qolsys_controller/database/table_history.py +16 -15
  13. qolsys_controller/database/table_iqremotesettings.py +13 -12
  14. qolsys_controller/database/table_iqrouter_network_config.py +5 -5
  15. qolsys_controller/database/table_iqrouter_user_device.py +5 -5
  16. qolsys_controller/database/table_master_slave.py +28 -25
  17. qolsys_controller/database/table_partition.py +10 -10
  18. qolsys_controller/database/table_powerg_device.py +5 -5
  19. qolsys_controller/database/table_qolsyssettings.py +10 -10
  20. qolsys_controller/database/table_scene.py +20 -17
  21. qolsys_controller/database/table_sensor.py +56 -47
  22. qolsys_controller/database/table_smartsocket.py +5 -5
  23. qolsys_controller/database/table_state.py +12 -11
  24. qolsys_controller/database/table_tcc.py +6 -5
  25. qolsys_controller/database/table_thermostat.py +41 -34
  26. qolsys_controller/database/table_trouble_conditions.py +14 -13
  27. qolsys_controller/database/table_user.py +17 -16
  28. qolsys_controller/database/table_virtual_device.py +5 -5
  29. qolsys_controller/database/table_weather.py +16 -15
  30. qolsys_controller/database/table_zigbee_device.py +5 -5
  31. qolsys_controller/database/table_zwave_association_group.py +19 -17
  32. qolsys_controller/database/table_zwave_history.py +22 -20
  33. qolsys_controller/database/table_zwave_node.py +73 -68
  34. qolsys_controller/database/table_zwave_other.py +5 -5
  35. qolsys_controller/enum.py +44 -41
  36. qolsys_controller/errors.py +13 -13
  37. qolsys_controller/mdns.py +3 -3
  38. qolsys_controller/mqtt_command_queue.py +2 -3
  39. qolsys_controller/observable.py +3 -2
  40. qolsys_controller/panel.py +147 -146
  41. qolsys_controller/partition.py +46 -43
  42. qolsys_controller/pki.py +72 -65
  43. qolsys_controller/plugin.py +5 -4
  44. qolsys_controller/plugin_c4.py +8 -9
  45. qolsys_controller/plugin_remote.py +237 -228
  46. qolsys_controller/settings.py +75 -8
  47. qolsys_controller/state.py +68 -65
  48. qolsys_controller/task_manager.py +3 -3
  49. qolsys_controller/utils_mqtt.py +14 -11
  50. qolsys_controller/zone.py +69 -68
  51. qolsys_controller/zwave_device.py +46 -43
  52. qolsys_controller/zwave_dimmer.py +28 -26
  53. qolsys_controller/zwave_garagedoor.py +1 -0
  54. qolsys_controller/zwave_generic.py +2 -1
  55. qolsys_controller/zwave_lock.py +28 -30
  56. qolsys_controller/zwave_outlet.py +1 -0
  57. qolsys_controller/zwave_thermostat.py +58 -55
  58. {qolsys_controller-0.0.2.dist-info → qolsys_controller-0.0.4.dist-info}/METADATA +1 -1
  59. qolsys_controller-0.0.4.dist-info/RECORD +62 -0
  60. qolsys_controller-0.0.2.dist-info/RECORD +0 -62
  61. {qolsys_controller-0.0.2.dist-info → qolsys_controller-0.0.4.dist-info}/WHEEL +0 -0
  62. {qolsys_controller-0.0.2.dist-info → qolsys_controller-0.0.4.dist-info}/licenses/LICENSE +0 -0
@@ -18,17 +18,18 @@ from .plugin import QolsysPlugin
18
18
  from .settings import QolsysSettings
19
19
  from .state import QolsysState
20
20
  from .task_manager import QolsysTaskManager
21
- from .utils_mqtt import fix_json_string, generate_random_mac
21
+ from .utils_mqtt import generate_random_mac
22
22
 
23
23
  LOGGER = logging.getLogger(__name__)
24
24
 
25
+
25
26
  class QolsysPluginRemote(QolsysPlugin):
26
27
 
27
- def __init__(self,state:QolsysState,panel:QolsysPanel,settings:QolsysSettings,config_directory:str)-> None:
28
- super().__init__(state,panel,settings)
28
+ def __init__(self, state: QolsysState, panel: QolsysPanel, settings: QolsysSettings) -> None:
29
+ super().__init__(state, panel, settings)
29
30
 
30
31
  # PKI
31
- self._pki = QolsysPKI(keys_directory = config_directory + "pki/")
32
+ self._pki = QolsysPKI(settings=settings)
32
33
  self._auto_discover_pki = True
33
34
 
34
35
  # Plugin
@@ -40,8 +41,6 @@ class QolsysPluginRemote(QolsysPlugin):
40
41
 
41
42
  # MQTT Client
42
43
  self.aiomqtt = None
43
- self._mqtt_timeout = 30
44
- self._mqtt_ping = 600
45
44
  self._mqtt_task_config_label = "mqtt_task_config"
46
45
  self._mqtt_task_listen_label = "mqtt_task_listen"
47
46
  self._mqtt_task_connect_label = "mqtt_task_connect"
@@ -52,7 +51,7 @@ class QolsysPluginRemote(QolsysPlugin):
52
51
  return self._log_mqtt_messages
53
52
 
54
53
  @log_mqtt_mesages.setter
55
- def log_mqtt_mesages(self,log_mqtt_mesages:bool) -> None:
54
+ def log_mqtt_mesages(self, log_mqtt_mesages: bool) -> None:
56
55
  self._log_mqtt_messages = log_mqtt_mesages
57
56
 
58
57
  @property
@@ -60,7 +59,7 @@ class QolsysPluginRemote(QolsysPlugin):
60
59
  return self._check_user_code_on_disarm
61
60
 
62
61
  @check_user_code_on_disarm.setter
63
- def check_user_code_on_disarm(self,check_user_code_on_disarm:bool) -> None:
62
+ def check_user_code_on_disarm(self, check_user_code_on_disarm: bool) -> None:
64
63
  self._check_user_code_on_disarm = check_user_code_on_disarm
65
64
 
66
65
  @property
@@ -68,7 +67,7 @@ class QolsysPluginRemote(QolsysPlugin):
68
67
  return self._auto_discover_pki
69
68
 
70
69
  @auto_discover_pki.setter
71
- def auto_discover_pki(self,value:bool) -> None:
70
+ def auto_discover_pki(self, value: bool) -> None:
72
71
  self._auto_discover_pki = value
73
72
 
74
73
  def is_paired(self) -> bool:
@@ -78,25 +77,33 @@ class QolsysPluginRemote(QolsysPlugin):
78
77
  # 3- Signed certificate file present
79
78
  # 4- Qolsys certificate present
80
79
  # 5- Qolsys Panel IP present
81
- return (self._pki.id != "" and
80
+ return (
81
+ self._pki.id != "" and
82
82
  self._pki.check_key_file() and
83
- self._pki.check_secure_file() and
83
+ self._pki.check_cer_file() and
84
84
  self._pki.check_qolsys_cer_file() and
85
+ self._pki.check_secure_file() and
85
86
  self.settings.check_panel_ip() and
86
- self.settings.check_plugin_ip())
87
+ self.settings.check_plugin_ip()
88
+ )
87
89
 
88
- async def config(self,start_pairing:bool) -> bool:
90
+ async def config(self, start_pairing: bool) -> bool:
89
91
  return await self._task_manager.run(self.config_task(start_pairing), self._mqtt_task_config_label)
90
92
 
91
- async def config_task(self,start_pairing:bool) -> bool:
93
+ async def config_task(self, start_pairing: bool) -> bool:
92
94
  LOGGER.debug("Configuring Plugin")
93
95
  super().config()
94
96
 
97
+ # Check and created config_directory
98
+ if not self.settings.check_config_directory(create=start_pairing):
99
+ return False
100
+
95
101
  # Read user file for access code
96
102
  loop = asyncio.get_running_loop()
97
- if not loop.run_in_executor(None,self.panel.read_users_file):
103
+ if not loop.run_in_executor(None, self.panel.read_users_file):
98
104
  return False
99
105
 
106
+ # Config PKI
100
107
  if self._auto_discover_pki:
101
108
  if self._pki.auto_discover_pki():
102
109
  self.settings.random_mac = self._pki.formatted_id()
@@ -105,7 +112,7 @@ class QolsysPluginRemote(QolsysPlugin):
105
112
 
106
113
  # Check if plugin is paired
107
114
  if self.is_paired():
108
- LOGGER.debug("Panel is paired")
115
+ LOGGER.debug("Panel is Paired")
109
116
 
110
117
  else:
111
118
  LOGGER.debug("Panel not paired")
@@ -124,16 +131,14 @@ class QolsysPluginRemote(QolsysPlugin):
124
131
  return True
125
132
 
126
133
  async def start_operation(self) -> None:
127
- await self._task_manager.run(self.mqtt_connect_task(reconnect=True),self._mqtt_task_connect_label)
128
-
129
- async def mqtt_connect_task(self,reconnect:bool) -> None:
130
- if not self.is_paired():
131
- return
134
+ await self._task_manager.run(self.mqtt_connect_task(reconnect=True), self._mqtt_task_connect_label)
132
135
 
136
+ async def mqtt_connect_task(self, reconnect: bool) -> None:
137
+ # Configure TLS parameters for MQTT connection
133
138
  tls_params = aiomqtt.TLSParameters(
134
- ca_certs = self._pki.qolsys_cer_file_path,
135
- certfile = self._pki.secure_file_path,
136
- keyfile = self._pki.key_file_path,
139
+ ca_certs=self._pki.qolsys_cer_file_path,
140
+ certfile=self._pki.secure_file_path,
141
+ keyfile=self._pki.key_file_path,
137
142
  cert_reqs=ssl.CERT_REQUIRED,
138
143
  tls_version=ssl.PROTOCOL_TLSv1_2,
139
144
  ciphers="ALL:@SECLEVEL=0",
@@ -149,8 +154,9 @@ class QolsysPluginRemote(QolsysPlugin):
149
154
  tls_params=tls_params,
150
155
  tls_insecure=True,
151
156
  clean_session=True,
152
- timeout=self._mqtt_timeout,
153
- identifier="QolsysController")
157
+ timeout=self.settings.mqtt_timeout,
158
+ identifier="QolsysController",
159
+ )
154
160
 
155
161
  await self.aiomqtt.__aenter__()
156
162
 
@@ -160,25 +166,25 @@ class QolsysPluginRemote(QolsysPlugin):
160
166
  await self.aiomqtt.subscribe("iq2meid")
161
167
 
162
168
  # Subscribte to MQTT commands response
163
- await self.aiomqtt.subscribe("response_" + self.settings.random_mac,qos=2)
169
+ await self.aiomqtt.subscribe("response_" + self.settings.random_mac, qos=2)
164
170
 
165
171
  # Only log mastermeid traffic for debug purposes
166
172
  if self.log_mqtt_mesages:
167
173
  # Subscribe to MQTT commands send to panel by other devices
168
- await self.aiomqtt.subscribe("mastermeid",qos=2)
174
+ await self.aiomqtt.subscribe("mastermeid", qos=2)
169
175
 
170
176
  # Subscribe to all topics
171
- await self.aiomqtt.subscribe("#",qos=2)
177
+ await self.aiomqtt.subscribe("#", qos=2)
172
178
 
173
179
  # Start mqtt_listent_task and mqtt_ping_task
174
180
  self._task_manager.cancel(self._mqtt_task_listen_label)
175
181
  self._task_manager.cancel(self._mqtt_task_ping_label)
176
182
  self._task_manager.run(self.mqtt_listen_task(), self._mqtt_task_listen_label)
177
- self._task_manager.run(self.mqtt_ping_task(),self._mqtt_task_ping_label)
183
+ self._task_manager.run(self.mqtt_ping_task(), self._mqtt_task_ping_label)
178
184
 
179
185
  response_connect = await self.command_connect()
180
- self.panel.imei = response_connect.get("master_imei","")
181
- self.panel.product_type = response_connect.get("primary_product_type","")
186
+ self.panel.imei = response_connect.get("master_imei", "")
187
+ self.panel.product_type = response_connect.get("primary_product_type", "")
182
188
 
183
189
  await self.command_pairing_request()
184
190
  await self.command_pingevent()
@@ -199,12 +205,12 @@ class QolsysPluginRemote(QolsysPlugin):
199
205
  # Receive pannel network error
200
206
  self.connected = False
201
207
  self.connected_observer.notify()
202
- await self.aiomqtt.__aexit__(None,None,None)
208
+ await self.aiomqtt.__aexit__(None, None, None)
203
209
  self.aiomqtt = None
204
210
 
205
211
  if reconnect:
206
- LOGGER.debug("MQTT Error - %s: Reconnecting in %s seconds ...",err,self._mqtt_timeout)
207
- await asyncio.sleep(self._mqtt_timeout)
212
+ LOGGER.debug("MQTT Error - %s: Reconnecting in %s seconds ...", err, self.settings.mqtt_timeout)
213
+ await asyncio.sleep(self.settings.mqtt_timeout)
208
214
  else:
209
215
  raise QolsysMqttError from err
210
216
 
@@ -214,7 +220,7 @@ class QolsysPluginRemote(QolsysPlugin):
214
220
  # Pannels need to be re-paired
215
221
  self.connected = False
216
222
  self.connected_observer.notify()
217
- await self.aiomqtt.__aexit__(None,None,None)
223
+ await self.aiomqtt.__aexit__(None, None, None)
218
224
  self.aiomqtt = None
219
225
  raise QolsysSslError from err
220
226
 
@@ -222,20 +228,20 @@ class QolsysPluginRemote(QolsysPlugin):
222
228
  while True:
223
229
  if self.aiomqtt is not None and self.connected:
224
230
  await self.command_pingevent()
225
- await asyncio.sleep(self._mqtt_ping)
231
+ await asyncio.sleep(self.settings.mqtt_ping)
226
232
 
227
233
  async def mqtt_listen_task(self) -> None:
228
234
  try:
229
235
  async for message in self.aiomqtt.messages:
230
236
 
231
237
  if self.log_mqtt_mesages:
232
- LOGGER.debug("MQTT TOPIC: %s\n%s",message.topic,message.payload.decode())
238
+ LOGGER.debug("MQTT TOPIC: %s\n%s", message.topic, message.payload.decode())
233
239
 
234
240
  # Panel response to MQTT Commands
235
241
  if message.topic.matches("response_" + self.settings.random_mac):
236
242
  data = message.payload.decode()
237
- #data = message.payload.decode().replace("\\\\", "\\") # noqa: ERA001
238
- #data = fix_json_string(data) # noqa: ERA001
243
+ # data = message.payload.decode().replace("\\\\", "\\")
244
+ # data = fix_json_string(data)
239
245
  data = json.loads(data)
240
246
  await self._mqtt_command_queue.handle_response(data)
241
247
 
@@ -248,9 +254,9 @@ class QolsysPluginRemote(QolsysPlugin):
248
254
  self.connected = False
249
255
  self.connected_observer.notify()
250
256
 
251
- LOGGER.debug("%s: Reconnecting in %s seconds ...",err,self._mqtt_timeout)
252
- await asyncio.sleep(self._mqtt_timeout)
253
- self._task_manager.run(self.mqtt_connect_task(reconnect=True),self._mqtt_task_connect_label)
257
+ LOGGER.debug("%s: Reconnecting in %s seconds ...", err, self.settings.mqtt_timeout)
258
+ await asyncio.sleep(self.settings.mqtt_timeout)
259
+ self._task_manager.run(self.mqtt_connect_task(reconnect=True), self._mqtt_task_connect_label)
254
260
 
255
261
  except ssl.SSLError as err:
256
262
  # SSL error is and authentication error with invalid certificates en pki
@@ -258,23 +264,25 @@ class QolsysPluginRemote(QolsysPlugin):
258
264
  # Pannels need to be re-paired
259
265
  self.connected = False
260
266
  self.connected_observer.notify()
261
- await self.aiomqtt.__aexit__(None,None,None)
267
+ await self.aiomqtt.__aexit__(None, None, None)
262
268
  self.aiomqtt = None
263
269
  raise QolsysSslError from err
264
270
 
265
- async def start_initial_pairing(self)->bool:
271
+ async def start_initial_pairing(self) -> bool:
266
272
  # check if random_mac exist
267
273
  if self.settings.random_mac == "":
268
274
  LOGGER.debug("Creating random_mac")
269
275
  self.settings.random_mac = generate_random_mac()
270
- self._pki.create(self.settings.random_mac,key_size=2048)
276
+ self._pki.create(self.settings.random_mac, key_size=self.settings.key_size)
271
277
 
272
278
  # Check if PKI is valid
273
279
  self._pki.set_id(self.settings.random_mac)
274
280
  LOGGER.debug("Checking PKI")
275
- if not(self._pki.check_key_file() and
276
- self._pki.check_cer_file() and
277
- self._pki.check_csr_file()):
281
+ if not (
282
+ self._pki.check_key_file() and
283
+ self._pki.check_cer_file() and
284
+ self._pki.check_csr_file()
285
+ ):
278
286
  LOGGER.error("PKI Error")
279
287
  return False
280
288
 
@@ -291,15 +299,16 @@ class QolsysPluginRemote(QolsysPlugin):
291
299
  pairing_port = random.randint(50000, 55000)
292
300
 
293
301
  # Start Pairing mDNS Brodcast
294
- LOGGER.debug("Starting mDNS Service Discovery: %s:%s",self.settings.plugin_ip,str(pairing_port))
295
- mdns_server = QolsysMDNS(self.settings.plugin_ip,pairing_port)
302
+ LOGGER.debug("Starting mDNS Service Discovery: %s:%s", self.settings.plugin_ip, str(pairing_port))
303
+ mdns_server = QolsysMDNS(self.settings.plugin_ip, pairing_port)
296
304
  await mdns_server.start_mdns()
297
305
 
298
306
  # Start Key Exchange Server
299
307
  LOGGER.debug("Starting Certificate Exchange Server")
300
308
  context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
301
- context.load_cert_chain(certfile = self._pki.cer_file_path, keyfile = self._pki.key_file_path)
302
- self.certificate_exchange_server = await asyncio.start_server(self.handle_key_exchange_client,self.settings.plugin_ip, pairing_port,ssl=context)
309
+ context.load_cert_chain(certfile=self._pki.cer_file_path, keyfile=self._pki.key_file_path)
310
+ self.certificate_exchange_server = await asyncio.start_server(self.handle_key_exchange_client,
311
+ self.settings.plugin_ip, pairing_port, ssl=context)
303
312
 
304
313
  LOGGER.debug("Certificate Exchange Server Waiting for Panel")
305
314
  LOGGER.debug("Press Pair Button in IQ Remote Config Page ...")
@@ -317,11 +326,11 @@ class QolsysPluginRemote(QolsysPlugin):
317
326
 
318
327
  # We have client sgined certificate at this point
319
328
  # Connect to Panel MQTT to send pairing command
320
- await self._task_manager.run(self.mqtt_connect_task(reconnect=False),self._mqtt_task_connect_label)
329
+ await self._task_manager.run(self.mqtt_connect_task(reconnect=False), self._mqtt_task_connect_label)
321
330
  LOGGER.debug("Plugin Pairing Completed ")
322
331
  return True
323
332
 
324
- async def handle_key_exchange_client(self,reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None: # noqa: PLR0915
333
+ async def handle_key_exchange_client(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
325
334
 
326
335
  received_panel_mac = False
327
336
  received_signed_client_certificate = False
@@ -335,16 +344,14 @@ class QolsysPluginRemote(QolsysPlugin):
335
344
  while continue_pairing:
336
345
 
337
346
  # Plugin is receiving panel_mac from panel
338
- if(not received_panel_mac and
339
- not received_signed_client_certificate and
340
- not received_qolsys_cer):
347
+ if (not received_panel_mac and not received_signed_client_certificate and not received_qolsys_cer):
341
348
 
342
349
  request = (await reader.read(2048))
343
350
  mac = request.decode()
344
351
 
345
352
  address, port = writer.get_extra_info("peername")
346
- LOGGER.debug("Panel Connected from: %s:%s",address,port)
347
- LOGGER.debug("Receiving from Panel: %s",mac)
353
+ LOGGER.debug("Panel Connected from: %s:%s", address, port)
354
+ LOGGER.debug("Receiving from Panel: %s", mac)
348
355
 
349
356
  # Remove \x00 and \x01 from received string
350
357
  self.settings.panel_mac = "".join(char for char in mac if char.isprintable())
@@ -353,11 +360,11 @@ class QolsysPluginRemote(QolsysPlugin):
353
360
 
354
361
  # Sending random_mac to panel
355
362
  message = b"\x00\x11" + self.settings.random_mac.encode()
356
- LOGGER.debug("Sending to Panel: %s",message.decode())
363
+ LOGGER.debug("Sending to Panel: %s", message.decode())
357
364
  writer.write(message)
358
365
  await writer.drain()
359
366
 
360
- #Sending CSR File to panel
367
+ # Sending CSR File to panel
361
368
  with open(self._pki.csr_file_path, "rb") as file:
362
369
  content = file.read()
363
370
  LOGGER.debug("Sending to Panel: [CSR File Content]")
@@ -368,9 +375,7 @@ class QolsysPluginRemote(QolsysPlugin):
368
375
  continue
369
376
 
370
377
  # Read signed certificate data
371
- if(received_panel_mac and
372
- not received_signed_client_certificate and
373
- not received_qolsys_cer):
378
+ if (received_panel_mac and not received_signed_client_certificate and not received_qolsys_cer):
374
379
 
375
380
  request = (await reader.readline())
376
381
  signed_certificate_data += request.decode()
@@ -386,9 +391,7 @@ class QolsysPluginRemote(QolsysPlugin):
386
391
  qolsys_certificate_data += certificates[1]
387
392
 
388
393
  # Read qolsys certificate data
389
- if(received_panel_mac and
390
- received_signed_client_certificate and
391
- not received_qolsys_cer):
394
+ if (received_panel_mac and received_signed_client_certificate and not received_qolsys_cer):
392
395
 
393
396
  request = (await reader.readline())
394
397
  qolsys_certificate_data += request.decode()
@@ -416,12 +419,12 @@ class QolsysPluginRemote(QolsysPlugin):
416
419
  writer.close()
417
420
  self.certificate_exchange_server.close()
418
421
 
419
- async def send_command(self,topic:str,json_payload:str,request_id:str) -> dict:
422
+ async def send_command(self, topic: str, json_payload: str, request_id: str) -> dict:
420
423
  if self.aiomqtt is None:
421
424
  LOGGER.error("MQTT Client not configured")
422
425
  raise QolsysMqttError
423
426
 
424
- await self.aiomqtt.publish(topic=topic,payload=json.dumps(json_payload),qos=2)
427
+ await self.aiomqtt.publish(topic=topic, payload=json.dumps(json_payload), qos=2)
425
428
  return await self._mqtt_command_queue.wait_for_response(request_id)
426
429
 
427
430
  async def command_connect(self) -> dict:
@@ -454,43 +457,44 @@ class QolsysPluginRemote(QolsysPlugin):
454
457
  remoteMacAddress = self.settings.random_mac
455
458
 
456
459
  dhcpInfo = {
457
- "ipaddress":"",
458
- "gateway":"",
459
- "netmask":"",
460
- "dns1":"",
461
- "dns2":"",
462
- "dhcpServer":"",
463
- "leaseDuration":"",
460
+ "ipaddress": "",
461
+ "gateway": "",
462
+ "netmask": "",
463
+ "dns1": "",
464
+ "dns2": "",
465
+ "dhcpServer": "",
466
+ "leaseDuration": "",
467
+ }
468
+
469
+ payload = {
470
+ "eventName": eventName,
471
+ "ipAddress": ipAddress,
472
+ "macAddress": macAddress,
473
+ "remoteClientID": remoteClientID,
474
+ "softwareVersion": softwareVersion,
475
+ "producType": producType,
476
+ "bssid": bssid,
477
+ "dhcpInfo": json.dumps(dhcpInfo),
478
+ "lastUpdateChecksum": lastUpdateChecksum,
479
+ "dealerIconsCheckSum": dealerIconsCheckSum,
480
+ "remote_feature_support_version": remote_feature_support_version,
481
+ "current_battery_status": current_battery_status,
482
+ "remote_panel_battery_status": remote_panel_battery_status,
483
+ "remote_panel_battery_health": remote_panel_battery_health,
484
+ "remote_panel_battery_level": remote_panel_battery_level,
485
+ "remote_panel_battery_present": remote_panel_battery_present,
486
+ "remote_panel_battery_percentage": remote_panel_battery_percentage,
487
+ "remote_panel_battery_scale": remote_panel_battery_scale,
488
+ "remote_panel_battery_voltage": remote_panel_battery_voltage,
489
+ "remote_panel_battery_technology": remote_panel_battery_technology,
490
+ "remote_panel_plugged": remote_panel_plugged,
491
+ "remote_panel_battery_temperature": remote_panel_battery_temperature,
492
+ "requestID": requestID,
493
+ "responseTopic": responseTopic,
494
+ "remoteMacAddess": remoteMacAddress,
464
495
  }
465
496
 
466
- payload = { "eventName":eventName,
467
- "ipAddress":ipAddress,
468
- "macAddress":macAddress,
469
- "remoteClientID": remoteClientID,
470
- "softwareVersion":softwareVersion,
471
- "producType": producType,
472
- "bssid": bssid,
473
- "dhcpInfo": json.dumps(dhcpInfo),
474
- "lastUpdateChecksum":lastUpdateChecksum,
475
- "dealerIconsCheckSum" : dealerIconsCheckSum,
476
- "remote_feature_support_version":remote_feature_support_version,
477
- "current_battery_status": current_battery_status,
478
- "remote_panel_battery_status":remote_panel_battery_status,
479
- "remote_panel_battery_health": remote_panel_battery_health,
480
- "remote_panel_battery_level": remote_panel_battery_level,
481
- "remote_panel_battery_present": remote_panel_battery_present,
482
- "remote_panel_battery_percentage": remote_panel_battery_percentage,
483
- "remote_panel_battery_scale": remote_panel_battery_scale,
484
- "remote_panel_battery_voltage": remote_panel_battery_voltage,
485
- "remote_panel_battery_technology": remote_panel_battery_technology,
486
- "remote_panel_plugged": remote_panel_plugged,
487
- "remote_panel_battery_temperature" : remote_panel_battery_temperature,
488
- "requestID":requestID,
489
- "responseTopic":responseTopic ,
490
- "remoteMacAddess":remoteMacAddress,
491
- }
492
-
493
- response = await self.send_command(topic,payload,requestID)
497
+ response = await self.send_command(topic, payload, requestID)
494
498
  LOGGER.debug("MQTT: Receiving connect command")
495
499
  return response
496
500
 
@@ -517,30 +521,30 @@ class QolsysPluginRemote(QolsysPlugin):
517
521
  remoteMacAddress = self.settings.random_mac
518
522
  responseTopic = "response_" + self.settings.random_mac
519
523
 
520
- payload = {"eventName":eventName,
521
- "macAddress": macAddress,
522
- "remote_panel_status": remote_panel_status,
523
- "ipAddress": ipAddress,
524
- "current_battery_status" : current_battery_status,
525
- "remote_panel_battery_percentage":remote_panel_battery_percentage,
526
- "remote_panel_battery_temperature" : remote_panel_battery_temperature,
527
- "remote_panel_battery_status" : remote_panel_battery_status,
528
- "remote_panel_battery_scale": remote_panel_battery_scale,
529
- "remote_panel_battery_voltage" : remote_panel_battery_voltage,
530
- "remote_panel_battery_present" : remote_panel_battery_present,
531
- "remote_panel_battery_technology": remote_panel_battery_technology,
532
- "remote_panel_battery_level": remote_panel_battery_level,
533
- "remote_panel_battery_health" : remote_panel_battery_health,
534
- "remote_panel_plugged" : remote_panel_plugged,
535
- "requestID":requestID,
536
- "responseTopic": responseTopic,
537
- "remoteMacAddess":remoteMacAddress,
524
+ payload = {
525
+ "eventName": eventName,
526
+ "macAddress": macAddress,
527
+ "remote_panel_status": remote_panel_status,
528
+ "ipAddress": ipAddress,
529
+ "current_battery_status": current_battery_status,
530
+ "remote_panel_battery_percentage": remote_panel_battery_percentage,
531
+ "remote_panel_battery_temperature": remote_panel_battery_temperature,
532
+ "remote_panel_battery_status": remote_panel_battery_status,
533
+ "remote_panel_battery_scale": remote_panel_battery_scale,
534
+ "remote_panel_battery_voltage": remote_panel_battery_voltage,
535
+ "remote_panel_battery_present": remote_panel_battery_present,
536
+ "remote_panel_battery_technology": remote_panel_battery_technology,
537
+ "remote_panel_battery_level": remote_panel_battery_level,
538
+ "remote_panel_battery_health": remote_panel_battery_health,
539
+ "remote_panel_plugged": remote_panel_plugged,
540
+ "requestID": requestID,
541
+ "responseTopic": responseTopic,
542
+ "remoteMacAddess": remoteMacAddress,
538
543
  }
539
544
 
540
- await self.send_command(topic,payload,requestID)
545
+ await self.send_command(topic, payload, requestID)
541
546
  LOGGER.debug("MQTT: Receiving pingevent command")
542
547
 
543
-
544
548
  async def command_timesync(self) -> None:
545
549
  LOGGER.debug("MQTT: Sending timeSync command")
546
550
 
@@ -551,14 +555,15 @@ class QolsysPluginRemote(QolsysPlugin):
551
555
  responseTopic = "response_" + self.settings.random_mac
552
556
  remoteMacAddress = self.settings.random_mac
553
557
 
554
- payload = {"eventName":eventName,
555
- "startTimestamp": startTimestamp,
556
- "requestID":requestID,
557
- "responseTopic":responseTopic,
558
- "remoteMacAddess":remoteMacAddress,
558
+ payload = {
559
+ "eventName": eventName,
560
+ "startTimestamp": startTimestamp,
561
+ "requestID": requestID,
562
+ "responseTopic": responseTopic,
563
+ "remoteMacAddess": remoteMacAddress,
559
564
  }
560
565
 
561
- await self.send_command(topic,payload,requestID)
566
+ await self.send_command(topic, payload, requestID)
562
567
  LOGGER.debug("MQTT: Receiving timeSync command")
563
568
 
564
569
  async def command_sync_database(self) -> dict:
@@ -577,7 +582,7 @@ class QolsysPluginRemote(QolsysPlugin):
577
582
  "remoteMacAddess": remoteMacAddress,
578
583
  }
579
584
 
580
- response = await self.send_command(topic,payload,requestID)
585
+ response = await self.send_command(topic, payload, requestID)
581
586
  LOGGER.debug("MQTT: Receiving syncdatabase command")
582
587
  return response
583
588
 
@@ -591,13 +596,13 @@ class QolsysPluginRemote(QolsysPlugin):
591
596
  remoteMacAddress = self.settings.random_mac
592
597
  acStatus = "Connected"
593
598
 
594
- payload = {"eventName":eventName,
595
- "acStatus" : acStatus,
596
- "requestID":requestID,
597
- "responseTopic":responseTopic,
598
- "remoteMacAddess":remoteMacAddress}
599
+ payload = {"eventName": eventName,
600
+ "acStatus": acStatus,
601
+ "requestID": requestID,
602
+ "responseTopic": responseTopic,
603
+ "remoteMacAddess": remoteMacAddress}
599
604
 
600
- await self.send_command(topic,payload,requestID)
605
+ await self.send_command(topic, payload, requestID)
601
606
 
602
607
  async def command_dealer_logo(self) -> None:
603
608
  LOGGER.debug("MQTT: Sending dealerLogo command")
@@ -609,13 +614,13 @@ class QolsysPluginRemote(QolsysPlugin):
609
614
  remoteMacAddress = self.settings.random_mac
610
615
 
611
616
  payload = {
612
- "eventName":eventName,
613
- "requestID":requestID,
614
- "responseTopic":responseTopic,
615
- "remoteMacAddess":remoteMacAddress,
617
+ "eventName": eventName,
618
+ "requestID": requestID,
619
+ "responseTopic": responseTopic,
620
+ "remoteMacAddess": remoteMacAddress,
616
621
  }
617
622
 
618
- await self.send_command(topic,payload,requestID)
623
+ await self.send_command(topic, payload, requestID)
619
624
 
620
625
  async def command_pair_status_request(self) -> None:
621
626
  LOGGER.debug("MQTT: Sending pair_status_request command")
@@ -627,13 +632,13 @@ class QolsysPluginRemote(QolsysPlugin):
627
632
  responseTopic = "response_" + self.settings.random_mac
628
633
 
629
634
  payload = {
630
- "eventName":eventName,
631
- "requestID":requestID,
632
- "responseTopic":responseTopic,
633
- "remoteMacAddess":remoteMacAddress,
635
+ "eventName": eventName,
636
+ "requestID": requestID,
637
+ "responseTopic": responseTopic,
638
+ "remoteMacAddess": remoteMacAddress,
634
639
  }
635
640
 
636
- await self.send_command(topic,payload,requestID)
641
+ await self.send_command(topic, payload, requestID)
637
642
  LOGGER.debug("MQTT: Receiving pair_status_request command")
638
643
 
639
644
  async def command_disconnect(self) -> None:
@@ -646,13 +651,13 @@ class QolsysPluginRemote(QolsysPlugin):
646
651
  remoteMacAddress = self.settings.random_mac
647
652
 
648
653
  payload = {
649
- "eventName":eventName,
654
+ "eventName": eventName,
650
655
  "remoteClientID": remoteClientID,
651
- "requestID":requestID,
652
- "remoteMacAddess":remoteMacAddress,
656
+ "requestID": requestID,
657
+ "remoteMacAddess": remoteMacAddress,
653
658
  }
654
659
 
655
- await self.send_command(topic,payload,requestID)
660
+ await self.send_command(topic, payload, requestID)
656
661
 
657
662
  async def command_pairing_request(self) -> dict:
658
663
  LOGGER.debug("MQTT: Sending pairing_request command")
@@ -674,13 +679,13 @@ class QolsysPluginRemote(QolsysPlugin):
674
679
  remoteMacAddress = self.settings.random_mac
675
680
 
676
681
  dhcpInfo = {
677
- "ipaddress":"",
678
- "gateway":"",
679
- "netmask":"",
680
- "dns1":"",
681
- "dns2":"",
682
- "dhcpServer":"",
683
- "leaseDuration":"",
682
+ "ipaddress": "",
683
+ "gateway": "",
684
+ "netmask": "",
685
+ "dns1": "",
686
+ "dns2": "",
687
+ "dhcpServer": "",
688
+ "leaseDuration": "",
684
689
  }
685
690
 
686
691
  payload = {
@@ -689,35 +694,35 @@ class QolsysPluginRemote(QolsysPlugin):
689
694
  "ipAddress": ipAddress,
690
695
  "macAddress": macAddress,
691
696
  "remoteClientID": remoteClientID,
692
- "softwareVersion":softwareVersion,
697
+ "softwareVersion": softwareVersion,
693
698
  "producType": producType,
694
699
  "bssid": bssid,
695
700
  "dhcpInfo": json.dumps(dhcpInfo),
696
701
  "lastUpdateChecksum": lastUpdateChecksum,
697
- "dealerIconsCheckSum" : dealerIconsCheckSum,
702
+ "dealerIconsCheckSum": dealerIconsCheckSum,
698
703
  "remote_feature_support_version": remote_feature_support_version,
699
704
  "requestID": requestID,
700
705
  "responseTopic": responseTopic,
701
706
  "remoteMacAddess": remoteMacAddress,
702
707
  }
703
708
 
704
- response = await self.send_command(topic,payload,requestID)
709
+ response = await self.send_command(topic, payload, requestID)
705
710
  LOGGER.debug("MQTT: Receiving pairing_request command")
706
711
  return response
707
712
 
708
- async def command_ui_delay(self,partition_id:str) -> None:
713
+ async def command_ui_delay(self, partition_id: str) -> None:
709
714
  LOGGER.debug("MQTT: Sending ui_delay command")
710
715
 
711
716
  # partition state needs to be sent for ui_delay to work
712
717
  partition = self.state.partition(partition_id)
713
718
 
714
- arming_command ={
719
+ arming_command = {
715
720
  "operation_name": "ui_delay",
716
721
  "panel_status": partition.system_status,
717
- "userID":0,
718
- "partitionID": partition_id, # STR EXPECTED
722
+ "userID": 0,
723
+ "partitionID": partition_id, # STR EXPECTED
719
724
  "operation_source": 1,
720
- "macAddress" : self.settings.random_mac,
725
+ "macAddress": self.settings.random_mac,
721
726
  }
722
727
 
723
728
  topic = "mastermeid"
@@ -730,9 +735,9 @@ class QolsysPluginRemote(QolsysPlugin):
730
735
  responseTopic = "response_" + self.settings.random_mac
731
736
 
732
737
  payload = {
733
- "eventName":eventName,
734
- "ipcServiceName" : ipcServiceName,
735
- "ipcInterfaceName" : ipcInterfaceName,
738
+ "eventName": eventName,
739
+ "ipcServiceName": ipcServiceName,
740
+ "ipcInterfaceName": ipcInterfaceName,
736
741
  "ipcTransactionID": ipcTransactionID,
737
742
  "ipcRequest": [{
738
743
  "dataType": "string",
@@ -743,11 +748,11 @@ class QolsysPluginRemote(QolsysPlugin):
743
748
  "remoteMacAddress": remoteMacAddress,
744
749
  }
745
750
 
746
- await self.send_command(topic,payload,requestID)
751
+ await self.send_command(topic, payload, requestID)
747
752
  LOGGER.debug("MQTT: Receiving ui_delay command")
748
753
 
749
- async def command_disarm(self,partition_id:str,user_code:str="",exit_sounds:bool=True) -> bool:
750
- LOGGER.debug("MQTT: Sending disarm command - check_user_code:%s",self.check_user_code_on_disarm)
754
+ async def command_disarm(self, partition_id: str, user_code: str = "", exit_sounds: bool = True) -> bool:
755
+ LOGGER.debug("MQTT: Sending disarm command - check_user_code:%s", self.check_user_code_on_disarm)
751
756
 
752
757
  partition = self.state.partition(partition_id)
753
758
  if not partition:
@@ -763,24 +768,28 @@ class QolsysPluginRemote(QolsysPlugin):
763
768
  return False
764
769
 
765
770
  async def get_mqtt_disarm_command() -> str:
766
- if partition.alarm_state == PartitionAlarmState.ALARM:
771
+ if partition.alarm_state == PartitionAlarmState.ALARM:
767
772
  return "disarm_from_emergency"
768
- if partition.system_status in {PartitionSystemStatus.ARM_AWAY_EXIT_DELAY, PartitionSystemStatus.ARM_STAY_EXIT_DELAY,PartitionSystemStatus.ARM_NIGHT_EXIT_DELAY}:
773
+ if partition.system_status in {PartitionSystemStatus.ARM_AWAY_EXIT_DELAY,
774
+ PartitionSystemStatus.ARM_STAY_EXIT_DELAY,
775
+ PartitionSystemStatus.ARM_NIGHT_EXIT_DELAY}:
769
776
  return "disarm_from_openlearn_sensor"
770
- if partition.system_status in {PartitionSystemStatus.ARM_AWAY, PartitionSystemStatus.ARM_STAY, PartitionSystemStatus.ARM_NIGHT}:
777
+ if partition.system_status in {PartitionSystemStatus.ARM_AWAY,
778
+ PartitionSystemStatus.ARM_STAY,
779
+ PartitionSystemStatus.ARM_NIGHT}:
771
780
  await self.command_ui_delay(partition_id)
772
781
  return "disarm_the_panel_from_entry_delay"
773
782
  return "disarm_from_openlearn_sensor"
774
783
 
775
784
  mqtt_disarm_command = await get_mqtt_disarm_command()
776
785
 
777
- disarm_command ={
786
+ disarm_command = {
778
787
  "operation_name": mqtt_disarm_command,
779
- "userID":user_id,
780
- "partitionID":int(partition_id), # INT EXPECTED
788
+ "userID": user_id,
789
+ "partitionID": int(partition_id), # INT EXPECTED
781
790
  "operation_source": 1,
782
791
  "disarm_exit_sounds": exit_sounds,
783
- "macAddress" : self.settings.random_mac,
792
+ "macAddress": self.settings.random_mac,
784
793
  }
785
794
 
786
795
  topic = "mastermeid"
@@ -792,48 +801,48 @@ class QolsysPluginRemote(QolsysPlugin):
792
801
  remoteMacAddress = self.settings.random_mac
793
802
  responseTopic = "response_" + self.settings.random_mac
794
803
 
795
- payload = {"eventName":eventName,
796
- "ipcServiceName" : ipcServiceName,
797
- "ipcInterfaceName" : ipcInterfaceName,
804
+ payload = {"eventName": eventName,
805
+ "ipcServiceName": ipcServiceName,
806
+ "ipcInterfaceName": ipcInterfaceName,
798
807
  "ipcTransactionID": ipcTransactionID,
799
808
  "ipcRequest": [{
800
809
  "dataType": "string",
801
810
  "dataValue": json.dumps(disarm_command),
802
811
  }],
803
- "requestID":requestID,
804
- "responseTopic":responseTopic,
805
- "remoteMacAddress":remoteMacAddress}
812
+ "requestID": requestID,
813
+ "responseTopic": responseTopic,
814
+ "remoteMacAddress": remoteMacAddress}
806
815
 
807
- await self.send_command(topic,payload,requestID)
816
+ await self.send_command(topic, payload, requestID)
808
817
  LOGGER.debug("MQTT: Receiving disarm command")
809
818
 
810
819
  return True
811
820
 
812
- async def command_zwave_switch_multi_level(self,node_id:int,level:int) -> None:
821
+ async def command_zwave_switch_multi_level(self, node_id: int, level: int) -> None:
813
822
 
814
- ipcRequest =[{
815
- "dataType":"int", # Node ID
816
- "dataValue":node_id,
823
+ ipcRequest = [{
824
+ "dataType": "int", # Node ID
825
+ "dataValue": node_id,
817
826
  },
818
827
  {
819
- "dataType":"int", # ?
820
- "dataValue":0,
828
+ "dataType": "int", # ?
829
+ "dataValue": 0,
821
830
  },
822
831
  {
823
- "dataType":"byteArray", # ZWAVE MULTILEVELSWITCH COMMAND
824
- "dataValue":[38,1,level],
832
+ "dataType": "byteArray", # ZWAVE MULTILEVELSWITCH COMMAND
833
+ "dataValue": [38, 1, level],
825
834
  },
826
835
  {
827
- "dataType":"int", # ?
828
- "dataValue":0,
836
+ "dataType": "int", # ?
837
+ "dataValue": 0,
829
838
  },
830
839
  {
831
- "dataType":"int", # ?
832
- "dataValue":106,
840
+ "dataType": "int", # ?
841
+ "dataValue": 106,
833
842
  },
834
843
  {
835
- "dataType":"byteArray",
836
- "dataValue":[0],
844
+ "dataType": "byteArray",
845
+ "dataValue": [0],
837
846
  },
838
847
  ]
839
848
 
@@ -846,21 +855,22 @@ class QolsysPluginRemote(QolsysPlugin):
846
855
  remoteMacAddress = self.settings.random_mac
847
856
  responseTopic = "response_" + self.settings.random_mac
848
857
 
849
- payload = {"eventName":eventName,
850
- "ipcServiceName" : ipcServiceName,
851
- "ipcInterfaceName" : ipcInterfaceName,
858
+ payload = {"eventName": eventName,
859
+ "ipcServiceName": ipcServiceName,
860
+ "ipcInterfaceName": ipcInterfaceName,
852
861
  "ipcTransactionID": ipcTransactionID,
853
862
  "ipcRequest": ipcRequest,
854
- "requestID":requestID,
855
- "responseTopic":responseTopic,
856
- "remoteMacAddress":remoteMacAddress}
857
-
858
- await self.send_command(topic,payload,requestID)
863
+ "requestID": requestID,
864
+ "responseTopic": responseTopic,
865
+ "remoteMacAddress": remoteMacAddress}
859
866
 
867
+ await self.send_command(topic, payload, requestID)
860
868
 
861
- async def command_arm(self,partition_id:str,arming_type:str,user_code:str="",exit_sounds:bool=False,instant_arm:bool=False) -> bool:
869
+ async def command_arm(self, partition_id: str, arming_type: str, user_code: str = "", exit_sounds: bool = False,
870
+ instant_arm: bool = False) -> bool:
862
871
 
863
- LOGGER.debug("MQTT: Sending arm command: partition%s, arming_type:%s, secure_arm:%s",partition_id,arming_type,self.panel.SECURE_ARMING)
872
+ LOGGER.debug("MQTT: Sending arm command: partition%s, arming_type:%s, secure_arm:%s",
873
+ partition_id, arming_type, self.panel.SECURE_ARMING)
864
874
 
865
875
  user_id = 0
866
876
 
@@ -872,7 +882,7 @@ class QolsysPluginRemote(QolsysPlugin):
872
882
  if self.panel.SECURE_ARMING == "true":
873
883
  # Do local user code verification to arm if secure arming is enabled
874
884
  user_id = self.panel.check_user(user_code)
875
- if user_id == -1:
885
+ if user_id == -1:
876
886
  LOGGER.debug("MQTT: arm command error - user_code error")
877
887
  return False
878
888
 
@@ -888,26 +898,26 @@ class QolsysPluginRemote(QolsysPlugin):
888
898
  mqtt_arming_type = "ui_armnight"
889
899
 
890
900
  case _:
891
- LOGGER.debug("MQTT: Sending arm command: Unknow arming_type:%s",arming_type)
901
+ LOGGER.debug("MQTT: Sending arm command: Unknow arming_type:%s", arming_type)
892
902
  return False
893
903
 
894
904
  exitSoundValue = "ON"
895
905
  if not exit_sounds:
896
- exitSoundValue = "OFF"
906
+ exitSoundValue = "OFF"
897
907
 
898
- arming_command ={
908
+ arming_command = {
899
909
  "operation_name": mqtt_arming_type,
900
910
  "bypass_zoneid_set": "[]",
901
- "userID":user_id,
902
- "partitionID":int(partition_id),
911
+ "userID": user_id,
912
+ "partitionID": int(partition_id),
903
913
  "exitSoundValue": exitSoundValue,
904
914
  "entryDelayValue": "OFF",
905
- "multiplePartitionsSelected" : False,
915
+ "multiplePartitionsSelected": False,
906
916
  "instant_arming": instant_arm,
907
- "final_exit_arming_selected" : False,
917
+ "final_exit_arming_selected": False,
908
918
  "manually_selected_zones": "[]",
909
919
  "operation_source": 1,
910
- "macAddress" : self.settings.random_mac,
920
+ "macAddress": self.settings.random_mac,
911
921
  }
912
922
 
913
923
  topic = "mastermeid"
@@ -920,20 +930,19 @@ class QolsysPluginRemote(QolsysPlugin):
920
930
  responseTopic = "response_" + self.settings.random_mac
921
931
 
922
932
  payload = {
923
- "eventName":eventName,
924
- "ipcServiceName" : ipcServiceName,
925
- "ipcInterfaceName" : ipcInterfaceName,
933
+ "eventName": eventName,
934
+ "ipcServiceName": ipcServiceName,
935
+ "ipcInterfaceName": ipcInterfaceName,
926
936
  "ipcTransactionID": ipcTransactionID,
927
937
  "ipcRequest": [{
928
938
  "dataType": "string",
929
939
  "dataValue": json.dumps(arming_command),
930
940
  }],
931
- "requestID":requestID,
932
- "responseTopic":responseTopic,
933
- "remoteMacAddress":remoteMacAddress,
941
+ "requestID": requestID,
942
+ "responseTopic": responseTopic,
943
+ "remoteMacAddress": remoteMacAddress,
934
944
  }
935
945
 
936
- await self.send_command(topic,payload,requestID)
946
+ await self.send_command(topic, payload, requestID)
937
947
 
938
948
  return True
939
-