|
- """
- Message representations received from the panel through the AD2 devices.
-
- .. moduleauthor:: Scott Petersen <scott@nutech.com>
- """
-
- import re
-
- from .util import InvalidMessageError
-
- class BaseMessage(object):
- """
- Base class for messages.
- """
- def __init__(self):
- """
- Constructor
- """
- self.raw = None
-
- def __str__(self):
- """
- String conversion operator.
- """
- return self.raw
-
- class Message(BaseMessage):
- """
- Represents a message from the alarm panel.
- """
-
- def __init__(self, data=None):
- """
- Constructor
-
- :param data: Message data to parse.
- :type data: str
- """
- self.ready = False
- self.armed_away = False
- self.armed_home = False
- self.backlight_on = False
- self.programming_mode = False
- self.beeps = -1
- self.zone_bypassed = False
- self.ac_power = False
- self.chime_on = False
- self.alarm_event_occurred = False
- self.alarm_sounding = False
- self.battery_low = False
- self.entry_delay_off = False
- self.fire_alarm = False
- self.check_zone = False
- self.perimeter_only = False
- self.numeric_code = ""
- self.text = ""
- self.cursor_location = -1
- self.data = ""
- self.mask = ""
- self.bitfield = ""
- self.panel_data = ""
-
- self._regex = re.compile('("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*)')
-
- if data is not None:
- self._parse_message(data)
-
- def _parse_message(self, data):
- """
- Parse the message from the device.
-
- :param data: The message data.
- :type data: str
-
- :raises: InvalidMessageError
- """
- m = self._regex.match(data)
-
- if m is None:
- raise InvalidMessageError('Received invalid message: {0}'.format(data))
-
- self.bitfield, self.numeric_code, self.panel_data, alpha = m.group(1, 2, 3, 4)
- self.mask = int(self.panel_data[3:3+8], 16)
-
- is_bit_set = lambda bit: not self.bitfield[bit] == "0"
-
- self.raw = data
- self.ready = is_bit_set(1)
- self.armed_away = is_bit_set(2)
- self.armed_home = is_bit_set(3)
- self.backlight_on = is_bit_set(4)
- self.programming_mode = is_bit_set(5)
- self.beeps = int(self.bitfield[6], 16)
- self.zone_bypassed = is_bit_set(7)
- self.ac_power = is_bit_set(8)
- self.chime_on = is_bit_set(9)
- self.alarm_event_occurred = is_bit_set(10)
- self.alarm_sounding = is_bit_set(11)
- self.battery_low = is_bit_set(12)
- self.entry_delay_off = is_bit_set(13)
- 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.text = alpha.strip('"')
-
- if int(self.panel_data[19:21], 16) & 0x01 > 0:
- self.cursor_location = int(self.bitfield[21:23], 16) # Alpha character index that the cursor is on.
-
- def __str__(self):
- """
- String conversion operator.
- """
- return self.raw
-
- class ExpanderMessage(BaseMessage):
- """
- Represents a message from a zone or relay expansion module.
- """
-
- ZONE = 0
- """Flag indicating that the expander message relates to a Zone Expander."""
- RELAY = 1
- """Flag indicating that the expander message relates to a Relay Expander."""
-
- def __init__(self, data=None):
- """
- Constructor
-
- :param data: The message data to parse.
- :type data: str
- """
- self.type = None
- self.address = None
- self.channel = None
- self.value = None
- self.raw = None
-
- if data is not None:
- self._parse_message(data)
-
- def __str__(self):
- """
- String conversion operator.
- """
- return self.raw
-
- def _parse_message(self, data):
- """
- Parse the raw message from the device.
-
- :param data: The message data
- :type data: str
- """
- try:
- header, values = data.split(':')
- address, channel, value = values.split(',')
-
- self.raw = data
- self.address = int(address)
- self.channel = int(channel)
- self.value = int(value)
-
- except ValueError:
- raise InvalidMessageError('Received invalid message: {0}'.format(data))
-
- if header == '!EXP':
- self.type = ExpanderMessage.ZONE
- elif header == '!REL':
- self.type = ExpanderMessage.RELAY
- else:
- raise InvalidMessageError('Unknown expander message header: {0}'.format(data))
-
- class RFMessage(BaseMessage):
- """
- Represents a message from an RF receiver.
- """
-
- def __init__(self, data=None):
- """
- Constructor
-
- :param data: The message data to parse
- :type data: str
- """
- self.raw = None
- self.serial_number = None
- self.value = None
- self.battery = None
- self.supervision = None
- self.loop = {}
-
- if data is not None:
- self._parse_message(data)
-
- def __str__(self):
- """
- String conversion operator.
- """
- return self.raw
-
- def _parse_message(self, data):
- """
- Parses the raw message from the device.
-
- :param data: The message data.
- :type data: str
- """
- try:
- self.raw = data
-
- _, values = data.split(':')
- self.serial_number, self.value = values.split(',')
- self.value = int(self.value, 16)
-
- is_bit_set = lambda b: self.value & (1 << b) > 0
-
- # Bit 1 = unknown
- self.battery = is_bit_set(2)
- self.supervision = is_bit_set(3)
- # Bit 8 = unknown
- self.loop[0] = is_bit_set(5)
- self.loop[1] = is_bit_set(6)
- self.loop[2] = is_bit_set(7)
- self.loop[3] = is_bit_set(8)
-
- except ValueError:
- raise InvalidMessageError('Received invalid message: {0}'.format(data))
-
-
- class LRRMessage(BaseMessage):
- """
- Represent a message from a Long Range Radio.
- """
-
- def __init__(self, data=None):
- """
- Constructor
-
- :param data: The message data to parse.
- :type data: str
- """
- self.raw = None
- self.event_data = None
- self.partition = None
- self.event_type = None
-
- if data is not None:
- self._parse_message(data)
-
- def __str__(self):
- """
- String conversion operator.
- """
- return self.raw
-
- def _parse_message(self, data):
- """
- Parses the raw message from the device.
-
- :param data: The message data.
- :type data: str
- """
- try:
- self.raw = data
-
- _, values = data.split(':')
- self.event_data, self.partition, self.event_type = values.split(',')
-
- except ValueError:
- raise InvalidMessageError('Received invalid message: {0}'.format(data))
|