diff --git a/docs/build/doctrees/alarmdecoder.doctree b/docs/build/doctrees/alarmdecoder.doctree
index 24872c4..ab1f77f 100644
Binary files a/docs/build/doctrees/alarmdecoder.doctree and b/docs/build/doctrees/alarmdecoder.doctree differ
diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle
index ef4d879..a677512 100644
Binary files a/docs/build/doctrees/environment.pickle and b/docs/build/doctrees/environment.pickle differ
diff --git a/docs/build/html/_modules/alarmdecoder/decoder.html b/docs/build/html/_modules/alarmdecoder/decoder.html
index 358fe9b..a6e8b73 100644
--- a/docs/build/html/_modules/alarmdecoder/decoder.html
+++ b/docs/build/html/_modules/alarmdecoder/decoder.html
@@ -58,6 +58,8 @@
import time
import re
+from builtins import chr
+
from .event import event
from .util import InvalidMessageError
from .messages import Message, ExpanderMessage, RFMessage, LRRMessage
@@ -100,15 +102,15 @@
on_write = event.Event("This event is called when data has been written to the device.\n\n**Callback definition:** *def callback(device, data)*")
# Constants
- KEY_F1 = unichr(1) + unichr(1) + unichr(1)
+ KEY_F1 = chr(1) + chr(1) + chr(1)
"""Represents panel function key #1"""
- KEY_F2 = unichr(2) + unichr(2) + unichr(2)
+ KEY_F2 = chr(2) + chr(2) + chr(2)
"""Represents panel function key #2"""
- KEY_F3 = unichr(3) + unichr(3) + unichr(3)
+ KEY_F3 = chr(3) + chr(3) + chr(3)
"""Represents panel function key #3"""
- KEY_F4 = unichr(4) + unichr(4) + unichr(4)
+ KEY_F4 = chr(4) + chr(4) + chr(4)
"""Represents panel function key #4"""
- KEY_PANIC = unichr(5) + unichr(5) + unichr(5)
+ KEY_PANIC = chr(5) + chr(5) + chr(5)
"""Represents a panic keypress"""
BATTERY_TIMEOUT = 30
@@ -123,9 +125,9 @@
"""The configuration bits set on the device."""
address_mask = 0xFFFFFFFF
"""The address mask configured on the device."""
- emulate_zone = [False for _ in range(5)]
+ emulate_zone = [False for _ in list(range(5))]
"""List containing the devices zone emulation status."""
- emulate_relay = [False for _ in range(4)]
+ emulate_relay = [False for _ in list(range(4))]
"""List containing the devices relay emulation status."""
emulate_lrr = False
"""The status of the devices LRR emulation."""
@@ -134,6 +136,14 @@
mode = ADEMCO
"""The panel mode that the AlarmDecoder is in. Currently supports ADEMCO and DSC."""
+ #Version Information
+ serial_number = 0xFFFFFFFF
+ """The device serial number"""
+ version_number = 'Unknown'
+ """The device firmware version"""
+ version_flags = ""
+ """Device flags enabled"""
+
def __init__(self, device):
"""
Constructor
@@ -153,19 +163,23 @@
self._armed_status = None
self._fire_status = (False, 0)
self._battery_status = (False, 0)
- self._panic_status = None
+ self._panic_status = False
self._relay_status = {}
self._internal_address_mask = 0xFFFFFFFF
self.address = 18
self.configbits = 0xFF00
- self.address_mask = 0x00000000
- self.emulate_zone = [False for x in range(5)]
- self.emulate_relay = [False for x in range(4)]
+ self.address_mask = 0xFFFFFFFF
+ self.emulate_zone = [False for x in list(range(5))]
+ self.emulate_relay = [False for x in list(range(4))]
self.emulate_lrr = False
self.deduplicate = False
self.mode = ADEMCO
+ self.serial_number = 0xFFFFFFFF
+ self.version_number = 'Unknown'
+ self.version_flags = ""
+
def __enter__(self):
"""
Support for context manager __enter__.
@@ -280,7 +294,7 @@
"""
if self._device:
- self._device.write(str(data))
+ self._device.write(str.encode(data))
[docs] def get_config(self):
"""
@@ -292,7 +306,9 @@
"""
Sets configuration entries on the device.
"""
-
config_string = ''
+
self.send("C{0}\r".format(self.get_config_string()))
+
+[docs] def get_config_string(self):
config_entries = []
# HACK: This is ugly.. but I can't think of an elegant way of doing it.
@@ -305,11 +321,17 @@
''.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(('MODE', PANEL_TYPES.keys()[PANEL_TYPES.values().index(self.mode)]))
+
config_entries.append(('MODE', list(PANEL_TYPES)[list(PANEL_TYPES.values()).index(self.mode)]))
config_string = '&'.join(['='.join(t) for t in config_entries])
-
self.send("C{0}\r".format(config_string))
+
return '&'.join(['='.join(t) for t in config_entries])
+
+[docs] def get_version(self):
+
"""
+
Retrieves the version string from the device. Called automatically by :py:meth:`_on_open`.
+
"""
+
self.send("V\r")
[docs] def reboot(self):
"""
@@ -370,6 +392,8 @@
:returns: :py:class:`~alarmdecoder.messages.Message`
"""
+
data = data.decode('utf-8')
+
if data is not None:
data = data.lstrip('\0')
@@ -397,6 +421,9 @@
elif data.startswith('!CONFIG'):
self._handle_config(data)
+
elif data.startswith('!VER'):
+
self._handle_version(data)
+
elif data.startswith('!Sending'):
self._handle_sending(data)
@@ -475,6 +502,21 @@
return msg
+
def _handle_version(self, data):
+
"""
+
Handles received version data.
+
+
:param data: Version string to parse
+
:type data: string
+
"""
+
+
_, version_string = data.split(':')
+
version_parts = version_string.split(',')
+
+
self.serial_number = version_parts[0]
+
self.version_number = version_parts[1]
+
self.version_flags = version_parts[2]
+
def _handle_config(self, data):
"""
Handles received configuration data.
@@ -493,9 +535,9 @@
elif key == 'MASK':
self.address_mask = int(val, 16)
elif key == 'EXP':
-
self.emulate_zone = [val[z] == 'Y' for z in range(5)]
+
self.emulate_zone = [val[z] == 'Y' for z in list(range(5))]
elif key == 'REL':
-
self.emulate_relay = [val[r] == 'Y' for r in range(4)]
+
self.emulate_relay = [val[r] == 'Y' for r in list(range(4))]
elif key == 'LRR':
self.emulate_lrr = (val == 'Y')
elif key == 'DEDUPLICATE':
@@ -699,6 +741,8 @@
"""
self.get_config()
+
self.get_version()
+
self.on_open()
def _on_close(self, sender, *args, **kwargs):
diff --git a/docs/build/html/_modules/alarmdecoder/devices.html b/docs/build/html/_modules/alarmdecoder/devices.html
index 619e06c..6fca0ca 100644
--- a/docs/build/html/_modules/alarmdecoder/devices.html
+++ b/docs/build/html/_modules/alarmdecoder/devices.html
@@ -69,10 +69,13 @@
import serial
import serial.tools.list_ports
import socket
+
import select
+
from builtins import bytes
from .util import CommError, TimeoutError, NoDeviceError, InvalidMessageError
from .event import event
+
have_pyftdi = False
try:
from pyftdi.pyftdi.ftdi import Ftdi, FtdiError
import usb.core
@@ -81,7 +84,15 @@
have_pyftdi = True
except ImportError:
-
have_pyftdi = False
+
try:
+
from pyftdi.ftdi import Ftdi, FtdiError
+
import usb.core
+
import usb.util
+
+
have_pyftdi = True
+
+
except ImportError:
+
have_pyftdi = False
try:
from OpenSSL import SSL, crypto
@@ -89,8 +100,16 @@
have_openssl = True
except ImportError:
-
from collections import namedtuple
-
SSL = namedtuple('SSL', ['Error', 'WantReadError', 'SysCallError'])
+
class SSL:
+
class Error(BaseException):
+
pass
+
+
class WantReadError(BaseException):
+
pass
+
+
class SysCallError(BaseException):
+
pass
+
have_openssl = False
@@ -110,7 +129,7 @@
Constructor
"""
self._id = ''
-
self._buffer = ''
+
self._buffer = b''
self._device = None
self._running = False
self._read_thread = None
@@ -220,10 +239,10 @@
except SSL.WantReadError:
pass
-
except CommError, err:
+
except CommError as err:
self._device.close()
-
except Exception, err:
+
except Exception as err:
self._device.close()
self._running = False
raise
@@ -275,7 +294,7 @@
try:
cls.__devices = Ftdi.find_all(query, nocache=True)
-
except (usb.core.USBError, FtdiError), err:
+
except (usb.core.USBError, FtdiError) as err:
raise CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)
return cls.__devices
@@ -482,10 +501,10 @@
self._id = self._serial_number
-
except (usb.core.USBError, FtdiError), err:
+
except (usb.core.USBError, FtdiError) as err:
raise NoDeviceError('Error opening device: {0}'.format(str(err)), err)
-
except KeyError, err:
+
except KeyError as err:
raise NoDeviceError('Unsupported device. ({0:04x}:{1:04x}) You probably need a newer version of pyftdi.'.format(err[0][0], err[0][1]))
else:
@@ -527,7 +546,7 @@
self.on_write(data=data)
-
except FtdiError, err:
+
except FtdiError as err:
raise CommError('Error writing to device: {0}'.format(str(err)), err)
[docs] def read(self):
@@ -542,7 +561,7 @@
try:
ret = self._device.read_data(1)
-
except (usb.core.USBError, FtdiError), err:
+
except (usb.core.USBError, FtdiError) as err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
return ret
@@ -567,7 +586,7 @@
timeout_event.reading = True
if purge_buffer:
-
self._buffer = ''
+
self._buffer = b''
got_line, ret = False, None
@@ -579,11 +598,11 @@
while timeout_event.reading:
buf = self._device.read_data(1)
-
if buf != '':
+
if buf != b'':
self._buffer += buf
-
if buf == "\n":
-
self._buffer = self._buffer.rstrip("\r\n")
+
if buf == b"\n":
+
self._buffer = self._buffer.rstrip(b"\r\n")
if len(self._buffer) > 0:
got_line = True
@@ -591,12 +610,12 @@
else:
time.sleep(0.01)
-
except (usb.core.USBError, FtdiError), err:
+
except (usb.core.USBError, FtdiError) as err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
else:
if got_line:
-
ret, self._buffer = self._buffer, ''
+
ret, self._buffer = self._buffer, b''
self.on_read(data=ret)
@@ -607,6 +626,12 @@
timer.cancel()
return ret
+
+[docs] def purge(self):
+
"""
+
Purges read/write buffers.
+
"""
+
self._device.purge_buffers()
def _get_serial_number(self):
"""
@@ -702,7 +727,7 @@
else:
devices = serial.tools.list_ports.comports()
- except serial.SerialException, err:
+ except serial.SerialException as err:
raise CommError('Error enumerating serial devices: {0}'.format(str(err)), err)
return devices
@@ -773,7 +798,7 @@
# all issues with it.
self._device.baudrate = baudrate
- except (serial.SerialException, ValueError, OSError), err:
+ except (serial.SerialException, ValueError, OSError) as err:
raise NoDeviceError('Error opening device on {0}.'.format(self._port), err)
else:
@@ -813,7 +838,7 @@
except serial.SerialTimeoutException:
pass
- except serial.SerialException, err:
+ except serial.SerialException as err:
raise CommError('Error writing to device.', err)
else:
@@ -831,7 +856,7 @@
try:
ret = self._device.read(1)
- except serial.SerialException, err:
+ except serial.SerialException as err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
return ret
@@ -856,7 +881,7 @@
timeout_event.reading = True
if purge_buffer:
- self._buffer = ''
+ self._buffer = b''
got_line, ret = False, None
@@ -869,11 +894,11 @@
buf = self._device.read(1)
# NOTE: AD2SERIAL apparently sends down \xFF on boot.
- if buf != '' and buf != "\xff":
+ if buf != b'' and buf != b"\xff":
self._buffer += buf
- if buf == "\n":
- self._buffer = self._buffer.rstrip("\r\n")
+ if buf == b"\n":
+ self._buffer = self._buffer.rstrip(b"\r\n")
if len(self._buffer) > 0:
got_line = True
@@ -881,12 +906,12 @@
else:
time.sleep(0.01)
- except (OSError, serial.SerialException), err:
+ except (OSError, serial.SerialException) as err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
else:
if got_line:
- ret, self._buffer = self._buffer, ''
+ ret, self._buffer = self._buffer, b''
self.on_read(data=ret)
@@ -897,6 +922,13 @@
timer.cancel()
return ret
+
+[docs] def purge(self):
+
"""
+
Purges read/write buffers.
+
"""
+
self._device.flushInput()
+
self._device.flushOutput()
[docs]class SocketDevice(Device):
@@ -1038,7 +1070,6 @@
self._init_ssl()
self._device.connect((self._host, self._port))
-
#self._device.setblocking(1)
if self._use_ssl:
while True:
@@ -1050,7 +1081,7 @@
self._id = '{0}:{1}'.format(self._host, self._port)
-
except socket.error, err:
+
except socket.error as err:
raise NoDeviceError('Error opening device at {0}:{1}'.format(self._host, self._port), err)
else:
@@ -1103,7 +1134,7 @@
self.on_write(data=data)
-
except (SSL.Error, socket.error), err:
+
except (SSL.Error, socket.error) as err:
raise CommError('Error writing to device.', err)
return data_sent
@@ -1118,9 +1149,12 @@
data = None
try:
-
data = self._device.recv(1)
+
read_ready, _, _ = select.select([self._device], [], [], 0)
+
+
if (len(read_ready) != 0):
+
data = self._device.recv(1)
-
except socket.error, err:
+
except socket.error as err:
raise CommError('Error while reading from device: {0}'.format(str(err)), err)
return data
@@ -1145,7 +1179,7 @@
timeout_event.reading = True
if purge_buffer:
-
self._buffer = ''
+
self._buffer = b''
got_line, ret = False, None
@@ -1155,24 +1189,31 @@
try:
while timeout_event.reading:
+
read_ready, _, _ = select.select([self._device], [], [], 0)
+
+
if (len(read_ready) == 0):
+
time.sleep(0.01)
+
continue
+
buf = self._device.recv(1)
-
if buf != '':
+
if buf != b'':
self._buffer += buf
-
if buf == "\n":
-
self._buffer = self._buffer.rstrip("\r\n")
+
if buf == b"\n":
+
self._buffer = self._buffer.rstrip(b"\r\n")
if len(self._buffer) > 0:
got_line = True
break
+
else:
time.sleep(0.01)
-
except socket.error, err:
+
except socket.error as err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
-
except SSL.SysCallError, err:
+
except SSL.SysCallError as err:
errno, msg = err
raise CommError('SSL error while reading from device: {0} ({1})'.format(msg, errno))
@@ -1181,7 +1222,7 @@
else:
if got_line:
-
ret, self._buffer = self._buffer, ''
+
ret, self._buffer = self._buffer, b''
self.on_read(data=ret)
@@ -1192,6 +1233,19 @@
timer.cancel()
return ret
+
+[docs] def purge(self):
+
"""
+
Purges read/write buffers.
+
"""
+
try:
+
self._device.setblocking(0)
+
while(self._device.recv(1)):
+
pass
+
except socket.error as err:
+
pass
+
finally:
+
self._device.setblocking(1)
def _init_ssl(self):
"""
@@ -1226,7 +1280,7 @@
self._device = SSL.Connection(ctx, self._device)
- except SSL.Error, err:
+ except SSL.Error as err:
raise CommError('Error setting up SSL connection.', err)
def _verify_ssl_callback(self, connection, x509, errnum, errdepth, ok):
diff --git a/docs/build/html/_modules/alarmdecoder/messages.html b/docs/build/html/_modules/alarmdecoder/messages.html
index ae01e4f..0f88b41 100644
--- a/docs/build/html/_modules/alarmdecoder/messages.html
+++ b/docs/build/html/_modules/alarmdecoder/messages.html
@@ -64,6 +64,8 @@
import re
import datetime
+from reprlib import repr
+
from .util import InvalidMessageError
from .panels import PANEL_TYPES, ADEMCO, DSC
@@ -185,7 +187,7 @@
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
- match = self._regex.match(data)
+ match = self._regex.match(str(data))
if match is None:
raise InvalidMessageError('Received invalid message: {0}'.format(data))
@@ -212,13 +214,13 @@
self.check_zone = is_bit_set(15)
self.perimeter_only = is_bit_set(16)
self.system_fault = is_bit_set(17)
- if self.bitfield[18] in PANEL_TYPES.keys():
+ if self.bitfield[18] in list(PANEL_TYPES):
self.panel_type = PANEL_TYPES[self.bitfield[18]]
# pos 20-21 - Unused.
self.text = alpha.strip('"')
self.mask = int(self.panel_data[3:3+8], 16)
- if self.panel_type == ADEMCO:
+ if self.panel_type in (ADEMCO, DSC):
if int(self.panel_data[19:21], 16) & 0x01 > 0:
# Current cursor location on the alpha display.
self.cursor_location = int(self.panel_data[21:23], 16)
@@ -340,7 +342,7 @@
"""Low battery indication"""
supervision = False
"""Supervision required indication"""
- loop = [False for _ in range(4)]
+ loop = [False for _ in list(range(4))]
"""Loop indicators"""
def __init__(self, data=None):
diff --git a/docs/build/html/_modules/alarmdecoder/util.html b/docs/build/html/_modules/alarmdecoder/util.html
index fd573e3..17cfdb7 100644
--- a/docs/build/html/_modules/alarmdecoder/util.html
+++ b/docs/build/html/_modules/alarmdecoder/util.html
@@ -57,6 +57,7 @@
import time
import threading
+from io import open
[docs]class NoDeviceError(Exception):
@@ -86,6 +87,20 @@
"""
pass
+
+[docs]class UploadError(Exception):
+
"""
+
Generic firmware upload error.
+
"""
+
pass
+
+
+[docs]class UploadChecksumError(UploadError):
+
"""
+
The firmware upload failed due to a checksum error.
+
"""
+
pass
+
[docs]class Firmware(object):
"""
@@ -99,10 +114,12 @@
STAGE_LOAD = 3
STAGE_UPLOADING = 4
STAGE_DONE = 5
+
STAGE_ERROR = 98
+
STAGE_DEBUG = 99
# FIXME: Rewrite this monstrosity.
@staticmethod
-
[docs] def upload(dev, filename, progress_callback=None):
+
[docs] def upload(dev, filename, progress_callback=None, debug=False):
"""
Uploads firmware to an `AlarmDecoder`_ device.
@@ -119,15 +136,29 @@
Perform the actual firmware upload to the device.
"""
with open(filename) as upload_file:
+
line_cnt = 0
for line in upload_file:
+
line_cnt += 1
line = line.rstrip()
if line[0] == ':':
dev.write(line + "\r")
-
dev.read_line(timeout=10.0)
+
response = dev.read_line(timeout=5.0, purge_buffer=True)
+
if debug:
+
stage_callback(Firmware.STAGE_DEBUG, data="line={0} - line={1} response={2}".format(line_cnt, line, response));
+
+
if '!ce' in response:
+
raise UploadChecksumError("Checksum error on line " + str(line_cnt) + " of " + filename);
+
+
elif '!no' in response:
+
raise UploadError("Incorrect data sent to bootloader.")
+
+
elif '!ok' in response:
+
break
-
if progress_callback is not None:
-
progress_callback(Firmware.STAGE_UPLOADING)
+
else:
+
if progress_callback is not None:
+
progress_callback(Firmware.STAGE_UPLOADING)
time.sleep(0.0)
@@ -149,6 +180,8 @@
position = 0
+
dev.purge()
+
while timeout_event.reading:
try:
char = dev.read()
@@ -161,7 +194,7 @@
else:
position = 0
-
except Exception:
+
except Exception as err:
pass
if timer:
@@ -170,10 +203,10 @@
else:
raise TimeoutError('Timeout while waiting for line terminator.')
-
def stage_callback(stage):
+
def stage_callback(stage, **kwargs):
"""Callback to update progress for the specified stage."""
if progress_callback is not None:
-
progress_callback(stage)
+
progress_callback(stage, **kwargs)
if dev is None:
raise NoDeviceError('No device specified for firmware upload.')
@@ -186,24 +219,39 @@
dev.stop_reader()
while dev._read_thread.is_alive():
stage_callback(Firmware.STAGE_WAITING)
-
time.sleep(1)
-
-
time.sleep(2)
+
time.sleep(0.5)
# Reboot the device and wait for the boot loader.
-
stage_callback(Firmware.STAGE_BOOT)
-
dev.write("=")
-
read_until('......', timeout=15.0)
-
-
# Get ourselves into the boot loader and wait for indication
-
# that it's ready for the firmware upload.
-
stage_callback(Firmware.STAGE_LOAD)
-
dev.write("=")
-
read_until('!load', timeout=15.0)
+
retry = 3
+
found_loader = False
+
while retry > 0:
+
try:
+
stage_callback(Firmware.STAGE_BOOT)
+
dev.write("=")
+
read_until('!boot', timeout=15.0)
+
+
# Get ourselves into the boot loader and wait for indication
+
# that it's ready for the firmware upload.
+
stage_callback(Firmware.STAGE_LOAD)
+
dev.write("=")
+
read_until('!load', timeout=15.0)
+
+
except TimeoutError as err:
+
retry -= 1
+
else:
+
retry = 0
+
found_loader = True
# And finally do the upload.
-
do_upload()
-
stage_callback(Firmware.STAGE_DONE)
+
if found_loader:
+
try:
+
do_upload()
+
except UploadError as err:
+
stage_callback(Firmware.STAGE_ERROR, error=str(err))
+
else:
+
stage_callback(Firmware.STAGE_DONE)
+
else:
+
stage_callback(Firmware.STAGE_ERROR, error="Error entering bootloader.")
diff --git a/docs/build/html/_modules/alarmdecoder/zonetracking.html b/docs/build/html/_modules/alarmdecoder/zonetracking.html
index b895296..090fccb 100644
--- a/docs/build/html/_modules/alarmdecoder/zonetracking.html
+++ b/docs/build/html/_modules/alarmdecoder/zonetracking.html
@@ -226,7 +226,7 @@
self._last_zone_fault = 0
# Process fault
- elif message.check_zone or message.text.startswith("FAULT"):
+ elif message.check_zone or message.text.startswith("FAULT") or message.text.startswith("ALARM"):
# Apparently this representation can be both base 10
# or base 16, depending on where the message came
# from.
@@ -307,7 +307,7 @@
it = iter(self._zones_faulted)
try:
while not found_last_faulted:
- z = it.next()
+ z = next(it)
if z == self._last_zone_fault:
found_last_faulted = True
@@ -320,7 +320,7 @@
# between to our clear list.
try:
while not at_end and not found_current:
- z = it.next()
+ z = next(it)
if z == zone:
found_current = True
@@ -338,7 +338,7 @@
try:
while not found_current:
- z = it.next()
+ z = next(it)
if z == zone:
found_current = True
@@ -359,7 +359,7 @@
"""
zones = []
- for z in self._zones.keys():
+ for z in list(self._zones.keys()):
zones += [z]
for z in zones:
diff --git a/docs/build/html/alarmdecoder.html b/docs/build/html/alarmdecoder.html
index 1130dbd..e0774a8 100644
--- a/docs/build/html/alarmdecoder.html
+++ b/docs/build/html/alarmdecoder.html
@@ -309,6 +309,24 @@
The panel mode that the AlarmDecoder is in. Currently supports ADEMCO and DSC.
+
+-
+serial_number = 4294967295
+The device serial number
+
+
+
+-
+version_number = 'Unknown'
+The device firmware version
+
+
+
+-
+version_flags = ''
+Device flags enabled
+
+
-
id[source]
@@ -416,6 +434,17 @@ thread should be started.
Sets configuration entries on the device.
+
+-
+get_config_string()[source]
+
+
+
+-
+get_version()[source]
+Retrieves the version string from the device. Called automatically by _on_open().
+
+
-
reboot()[source]
@@ -813,6 +842,12 @@ reading.
+
+-
+purge()[source]
+Purges read/write buffers.
+
+
-
class DetectThread(on_attached=None, on_detached=None)[source]
@@ -981,6 +1016,12 @@ reading.
+
+-
+purge()[source]
+Purges read/write buffers.
+
+
@@ -1152,6 +1193,12 @@ reading.
+
+-
+purge()[source]
+Purges read/write buffers.
+
+
@@ -1656,6 +1703,20 @@ devices.
The format of the panel message was invalid.
+
+-
+exception alarmdecoder.util.UploadError[source]
+Bases: exceptions.Exception
+Generic firmware upload error.
+
+
+
+-
+exception alarmdecoder.util.UploadChecksumError[source]
+Bases: alarmdecoder.util.UploadError
+The firmware upload failed due to a checksum error.
+
+
-
class alarmdecoder.util.Firmware[source]
@@ -1691,9 +1752,19 @@ devices.
STAGE_DONE = 5
+
+-
+STAGE_ERROR = 98
+
+
+
+-
+STAGE_DEBUG = 99
+
+
-
-static upload(dev, filename, progress_callback=None)[source]
+static upload(dev, filename, progress_callback=None, debug=False)[source]
Uploads firmware to an AlarmDecoder device.
@@ -771,12 +781,12 @@
- partition (alarmdecoder.messages.LRRMessage attribute)
-
-
- perimeter_only (alarmdecoder.messages.Message attribute)
+ |
+
- PRODUCT_IDS (alarmdecoder.devices.USBDevice attribute)
@@ -785,6 +795,20 @@
- programming_mode (alarmdecoder.messages.Message attribute)
+
+ - purge() (alarmdecoder.devices.SerialDevice method)
+
+
+
+
+ - (alarmdecoder.devices.SocketDevice method)
+
+
+
+ - (alarmdecoder.devices.USBDevice method)
+
+
+
|
@@ -874,11 +898,15 @@
- serial_number (alarmdecoder.devices.USBDevice attribute)
+ serial_number (alarmdecoder.decoder.AlarmDecoder attribute)
+ - (alarmdecoder.devices.USBDevice attribute)
+
+
+
- (alarmdecoder.messages.RFMessage attribute)
@@ -912,16 +940,24 @@
+ - STAGE_DEBUG (alarmdecoder.util.Firmware attribute)
+
+
+
- STAGE_DONE (alarmdecoder.util.Firmware attribute)
- - STAGE_LOAD (alarmdecoder.util.Firmware attribute)
+
- STAGE_ERROR (alarmdecoder.util.Firmware attribute)
+ - STAGE_LOAD (alarmdecoder.util.Firmware attribute)
+
+
+
- STAGE_START (alarmdecoder.util.Firmware attribute)
@@ -1015,9 +1051,17 @@
- upload() (alarmdecoder.util.Firmware static method)
+
+ - UploadChecksumError
+
+
|
+ - UploadError
+
+
+
- USBDevice (class in alarmdecoder.devices)
@@ -1041,6 +1085,16 @@
+
+ version_flags (alarmdecoder.decoder.AlarmDecoder attribute)
+
+
+ |
+
+
+ - version_number (alarmdecoder.decoder.AlarmDecoder attribute)
+
+
|
diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv
index f375d3b..4a2c459 100644
Binary files a/docs/build/html/objects.inv and b/docs/build/html/objects.inv differ
diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js
index 4ae7fa2..dee317e 100644
--- a/docs/build/html/searchindex.js
+++ b/docs/build/html/searchindex.js
@@ -1 +1 @@
-Search.setIndex({envversion:42,terms:{represent:3,all:[0,3],code:[3,2],sleep:2,on_boot:3,stage_don:3,backlight:3,zone:3,readabl:3,send:3,program:3,x03:3,x02:3,x01:3,must:0,sent:3,x04:3,sourc:[0,2,3],string:3,clear_zon:3,fals:3,on_messag:[3,2],perimeter_onli:3,lrr:3,on_alarm_restor:3,level:3,list:3,upload:3,dsc:3,"try":[3,2],emul:3,expandermessag:3,pleas:2,second:3,port:3,supervis:3,ad2seri:[3,2],current:3,"new":0,method:3,ser2sock:3,perimet:3,timeouterror:3,usbdevic:[3,2],entry_delay_off:3,here:2,on_config_receiv:3,address:3,path:3,valu:3,fire_alarm:3,search:[3,2],sender:[0,2],prior:3,def:[3,2],invalidmessageerror:3,via:3,vid:3,appli:3,filenam:3,api:2,famili:[3,2],key_pan:3,from:[3,2],usb:[3,2],commun:3,is_reader_al:3,handler:[0,2],call:[0,3],type:3,more:2,relat:3,stage_boot:3,pkei:3,flag:3,templat:3,relai:3,expander_to_zon:3,cach:3,serialdevic:3,product_id:3,none:[0,3],retriev:[3,2],thread:3,on_restor:3,restor:3,dev:3,itself:0,can:0,aliv:3,backlight_on:3,process:3,indic:[],high:3,cursor_loc:3,serial:3,occur:3,delai:3,progress_callback:3,secur:2,anoth:3,simulate_wire_problem:3,write:3,purg:3,instead:0,panic:3,panel_typ:3,updat:3,product:3,recogn:3,x509:3,ftdi:3,befor:3,attent:3,mai:2,associ:3,classmethod:3,ssl_ca:3,issu:3,callback:3,"switch":3,ttimeout:3,socketdevic:3,disarm:3,jpath:3,through:3,paramet:3,bypass:3,on_read:3,main:[3,2],"return":3,python:2,timestamp:3,on_bypass:3,detach:3,name:3,revert:3,on_pan:3,authent:3,stage_wait:3,mode:3,timeout:3,found:[3,2],nodeviceerror:3,"static":3,connect:3,our:3,read_lin:3,event:[],ad2pi:[3,2],reboot:3,content:2,reader:3,print:2,factori:3,state:3,standard:3,on_clos:3,base:[0,3],dictionari:3,"byte":3,armed_hom:3,on_detach:3,key_f4:3,key_f1:3,key_f2:3,key_f3:3,emulate_relai:3,openssl:3,readthread:3,get_config:3,on_rfx_messag:3,find_al:3,ad2usb:[3,2],first:[3,2],oper:0,rang:3,number:3,done:3,on_writ:3,configbit:3,open:[3,2],on_power_chang:3,differ:3,data:3,interact:2,system:3,wrapper:3,attach:3,start_detect:3,on_open:3,termin:2,battery_low:3,specifi:3,rfmessag:3,on_fir:3,provid:[3,2],remov:[0,3],charact:3,project:2,save_config:3,bitfield:3,check_zon:3,on_fault:3,expir:3,"__main__":2,programming_mod:3,also:[0,3],exampl:2,which:3,event_data:3,channel:3,thi:[3,2],index:2,buffer:3,object:[0,3],most:3,detect:3,basemessag:3,"class":[0,3],armed_awai:3,doc:0,clear:3,request:3,emulate_lrr:3,doe:3,on_low_batteri:3,text:3,default_product_id:3,ssl_kei:3,radio:3,find:[3,2],locat:3,configur:3,solut:3,fault_zon:3,should:3,dict:3,serial_numb:3,stop:3,ssl:3,"import":2,report:3,requir:[3,2],fileno:3,enabl:3,earg:0,"default":3,common:3,partit:3,contain:3,alarm_event_occur:3,certif:3,set:[3,2],keypad:3,ac_pow:3,displai:3,see:2,arg:0,close:3,arm:3,stop_read:3,pyseri:3,statu:3,wire:3,pattern:3,keypress:3,written:3,between:3,progress:3,awai:3,kei:3,numer:3,alarmdecoder_object:3,last:3,fault:3,internal_address_mask:3,batteri:3,on_attach:3,detectthread:3,been:3,beep:3,trigger:3,basic:2,no_reader_thread:3,fire:[0,3],commerror:3,chime_on:3,convert:3,func:0,present:3,sound:3,raw:[3,2],dedupl:3,cursor:3,defin:0,"while":[3,2],stage_upload:3,error:3,loop:3,readi:3,kwarg:[0,3],ftdi_vendor_id:3,on_zone_fault:3,alarm_sound:3,panel_data:3,author:3,receiv:3,belong:3,handl:[3,2],status:3,finish:3,expans:3,rais:3,user:3,expand:3,lower:3,entri:3,client:3,zone_bypass:3,usual:3,when:3,human:3,baudrat:3,expos:3,on_disarm:3,"_on_open":3,except:[3,2],identif:3,add:0,board:3,match:3,applic:2,vendor:3,around:3,format:3,read:3,numeric_cod:3,lcd:3,bit:3,ad2:[3,2],like:0,deprec:3,singl:3,page:2,default_vendor_id:3,crypto:3,intern:3,sampl:2,system_fault:3,fire_timeout:3,home:3,librari:2,definit:3,pyftdi:3,localhost:3,run:3,power:3,event_typ:3,stage_load:3,ssl_certif:3,"__name__":2,describ:3,actual:3,simul:3,stage_start:3,includ:2,address_mask:3,"float":3,automat:3,chime:3,support:[3,2],on_relay_chang:3,"long":3,start:3,interfac:3,low:3,on_expander_messag:3,stop_detect:3,"function":[0,3],tupl:3,eventhandl:0,line:3,"true":2,emulate_zon:3,whether:3,on_alarm:3,purge_buff:3,below:2,alarm:[],"int":3,mask:3,x05:3,pid:3,repres:3,on_zone_restor:3,exist:[0,3],ademco:3,read_timeout:3,ftdi_product_id:3,check:3,battery_timeout:3,handle_messag:2,boot:3,invalid:3,field:3,bool:3,you:0,intend:3,firmwar:3,track:3,on_arm:3,on_sending_receiv:3,directori:2,descript:3,lrrmessag:3,on_lrr_messag:3,obj:0,time:2},objtypes:{"0":"py:module","1":"py:attribute","2":"py:class","3":"py:method","4":"py:exception","5":"py:classmethod","6":"py:staticmethod"},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","exception","Python exception"],"5":["py","classmethod","Python class method"],"6":["py","staticmethod","Python static method"]},filenames:["alarmdecoder.event","modules","index","alarmdecoder"],titles:["event Package","alarmdecoder","Welcome to Alarm Decoder’s documentation!","alarmdecoder Package"],objects:{"alarmdecoder.messages.LRRMessage":{partition:[3,1,1,""],dict:[3,3,1,""],event_data:[3,1,1,""],event_type:[3,1,1,""]},"alarmdecoder.messages.BaseMessage":{raw:[3,1,1,""],dict:[3,3,1,""],timestamp:[3,1,1,""]},"alarmdecoder.messages.ExpanderMessage":{ZONE:[3,1,1,""],RELAY:[3,1,1,""],value:[3,1,1,""],dict:[3,3,1,""],address:[3,1,1,""],type:[3,1,1,""],channel:[3,1,1,""]},"alarmdecoder.event.event":{EventHandler:[0,2,1,""],Event:[0,2,1,""]},"alarmdecoder.zonetracking.Zone":{status:[3,1,1,""],STATUS:[3,1,1,""],name:[3,1,1,""],zone:[3,1,1,""],timestamp:[3,1,1,""],CLEAR:[3,1,1,""],expander:[3,1,1,""],FAULT:[3,1,1,""],CHECK:[3,1,1,""]},"alarmdecoder.devices.SerialDevice":{fileno:[3,3,1,""],BAUDRATE:[3,1,1,""],read:[3,3,1,""],read_line:[3,3,1,""],write:[3,3,1,""],find_all:[3,6,1,""],"interface":[3,1,1,""],close:[3,3,1,""],open:[3,3,1,""]},"alarmdecoder.zonetracking":{Zonetracker:[3,2,1,""],Zone:[3,2,1,""]},"alarmdecoder.zonetracking.Zonetracker":{faulted:[3,1,1,""],on_restore:[3,1,1,""],update:[3,3,1,""],zones:[3,1,1,""],on_fault:[3,1,1,""],EXPIRE:[3,1,1,""],expander_to_zone:[3,3,1,""]},"alarmdecoder.devices.Device.ReadThread":{READ_TIMEOUT:[3,1,1,""],stop:[3,3,1,""],run:[3,3,1,""]},"alarmdecoder.event":{event:[0,0,0,"-"]},"alarmdecoder.messages":{Message:[3,2,1,""],LRRMessage:[3,2,1,""],RFMessage:[3,2,1,""],ExpanderMessage:[3,2,1,""],BaseMessage:[3,2,1,""]},"alarmdecoder.devices":{Device:[3,2,1,""],SocketDevice:[3,2,1,""],USBDevice:[3,2,1,""],SerialDevice:[3,2,1,""]},"alarmdecoder.devices.USBDevice.DetectThread":{stop:[3,3,1,""],run:[3,3,1,""],on_attached:[3,1,1,""],on_detached:[3,1,1,""]},alarmdecoder:{zonetracking:[3,0,0,"-"],messages:[3,0,0,"-"],devices:[3,0,0,"-"],util:[3,0,0,"-"],decoder:[3,0,0,"-"],panels:[3,0,0,"-"],event:[0,0,0,"-"]},"alarmdecoder.decoder.AlarmDecoder":{configbits:[3,1,1,""],on_rfx_message:[3,1,1,""],fault_zone:[3,3,1,""],on_expander_message:[3,1,1,""],on_open:[3,1,1,""],save_config:[3,3,1,""],on_alarm:[3,1,1,""],on_arm:[3,1,1,""],internal_address_mask:[3,1,1,""],on_sending_received:[3,1,1,""],KEY_PANIC:[3,1,1,""],fire_timeout:[3,1,1,""],close:[3,3,1,""],open:[3,3,1,""],id:[3,1,1,""],on_power_changed:[3,1,1,""],BATTERY_TIMEOUT:[3,1,1,""],KEY_F1:[3,1,1,""],KEY_F2:[3,1,1,""],KEY_F3:[3,1,1,""],on_message:[3,1,1,""],reboot:[3,3,1,""],send:[3,3,1,""],on_zone_restore:[3,1,1,""],on_disarm:[3,1,1,""],on_fire:[3,1,1,""],on_write:[3,1,1,""],on_read:[3,1,1,""],on_lrr_message:[3,1,1,""],KEY_F4:[3,1,1,""],clear_zone:[3,3,1,""],on_zone_fault:[3,1,1,""],on_config_received:[3,1,1,""],on_alarm_restored:[3,1,1,""],emulate_relay:[3,1,1,""],on_close:[3,1,1,""],on_bypass:[3,1,1,""],address:[3,1,1,""],battery_timeout:[3,1,1,""],on_panic:[3,1,1,""],on_relay_changed:[3,1,1,""],on_low_battery:[3,1,1,""],emulate_lrr:[3,1,1,""],deduplicate:[3,1,1,""],emulate_zone:[3,1,1,""],get_config:[3,3,1,""],mode:[3,1,1,""],address_mask:[3,1,1,""],FIRE_TIMEOUT:[3,1,1,""],on_boot:[3,1,1,""]},"alarmdecoder.devices.SocketDevice":{ssl_certificate:[3,1,1,""],ssl_key:[3,1,1,""],fileno:[3,3,1,""],read:[3,3,1,""],ssl_ca:[3,1,1,""],read_line:[3,3,1,""],ssl:[3,1,1,""],write:[3,3,1,""],"interface":[3,1,1,""],close:[3,3,1,""],open:[3,3,1,""]},"alarmdecoder.devices.USBDevice":{fileno:[3,3,1,""],BAUDRATE:[3,1,1,""],description:[3,1,1,""],read:[3,3,1,""],DetectThread:[3,2,1,""],stop_detection:[3,5,1,""],DEFAULT_PRODUCT_ID:[3,1,1,""],DEFAULT_VENDOR_ID:[3,1,1,""],devices:[3,5,1,""],start_detection:[3,5,1,""],read_line:[3,3,1,""],write:[3,3,1,""],find_all:[3,5,1,""],FTDI_VENDOR_ID:[3,1,1,""],serial_number:[3,1,1,""],"interface":[3,1,1,""],close:[3,3,1,""],FTDI_PRODUCT_ID:[3,1,1,""],open:[3,3,1,""],find:[3,5,1,""],PRODUCT_IDS:[3,1,1,""]},"alarmdecoder.messages.Message":{backlight_on:[3,1,1,""],alarm_event_occurred:[3,1,1,""],programming_mode:[3,1,1,""],text:[3,1,1,""],bitfield:[3,1,1,""],armed_home:[3,1,1,""],alarm_sounding:[3,1,1,""],ready:[3,1,1,""],zone_bypassed:[3,1,1,""],panel_data:[3,1,1,""],check_zone:[3,1,1,""],numeric_code:[3,1,1,""],dict:[3,3,1,""],battery_low:[3,1,1,""],chime_on:[3,1,1,""],entry_delay_off:[3,1,1,""],perimeter_only:[3,1,1,""],fire_alarm:[3,1,1,""],ac_power:[3,1,1,""],beeps:[3,1,1,""],mask:[3,1,1,""],system_fault:[3,1,1,""],armed_away:[3,1,1,""],panel_type:[3,1,1,""],cursor_location:[3,1,1,""]},"alarmdecoder.devices.Device":{stop_reader:[3,3,1,""],on_open:[3,1,1,""],on_write:[3,1,1,""],ReadThread:[3,2,1,""],on_close:[3,1,1,""],on_read:[3,1,1,""],close:[3,3,1,""],is_reader_alive:[3,3,1,""],id:[3,1,1,""]},"alarmdecoder.messages.RFMessage":{battery:[3,1,1,""],value:[3,1,1,""],dict:[3,3,1,""],supervision:[3,1,1,""],serial_number:[3,1,1,""],loop:[3,1,1,""]},"alarmdecoder.decoder":{AlarmDecoder:[3,2,1,""]},"alarmdecoder.event.event.EventHandler":{fire:[0,3,1,""],add:[0,3,1,""],remove:[0,3,1,""]},"alarmdecoder.util.Firmware":{STAGE_LOAD:[3,1,1,""],upload:[3,6,1,""],STAGE_BOOT:[3,1,1,""],STAGE_START:[3,1,1,""],STAGE_UPLOADING:[3,1,1,""],STAGE_WAITING:[3,1,1,""],STAGE_DONE:[3,1,1,""]},"alarmdecoder.util":{CommError:[3,4,1,""],Firmware:[3,2,1,""],TimeoutError:[3,4,1,""],NoDeviceError:[3,4,1,""],InvalidMessageError:[3,4,1,""]}},titleterms:{alarmdecod:[3,1],welcom:2,alarm:2,devic:3,messag:3,util:3,packag:[0,3],decod:[3,2],zonetrack:3,indic:2,tabl:2,modul:[0,3],document:2,event:0,panel:3}})
\ No newline at end of file
+Search.setIndex({envversion:42,terms:{represent:2,all:[0,2],code:[3,2],sleep:3,on_boot:2,stage_don:2,backlight:2,zone:2,readabl:2,send:2,program:2,x03:2,x02:2,x01:2,sent:2,x04:2,sourc:[0,2,3],string:2,clear_zon:2,fals:2,on_messag:[3,2],perimeter_onli:2,lrr:2,on_alarm_restor:2,level:2,list:2,upload:2,dsc:2,"try":[3,2],emul:2,expandermessag:2,pleas:3,second:2,port:2,supervis:2,ad2seri:[3,2],current:2,version:2,"new":0,method:2,ser2sock:2,perimet:2,timeouterror:2,gener:2,usbdevic:[3,2],entry_delay_off:2,here:3,on_config_receiv:2,address:2,path:2,valu:2,fire_alarm:2,search:[3,2],sender:[0,3],checksum:2,prior:2,def:[3,2],invalidmessageerror:2,via:2,vid:2,appli:2,filenam:2,api:3,famili:[3,2],key_pan:2,from:[3,2],usb:[3,2],commun:2,is_reader_al:2,handler:[0,3],call:[0,2],type:2,more:3,relat:2,stage_boot:2,pkei:2,flag:2,templat:2,relai:2,actual:2,cach:2,serialdevic:2,must:0,none:[0,2],retriev:[3,2],key_f2:2,on_restor:2,restor:2,dev:2,itself:0,can:0,aliv:2,backlight_on:2,process:2,indic:[],high:2,cursor_loc:2,serial:2,occur:2,delai:2,progress_callback:2,secur:3,anoth:2,simulate_wire_problem:2,write:2,uploadchecksumerror:2,purg:2,low:2,instead:0,panic:2,panel_typ:2,updat:2,product:2,recogn:2,x509:2,ftdi:2,befor:2,attent:2,mai:3,data:2,classmethod:2,ssl_ca:2,issu:2,callback:2,"switch":2,ttimeout:2,socketdevic:2,disarm:2,jpath:2,through:2,paramet:2,bypass:2,on_read:2,main:[3,2],"return":2,python:3,timestamp:2,on_bypass:2,detach:2,name:2,revert:2,version_flag:2,authent:2,stage_wait:2,mode:2,timeout:2,debug:2,found:[3,2],nodeviceerror:2,"static":2,connect:2,our:2,read_lin:2,event:[],ad2pi:[3,2],reboot:2,content:3,reader:2,print:3,factori:2,written:2,standard:2,on_clos:2,base:[0,2],dictionari:2,"byte":2,armed_hom:2,on_detach:2,key_f4:2,product_id:2,thread:2,key_f3:2,emulate_relai:2,openssl:2,readthread:2,get_config:2,on_rfx_messag:2,find_al:2,ad2usb:[3,2],first:[3,2],oper:0,rang:2,number:2,done:2,on_writ:2,configbit:2,open:[3,2],on_power_chang:2,differ:2,unknown:2,interact:3,system:2,wrapper:2,attach:2,start_detect:2,on_open:2,termin:3,battery_low:2,specifi:2,rfmessag:2,on_fir:2,provid:[3,2],remov:[0,2],charact:2,project:3,save_config:2,bitfield:2,raw:[3,2],dedupl:2,expir:2,"__main__":3,programming_mod:2,also:[0,2],exampl:3,which:2,event_data:2,channel:2,thi:[3,2],index:3,buffer:2,object:[0,2],most:2,detect:2,basemessag:2,"class":[0,2],armed_awai:2,doc:0,clear:2,request:2,emulate_lrr:2,doe:2,on_low_batteri:2,error:2,text:2,default_product_id:2,ssl_kei:2,radio:2,find:[3,2],locat:2,configur:2,solut:2,fault_zon:2,should:2,key_f1:2,dict:2,get_vers:2,serial_numb:2,stop:2,ssl:2,progress:2,report:2,requir:[3,2],fileno:2,enabl:2,earg:0,whether:2,common:2,partit:2,contain:2,alarm_event_occur:2,certif:2,set:[3,2],keypad:2,ac_pow:2,on_alarm:2,see:3,arg:0,fail:2,close:2,arm:2,stop_read:2,pyseri:2,statu:2,wire:2,pattern:2,keypress:2,state:2,between:2,"import":3,awai:2,kei:2,numer:2,baudrat:2,alarmdecoder_object:2,last:2,fault:2,internal_address_mask:2,batteri:2,identif:2,detectthread:2,due:2,been:2,beep:2,trigger:2,basic:3,no_reader_thread:2,fire:[0,2],commerror:2,chime_on:2,convert:2,func:0,present:2,sound:2,check_zon:2,on_fault:2,cursor:2,defin:0,"while":[3,2],match:2,version_numb:2,loop:2,readi:2,kwarg:[0,2],ftdi_vendor_id:2,vendor:2,alarm_sound:2,panel_data:2,author:2,receiv:2,belong:2,handl:[3,2],status:2,finish:2,expans:2,rais:2,user:2,expand:2,lower:2,entri:2,client:2,zone_bypass:2,usual:2,boot:2,human:2,stage_error:2,expos:2,field:2,"_on_open":2,except:[3,2],on_attach:2,add:0,board:2,get_config_str:2,uploaderror:2,stage_upload:2,applic:3,on_zone_fault:2,around:2,format:2,read:2,numeric_cod:2,lcd:2,bit:2,associ:2,ad2:[3,2],like:0,deprec:2,singl:2,page:3,default_vendor_id:2,on_pan:2,intern:2,sampl:3,system_fault:2,fire_timeout:2,home:2,librari:3,definit:2,pyftdi:2,localhost:2,run:2,power:2,event_typ:2,stage_load:2,ssl_certif:2,"__name__":3,describ:2,expander_to_zon:2,simul:2,stage_start:2,address_mask:2,"float":2,automat:2,chime:2,crypto:2,support:[3,2],on_relay_chang:2,"long":2,start:2,interfac:2,includ:3,on_expander_messag:2,stop_detect:2,"function":[0,2],tupl:2,eventhandl:0,line:2,"true":3,emulate_zon:2,"default":2,displai:2,purge_buff:2,below:3,stage_debug:2,alarm:[],"int":2,descript:2,x05:2,pid:2,repres:2,on_zone_restor:2,exist:[0,2],ademco:2,read_timeout:2,ftdi_product_id:2,check:2,battery_timeout:2,handle_messag:3,when:2,invalid:2,on_disarm:2,bool:2,you:0,intend:2,firmwar:2,track:2,on_arm:2,on_sending_receiv:2,directori:3,mask:2,lrrmessag:2,on_lrr_messag:2,obj:0,time:3},objtypes:{"0":"py:module","1":"py:attribute","2":"py:class","3":"py:method","4":"py:exception","5":"py:classmethod","6":"py:staticmethod"},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","exception","Python exception"],"5":["py","classmethod","Python class method"],"6":["py","staticmethod","Python static method"]},filenames:["alarmdecoder.event","modules","alarmdecoder","index"],titles:["event Package","alarmdecoder","alarmdecoder Package","Welcome to Alarm Decoder’s documentation!"],objects:{"alarmdecoder.messages.LRRMessage":{partition:[2,1,1,""],dict:[2,3,1,""],event_data:[2,1,1,""],event_type:[2,1,1,""]},"alarmdecoder.messages.BaseMessage":{raw:[2,1,1,""],dict:[2,3,1,""],timestamp:[2,1,1,""]},"alarmdecoder.messages.ExpanderMessage":{ZONE:[2,1,1,""],RELAY:[2,1,1,""],value:[2,1,1,""],dict:[2,3,1,""],address:[2,1,1,""],type:[2,1,1,""],channel:[2,1,1,""]},"alarmdecoder.event.event":{EventHandler:[0,2,1,""],Event:[0,2,1,""]},"alarmdecoder.zonetracking.Zone":{status:[2,1,1,""],STATUS:[2,1,1,""],name:[2,1,1,""],zone:[2,1,1,""],timestamp:[2,1,1,""],CLEAR:[2,1,1,""],expander:[2,1,1,""],FAULT:[2,1,1,""],CHECK:[2,1,1,""]},"alarmdecoder.devices.SerialDevice":{write:[2,3,1,""],BAUDRATE:[2,1,1,""],fileno:[2,3,1,""],read:[2,3,1,""],read_line:[2,3,1,""],purge:[2,3,1,""],find_all:[2,6,1,""],"interface":[2,1,1,""],close:[2,3,1,""],open:[2,3,1,""]},"alarmdecoder.zonetracking":{Zonetracker:[2,2,1,""],Zone:[2,2,1,""]},"alarmdecoder.zonetracking.Zonetracker":{faulted:[2,1,1,""],on_restore:[2,1,1,""],update:[2,3,1,""],zones:[2,1,1,""],on_fault:[2,1,1,""],EXPIRE:[2,1,1,""],expander_to_zone:[2,3,1,""]},"alarmdecoder.devices.Device.ReadThread":{READ_TIMEOUT:[2,1,1,""],stop:[2,3,1,""],run:[2,3,1,""]},"alarmdecoder.event":{event:[0,0,0,"-"]},"alarmdecoder.messages":{Message:[2,2,1,""],LRRMessage:[2,2,1,""],RFMessage:[2,2,1,""],ExpanderMessage:[2,2,1,""],BaseMessage:[2,2,1,""]},"alarmdecoder.devices":{Device:[2,2,1,""],SocketDevice:[2,2,1,""],USBDevice:[2,2,1,""],SerialDevice:[2,2,1,""]},"alarmdecoder.devices.USBDevice.DetectThread":{stop:[2,3,1,""],run:[2,3,1,""],on_attached:[2,1,1,""],on_detached:[2,1,1,""]},alarmdecoder:{zonetracking:[2,0,0,"-"],messages:[2,0,0,"-"],devices:[2,0,0,"-"],util:[2,0,0,"-"],decoder:[2,0,0,"-"],panels:[2,0,0,"-"],event:[0,0,0,"-"]},"alarmdecoder.decoder.AlarmDecoder":{configbits:[2,1,1,""],on_rfx_message:[2,1,1,""],fault_zone:[2,3,1,""],on_expander_message:[2,1,1,""],on_open:[2,1,1,""],save_config:[2,3,1,""],serial_number:[2,1,1,""],on_alarm:[2,1,1,""],on_arm:[2,1,1,""],internal_address_mask:[2,1,1,""],on_sending_received:[2,1,1,""],KEY_PANIC:[2,1,1,""],fire_timeout:[2,1,1,""],close:[2,3,1,""],open:[2,3,1,""],id:[2,1,1,""],on_power_changed:[2,1,1,""],BATTERY_TIMEOUT:[2,1,1,""],KEY_F1:[2,1,1,""],KEY_F2:[2,1,1,""],KEY_F3:[2,1,1,""],on_message:[2,1,1,""],get_version:[2,3,1,""],reboot:[2,3,1,""],send:[2,3,1,""],version_flags:[2,1,1,""],on_zone_restore:[2,1,1,""],on_disarm:[2,1,1,""],on_fire:[2,1,1,""],on_write:[2,1,1,""],on_read:[2,1,1,""],on_lrr_message:[2,1,1,""],KEY_F4:[2,1,1,""],clear_zone:[2,3,1,""],on_zone_fault:[2,1,1,""],on_config_received:[2,1,1,""],on_alarm_restored:[2,1,1,""],get_config_string:[2,3,1,""],emulate_relay:[2,1,1,""],on_close:[2,1,1,""],on_bypass:[2,1,1,""],address:[2,1,1,""],battery_timeout:[2,1,1,""],on_panic:[2,1,1,""],on_relay_changed:[2,1,1,""],version_number:[2,1,1,""],on_low_battery:[2,1,1,""],emulate_lrr:[2,1,1,""],deduplicate:[2,1,1,""],emulate_zone:[2,1,1,""],get_config:[2,3,1,""],mode:[2,1,1,""],address_mask:[2,1,1,""],FIRE_TIMEOUT:[2,1,1,""],on_boot:[2,1,1,""]},"alarmdecoder.devices.SocketDevice":{ssl_certificate:[2,1,1,""],ssl_key:[2,1,1,""],ssl:[2,1,1,""],fileno:[2,3,1,""],read:[2,3,1,""],ssl_ca:[2,1,1,""],read_line:[2,3,1,""],purge:[2,3,1,""],write:[2,3,1,""],"interface":[2,1,1,""],close:[2,3,1,""],open:[2,3,1,""]},"alarmdecoder.devices.USBDevice":{stop_detection:[2,5,1,""],start_detection:[2,5,1,""],close:[2,3,1,""],open:[2,3,1,""],find:[2,5,1,""],DEFAULT_VENDOR_ID:[2,1,1,""],write:[2,3,1,""],PRODUCT_IDS:[2,1,1,""],serial_number:[2,1,1,""],BAUDRATE:[2,1,1,""],description:[2,1,1,""],read:[2,3,1,""],DEFAULT_PRODUCT_ID:[2,1,1,""],read_line:[2,3,1,""],find_all:[2,5,1,""],FTDI_VENDOR_ID:[2,1,1,""],"interface":[2,1,1,""],fileno:[2,3,1,""],DetectThread:[2,2,1,""],devices:[2,5,1,""],purge:[2,3,1,""],FTDI_PRODUCT_ID:[2,1,1,""]},"alarmdecoder.messages.Message":{backlight_on:[2,1,1,""],alarm_event_occurred:[2,1,1,""],programming_mode:[2,1,1,""],text:[2,1,1,""],bitfield:[2,1,1,""],armed_home:[2,1,1,""],alarm_sounding:[2,1,1,""],ready:[2,1,1,""],zone_bypassed:[2,1,1,""],panel_data:[2,1,1,""],check_zone:[2,1,1,""],numeric_code:[2,1,1,""],dict:[2,3,1,""],battery_low:[2,1,1,""],chime_on:[2,1,1,""],entry_delay_off:[2,1,1,""],perimeter_only:[2,1,1,""],fire_alarm:[2,1,1,""],ac_power:[2,1,1,""],beeps:[2,1,1,""],mask:[2,1,1,""],system_fault:[2,1,1,""],armed_away:[2,1,1,""],panel_type:[2,1,1,""],cursor_location:[2,1,1,""]},"alarmdecoder.devices.Device":{stop_reader:[2,3,1,""],on_open:[2,1,1,""],on_write:[2,1,1,""],ReadThread:[2,2,1,""],on_close:[2,1,1,""],on_read:[2,1,1,""],close:[2,3,1,""],is_reader_alive:[2,3,1,""],id:[2,1,1,""]},"alarmdecoder.messages.RFMessage":{battery:[2,1,1,""],value:[2,1,1,""],dict:[2,3,1,""],supervision:[2,1,1,""],serial_number:[2,1,1,""],loop:[2,1,1,""]},"alarmdecoder.decoder":{AlarmDecoder:[2,2,1,""]},"alarmdecoder.event.event.EventHandler":{fire:[0,3,1,""],add:[0,3,1,""],remove:[0,3,1,""]},"alarmdecoder.util.Firmware":{STAGE_ERROR:[2,1,1,""],STAGE_LOAD:[2,1,1,""],upload:[2,6,1,""],STAGE_BOOT:[2,1,1,""],STAGE_START:[2,1,1,""],STAGE_UPLOADING:[2,1,1,""],STAGE_DEBUG:[2,1,1,""],STAGE_WAITING:[2,1,1,""],STAGE_DONE:[2,1,1,""]},"alarmdecoder.util":{Firmware:[2,2,1,""],TimeoutError:[2,4,1,""],NoDeviceError:[2,4,1,""],CommError:[2,4,1,""],UploadChecksumError:[2,4,1,""],UploadError:[2,4,1,""],InvalidMessageError:[2,4,1,""]}},titleterms:{alarmdecod:[2,1],welcom:3,alarm:3,devic:2,messag:2,event:0,util:2,packag:[0,2],decod:[3,2],zonetrack:2,indic:3,tabl:3,document:3,modul:[0,2],panel:2}})
\ No newline at end of file
diff --git a/setup.py b/setup.py
index e053e1b..135f1cd 100644
--- a/setup.py
+++ b/setup.py
@@ -14,12 +14,12 @@ if sys.version_info < (3,):
extra_requirements.append('future==0.14.3')
setup(name='alarmdecoder',
- version='0.10.3',
+ version='0.11.0',
description='Python interface for the AlarmDecoder (AD2) family '
'of alarm devices which includes the AD2USB, AD2SERIAL and AD2PI.',
long_description=readme(),
classifiers=[
- 'Development Status :: 4 - Beta',
+ 'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries :: Python Modules',