@@ -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() | |||
@@ -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): | |||
""" | |||
@@ -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 = { | |||