diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index 7c32179..f377e57 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 PANEL_TYPES, 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', PANEL_TYPES.keys()[PANEL_TYPES.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 = PANEL_TYPES[val] self.on_config_received() diff --git a/alarmdecoder/messages.py b/alarmdecoder/messages.py index f44edff..de1d491 100644 --- a/alarmdecoder/messages.py +++ b/alarmdecoder/messages.py @@ -16,6 +16,7 @@ import re import datetime from .util import InvalidMessageError +from .panels import PANEL_TYPES, ADEMCO, DSC class BaseMessage(object): @@ -95,13 +96,17 @@ 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 """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.""" @@ -137,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" @@ -158,12 +162,18 @@ 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 PANEL_TYPES.keys(): + self.panel_type = PANEL_TYPES[self.bitfield[18]] + # 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): """ diff --git a/alarmdecoder/panels.py b/alarmdecoder/panels.py index 00a2e95..c1f981a 100644 --- a/alarmdecoder/panels.py +++ b/alarmdecoder/panels.py @@ -4,6 +4,14 @@ Representations of Panels and their templates. .. moduleauthor:: Scott Petersen <scott@nutech.com> """ +ADEMCO = 0 +DSC = 1 + +PANEL_TYPES = { + 'A': ADEMCO, + 'D': DSC, +} + VISTA20 = 0 TEMPLATES = {