paradox-alarm-interface 3.4.0__tar.gz → 3.4.2.dev0__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.
Files changed (115) hide show
  1. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/PKG-INFO +5 -5
  2. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/README.md +2 -2
  3. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/__init__.py +1 -1
  4. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/config.py +1 -0
  5. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/connection.py +8 -7
  6. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/protocols.py +17 -15
  7. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/adapters.py +17 -12
  8. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/basic.py +3 -2
  9. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/async_message_manager.py +6 -4
  10. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/handlers.py +9 -5
  11. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/help.py +8 -5
  12. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/paradox.py +56 -57
  13. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/PKG-INFO +5 -5
  14. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/requires.txt +1 -1
  15. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/requirements.txt +1 -1
  16. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/setup.cfg +2 -2
  17. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/LICENSE +0 -0
  18. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/MANIFEST.in +0 -0
  19. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/__init__.py +0 -0
  20. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/connection.py +0 -0
  21. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/handler.py +0 -0
  22. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/__init__.py +0 -0
  23. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/commands.py +0 -0
  24. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/parsers.py +0 -0
  25. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/stun_session.py +0 -0
  26. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/serial_connection.py +0 -0
  27. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/__init__.py +0 -0
  28. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/ip150_connection_decrypt.py +0 -0
  29. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/pai_dump_memory.py +0 -0
  30. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/pai_run.py +0 -0
  31. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/__init__.py +0 -0
  32. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/element_type_container.py +0 -0
  33. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/enums.py +0 -0
  34. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/memory_storage.py +0 -0
  35. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/model.py +0 -0
  36. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/event.py +0 -0
  37. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/exceptions.py +0 -0
  38. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/__init__.py +0 -0
  39. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/common.py +0 -0
  40. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/__init__.py +0 -0
  41. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/adapters.py +0 -0
  42. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/event.py +0 -0
  43. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/__init__.py +0 -0
  44. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo192.py +0 -0
  45. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo48.py +0 -0
  46. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo96.py +0 -0
  47. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evohd.py +0 -0
  48. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/panel.py +0 -0
  49. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/parsers.py +0 -0
  50. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/property.py +0 -0
  51. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/panel.py +0 -0
  52. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/parsers.py +0 -0
  53. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/__init__.py +0 -0
  54. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/event.py +0 -0
  55. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/panel.py +0 -0
  56. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/parsers.py +0 -0
  57. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/property.py +0 -0
  58. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/__init__.py +0 -0
  59. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/interface_manager.py +0 -0
  60. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/__init__.py +0 -0
  61. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/client_connection.py +0 -0
  62. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/interface.py +0 -0
  63. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/__init__.py +0 -0
  64. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/core.py +0 -0
  65. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/__init__.py +0 -0
  66. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/abstract_entity.py +0 -0
  67. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/alarm_control_panel.py +0 -0
  68. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/binary_sensors.py +0 -0
  69. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/device.py +0 -0
  70. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/factory.py +0 -0
  71. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/sensor.py +0 -0
  72. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/switch.py +0 -0
  73. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/helpers.py +0 -0
  74. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/homeassistant.py +0 -0
  75. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/__init__.py +0 -0
  76. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/core.py +0 -0
  77. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/dummy.py +0 -0
  78. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/gsm.py +0 -0
  79. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/homeassistant_notifications.py +0 -0
  80. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/pushbullet.py +0 -0
  81. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/pushover.py +0 -0
  82. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/signal.py +0 -0
  83. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/__init__.py +0 -0
  84. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/crypto.py +0 -0
  85. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/__init__.py +0 -0
  86. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/__init__.py +0 -0
  87. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ar.py +0 -0
  88. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/de.py +0 -0
  89. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/el.py +0 -0
  90. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/en.py +0 -0
  91. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/et.py +0 -0
  92. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/he.py +0 -0
  93. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/hu.py +0 -0
  94. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/pl.py +0 -0
  95. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/pt.py +0 -0
  96. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ro.py +0 -0
  97. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ru.py +0 -0
  98. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/tr.py +0 -0
  99. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/event_filter.py +0 -0
  100. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/format.py +0 -0
  101. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/ps.py +0 -0
  102. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/stun.py +0 -0
  103. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/utils.py +0 -0
  104. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/main.py +0 -0
  105. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/parsers/__init__.py +0 -0
  106. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/parsers/status.py +0 -0
  107. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/SOURCES.txt +0 -0
  108. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/dependency_links.txt +0 -0
  109. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/entry_points.txt +0 -0
  110. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/top_level.txt +0 -0
  111. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/zip-safe +0 -0
  112. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/pyproject.toml +0 -0
  113. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/tests/test_async_queue.py +0 -0
  114. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/tests/test_config.py +0 -0
  115. {paradox-alarm-interface-3.4.0 → paradox_alarm_interface-3.4.2.dev0}/tests/test_paradox.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: paradox-alarm-interface
3
- Version: 3.4.0
3
+ Version: 3.4.2.dev0
4
4
  Summary: Interface to Paradox Alarm Panels
5
5
  Home-page: https://github.com/ParadoxAlarmInterface/pai
6
6
  Author: Jevgeni Kiski, João Paulo Barraca
@@ -18,14 +18,14 @@ Classifier: Programming Language :: Python :: 3.8
18
18
  Classifier: Programming Language :: Python :: 3.9
19
19
  Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
- Requires-Python: >=3.8
21
+ Requires-Python: <3.12,>=3.8
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: construct~=2.9.43
25
25
  Requires-Dist: argparse>=1.4.0
26
26
  Requires-Dist: python-slugify>=4.0.1
27
27
  Requires-Dist: pytz>=2021.3
28
- Requires-Dist: paho_mqtt>=1.5.0
28
+ Requires-Dist: paho_mqtt<2,>=1.5.0
29
29
  Requires-Dist: requests>=2.20.0
30
30
  Requires-Dist: pyserial-asyncio>=0.4
31
31
  Provides-Extra: yaml
@@ -107,8 +107,8 @@ See [wiki](https://github.com/ParadoxAlarmInterface/pai/wiki/Installation)
107
107
  ## Tested Environment
108
108
 
109
109
  Tested in the following environment:
110
- * Python 3.6, 3.7, 3.8
111
- * Mosquitto MQTT Broker >v 1.4.8
110
+ * Python 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
111
+ * Mosquitto MQTT Broker > 1.4.8
112
112
  * OrangePi 2G-IOT, NanoPi NEO, and Raspberry Pi 3 through their built in Serial Port (with a level shifter!), or a USB RS232 TTL adapter (CP2102, PL2303, CH340, etc..)
113
113
  * Ubuntu Server 16.04.3 LTS
114
114
  * Paradox MG5050, SP7000 and EVO panels
@@ -65,8 +65,8 @@ See [wiki](https://github.com/ParadoxAlarmInterface/pai/wiki/Installation)
65
65
  ## Tested Environment
66
66
 
67
67
  Tested in the following environment:
68
- * Python 3.6, 3.7, 3.8
69
- * Mosquitto MQTT Broker >v 1.4.8
68
+ * Python 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
69
+ * Mosquitto MQTT Broker > 1.4.8
70
70
  * OrangePi 2G-IOT, NanoPi NEO, and Raspberry Pi 3 through their built in Serial Port (with a level shifter!), or a USB RS232 TTL adapter (CP2102, PL2303, CH340, etc..)
71
71
  * Ubuntu Server 16.04.3 LTS
72
72
  * Paradox MG5050, SP7000 and EVO panels
@@ -1,3 +1,3 @@
1
- VERSION = "3.4.0"
1
+ VERSION = "3.4.2-dev"
2
2
 
3
3
  __version__ = VERSION
@@ -55,6 +55,7 @@ class Config:
55
55
  "IP_CONNECTION_BARE": False, # IP endpoint connects directly to panel. Used for Serial Tunnels over TCP
56
56
  # Paradox
57
57
  "KEEP_ALIVE_INTERVAL": 10, # Interval between status updates
58
+ "IO_TIMEOUT": 0.5, # Timeout for IO operations
58
59
  "LIMITS": {}, # By default all zones will be monitored
59
60
  "LABEL_ENCODING": "paradox-en", # Encoding to use when decoding labels. paradox-* or https://docs.python.org/3/library/codecs.html#standard-encodings
60
61
  "LABEL_REFRESH_INTERVAL": (
@@ -1,17 +1,15 @@
1
- # -*- coding: utf-8 -*-
2
-
1
+ from abc import ABC, abstractmethod
3
2
  import asyncio
4
3
  import logging
5
- from abc import ABC, abstractmethod
6
4
 
7
5
  from construct import Container
8
6
 
7
+ from paradox.config import config as cfg
9
8
  from paradox.connections.connection import Connection
10
9
  from paradox.connections.handler import IPConnectionHandler
11
10
  from paradox.connections.ip.commands import IPModuleConnectCommand
12
11
  from paradox.connections.ip.stun_session import StunSession
13
- from paradox.connections.protocols import (IPConnectionProtocol,
14
- SerialConnectionProtocol)
12
+ from paradox.connections.protocols import IPConnectionProtocol, SerialConnectionProtocol
15
13
  from paradox.exceptions import PAICriticalException
16
14
  from paradox.lib.handlers import FutureHandler, HandlerRegistry
17
15
 
@@ -94,7 +92,7 @@ class IPConnectionWithEncryption(MultiAttemptConnection, IPConnectionHandler, AB
94
92
  def on_ip_message(self, container: Container):
95
93
  return self.loop.create_task(self.ip_handler_registry.handle(container))
96
94
 
97
- async def wait_for_ip_message(self, timeout=2) -> Container:
95
+ async def wait_for_ip_message(self, timeout=cfg.IO_TIMEOUT) -> Container:
98
96
  future = FutureHandler()
99
97
  return await self.ip_handler_registry.wait_until_complete(future, timeout)
100
98
 
@@ -107,7 +105,10 @@ class IPConnectionWithEncryption(MultiAttemptConnection, IPConnectionHandler, AB
107
105
 
108
106
  class LocalIPConnection(IPConnectionWithEncryption):
109
107
  def __init__(
110
- self, host, port, password,
108
+ self,
109
+ host,
110
+ port,
111
+ password,
111
112
  ):
112
113
  super().__init__(password)
113
114
  self.host = host
@@ -1,12 +1,16 @@
1
+ from abc import abstractmethod
1
2
  import asyncio
2
3
  import binascii
3
4
  import logging
4
- from abc import abstractmethod
5
5
 
6
6
  from paradox.config import config as cfg
7
7
  from paradox.connections.handler import ConnectionHandler, IPConnectionHandler
8
- from paradox.connections.ip.parsers import (IPMessageCommand, IPMessageRequest,
9
- IPMessageResponse, IPMessageType)
8
+ from paradox.connections.ip.parsers import (
9
+ IPMessageCommand,
10
+ IPMessageRequest,
11
+ IPMessageResponse,
12
+ IPMessageType,
13
+ )
10
14
 
11
15
  logger = logging.getLogger("PAI").getChild(__name__)
12
16
 
@@ -52,11 +56,11 @@ class ConnectionProtocol(asyncio.Protocol):
52
56
  if self.transport:
53
57
  try:
54
58
  self.transport.close()
55
- except:
59
+ except Exception:
56
60
  logger.exception("Connection transport close raised Exception")
57
61
  self.transport = None
58
62
 
59
- await asyncio.wait_for(self._closed, timeout=1)
63
+ await asyncio.wait_for(self._closed, timeout=cfg.IO_TIMEOUT)
60
64
 
61
65
  @abstractmethod
62
66
  def send_message(self, message):
@@ -94,7 +98,7 @@ class ConnectionProtocol(asyncio.Protocol):
94
98
  class SerialConnectionProtocol(ConnectionProtocol):
95
99
  def send_message(self, message):
96
100
  if cfg.LOGGING_DUMP_PACKETS:
97
- logger.debug("PAI -> SER {}".format(binascii.hexlify(message)))
101
+ logger.debug(f"PAI -> SER {binascii.hexlify(message)}")
98
102
 
99
103
  self.check_active()
100
104
 
@@ -137,7 +141,7 @@ class SerialConnectionProtocol(ConnectionProtocol):
137
141
  if checksum(frame, min_length):
138
142
  self.buffer = self.buffer[len(frame) :] # Remove message
139
143
  if cfg.LOGGING_DUMP_PACKETS:
140
- logger.debug("SER -> PAI {}".format(binascii.hexlify(frame)))
144
+ logger.debug(f"SER -> PAI {binascii.hexlify(frame)}")
141
145
 
142
146
  self.handler.on_message(frame)
143
147
  else:
@@ -146,14 +150,14 @@ class SerialConnectionProtocol(ConnectionProtocol):
146
150
 
147
151
  class IPConnectionProtocol(ConnectionProtocol):
148
152
  def __init__(self, handler: IPConnectionHandler, key):
149
- super(IPConnectionProtocol, self).__init__(handler)
153
+ super().__init__(handler)
150
154
 
151
155
  self.handler = handler
152
156
  self.key = key
153
157
 
154
158
  def send_raw(self, raw):
155
159
  if cfg.LOGGING_DUMP_PACKETS:
156
- logger.debug("PAI -> IP (raw) {}".format(binascii.hexlify(raw)))
160
+ logger.debug(f"PAI -> IP (raw) {binascii.hexlify(raw)}")
157
161
 
158
162
  self.check_active()
159
163
 
@@ -161,7 +165,7 @@ class IPConnectionProtocol(ConnectionProtocol):
161
165
 
162
166
  def send_message(self, message):
163
167
  if cfg.LOGGING_DUMP_PACKETS:
164
- logger.debug("PAI -> IP (payload) {}".format(binascii.hexlify(message)))
168
+ logger.debug(f"PAI -> IP (payload) {binascii.hexlify(message)}")
165
169
 
166
170
  self.check_active()
167
171
 
@@ -180,7 +184,7 @@ class IPConnectionProtocol(ConnectionProtocol):
180
184
  password=self.key,
181
185
  )
182
186
  if cfg.LOGGING_DUMP_PACKETS:
183
- logger.debug("PAI -> IP (raw) {}".format(binascii.hexlify(msg)))
187
+ logger.debug(f"PAI -> IP (raw) {binascii.hexlify(msg)}")
184
188
 
185
189
  self.transport.write(msg)
186
190
 
@@ -188,9 +192,7 @@ class IPConnectionProtocol(ConnectionProtocol):
188
192
  message = IPMessageResponse.parse(data, password=self.key)
189
193
 
190
194
  if cfg.LOGGING_DUMP_PACKETS:
191
- logger.debug(
192
- "IP -> PAI (payload) {}".format(binascii.hexlify(message.payload))
193
- )
195
+ logger.debug(f"IP -> PAI (payload) {binascii.hexlify(message.payload)}")
194
196
 
195
197
  if message.header.message_type == IPMessageType.serial_passthrough_response:
196
198
  self.handler.on_message(message.payload)
@@ -218,7 +220,7 @@ class IPConnectionProtocol(ConnectionProtocol):
218
220
  return
219
221
 
220
222
  if cfg.LOGGING_DUMP_PACKETS:
221
- logger.debug("IP -> PAI (raw) {}".format(binascii.hexlify(self.buffer)))
223
+ logger.debug(f"IP -> PAI (raw) {binascii.hexlify(self.buffer)}")
222
224
 
223
225
  self._process_message(self.buffer)
224
226
  self.buffer = b""
@@ -1,9 +1,8 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  import datetime
2
+ from enum import Enum
4
3
 
5
4
  from construct import Adapter
6
- from enum import Enum
5
+
7
6
 
8
7
  class DateAdapter(Adapter):
9
8
  def _decode(self, obj, context, path):
@@ -35,7 +34,6 @@ class PartitionStateAdapter(Adapter):
35
34
  states = dict(arm=4, disarm=5, arm_sleep=3, arm_stay=1, none=0)
36
35
 
37
36
  def _decode(self, obj, context, path):
38
-
39
37
  for k, v in enumerate(self.states):
40
38
  if v == obj[0]:
41
39
  return k
@@ -53,7 +51,6 @@ class ZoneStateAdapter(Adapter):
53
51
  states = dict(bypass=0x10)
54
52
 
55
53
  def _decode(self, obj, context, path):
56
-
57
54
  for k, v in enumerate(self.states):
58
55
  if v == obj[0]:
59
56
  return k
@@ -227,16 +224,24 @@ class PGMDefinitionAdapter(Adapter):
227
224
  disabled = sum(obj) == 0
228
225
 
229
226
  if disabled:
230
- return 'disabled'
227
+ return "disabled"
231
228
 
232
229
  try:
233
- activation_event = PGMDefinitionAdapter.PGMEvent(obj[0]) if sum(obj[:3]) != 0 else 'disabled'
234
- except:
235
- activation_event = 'unknown'
230
+ activation_event = (
231
+ PGMDefinitionAdapter.PGMEvent(obj[0])
232
+ if sum(obj[:3]) != 0
233
+ else "disabled"
234
+ )
235
+ except Exception:
236
+ activation_event = "unknown"
236
237
 
237
238
  try:
238
- deactivation_event = PGMDefinitionAdapter.PGMEvent(obj[3]) if sum(obj[3:]) != 0 else 'disabled'
239
- except:
240
- deactivation_event = 'unknown'
239
+ deactivation_event = (
240
+ PGMDefinitionAdapter.PGMEvent(obj[3])
241
+ if sum(obj[3:]) != 0
242
+ else "disabled"
243
+ )
244
+ except Exception:
245
+ deactivation_event = "unknown"
241
246
 
242
247
  return dict(activation=activation_event, deactivation=deactivation_event)
@@ -461,7 +461,8 @@ class BasicMQTTInterface(AbstractMQTTInterface):
461
461
  if i not in labels:
462
462
  continue
463
463
 
464
- for attribute in definitions[i]: # attribute
464
+ definition = {**(definitions[i]), "id": i}
465
+ for attribute in definition: # attribute
465
466
  if element_type == "user" and attribute == "code":
466
467
  continue
467
468
  self._publish(
@@ -469,7 +470,7 @@ class BasicMQTTInterface(AbstractMQTTInterface):
469
470
  element_type,
470
471
  labels[i]["key"],
471
472
  attribute,
472
- definitions[i][attribute],
473
+ definition[attribute],
473
474
  )
474
475
 
475
476
  if (
@@ -4,8 +4,8 @@ from typing import Callable, Optional
4
4
 
5
5
  from construct import Container
6
6
 
7
- from paradox.lib.handlers import (FutureHandler, HandlerRegistry,
8
- PersistentHandler)
7
+ from paradox.config import config as cfg
8
+ from paradox.lib.handlers import FutureHandler, HandlerRegistry, PersistentHandler
9
9
 
10
10
  logger = logging.getLogger("PAI").getChild(__name__)
11
11
 
@@ -27,7 +27,7 @@ class ErrorMessageHandler(PersistentHandler):
27
27
 
28
28
  class AsyncMessageManager:
29
29
  def __init__(self, loop=None):
30
- super(AsyncMessageManager, self).__init__()
30
+ super().__init__()
31
31
 
32
32
  if not loop:
33
33
  loop = asyncio.get_event_loop()
@@ -37,7 +37,9 @@ class AsyncMessageManager:
37
37
  self.raw_handler_registry = HandlerRegistry()
38
38
 
39
39
  async def wait_for_message(
40
- self, check_fn: Optional[Callable[[Container], bool]] = None, timeout=2
40
+ self,
41
+ check_fn: Optional[Callable[[Container], bool]] = None,
42
+ timeout=cfg.IO_TIMEOUT,
41
43
  ) -> Container:
42
44
  return await self.handler_registry.wait_until_complete(
43
45
  FutureHandler(check_fn), timeout
@@ -1,8 +1,10 @@
1
+ from abc import abstractmethod
1
2
  import asyncio
2
3
  import logging
3
- from abc import abstractmethod
4
4
  from typing import Any, Awaitable, Callable, List, Optional, Union
5
5
 
6
+ from paradox.config import config as cfg
7
+
6
8
  logger = logging.getLogger("PAI").getChild(__name__)
7
9
 
8
10
 
@@ -30,7 +32,9 @@ class AlreadyHandledError(Exception):
30
32
 
31
33
  class FutureHandler(Handler, asyncio.Future):
32
34
  def __init__(
33
- self, check_fn: Optional[Callable[[Any], bool]] = None, name=None,
35
+ self,
36
+ check_fn: Optional[Callable[[Any], bool]] = None,
37
+ name=None,
34
38
  ):
35
39
  super().__init__()
36
40
  self.name = name if name is not None else self.__class__.__name__
@@ -53,7 +57,7 @@ class PersistentHandler(Handler):
53
57
  def __init__(
54
58
  self, callback: Callable[[Any], Union[None, Awaitable[None]]], name=None
55
59
  ):
56
- super(PersistentHandler, self).__init__(name)
60
+ super().__init__(name)
57
61
  self._handle = callback
58
62
  self.persistent = True
59
63
 
@@ -90,7 +94,7 @@ class HandlerRegistry:
90
94
  for handler in to_remove:
91
95
  self.remove(handler)
92
96
 
93
- async def wait_until_complete(self, handler: Handler, timeout=2):
97
+ async def wait_until_complete(self, handler: Handler, timeout=cfg.IO_TIMEOUT):
94
98
  self.append(handler)
95
99
  try:
96
100
  return await asyncio.wait_for(handler, timeout=timeout)
@@ -112,7 +116,7 @@ class HandlerRegistry:
112
116
  await handler(data)
113
117
  except AlreadyHandledError:
114
118
  logger.error("Already handled")
115
- except:
119
+ except Exception:
116
120
  logger.exception("Exception caught during message handling")
117
121
  raise
118
122
 
@@ -33,7 +33,9 @@ MODULES = {
33
33
  "ws4py": dict(
34
34
  mandatory=False, desc="the Pushbullet interface", install_name="ws4py>=0.4.2"
35
35
  ),
36
- "yaml": dict(mandatory=False, desc="the IP150 connection", install_name="pyyaml>=5.2.0"),
36
+ "yaml": dict(
37
+ mandatory=False, desc="the IP150 connection", install_name="pyyaml>=5.2.0"
38
+ ),
37
39
  "chump": dict(
38
40
  mandatory=False, desc="the Pushover interface", install_name="chump>=1.6.0"
39
41
  ),
@@ -44,9 +46,10 @@ MODULES = {
44
46
  mandatory=False, desc="the Signal interface", install_name="pygobject>=3.20.0"
45
47
  ),
46
48
  "gi": dict(mandatory=False, desc="the Signal interface", install_name="gi>=1.2"),
47
- "pytz": dict(mandatory=False, desc="Panel time sync", install_name="pytz>=2023.3.post1"),
48
- "mqtt": dict(mandatory=False, desc="MQTT", install_name="paho_mqtt>=1.5.0"),
49
-
49
+ "pytz": dict(
50
+ mandatory=False, desc="Panel time sync", install_name="pytz>=2023.3.post1"
51
+ ),
52
+ "mqtt": dict(mandatory=False, desc="MQTT", install_name="paho_mqtt>=1.5.0,<2"),
50
53
  "pre-commit": dict(mandatory=False, desc="Development", install_name="pre-commit"),
51
54
  "flake8": dict(mandatory=False, desc="Code checker", install_name="flake8"),
52
55
  "tox": dict(mandatory=False, desc="virtual env / testing", install_name="tox"),
@@ -54,7 +57,7 @@ MODULES = {
54
57
 
55
58
 
56
59
  def import_error_help(error):
57
- logger.error("Could not import Python3 module '{}': {}\n".format(error.name, error))
60
+ logger.error(f"Could not import Python3 module '{error.name}': {error}\n")
58
61
 
59
62
  if error.name in MODULES:
60
63
  m = MODULES[error.name]
@@ -1,14 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  import asyncio
4
- import logging
5
- import time
6
- import pytz
7
2
  from binascii import hexlify
8
3
  from datetime import datetime
9
- from typing import Callable, Iterable, Optional, Sequence
4
+ import logging
5
+ import time
6
+ from typing import Callable, Iterable, Optional
10
7
 
11
8
  from construct import Container
9
+ import pytz
12
10
 
13
11
  from paradox.config import config as cfg, get_limits_for_type
14
12
  from paradox.connections.connection import Connection
@@ -16,13 +14,16 @@ from paradox.data.enums import RunState
16
14
  from paradox.data.memory_storage import MemoryStorage as Storage
17
15
  from paradox.data.model import DetectedPanel
18
16
  from paradox.event import Change, ChangeEvent, Event, LiveEvent
19
- from paradox.exceptions import (AuthenticationFailed, PanelNotDetected,
20
- StatusRequestException,
21
- async_loop_unhandled_exception_handler, CodeLockout)
17
+ from paradox.exceptions import (
18
+ AuthenticationFailed,
19
+ CodeLockout,
20
+ PanelNotDetected,
21
+ StatusRequestException,
22
+ async_loop_unhandled_exception_handler,
23
+ )
22
24
  from paradox.hardware import Panel, create_panel
23
25
  from paradox.lib import ps
24
- from paradox.lib.async_message_manager import (ErrorMessageHandler,
25
- EventMessageHandler)
26
+ from paradox.lib.async_message_manager import ErrorMessageHandler, EventMessageHandler
26
27
  from paradox.lib.handlers import PersistentHandler
27
28
  from paradox.lib.utils import deep_merge
28
29
  from paradox.parsers.status import convert_raw_status
@@ -35,7 +36,7 @@ class Paradox:
35
36
  self.panel: Panel = None
36
37
  self._connection: Connection = None
37
38
  self.retries = retries
38
- self.work_loop = asyncio.get_event_loop() # type: asyncio.AbstractEventLoop
39
+ self.work_loop = asyncio.get_event_loop()
39
40
  self.work_loop.set_exception_handler(async_loop_unhandled_exception_handler)
40
41
 
41
42
  self.storage = Storage()
@@ -70,7 +71,8 @@ class Paradox:
70
71
  from paradox.connections.serial_connection import SerialCommunication
71
72
 
72
73
  self._connection = SerialCommunication(
73
- port=cfg.SERIAL_PORT, baud=cfg.SERIAL_BAUD,
74
+ port=cfg.SERIAL_PORT,
75
+ baud=cfg.SERIAL_BAUD,
74
76
  )
75
77
  elif cfg.CONNECTION_TYPE == "IP":
76
78
  logger.info("Using IP Connection")
@@ -81,10 +83,7 @@ class Paradox:
81
83
  self._connection = BareIPConnection(
82
84
  host=cfg.IP_CONNECTION_HOST, port=cfg.IP_CONNECTION_PORT
83
85
  )
84
- elif (
85
- cfg.IP_CONNECTION_SITEID
86
- and cfg.IP_CONNECTION_EMAIL
87
- ):
86
+ elif cfg.IP_CONNECTION_SITEID and cfg.IP_CONNECTION_EMAIL:
88
87
  from paradox.connections.ip.connection import StunIPConnection
89
88
 
90
89
  self._connection = StunIPConnection(
@@ -102,9 +101,7 @@ class Paradox:
102
101
  password=cfg.IP_CONNECTION_PASSWORD,
103
102
  )
104
103
  else:
105
- raise AssertionError(
106
- "Invalid connection type: {}".format(cfg.CONNECTION_TYPE)
107
- )
104
+ raise AssertionError(f"Invalid connection type: {cfg.CONNECTION_TYPE}")
108
105
 
109
106
  self._register_connection_handlers()
110
107
 
@@ -140,7 +137,7 @@ class Paradox:
140
137
  initiate_reply = await self.send_wait(
141
138
  self.panel.get_message("InitiateCommunication"),
142
139
  None,
143
- reply_expected=0x7
140
+ reply_expected=0x7,
144
141
  )
145
142
 
146
143
  if initiate_reply:
@@ -156,9 +153,7 @@ class Paradox:
156
153
  initiate_reply.fields.value.serial_number
157
154
  ).decode()
158
155
 
159
- logger.info(
160
- "Panel Identified {} version {}".format(model, firmware_version)
161
- )
156
+ logger.info(f"Panel Identified {model} version {firmware_version}")
162
157
  else:
163
158
  raise ConnectionError("Panel did not replied to InitiateCommunication")
164
159
 
@@ -251,7 +246,9 @@ class Paradox:
251
246
  tzinfo = pytz.timezone(cfg.SYNC_TIME_TIMEZONE)
252
247
  now = now.astimezone(tzinfo)
253
248
  except pytz.exceptions.UnknownTimeZoneError:
254
- logger.debug(f"Panel Timezone Unknown ('{cfg.SYNC_TIME_TIMEZONE}'). Skipping sync")
249
+ logger.debug(
250
+ f"Panel Timezone Unknown ('{cfg.SYNC_TIME_TIMEZONE}'). Skipping sync"
251
+ )
255
252
  return
256
253
 
257
254
  if not self._is_time_sync_required(now.replace(tzinfo=None)):
@@ -297,13 +294,13 @@ class Paradox:
297
294
  logger.error("Lost communication with panel")
298
295
  await self.disconnect()
299
296
  return
300
- except:
297
+ except Exception:
301
298
  logger.exception("Loop")
302
299
  finally:
303
300
  self.busy.release()
304
301
 
305
302
  if replies_missing > 0:
306
- logger.debug("Loop: Replies missing: {}".format(replies_missing))
303
+ logger.debug(f"Loop: Replies missing: {replies_missing}")
307
304
 
308
305
  # cfg.Listen for events
309
306
 
@@ -353,15 +350,14 @@ class Paradox:
353
350
  # No message
354
351
  if recv_message is None:
355
352
  logger.debug(
356
- "Unknown message: %s"
357
- % (" ".join("{:02x} ".format(c) for c in message))
353
+ "Unknown message: %s" % (" ".join(f"{c:02x} " for c in message))
358
354
  )
359
355
  return
360
356
 
361
357
  self.connection.schedule_message_handling(
362
358
  recv_message
363
359
  ) # schedule handling in the loop
364
- except:
360
+ except Exception:
365
361
  logger.exception("Error parsing message")
366
362
 
367
363
  async def send_wait(
@@ -370,10 +366,9 @@ class Paradox:
370
366
  args=None,
371
367
  message=None,
372
368
  retries=5,
373
- timeout=0.5,
369
+ timeout=cfg.IO_TIMEOUT,
374
370
  reply_expected=None,
375
371
  ) -> Optional[Container]:
376
-
377
372
  # Connection closed
378
373
  if not self.connection.connected:
379
374
  raise ConnectionError("Not connected")
@@ -422,12 +417,12 @@ class Paradox:
422
417
  except ConnectionError:
423
418
  result = "connection error"
424
419
  raise
425
- except:
420
+ except Exception:
426
421
  result = "exception"
427
422
  logger.exception("Unexpected exception during send_wait")
428
423
  raise
429
- #finally:
430
- #logger.debug("send/receive %s in %.4f s", result, time.time() - t1)
424
+ finally:
425
+ logger.debug("send/receive %s in %.4f s", result, time.time() - t1)
431
426
 
432
427
  attempt += 1
433
428
 
@@ -435,11 +430,9 @@ class Paradox:
435
430
 
436
431
  async def control_zone(self, zone: str, command: str) -> bool:
437
432
  command = command.lower()
438
- logger.debug("Control Zone: {} - {}".format(zone, command))
433
+ logger.debug(f"Control Zone: {zone} - {command}")
439
434
 
440
- zones_selected = self.storage.get_container("zone").select(
441
- zone
442
- ) # type: Sequence[int]
435
+ zones_selected = self.storage.get_container("zone").select(zone)
443
436
 
444
437
  # Not Found
445
438
  if len(zones_selected) == 0:
@@ -464,11 +457,9 @@ class Paradox:
464
457
 
465
458
  async def control_partition(self, partition: str, command: str) -> bool:
466
459
  command = command.lower()
467
- logger.debug("Control Partition: {} - {}".format(partition, command))
460
+ logger.debug(f"Control Partition: {partition} - {command}")
468
461
 
469
- partitions_selected = self.storage.get_container("partition").select(
470
- partition
471
- ) # type: Sequence[int]
462
+ partitions_selected = self.storage.get_container("partition").select(partition)
472
463
 
473
464
  # Not Found
474
465
  if len(partitions_selected) == 0:
@@ -493,7 +484,7 @@ class Paradox:
493
484
 
494
485
  async def control_output(self, output, command) -> bool:
495
486
  command = command.lower()
496
- logger.debug("Control Output: {} - {}".format(output, command))
487
+ logger.debug(f"Control Output: {output} - {command}")
497
488
 
498
489
  outputs_selected = self.storage.get_container("pgm").select(output)
499
490
 
@@ -545,7 +536,7 @@ class Paradox:
545
536
 
546
537
  async def control_door(self, door, command) -> bool:
547
538
  command = command.lower()
548
- logger.debug("Control Door: {} - {}".format(door, command))
539
+ logger.debug(f"Control Door: {door} - {command}")
549
540
 
550
541
  doors_selected = self.storage.get_container("door").select(door)
551
542
 
@@ -585,7 +576,7 @@ class Paradox:
585
576
  event_map=self.panel.event_map,
586
577
  label_provider=self.get_label,
587
578
  )
588
- except AssertionError as e:
579
+ except AssertionError:
589
580
  logger.debug("Error creating event")
590
581
  return
591
582
 
@@ -633,7 +624,7 @@ class Paradox:
633
624
 
634
625
  ps.sendEvent(evt)
635
626
 
636
- except:
627
+ except Exception:
637
628
  logger.exception("Handle live event")
638
629
 
639
630
  def handle_error_message(self, message):
@@ -644,7 +635,7 @@ class Paradox:
644
635
  asyncio.get_event_loop().create_task(self.disconnect())
645
636
  else:
646
637
  message = self.panel.get_error_message(error_enum)
647
- logger.error("Got ERROR Message: {}".format(message))
638
+ logger.error(f"Got ERROR Message: {message}")
648
639
  if message == "Invalid PC Password":
649
640
  raise AuthenticationFailed()
650
641
  elif "code lockout" in message:
@@ -709,7 +700,13 @@ class Paradox:
709
700
  if element_type in ["troubles"]: # troubles was already parsed
710
701
  continue
711
702
  for element_item_key, element_item_status in element_items.items():
712
- if isinstance(element_item_status, (dict, list,)):
703
+ if isinstance(
704
+ element_item_status,
705
+ (
706
+ dict,
707
+ list,
708
+ ),
709
+ ):
713
710
  self.storage.update_container_object(
714
711
  element_type, element_item_key, element_item_status
715
712
  )
@@ -746,13 +743,15 @@ class Paradox:
746
743
  def _is_time_sync_required(self, now) -> bool:
747
744
  assert now.tzinfo is None
748
745
  try:
749
- drift = (now - self.storage.get_container("system")["date"]["time"]).total_seconds()
746
+ drift = (
747
+ now - self.storage.get_container("system")["date"]["time"]
748
+ ).total_seconds()
750
749
 
751
- if abs(drift) > cfg.SYNC_TIME_MIN_DRIFT:
752
- logger.info(f"Time drifted more than allowed: {drift} seconds")
753
- return True
754
- else:
755
- logger.debug(f"Time drifted within allowed range: {drift} seconds")
750
+ if abs(drift) > cfg.SYNC_TIME_MIN_DRIFT:
751
+ logger.info(f"Time drifted more than allowed: {drift} seconds")
752
+ return True
753
+ else:
754
+ logger.debug(f"Time drifted within allowed range: {drift} seconds")
756
755
 
757
756
  except KeyError:
758
757
  pass
@@ -795,7 +794,7 @@ class Paradox:
795
794
 
796
795
  def _on_event(self, event: Event):
797
796
  if cfg.LOGGING_DUMP_EVENTS:
798
- logger.debug("LiveEvent: {}".format(event))
797
+ logger.debug(f"LiveEvent: {event}")
799
798
 
800
799
  event.call_hook(storage=self.storage, alarm=self)
801
800
 
@@ -813,7 +812,7 @@ class Paradox:
813
812
  label_provider=self.get_label,
814
813
  )
815
814
  if cfg.LOGGING_DUMP_EVENTS:
816
- logger.debug("ChangeEvent: {}".format(event))
815
+ logger.debug(f"ChangeEvent: {event}")
817
816
  ps.sendEvent(event)
818
817
  except AssertionError:
819
818
  logger.debug("Could not create event from change")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: paradox-alarm-interface
3
- Version: 3.4.0
3
+ Version: 3.4.2.dev0
4
4
  Summary: Interface to Paradox Alarm Panels
5
5
  Home-page: https://github.com/ParadoxAlarmInterface/pai
6
6
  Author: Jevgeni Kiski, João Paulo Barraca
@@ -18,14 +18,14 @@ Classifier: Programming Language :: Python :: 3.8
18
18
  Classifier: Programming Language :: Python :: 3.9
19
19
  Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
- Requires-Python: >=3.8
21
+ Requires-Python: <3.12,>=3.8
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: construct~=2.9.43
25
25
  Requires-Dist: argparse>=1.4.0
26
26
  Requires-Dist: python-slugify>=4.0.1
27
27
  Requires-Dist: pytz>=2021.3
28
- Requires-Dist: paho_mqtt>=1.5.0
28
+ Requires-Dist: paho_mqtt<2,>=1.5.0
29
29
  Requires-Dist: requests>=2.20.0
30
30
  Requires-Dist: pyserial-asyncio>=0.4
31
31
  Provides-Extra: yaml
@@ -107,8 +107,8 @@ See [wiki](https://github.com/ParadoxAlarmInterface/pai/wiki/Installation)
107
107
  ## Tested Environment
108
108
 
109
109
  Tested in the following environment:
110
- * Python 3.6, 3.7, 3.8
111
- * Mosquitto MQTT Broker >v 1.4.8
110
+ * Python 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
111
+ * Mosquitto MQTT Broker > 1.4.8
112
112
  * OrangePi 2G-IOT, NanoPi NEO, and Raspberry Pi 3 through their built in Serial Port (with a level shifter!), or a USB RS232 TTL adapter (CP2102, PL2303, CH340, etc..)
113
113
  * Ubuntu Server 16.04.3 LTS
114
114
  * Paradox MG5050, SP7000 and EVO panels
@@ -2,7 +2,7 @@ construct~=2.9.43
2
2
  argparse>=1.4.0
3
3
  python-slugify>=4.0.1
4
4
  pytz>=2021.3
5
- paho_mqtt>=1.5.0
5
+ paho_mqtt<2,>=1.5.0
6
6
  requests>=2.20.0
7
7
  pyserial-asyncio>=0.4
8
8
 
@@ -2,7 +2,7 @@ argparse>=1.4.0
2
2
  chump>=1.6.0
3
3
  construct~=2.9.43
4
4
  flake8
5
- paho_mqtt>=1.5.0
5
+ paho_mqtt>=1.5.0,<2
6
6
 
7
7
  pre-commit
8
8
  pushbullet.py>=0.11.0
@@ -26,13 +26,13 @@ license = EPL
26
26
  [options]
27
27
  zip_safe = True
28
28
  packages = find:
29
- python_requires = >=3.8
29
+ python_requires = >=3.8,<3.12
30
30
  install_requires =
31
31
  construct~=2.9.43
32
32
  argparse>=1.4.0
33
33
  python-slugify>=4.0.1
34
34
  pytz>=2021.3
35
- paho_mqtt>=1.5.0
35
+ paho_mqtt>=1.5.0,<2
36
36
  requests>=2.20.0
37
37
  pyserial-asyncio>=0.4
38
38