1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
"""
Message representations received from the panel through the `AlarmDecoder`_ (AD2)
devices.
:py:class:`LRRMessage`: Message received from a long-range radio module.
.. _AlarmDecoder: http://www.alarmdecoder.com
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
from .. import BaseMessage
from ...util import InvalidMessageError
from .events import LRR_EVENT_TYPE, get_event_description, get_event_data_type, get_event_source
class LRRMessage(BaseMessage):
"""
Represent a message from a Long Range Radio or emulated Long Range Radio.
"""
event_data_type = None
"""Data Type for specific LRR message. User or Zone"""
event_data = None
"""Data associated with the LRR message. Usually user ID or zone."""
partition = -1
"""The partition that this message applies to."""
event_type = None
"""The type of the event that occurred."""
version = 0
"""LRR message version"""
report_code = 0xFF
"""The report code used to override the last two digits of the event type."""
event_prefix = ''
"""Extracted prefix for the event_type."""
event_source = LRR_EVENT_TYPE.UNKNOWN
"""Extracted event type source."""
event_status = 0
"""Event status flag that represents triggered or restored events."""
event_code = 0
"""Event code for the LRR message."""
event_description = ''
"""Human-readable description of LRR event."""
def __init__(self, data=None, skip_report_override=False):
"""
Constructor
:param data: message data to parse
:type data: string
"""
BaseMessage.__init__(self, data)
self.skip_report_override = skip_report_override
if data is not None:
self._parse_message(data)
def _parse_message(self, data):
"""
Parses the raw message from the device.
:param data: message data to parse
:type data: string
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
try:
_, values = data.split(':')
values = values.split(',')
# Handle older-format events
if len(values) <= 3:
self.event_data, self.partition, self.event_type = values
self.version = 1
# Newer-format events
else:
self.event_data, self.partition, self.event_type, self.report_code = values
self.version = 2
event_type_data = self.event_type.split('_')
self.event_prefix = event_type_data[0] # Ex: CID
self.event_source = get_event_source(self.event_prefix) # Ex: LRR_EVENT_TYPE.CID
self.event_status = int(event_type_data[1][0]) # Ex: 1 or 3
self.event_code = int(event_type_data[1][1:], 16) # Ex: 0x100 = Medical
# replace last 2 digits of event_code with report_code, if applicable.
if not self.skip_report_override and self.report_code not in ['00', 'ff']:
self.event_code = int(event_type_data[1][1] + self.report_code, 16)
self.event_description = get_event_description(self.event_source, self.event_code)
self.event_data_type = get_event_data_type(self.event_source, self.event_code)
except ValueError:
raise InvalidMessageError('Received invalid message: {0}'.format(data))
def dict(self, **kwargs):
"""
Dictionary representation
"""
return dict(
time = self.timestamp,
event_data = self.event_data,
event_data_type = self.event_data_type,
event_type = self.event_type,
partition = self.partition,
report_code = self.report_code,
event_prefix = self.event_prefix,
event_source = self.event_source,
event_status = self.event_status,
event_code = hex(self.event_code),
event_description = self.event_description,
**kwargs
)
|