Browse Source

Message parsing complete. Added some new events to AD2USB.

pyserial_fix
Scott Petersen 11 years ago
parent
commit
8f74c84390
3 changed files with 143 additions and 11 deletions
  1. +120
    -11
      pyad2usb/ad2usb.py
  2. +6
    -0
      pyad2usb/util.py
  3. +17
    -0
      test.py

+ 120
- 11
pyad2usb/ad2usb.py View File

@@ -4,6 +4,7 @@ Provides the full AD2USB class and factory.

import time
import threading
import re
from .event import event
from . import devices
from . import util
@@ -154,18 +155,28 @@ class AD2USB(object):
"""

# High-level Events
on_open = event.Event('Called when the device has been opened')
on_close = event.Event('Called when the device has been closed')
on_open = event.Event('Called when the device has been opened.')
on_close = event.Event('Called when the device has been closed.')

on_status_changed = event.Event('Called when the panel status changes.')
on_power_changed = event.Event('Called when panel power switches between AC and DC.')
on_alarm = event.Event('Called when the alarm is triggered.')
on_bypass = event.Event('Called when a zone is bypassed.')

# Mid-level Events
on_message = event.Event('Called when a message has been received from the device.')

# Low-level Events
on_read = event.Event('Called when a line has been read from the device')
on_write = event.Event('Called when data has been written to the device')
on_read = event.Event('Called when a line has been read from the device.')
on_write = event.Event('Called when data has been written to the device.')

def __init__(self, device):
"""
Constructor
"""
self._power_status = None
self._alarm_status = None
self._bypass_status = None
self._device = device

def __del__(self):
@@ -204,9 +215,33 @@ class AD2USB(object):
if data[0] == '!': # TEMP: Remove this.
return None

msg = Message()
msg = Message(data)

# parse and build stuff

# TEMP
address_mask = 0xFF80

if address_mask & msg.mask > 0:
#print 'ac={0}, alarm={1}, bypass={2}'.format(msg.ac, msg.alarm_bell, msg.bypass)
if msg.ac != self._power_status:
self._power_status, old_status = msg.ac, self._power_status
#print '\tpower: new={0}, old={1}'.format(self._power_status, old_status)
if old_status is not None:
self.on_power_changed(self._power_status)

if msg.alarm_bell != self._alarm_status:
self._alarm_status, old_status = msg.alarm_bell, self._alarm_status
#print '\talarm: new={0}, old={1}'.format(self._alarm_status, old_status)
if old_status is not None:
self.on_alarm(self._alarm_status)

if msg.bypass != self._bypass_status:
self._bypass_status, old_status = msg.bypass, self._bypass_status
#print '\tbypass: new={0}, old={1}'.format(self._bypass_status, old_status)
if old_status is not None:
self.on_bypass(self._bypass_status)

def _on_open(self, sender, args):
"""
Internal handler for opening the device.
@@ -260,17 +295,77 @@ class Message(object):
self._text = ""
self._cursor = -1
self._raw = ""
self._mask = ""

self._msg_bitfields = ""
self._msg_zone = ""
self._msg_binary = ""
self._msg_alpha = ""

self._regex = re.compile('("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*)')

if data is not None:
self._parse_message(data)

def _parse_message(self, data):
pattern = '("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*)'




pass
m = self._regex.match(data)

if m is None:
raise util.InvalidMessageError('Received invalid message: {0}'.format(data))

self._msg_bitfields, self._msg_zone, self._msg_binary, self._msg_alpha = m.group(1, 2, 3, 4)
self.mask = int(self._msg_binary[3:3+8], 16)

self.raw = data
self.ready = not self._msg_bitfields[1:2] == "0"
self.armed_away = not self._msg_bitfields[2:3] == "0"
self.armed_home = not self._msg_bitfields[3:4] == "0"
self.backlight = not self._msg_bitfields[4:5] == "0"
self.programming_mode = not self._msg_bitfields[5:6] == "0"
self.beeps = int(self._msg_bitfields[6:7], 16)
self.bypass = not self._msg_bitfields[7:8] == "0"
self.ac = not self._msg_bitfields[8:9] == "0"
self.chime_mode = not self._msg_bitfields[9:10] == "0"
self.alarm_event_occurred = not self._msg_bitfields[10:11] == "0"
self.alarm_bell = not self._msg_bitfields[11:12] == "0"
self.numeric = self._msg_zone
self.text = self._msg_alpha.strip('"')

if int(self._msg_binary[19:21], 16) & 0x01 > 0:
self.cursor = int(self._msg_bitfields[21:23], 16)

#print "Message:\r\n" \
# "\tmask: {0}\r\n" \
# "\tready: {1}\r\n" \
# "\tarmed_away: {2}\r\n" \
# "\tarmed_home: {3}\r\n" \
# "\tbacklight: {4}\r\n" \
# "\tprogramming_mode: {5}\r\n" \
# "\tbeeps: {6}\r\n" \
# "\tbypass: {7}\r\n" \
# "\tac: {8}\r\n" \
# "\tchime_mode: {9}\r\n" \
# "\talarm_event_occurred: {10}\r\n" \
# "\talarm_bell: {11}\r\n" \
# "\tcursor: {12}\r\n" \
# "\tnumeric: {13}\r\n" \
# "\ttext: {14}\r\n".format(
# self.mask,
# self.ready,
# self.armed_away,
# self.armed_home,
# self.backlight,
# self.programming_mode,
# self.beeps,
# self.bypass,
# self.ac,
# self.chime_mode,
# self.alarm_event_occurred,
# self.alarm_bell,
# self.cursor,
# self.numeric,
# self.text
# )

@property
def ignore_packet(self):
@@ -495,3 +590,17 @@ class Message(object):
Sets the raw representation of the message data from the panel.
"""
self._raw = value

@property
def mask(self):
"""
The panel mask for which this message is intended.
"""
return self._mask

@mask.setter
def mask(self, value):
"""
Sets the panel mask for which this message is intended.
"""
self._mask = value

+ 6
- 0
pyad2usb/util.py View File

@@ -24,6 +24,12 @@ class TimeoutError(Exception):
"""
pass

class InvalidMessageError(Exception):
"""
The format of the panel message was invalid.
"""
pass

class Firmware(object):
"""
Represents firmware for the AD2USB/AD2SERIAL devices.


+ 17
- 0
test.py View File

@@ -31,6 +31,15 @@ def handle_attached(sender, args):
def handle_detached(sender, args):
print '-', args

def handle_power_changed(sender, args):
print 'power changed', args

def handle_alarm_bell(sender, args):
print 'alarm', args

def handle_bypass(sender, args):
print 'bypass', args

def handle_firmware(stage):
if stage == pyad2usb.ad2usb.util.Firmware.STAGE_START:
handle_firmware.wait_tick = 0
@@ -95,6 +104,10 @@ def test_usb():
a2u.on_read += handle_read
a2u.on_write += handle_write

a2u.on_power_changed += handle_power_changed
a2u.on_alarm += handle_alarm_bell
a2u.on_bypass += handle_bypass

a2u.open()

while running:
@@ -176,6 +189,10 @@ def test_socket():
a2u.on_read += handle_read
a2u.on_write += handle_write

a2u.on_power_changed += handle_power_changed
a2u.on_alarm += handle_alarm_bell
a2u.on_bypass += handle_bypass

a2u.open()

while running:


Loading…
Cancel
Save