paradox-alarm-interface 3.3.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.
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/PKG-INFO +5 -5
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/README.md +2 -2
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/__init__.py +1 -1
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/config.py +1 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/connection.py +8 -7
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/protocols.py +17 -15
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/ip150_connection_decrypt.py +61 -27
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/__init__.py +1 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/common.py +1 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/panel.py +40 -28
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/adapters.py +17 -12
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/interface.py +8 -12
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/basic.py +3 -2
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/async_message_manager.py +6 -4
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/handlers.py +9 -5
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/help.py +8 -5
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/paradox.py +56 -57
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/PKG-INFO +5 -5
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/requires.txt +1 -1
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/requirements.txt +1 -1
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/setup.cfg +2 -2
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/LICENSE +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/MANIFEST.in +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/connection.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/handler.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/commands.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/parsers.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/ip/stun_session.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/connections/serial_connection.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/pai_dump_memory.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/console_scripts/pai_run.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/element_type_container.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/enums.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/memory_storage.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/data/model.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/event.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/exceptions.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/adapters.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/event.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo192.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo48.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evo96.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/models/evohd.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/parsers.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/property.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/panel.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/parsers.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/event.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/panel.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/parsers.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/spectra_magellan/property.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/interface_manager.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/ip_interface/client_connection.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/core.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/abstract_entity.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/alarm_control_panel.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/binary_sensors.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/device.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/factory.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/sensor.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/entities/switch.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/helpers.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/mqtt/homeassistant.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/core.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/dummy.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/gsm.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/homeassistant_notifications.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/pushbullet.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/pushover.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/interfaces/text/signal.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/crypto.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ar.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/de.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/el.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/en.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/et.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/he.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/hu.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/pl.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/pt.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ro.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/ru.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/encodings/charmaps/tr.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/event_filter.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/format.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/ps.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/stun.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/lib/utils.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/main.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/parsers/__init__.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/parsers/status.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/SOURCES.txt +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/dependency_links.txt +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/entry_points.txt +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/top_level.txt +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox_alarm_interface.egg-info/zip-safe +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/pyproject.toml +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/tests/test_async_queue.py +0 -0
- {paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/tests/test_config.py +0 -0
- {paradox-alarm-interface-3.3.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.
|
|
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:
|
|
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
|
|
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 >
|
|
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 >
|
|
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
|
|
@@ -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
|
-
|
|
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
|
|
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=
|
|
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,
|
|
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 (
|
|
9
|
-
|
|
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=
|
|
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 {
|
|
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 {
|
|
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(
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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,27 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
import argparse
|
|
3
3
|
import binascii
|
|
4
|
-
import traceback
|
|
5
4
|
from collections import OrderedDict
|
|
5
|
+
import re
|
|
6
|
+
import traceback
|
|
6
7
|
|
|
7
8
|
import yaml
|
|
8
9
|
|
|
9
|
-
from paradox.connections.ip.parsers import (
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
from paradox.connections.ip.parsers import (
|
|
11
|
+
IPMessageCommand,
|
|
12
|
+
IPMessageRequest,
|
|
13
|
+
IPMessageResponse,
|
|
14
|
+
IPMessageType,
|
|
15
|
+
IPPayloadConnectResponse,
|
|
16
|
+
)
|
|
12
17
|
from paradox.hardware import create_panel
|
|
13
18
|
from paradox.hardware.parsers import InitiateCommunicationResponse
|
|
14
19
|
|
|
15
20
|
|
|
16
|
-
class Colors:
|
|
17
|
-
RED =
|
|
18
|
-
ENDC =
|
|
19
|
-
GREEN =
|
|
20
|
-
YELLOW =
|
|
21
|
-
BLUE =
|
|
22
|
-
MAGENTA =
|
|
23
|
-
CYAN =
|
|
24
|
-
ON_WHITE =
|
|
21
|
+
class Colors: # You may need to change color settings
|
|
22
|
+
RED = "\033[31m"
|
|
23
|
+
ENDC = "\033[m"
|
|
24
|
+
GREEN = "\033[32m"
|
|
25
|
+
YELLOW = "\033[33m"
|
|
26
|
+
BLUE = "\033[34m"
|
|
27
|
+
MAGENTA = "\033[95m"
|
|
28
|
+
CYAN = "\033[96m"
|
|
29
|
+
ON_WHITE = "\033[30m\033[47m"
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
def ordered_load(stream, Loader=yaml.loader.SafeLoader, object_pairs_hook=OrderedDict):
|
|
@@ -54,14 +59,22 @@ class PayloadParser:
|
|
|
54
59
|
elif message_type == IPMessageType.ip_response:
|
|
55
60
|
self._parse_ip_response(parsed)
|
|
56
61
|
except Exception:
|
|
62
|
+
print(f"{Colors.RED}Failed to parse message: \n{parsed}{Colors.ENDC}")
|
|
57
63
|
traceback.print_exc()
|
|
58
64
|
|
|
59
65
|
def _parse_ip_response(self, parsed):
|
|
60
|
-
if
|
|
61
|
-
|
|
66
|
+
if (
|
|
67
|
+
parsed.header.command == IPMessageCommand.connect
|
|
68
|
+
and parsed.header.sub_command == 0
|
|
69
|
+
):
|
|
70
|
+
print(
|
|
71
|
+
f"{Colors.ON_WHITE}{IPPayloadConnectResponse.parse(parsed.payload)}{Colors.ENDC}"
|
|
72
|
+
)
|
|
62
73
|
if len(parsed.payload) > 25:
|
|
63
74
|
p = parsed.payload[25:62]
|
|
64
|
-
print(
|
|
75
|
+
print(
|
|
76
|
+
f"{Colors.ON_WHITE}InitiateCommunicationResponse:\n{InitiateCommunicationResponse.parse(p)}{Colors.ENDC}"
|
|
77
|
+
)
|
|
65
78
|
elif parsed.header.command == IPMessageCommand.multicommand:
|
|
66
79
|
self._parse_multicommand(parsed, "frompanel")
|
|
67
80
|
else:
|
|
@@ -74,7 +87,7 @@ class PayloadParser:
|
|
|
74
87
|
self._parse_generic_multicommand(parsed, direction)
|
|
75
88
|
elif parsed.header.sub_command == 0x1: # MGSP multiread
|
|
76
89
|
self._parse_generic_mgsp_multiread(parsed, direction)
|
|
77
|
-
elif parsed.header.sub_command ==
|
|
90
|
+
elif parsed.header.sub_command == 0xDD: # Unified multiread
|
|
78
91
|
pass
|
|
79
92
|
|
|
80
93
|
def _parse_serial_passthrough_response(self, parsed):
|
|
@@ -95,7 +108,9 @@ class PayloadParser:
|
|
|
95
108
|
ram_address = parsed_payload.fields.value.address
|
|
96
109
|
ram_parser = self.panel.get_message("RAMDataParserMap").get(ram_address)
|
|
97
110
|
if ram_parser is not None:
|
|
98
|
-
print(
|
|
111
|
+
print(
|
|
112
|
+
f"{Colors.ON_WHITE}{ram_parser.parse(parsed_payload.fields.value.data)}{Colors.ENDC}"
|
|
113
|
+
)
|
|
99
114
|
else:
|
|
100
115
|
print(
|
|
101
116
|
f"{Colors.RED}No parser for {ram_address} ram address, data: {binascii.hexlify(parsed_payload.fields.value.data)}{Colors.ENDC}"
|
|
@@ -105,14 +120,16 @@ class PayloadParser:
|
|
|
105
120
|
if parsed.header.command == IPMessageCommand.multicommand:
|
|
106
121
|
self._parse_multicommand(parsed, "topanel")
|
|
107
122
|
else:
|
|
108
|
-
print(
|
|
123
|
+
print(
|
|
124
|
+
f"{Colors.RED}No parser for ip_request payload: {binascii.hexlify(parsed.payload)}{Colors.ENDC}"
|
|
125
|
+
)
|
|
109
126
|
|
|
110
127
|
def _parse_generic_multicommand(self, parsed, direction: str):
|
|
111
128
|
i = 0
|
|
112
129
|
while i < len(parsed.payload):
|
|
113
130
|
cmd_len = parsed.payload[i]
|
|
114
131
|
i += 1
|
|
115
|
-
cmd = parsed.payload[i:i + cmd_len]
|
|
132
|
+
cmd = parsed.payload[i : i + cmd_len]
|
|
116
133
|
assert len(cmd) == cmd_len
|
|
117
134
|
i += cmd_len
|
|
118
135
|
print(f"{Colors.ON_WHITE}Multicommand: {cmd}{Colors.ENDC}")
|
|
@@ -130,9 +147,20 @@ class PayloadParser:
|
|
|
130
147
|
return parsed_payload
|
|
131
148
|
|
|
132
149
|
def _parse_generic_mgsp_multiread(self, parsed, direction):
|
|
133
|
-
print(
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
print(f"{Colors.RED}No parser for {direction} mgsp_multiread{Colors.ENDC}")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def old_yaml_format_traverser(data):
|
|
154
|
+
re_key = re.compile(r"peer(\d+)_(\d+)")
|
|
155
|
+
for key, value in data.items():
|
|
156
|
+
# example peer0_0, where 0 is peer number and 0 is index number
|
|
157
|
+
matches = re_key.match(key)
|
|
158
|
+
|
|
159
|
+
yield {
|
|
160
|
+
"peer": int(matches.group(1)),
|
|
161
|
+
"data": value,
|
|
162
|
+
"index": int(matches.group(2)),
|
|
163
|
+
}
|
|
136
164
|
|
|
137
165
|
|
|
138
166
|
def decrypt_file(file, password, max_packets: int = None):
|
|
@@ -140,9 +168,16 @@ def decrypt_file(file, password, max_packets: int = None):
|
|
|
140
168
|
data = ordered_load(file, yaml.loader.SafeLoader)
|
|
141
169
|
parser = PayloadParser()
|
|
142
170
|
|
|
171
|
+
if "peers" in data and "packets" in data:
|
|
172
|
+
iterator = data["packets"]
|
|
173
|
+
else:
|
|
174
|
+
iterator = old_yaml_format_traverser(data)
|
|
175
|
+
|
|
143
176
|
n = 0
|
|
144
|
-
for
|
|
145
|
-
|
|
177
|
+
for packet in iterator:
|
|
178
|
+
value = packet["data"]
|
|
179
|
+
key = packet["index"]
|
|
180
|
+
if not value[0] == 0xAA:
|
|
146
181
|
print(f"{Colors.RED}Not an IP packet: {value}{Colors.ENDC}")
|
|
147
182
|
continue
|
|
148
183
|
header = value[0:16]
|
|
@@ -167,7 +202,6 @@ def decrypt_file(file, password, max_packets: int = None):
|
|
|
167
202
|
if parsed.header.sub_command == 0:
|
|
168
203
|
assert password == parsed.payload, "Wrong decryption password"
|
|
169
204
|
|
|
170
|
-
|
|
171
205
|
if (
|
|
172
206
|
parsed.header.command == IPMessageCommand.connect
|
|
173
207
|
and parsed.header.message_type == IPMessageType.ip_response
|
|
@@ -187,7 +221,7 @@ def decrypt_file(file, password, max_packets: int = None):
|
|
|
187
221
|
|
|
188
222
|
print(
|
|
189
223
|
f"\tpayload: {binascii.hexlify(parsed.payload)}\n",
|
|
190
|
-
f"\tpayload_raw: {parsed.payload}"
|
|
224
|
+
f"\tpayload_raw: {parsed.payload}",
|
|
191
225
|
)
|
|
192
226
|
|
|
193
227
|
print(parsed)
|
{paradox-alarm-interface-3.3.0 → paradox_alarm_interface-3.4.2.dev0}/paradox/hardware/evo/panel.py
RENAMED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
import binascii
|
|
4
2
|
import inspect
|
|
5
3
|
import logging
|
|
@@ -10,17 +8,26 @@ from construct import ChecksumError, Construct, Container, MappingError
|
|
|
10
8
|
from paradox.config import config as cfg
|
|
11
9
|
from paradox.exceptions import AuthenticationFailed, StatusRequestException
|
|
12
10
|
|
|
13
|
-
from ..panel import Panel as PanelBase
|
|
14
11
|
from . import parsers
|
|
12
|
+
from ..panel import Panel as PanelBase
|
|
15
13
|
from .event import event_map
|
|
16
14
|
from .property import property_map
|
|
17
15
|
|
|
18
16
|
logger = logging.getLogger("PAI").getChild(__name__)
|
|
19
17
|
|
|
20
18
|
ZONE_ACTIONS = dict(
|
|
21
|
-
bypass={
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
bypass={
|
|
20
|
+
"flags": {"bypassed": True},
|
|
21
|
+
"operation": "set",
|
|
22
|
+
},
|
|
23
|
+
clear_bypass={
|
|
24
|
+
"flags": {"bypassed": True},
|
|
25
|
+
"operation": "clear",
|
|
26
|
+
},
|
|
27
|
+
clear_alarm_memory={
|
|
28
|
+
"flags": {"generated_alarm": True},
|
|
29
|
+
"operation": "clear",
|
|
30
|
+
},
|
|
24
31
|
)
|
|
25
32
|
|
|
26
33
|
|
|
@@ -33,14 +40,14 @@ class Panel_EVOBase(PanelBase):
|
|
|
33
40
|
def __init__(
|
|
34
41
|
self, core, start_communication_response, variable_message_length=True
|
|
35
42
|
):
|
|
36
|
-
super(
|
|
43
|
+
super().__init__(core, variable_message_length)
|
|
37
44
|
|
|
38
45
|
self._populate_settings(start_communication_response)
|
|
39
46
|
|
|
40
47
|
def _populate_settings(self, start_communication_response):
|
|
41
48
|
raw_data = (
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
start_communication_response.fields.data
|
|
50
|
+
+ start_communication_response.checksum
|
|
44
51
|
)
|
|
45
52
|
parsed = parsers.InitializeCommunication.parse(raw_data)
|
|
46
53
|
if cfg.LOGGING_DUMP_MESSAGES:
|
|
@@ -55,7 +62,7 @@ class Panel_EVOBase(PanelBase):
|
|
|
55
62
|
except ResourceWarning:
|
|
56
63
|
pass
|
|
57
64
|
|
|
58
|
-
return super(
|
|
65
|
+
return super().get_message(name)
|
|
59
66
|
|
|
60
67
|
async def dump_memory(self, file, memory_type):
|
|
61
68
|
"""
|
|
@@ -73,6 +80,12 @@ class Panel_EVOBase(PanelBase):
|
|
|
73
80
|
mem_type = "RAM" if ram else "EEPROM"
|
|
74
81
|
logger.info("Dump " + mem_type)
|
|
75
82
|
|
|
83
|
+
def expect(command, address):
|
|
84
|
+
return (
|
|
85
|
+
lambda m: m.fields.value.po.command == command
|
|
86
|
+
and m.fields.value.address == address
|
|
87
|
+
)
|
|
88
|
+
|
|
76
89
|
packet_length = 64 # 64 is max
|
|
77
90
|
for address in range_:
|
|
78
91
|
args = dict(
|
|
@@ -82,8 +95,7 @@ class Panel_EVOBase(PanelBase):
|
|
|
82
95
|
reply = await self.core.send_wait(
|
|
83
96
|
parsers.ReadEEPROM,
|
|
84
97
|
args,
|
|
85
|
-
reply_expected=
|
|
86
|
-
and m.fields.value.address == address,
|
|
98
|
+
reply_expected=expect(0x5, address),
|
|
87
99
|
)
|
|
88
100
|
|
|
89
101
|
if reply is None:
|
|
@@ -101,7 +113,7 @@ class Panel_EVOBase(PanelBase):
|
|
|
101
113
|
if message is None or len(message) == 0:
|
|
102
114
|
return None
|
|
103
115
|
|
|
104
|
-
parent_parsed = super(
|
|
116
|
+
parent_parsed = super().parse_message(message, direction)
|
|
105
117
|
if parent_parsed:
|
|
106
118
|
return parent_parsed
|
|
107
119
|
|
|
@@ -147,13 +159,9 @@ class Panel_EVOBase(PanelBase):
|
|
|
147
159
|
return parsers.RequestedEvent.parse(message)
|
|
148
160
|
|
|
149
161
|
except ChecksumError as e:
|
|
150
|
-
logger.error(
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
except:
|
|
154
|
-
logger.exception(
|
|
155
|
-
"Exception parsing message: %s" % (binascii.hexlify(message))
|
|
156
|
-
)
|
|
162
|
+
logger.error("ChecksumError %s, message: %s", e, binascii.hexlify(message))
|
|
163
|
+
except Exception:
|
|
164
|
+
logger.exception("Exception parsing message: %s", binascii.hexlify(message))
|
|
157
165
|
|
|
158
166
|
return None
|
|
159
167
|
|
|
@@ -179,13 +187,17 @@ class Panel_EVOBase(PanelBase):
|
|
|
179
187
|
"(Babyware) Tab."
|
|
180
188
|
)
|
|
181
189
|
raise AuthenticationFailed("Wrong PASSWORD")
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
logger.
|
|
188
|
-
|
|
190
|
+
|
|
191
|
+
if reply.fields.value.po.command == 0x1:
|
|
192
|
+
logger.info("Authentication Success")
|
|
193
|
+
|
|
194
|
+
if not reply.fields.value.po.status.Winload_connected:
|
|
195
|
+
logger.warning("Winload_connected is still False")
|
|
196
|
+
|
|
197
|
+
return True
|
|
198
|
+
|
|
199
|
+
logger.error("Invalid response to InitializeCommunication: %s", reply)
|
|
200
|
+
return False
|
|
189
201
|
|
|
190
202
|
@staticmethod
|
|
191
203
|
def _request_status_reply_check(message: Container, address: int):
|
|
@@ -223,7 +235,7 @@ class Panel_EVOBase(PanelBase):
|
|
|
223
235
|
:param str command: textual command
|
|
224
236
|
:return: True if we have at least one success
|
|
225
237
|
"""
|
|
226
|
-
args = dict(partitions=
|
|
238
|
+
args = dict(partitions={i: command for i in partitions})
|
|
227
239
|
|
|
228
240
|
try:
|
|
229
241
|
reply = await self.core.send_wait(
|
|
@@ -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
|
-
|
|
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
|
|
227
|
+
return "disabled"
|
|
231
228
|
|
|
232
229
|
try:
|
|
233
|
-
activation_event =
|
|
234
|
-
|
|
235
|
-
|
|
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 =
|
|
239
|
-
|
|
240
|
-
|
|
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)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
# IP Interface
|
|
4
2
|
|
|
5
3
|
import asyncio
|
|
@@ -46,16 +44,14 @@ class IPInterface(Interface):
|
|
|
46
44
|
async def run(self):
|
|
47
45
|
try:
|
|
48
46
|
self.server = await asyncio.start_server(
|
|
49
|
-
self.handle_client, self.addr, self.port
|
|
47
|
+
self.handle_client, self.addr, self.port
|
|
50
48
|
)
|
|
51
49
|
logger.info(
|
|
52
|
-
"IP Interface: serving on
|
|
53
|
-
self.server.sockets[0].getsockname()
|
|
54
|
-
)
|
|
50
|
+
"IP Interface: serving on %s", self.server.sockets[0].getsockname()
|
|
55
51
|
)
|
|
56
52
|
logger.info("IP Interface started")
|
|
57
53
|
except Exception as e:
|
|
58
|
-
logger.error("Failed to start IP Interface
|
|
54
|
+
logger.error("Failed to start IP Interface: %s", e)
|
|
59
55
|
|
|
60
56
|
async def handle_client(self, reader, writer):
|
|
61
57
|
"""
|
|
@@ -67,10 +63,10 @@ class IPInterface(Interface):
|
|
|
67
63
|
"""
|
|
68
64
|
|
|
69
65
|
self.client_nr = (self.client_nr + 1) % 256
|
|
70
|
-
logger.info("Client %d connected"
|
|
66
|
+
logger.info("Client %d connected", self.client_nr)
|
|
71
67
|
|
|
72
68
|
connection = ClientConnection(reader, writer, self.alarm, self.key)
|
|
73
|
-
handler_name = "
|
|
69
|
+
handler_name = f"{self.name}_{self.client_nr}"
|
|
74
70
|
self.alarm.connection.register_raw_handler(
|
|
75
71
|
PersistentHandler(connection.handle_panel_raw_message, name=handler_name)
|
|
76
72
|
)
|
|
@@ -79,10 +75,10 @@ class IPInterface(Interface):
|
|
|
79
75
|
|
|
80
76
|
try:
|
|
81
77
|
await connection.handle()
|
|
82
|
-
except:
|
|
83
|
-
logger.exception("Client %d connection raised exception"
|
|
78
|
+
except Exception:
|
|
79
|
+
logger.exception("Client %d connection raised exception", self.client_nr)
|
|
84
80
|
finally:
|
|
85
81
|
self.alarm.connection.deregister_raw_handler(handler_name)
|
|
86
82
|
|
|
87
83
|
asyncio.get_event_loop().create_task(self.alarm.resume())
|
|
88
|
-
logger.info("Client %d disconnected"
|
|
84
|
+
logger.info("Client %d disconnected", self.client_nr)
|