From 14cca0aaa92b35c02732f1c65b6c2750607dc344 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Mon, 5 May 2014 13:47:14 -0700 Subject: [PATCH 1/5] Added initial support for DSC in the beta firmware. --- alarmdecoder/decoder.py | 22 ++++++++++++---------- alarmdecoder/panels.py | 8 ++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index 7c32179..e16ff60 100644 --- a/alarmdecoder/decoder.py +++ b/alarmdecoder/decoder.py @@ -13,6 +13,7 @@ from .event import event from .util import InvalidMessageError from .messages import Message, ExpanderMessage, RFMessage, LRRMessage from .zonetracking import Zonetracker +from .panels import MODES, ADEMCO, DSC class AlarmDecoder(object): @@ -80,6 +81,8 @@ class AlarmDecoder(object): """The status of the devices LRR emulation.""" deduplicate = False """The status of message deduplication as configured on the device.""" + mode = ADEMCO + """The panel mode that the AlarmDecoder is in. Currently supports ADEMCO and DSC.""" def __init__(self, device): """ @@ -110,6 +113,7 @@ class AlarmDecoder(object): self.emulate_relay = [False for x in range(4)] self.emulate_lrr = False self.deduplicate = False + self.mode = ADEMCO def __enter__(self): """ @@ -222,20 +226,16 @@ class AlarmDecoder(object): config_entries = [] # HACK: This is ugly.. but I can't think of an elegant way of doing it. - config_entries.append(('ADDRESS', - '{0}'.format(self.address))) - config_entries.append(('CONFIGBITS', - '{0:x}'.format(self.configbits))) - config_entries.append(('MASK', - '{0:x}'.format(self.address_mask))) + config_entries.append(('ADDRESS', '{0}'.format(self.address))) + config_entries.append(('CONFIGBITS', '{0:x}'.format(self.configbits))) + config_entries.append(('MASK', '{0:x}'.format(self.address_mask))) config_entries.append(('EXP', ''.join(['Y' if z else 'N' for z in self.emulate_zone]))) config_entries.append(('REL', ''.join(['Y' if r else 'N' for r in self.emulate_relay]))) - config_entries.append(('LRR', - 'Y' if self.emulate_lrr else 'N')) - config_entries.append(('DEDUPLICATE', - 'Y' if self.deduplicate else 'N')) + config_entries.append(('LRR', 'Y' if self.emulate_lrr else 'N')) + config_entries.append(('DEDUPLICATE', 'Y' if self.deduplicate else 'N')) + config_entries.append(('MODE', MODES.keys()[MODES.values().index(self.mode)])) config_string = '&'.join(['='.join(t) for t in config_entries]) @@ -430,6 +430,8 @@ class AlarmDecoder(object): self.emulate_lrr = (val == 'Y') elif key == 'DEDUPLICATE': self.deduplicate = (val == 'Y') + elif key == 'MODE': + self.mode = MODES[val] self.on_config_received() diff --git a/alarmdecoder/panels.py b/alarmdecoder/panels.py index 00a2e95..34a9b12 100644 --- a/alarmdecoder/panels.py +++ b/alarmdecoder/panels.py @@ -4,6 +4,14 @@ Representations of Panels and their templates. .. moduleauthor:: Scott Petersen """ +ADEMCO = 0 +DSC = 1 + +MODES = { + 'A': ADEMCO, + 'D': DSC, +} + VISTA20 = 0 TEMPLATES = { From eb699b6032555a2bbb5bd0d476bef1f2fc7e767c Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Tue, 6 May 2014 10:08:31 -0700 Subject: [PATCH 2/5] Added support for the system fault bit as well as source panel type for messages. --- alarmdecoder/messages.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/alarmdecoder/messages.py b/alarmdecoder/messages.py index f44edff..1bff13d 100644 --- a/alarmdecoder/messages.py +++ b/alarmdecoder/messages.py @@ -16,6 +16,7 @@ import re import datetime from .util import InvalidMessageError +from .panels import MODES, ADEMCO, DSC class BaseMessage(object): @@ -95,6 +96,10 @@ class Message(BaseMessage): """Indicates whether or not there are zones that require attention.""" perimeter_only = False """Indicates whether or not the perimeter is armed.""" + system_fault = False + """Indicates whether a system fault has occurred.""" + panel_type = ADEMCO + """Indicates which panel type was the source of this message.""" numeric_code = None """The numeric code associated with the message.""" text = None @@ -158,7 +163,10 @@ class Message(BaseMessage): self.fire_alarm = is_bit_set(14) self.check_zone = is_bit_set(15) self.perimeter_only = is_bit_set(16) - # bits 17-20 unused. + self.system_fault = is_bit_set(17) + if self.bitfield[18] in MODES.keys(): + self.panel_type = MODES.keys()[MODES.values().index(self.bitfield[18])]) + # pos 20-21 - Unused. self.text = alpha.strip('"') if int(self.panel_data[19:21], 16) & 0x01 > 0: From 9de9e9f7c9dc3e3600fc30c5829ca4a2556fdb21 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Tue, 6 May 2014 10:10:55 -0700 Subject: [PATCH 3/5] Added check for ADEMCO panel before pulling out the mask and cursor location. Mask now defaults to 0xFFFFFFFF. --- alarmdecoder/messages.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/alarmdecoder/messages.py b/alarmdecoder/messages.py index 1bff13d..da32a9c 100644 --- a/alarmdecoder/messages.py +++ b/alarmdecoder/messages.py @@ -106,7 +106,7 @@ class Message(BaseMessage): """The human-readable text to be displayed on the panel LCD.""" cursor_location = -1 """Current cursor location on the keypad.""" - mask = None + mask = 0xFFFFFFFF """Address mask this message is intended for.""" bitfield = None """The bitfield associated with this message.""" @@ -142,7 +142,6 @@ class Message(BaseMessage): raise InvalidMessageError('Received invalid message: {0}'.format(data)) header, self.bitfield, self.numeric_code, self.panel_data, alpha = match.group(1, 2, 3, 4, 5) - self.mask = int(self.panel_data[3:3+8], 16) is_bit_set = lambda bit: not self.bitfield[bit] == "0" @@ -169,9 +168,12 @@ class Message(BaseMessage): # pos 20-21 - Unused. self.text = alpha.strip('"') - if int(self.panel_data[19:21], 16) & 0x01 > 0: - # Current cursor location on the alpha display. - self.cursor_location = int(self.bitfield[21:23], 16) + if self.panel_type == ADEMCO: + self.mask = int(self.panel_data[3:3+8], 16) + + if int(self.panel_data[19:21], 16) & 0x01 > 0: + # Current cursor location on the alpha display. + self.cursor_location = int(self.bitfield[21:23], 16) def dict(self, **kwargs): """ From e8e541e59268931efa8f53544594de53360b68a8 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Tue, 6 May 2014 10:18:39 -0700 Subject: [PATCH 4/5] Fixed backwards lookup. --- alarmdecoder/messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alarmdecoder/messages.py b/alarmdecoder/messages.py index da32a9c..4e5b5c5 100644 --- a/alarmdecoder/messages.py +++ b/alarmdecoder/messages.py @@ -164,7 +164,7 @@ class Message(BaseMessage): self.perimeter_only = is_bit_set(16) self.system_fault = is_bit_set(17) if self.bitfield[18] in MODES.keys(): - self.panel_type = MODES.keys()[MODES.values().index(self.bitfield[18])]) + self.panel_type = MODES[self.bitfield[18]] # pos 20-21 - Unused. self.text = alpha.strip('"') From 5ea201c05d4f6992299c95a0001508c491cb21fb Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Tue, 6 May 2014 10:23:19 -0700 Subject: [PATCH 5/5] Renamed MODES to PANEL_TYPES. --- alarmdecoder/decoder.py | 6 +++--- alarmdecoder/messages.py | 6 +++--- alarmdecoder/panels.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index e16ff60..f377e57 100644 --- a/alarmdecoder/decoder.py +++ b/alarmdecoder/decoder.py @@ -13,7 +13,7 @@ from .event import event from .util import InvalidMessageError from .messages import Message, ExpanderMessage, RFMessage, LRRMessage from .zonetracking import Zonetracker -from .panels import MODES, ADEMCO, DSC +from .panels import PANEL_TYPES, ADEMCO, DSC class AlarmDecoder(object): @@ -235,7 +235,7 @@ class AlarmDecoder(object): ''.join(['Y' if r else 'N' for r in self.emulate_relay]))) config_entries.append(('LRR', 'Y' if self.emulate_lrr else 'N')) config_entries.append(('DEDUPLICATE', 'Y' if self.deduplicate else 'N')) - config_entries.append(('MODE', MODES.keys()[MODES.values().index(self.mode)])) + config_entries.append(('MODE', PANEL_TYPES.keys()[PANEL_TYPES.values().index(self.mode)])) config_string = '&'.join(['='.join(t) for t in config_entries]) @@ -431,7 +431,7 @@ class AlarmDecoder(object): elif key == 'DEDUPLICATE': self.deduplicate = (val == 'Y') elif key == 'MODE': - self.mode = MODES[val] + self.mode = PANEL_TYPES[val] self.on_config_received() diff --git a/alarmdecoder/messages.py b/alarmdecoder/messages.py index 4e5b5c5..de1d491 100644 --- a/alarmdecoder/messages.py +++ b/alarmdecoder/messages.py @@ -16,7 +16,7 @@ import re import datetime from .util import InvalidMessageError -from .panels import MODES, ADEMCO, DSC +from .panels import PANEL_TYPES, ADEMCO, DSC class BaseMessage(object): @@ -163,8 +163,8 @@ class Message(BaseMessage): self.check_zone = is_bit_set(15) self.perimeter_only = is_bit_set(16) self.system_fault = is_bit_set(17) - if self.bitfield[18] in MODES.keys(): - self.panel_type = MODES[self.bitfield[18]] + if self.bitfield[18] in PANEL_TYPES.keys(): + self.panel_type = PANEL_TYPES[self.bitfield[18]] # pos 20-21 - Unused. self.text = alpha.strip('"') diff --git a/alarmdecoder/panels.py b/alarmdecoder/panels.py index 34a9b12..c1f981a 100644 --- a/alarmdecoder/panels.py +++ b/alarmdecoder/panels.py @@ -7,7 +7,7 @@ Representations of Panels and their templates. ADEMCO = 0 DSC = 1 -MODES = { +PANEL_TYPES = { 'A': ADEMCO, 'D': DSC, }