Skip to content

Commit f501e59

Browse files
committed
Compile parsers, formatting
1 parent 406ba85 commit f501e59

File tree

5 files changed

+167
-50
lines changed

5 files changed

+167
-50
lines changed

paradox/connections/ip/parsers.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1-
from construct import (Adapter, Aligned, BitStruct, Bytes, Const, Default,
2-
Enum, Flag, GreedyBytes, IfThenElse, Int8ub, Int16ub,
3-
Int16ul, Padding, Pointer, Rebuild, Struct, len_, this)
1+
from construct import (
2+
Adapter,
3+
Aligned,
4+
BitStruct,
5+
Bytes,
6+
Const,
7+
Default,
8+
Enum,
9+
Flag,
10+
GreedyBytes,
11+
IfThenElse,
12+
Int8ub,
13+
Int16ub,
14+
Int16ul,
15+
Padding,
16+
Pointer,
17+
Rebuild,
18+
Struct,
19+
this,
20+
)
421

522
from paradox.hardware.common import HexInt
623
from paradox.lib.crypto import decrypt, encrypt
@@ -55,7 +72,7 @@
5572
Pointer(21, Enum(Int8ub, IP150=0x71, IP100=0x70)),
5673
lambda ctx: ctx.ip_module_serial[0],
5774
),
58-
)
75+
).compile()
5976

6077

6178
class EncryptionAdapter(Adapter):
@@ -114,7 +131,7 @@ def _encode(self, obj, context, path):
114131
),
115132
b"",
116133
),
117-
)
134+
).compile()
118135

119136

120137
IPMessageResponse = Struct(
@@ -157,4 +174,4 @@ def _encode(self, obj, context, path):
157174
),
158175
b"",
159176
),
160-
)
177+
).compile()

paradox/hardware/evo/parsers.py

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
11
import binascii
22
from collections.abc import Mapping
3+
import logging
4+
5+
from construct import (
6+
Array,
7+
BitsInteger,
8+
BitsSwapped,
9+
BitStruct,
10+
Bitwise,
11+
Byte,
12+
Bytes,
13+
ByteSwapped,
14+
Checksum,
15+
Computed,
16+
Const,
17+
Default,
18+
Embedded,
19+
Enum,
20+
ExprAdapter,
21+
ExprSymmetricAdapter,
22+
Flag,
23+
Int8ub,
24+
Int16ub,
25+
Int16ul,
26+
Int24ub,
27+
Nibble,
28+
Padding,
29+
RawCopy,
30+
Struct,
31+
Subconstruct,
32+
ValidationError,
33+
obj_,
34+
this,
35+
)
336

4-
from construct import (Array, BitsInteger, BitsSwapped, BitStruct, Bitwise,
5-
Byte, Bytes, ByteSwapped, Checksum, Computed, Const,
6-
Default, Embedded, Enum, ExprAdapter,
7-
ExprSymmetricAdapter, Flag, Int8ub, Int16ub, Int16ul,
8-
Int24ub, Nibble, Padding, RawCopy, Struct, Subconstruct,
9-
ValidationError, obj_, this)
37+
from ..common import (
38+
CommunicationSourceIDEnum,
39+
PacketChecksum,
40+
PacketLength,
41+
ProductIdEnum,
42+
calculate_checksum,
43+
)
44+
from .adapters import (
45+
DateAdapter,
46+
DictArray,
47+
EnumerationAdapter,
48+
EventAdapter,
49+
ModuleTroubles,
50+
PartitionStatus,
51+
PGMFlags,
52+
StatusFlags,
53+
ZoneFlagBitStruct,
54+
ZoneFlags,
55+
)
1056

11-
from ..common import (CommunicationSourceIDEnum, PacketChecksum, PacketLength,
12-
ProductIdEnum, calculate_checksum)
13-
from .adapters import (DateAdapter, DictArray, EnumerationAdapter,
14-
EventAdapter, ModuleTroubles, PartitionStatus, PGMFlags,
15-
StatusFlags, ZoneFlagBitStruct, ZoneFlags)
57+
logger = logging.getLogger("PAI").getChild(__name__)
1658

1759
LoginConfirmationResponse = Struct(
1860
"fields"
@@ -161,12 +203,13 @@
161203
RAMDataParserMap = {
162204
1: Struct(
163205
"_weekday" / Int8ub,
164-
"_system_flags" / BitStruct( # TODO: Do we need BitsSwapped here?
206+
"_system_flags"
207+
/ BitStruct( # TODO: Do we need BitsSwapped here?
165208
"chime_zone_partition" / BitsSwapped(StatusFlags(4)),
166209
"power_smoke" / Flag,
167210
"ground_start" / Flag,
168211
"kiss_off" / Flag,
169-
"line_ring" / Flag
212+
"line_ring" / Flag,
170213
),
171214
"partition_bell" / BitsSwapped(Bitwise(StatusFlags(8))),
172215
"partition_fire_alarm" / BitsSwapped(Bitwise(StatusFlags(8))),
@@ -176,7 +219,7 @@
176219
"system"
177220
/ Struct(
178221
"troubles"
179-
/ BitStruct( # time_lost_trouble when actually battery_failure
222+
/ BitStruct( # time_lost_trouble when actually battery_failure
180223
"time_lost_trouble" / Flag,
181224
"zone_fault_trouble" / Flag,
182225
"zone_low_battery_trouble" / Flag,
@@ -185,7 +228,6 @@
185228
"module_trouble" / Flag,
186229
"dialer_trouble" / Flag,
187230
"system_trouble" / Flag,
188-
189231
"panel_tamper_trouble" / Flag,
190232
"_future_use_0" / Flag,
191233
"rom_error_trouble" / Flag,
@@ -194,7 +236,6 @@
194236
"aux_limit_trouble" / Flag,
195237
"battery_failure_trouble" / Flag,
196238
"ac_trouble" / Flag,
197-
198239
"_future_use_1" / Flag,
199240
"_future_use_2" / Flag,
200241
"com_pc_trouble" / Flag,
@@ -203,7 +244,6 @@
203244
"fail_central_2_trouble" / Flag,
204245
"fail_central_1_trouble" / Flag,
205246
"tlm_trouble" / Flag,
206-
207247
"module_aux_trouble" / Flag,
208248
"module_battery_fail" / Flag,
209249
"module_ac_trouble" / Flag,
@@ -212,7 +252,6 @@
212252
"module_tlm_trouble" / Flag,
213253
"module_rom_error_trouble" / Flag,
214254
"module_tamper_trouble" / Flag,
215-
216255
"mdl_com_error" / Flag,
217256
"bus_overload_trouble" / Flag,
218257
"bus_global_fail" / Flag,
@@ -255,9 +294,15 @@
255294
"panel_status"
256295
/ BitStruct("installer_lock_active" / Flag, "_free" / Padding(7)),
257296
"event"
258-
/ Struct("_event_pointer" / Int16ub, "_event_pointer_bus" / Int16ub,),
297+
/ Struct(
298+
"_event_pointer" / Int16ub,
299+
"_event_pointer_bus" / Int16ub,
300+
),
259301
"_recycle_system" / Array(8, Int8ub),
260-
"report" / Struct("arm_disarm_delay_timer" / Int8ub,),
302+
"report"
303+
/ Struct(
304+
"arm_disarm_delay_timer" / Int8ub,
305+
),
261306
),
262307
"_free" / Padding(34),
263308
),
@@ -279,9 +324,10 @@
279324
),
280325
10: Struct("zone_status" / ZoneFlags(64, start_index_from=125)),
281326
11: Struct(
282-
"zone_status" / ZoneFlags(4, start_index_from=189), "_not_used" / Bytes(60),
327+
"zone_status" / ZoneFlags(4, start_index_from=189),
328+
"_not_used" / Bytes(60),
283329
),
284-
16: Struct( # TODO: here should be panel modules
330+
16: Struct( # TODO: here should be panel modules
285331
"module_assigned" / BitsSwapped(Bitwise(StatusFlags(256, start_index_from=1))),
286332
"module_missing" / BitsSwapped(Bitwise(StatusFlags(256, start_index_from=1))),
287333
),
@@ -306,6 +352,16 @@
306352
# 56 ram address
307353
# 58 ram address
308354

355+
# compile all RAMDataParserMap parsers if possible
356+
for key, parser in RAMDataParserMap.items():
357+
try:
358+
RAMDataParserMap[key] = parser.compile()
359+
except Exception:
360+
logger.debug(
361+
"Could not compile parser for RAM address %s. Using the original version.",
362+
key,
363+
)
364+
309365

310366
def get_user_definition(settings):
311367
if (
@@ -575,7 +631,8 @@ def _parse(self, stream, context, path):
575631
Struct(
576632
"po"
577633
/ BitStruct(
578-
"command" / Const(0x5, Nibble), "block" / Default(Nibble, 0),
634+
"command" / Const(0x5, Nibble),
635+
"block" / Default(Nibble, 0),
579636
),
580637
"packet_length" / PacketLength(Int8ub),
581638
"control"
@@ -916,7 +973,13 @@ def _parse(self, stream, context, path):
916973
"unknown0" / Const(0x09, Int8ub),
917974
"_not_used" / Padding(3),
918975
"user_id" / Int16ub,
919-
"panic_type" / Enum(Int8ub, emergency=0, medical=1, fire=2,), # wild guess
976+
"panic_type"
977+
/ Enum(
978+
Int8ub,
979+
emergency=0,
980+
medical=1,
981+
fire=2,
982+
), # wild guess
920983
"partitions" / BitsSwapped(Bitwise(EnumerationAdapter(Array(8, Flag)))),
921984
)
922985
),

paradox/interfaces/mqtt/homeassistant.py

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import asyncio
2+
from collections import namedtuple
23
import json
34
import logging
4-
from collections import namedtuple
55

66
from paradox.config import config as cfg
7+
from paradox.data.model import DetectedPanel
78
from paradox.lib import ps
89
from paradox.lib.utils import SerializableToJSONEncoder
10+
11+
from .core import AbstractMQTTInterface
912
from .entities.abstract_entity import AbstractEntity
1013
from .entities.device import Device
1114
from .entities.factory import MQTTAutodiscoveryEntityFactory
1215

13-
from ...data.model import DetectedPanel
14-
from .core import AbstractMQTTInterface
15-
1616
logger = logging.getLogger("PAI").getChild(__name__)
1717

18-
PreparseResponse = namedtuple("preparse_response", "topics element content")
18+
PreparseResponse = namedtuple("PreparseResponse", "topics element content")
1919

2020

2121
class HomeAssistantMQTTInterface(AbstractMQTTInterface):
@@ -26,7 +26,9 @@ def __init__(self, alarm):
2626
self.zones = {}
2727
self.pgms = {}
2828

29-
self.entity_factory = MQTTAutodiscoveryEntityFactory(self.mqtt.availability_topic)
29+
self.entity_factory = MQTTAutodiscoveryEntityFactory(
30+
self.mqtt.availability_topic
31+
)
3032

3133
self.run_status_topic = self.mqtt.pai_status_topic
3234

@@ -79,14 +81,20 @@ def _publish_when_ready(self, panel: DetectedPanel, status):
7981
if "pgm" in status:
8082
self._publish_pgm_configs(status["pgm"])
8183
if "system" in status:
82-
self._publish_system_property_configs(status['system'])
84+
self._publish_system_property_configs(status["system"])
8385

8486
def _publish_config(self, entity: AbstractEntity):
85-
self.publish(entity.configuration_topic, json.dumps(entity, cls=SerializableToJSONEncoder), 0,
86-
cfg.MQTT_RETAIN)
87+
self.publish(
88+
entity.configuration_topic,
89+
json.dumps(entity, cls=SerializableToJSONEncoder),
90+
0,
91+
cfg.MQTT_RETAIN,
92+
)
8793

8894
def _publish_pai_state_sensor_config(self):
89-
pai_state_sensor_config = self.entity_factory.make_pai_status_sensor(self.run_status_topic)
95+
pai_state_sensor_config = self.entity_factory.make_pai_status_sensor(
96+
self.run_status_topic
97+
)
9098
self._publish_config(pai_state_sensor_config)
9199

92100
def _publish_partition_configs(self, partition_statuses):
@@ -95,16 +103,24 @@ def _publish_partition_configs(self, partition_statuses):
95103
continue
96104

97105
partition = self.partitions[partition_key]
98-
code = cfg.MQTT_HOMEASSISTANT_CODE or None # returns None on empty string. For HA Addon Schema parsing
106+
code = (
107+
cfg.MQTT_HOMEASSISTANT_CODE or None
108+
) # returns None on empty string. For HA Addon Schema parsing
99109

100-
partition_alarm_control_panel_config = self.entity_factory.make_alarm_control_panel_config(partition, code)
110+
partition_alarm_control_panel_config = (
111+
self.entity_factory.make_alarm_control_panel_config(partition, code)
112+
)
101113
self._publish_config(partition_alarm_control_panel_config)
102-
114+
103115
# Publish individual entities
104116
for property_name in partition_status:
105117
if property_name not in cfg.HOMEASSISTANT_PUBLISH_PARTITION_PROPERTIES:
106118
continue
107-
partition_property_binary_sensor_config = self.entity_factory.make_partition_status_binary_sensor(partition, property_name)
119+
partition_property_binary_sensor_config = (
120+
self.entity_factory.make_partition_status_binary_sensor(
121+
partition, property_name
122+
)
123+
)
108124
self._publish_config(partition_property_binary_sensor_config)
109125

110126
def _publish_zone_configs(self, zone_statuses):
@@ -119,25 +135,37 @@ def _publish_zone_configs(self, zone_statuses):
119135
if property_name not in cfg.HOMEASSISTANT_PUBLISH_ZONE_PROPERTIES:
120136
continue
121137
if property_name == "bypassed":
122-
zone_status_sensor = self.entity_factory.make_zone_bypass_switch(zone)
138+
zone_status_sensor = self.entity_factory.make_zone_bypass_switch(
139+
zone
140+
)
123141
elif property_name == "signal_strength":
124-
zone_status_sensor = self.entity_factory.make_zone_status_numeric_sensor(zone, property_name)
142+
zone_status_sensor = (
143+
self.entity_factory.make_zone_status_numeric_sensor(
144+
zone, property_name
145+
)
146+
)
125147
else:
126-
zone_status_sensor = self.entity_factory.make_zone_status_binary_sensor(zone, property_name)
148+
zone_status_sensor = (
149+
self.entity_factory.make_zone_status_binary_sensor(
150+
zone, property_name
151+
)
152+
)
127153
self._publish_config(zone_status_sensor)
128154

129155
def _publish_pgm_configs(self, pgm_statuses):
130-
for pgm_key, pgm_status in pgm_statuses.items():
156+
for pgm_key in pgm_statuses.keys():
131157
if pgm_key not in self.pgms:
132158
continue
133159

134160
pgm = self.pgms[pgm_key]
135161

136162
pgm_switch_config = self.entity_factory.make_pgm_switch(pgm)
137163
self._publish_config(pgm_switch_config)
138-
164+
139165
def _publish_system_property_configs(self, system_statuses):
140166
for system_key, system_status in system_statuses.items():
141167
for property_name in system_status:
142-
system_property_config = self.entity_factory.make_system_status(system_key, property_name)
168+
system_property_config = self.entity_factory.make_system_status(
169+
system_key, property_name
170+
)
143171
self._publish_config(system_property_config)

paradox/paradox.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ async def send_panic(self, partition_id, panic_type, user_id) -> bool:
534534
except asyncio.TimeoutError:
535535
logger.error("send_panic timeout")
536536

537+
return False
538+
537539
async def control_door(self, door, command) -> bool:
538540
command = command.lower()
539541
logger.debug(f"Control Door: {door} - {command}")

0 commit comments

Comments
 (0)