diff --git a/docs/build/doctrees/alarmdecoder.doctree b/docs/build/doctrees/alarmdecoder.doctree
index b01805f..9c26077 100644
Binary files a/docs/build/doctrees/alarmdecoder.doctree and b/docs/build/doctrees/alarmdecoder.doctree differ
diff --git a/docs/build/doctrees/alarmdecoder.event.doctree b/docs/build/doctrees/alarmdecoder.event.doctree
index efd7056..df7a5bf 100644
Binary files a/docs/build/doctrees/alarmdecoder.event.doctree and b/docs/build/doctrees/alarmdecoder.event.doctree differ
diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle
index 69bc766..f82c132 100644
Binary files a/docs/build/doctrees/environment.pickle and b/docs/build/doctrees/environment.pickle differ
diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree
index b6f4ae4..6f8981e 100644
Binary files a/docs/build/doctrees/index.doctree and b/docs/build/doctrees/index.doctree differ
diff --git a/docs/build/doctrees/modules.doctree b/docs/build/doctrees/modules.doctree
index 2e7af4e..ec9b935 100644
Binary files a/docs/build/doctrees/modules.doctree and b/docs/build/doctrees/modules.doctree differ
diff --git a/docs/build/html/_modules/alarmdecoder/decoder.html b/docs/build/html/_modules/alarmdecoder/decoder.html
index 619cd87..f6b1835 100644
--- a/docs/build/html/_modules/alarmdecoder/decoder.html
+++ b/docs/build/html/_modules/alarmdecoder/decoder.html
@@ -48,12 +48,15 @@
Source code for alarmdecoder.decoder
"""
-Provides the full AlarmDecoder class.
+Provides the main AlarmDecoder class.
+
+.. _AlarmDecoder: http://www.alarmdecoder.com
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
import time
+import re
from .event import event
from .util import InvalidMessageError
@@ -63,34 +66,36 @@
[docs]class AlarmDecoder(object):
"""
-
High-level wrapper around Alarm Decoder (AD2) devices.
+
High-level wrapper around `AlarmDecoder`_ (AD2) devices.
"""
# High-level Events
-
on_arm = event.Event('Called when the panel is armed.')
-
on_disarm = event.Event('Called when the panel is disarmed.')
-
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_fire = event.Event('Called when a fire is detected.')
-
on_bypass = event.Event('Called when a zone is bypassed.')
-
on_boot = event.Event('Called when the device finishes bootings.')
-
on_config_received = event.Event('Called when the device receives its configuration.')
-
on_zone_fault = event.Event('Called when the device detects a zone fault.')
-
on_zone_restore = event.Event('Called when the device detects that a fault is restored.')
-
on_low_battery = event.Event('Called when the device detects a low battery.')
-
on_panic = event.Event('Called when the device detects a panic.')
-
on_relay_changed = event.Event('Called when a relay is opened or closed on an expander board.')
+
on_arm = event.Event("This event is called when the panel is armed.\n\n**Callback definition:** *def callback(device)*")
+
on_disarm = event.Event("This event is called when the panel is disarmed.\n\n**Callback definition:** *def callback(device)*")
+
on_power_changed = event.Event("This event is called when panel power switches between AC and DC.\n\n**Callback definition:** *def callback(device, status)*")
+
on_alarm = event.Event("This event is called when the alarm is triggered.\n\n**Callback definition:** *def callback(device, status)*")
+
on_fire = event.Event("This event is called when a fire is detected.\n\n**Callback definition:** *def callback(device, status)*")
+
on_bypass = event.Event("This event is called when a zone is bypassed. \n\n\n\n**Callback definition:** *def callback(device, status)*")
+
on_boot = event.Event("This event is called when the device finishes booting.\n\n**Callback definition:** *def callback(device)*")
+
on_config_received = event.Event("This event is called when the device receives its configuration. \n\n**Callback definition:** *def callback(device)*")
+
on_zone_fault = event.Event("This event is called when :py:class:`~alarmdecoder.zonetracking.Zonetracker` detects a zone fault.\n\n**Callback definition:** *def callback(device, zone)*")
+
on_zone_restore = event.Event("This event is called when :py:class:`~alarmdecoder.zonetracking.Zonetracker` detects that a fault is restored.\n\n**Callback definition:** *def callback(device, zone)*")
+
on_low_battery = event.Event("This event is called when the device detects a low battery.\n\n**Callback definition:** *def callback(device, status)*")
+
on_panic = event.Event("This event is called when the device detects a panic.\n\n**Callback definition:** *def callback(device, status)*")
+
on_relay_changed = event.Event("This event is called when a relay is opened or closed on an expander board.\n\n**Callback definition:** *def callback(device, message)*")
# Mid-level Events
-
on_message = event.Event('Called when a message has been received from the device.')
-
on_lrr_message = event.Event('Called when an LRR message is received.')
-
on_rfx_message = event.Event('Called when an RFX message is received.')
+
on_message = event.Event("This event is called when standard panel :py:class:`~alarmdecoder.messages.Message` is received.\n\n**Callback definition:** *def callback(device, message)*")
+
on_expander_message = event.Event("This event is called when an :py:class:`~alarmdecoder.messages.ExpanderMessage` is received.\n\n**Callback definition:** *def callback(device, message)*")
+
on_lrr_message = event.Event("This event is called when an :py:class:`~alarmdecoder.messages.LRRMessage` is received.\n\n**Callback definition:** *def callback(device, message)*")
+
on_rfx_message = event.Event("This event is called when an :py:class:`~alarmdecoder.messages.RFMessage` is received.\n\n**Callback definition:** *def callback(device, message)*")
+
on_sending_received = event.Event("This event is called when a !Sending.done message is received from the AlarmDecoder.\n\n**Callback definition:** *def callback(device, status, message)*")
# Low-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_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_open = event.Event("This event is called when the device has been opened.\n\n**Callback definition:** *def callback(device)*")
+
on_close = event.Event("This event is called when the device has been closed.\n\n**Callback definition:** *def callback(device)*")
+
on_read = event.Event("This event is called when a line has been read from the device.\n\n**Callback definition:** *def callback(device, data)*")
+
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)
@@ -101,17 +106,35 @@
"""Represents panel function key #3"""
KEY_F4 = unichr(4) + unichr(4) + unichr(4)
"""Represents panel function key #4"""
+
KEY_PANIC = unichr(5) + unichr(5) + unichr(5)
+
"""Represents a panic keypress"""
BATTERY_TIMEOUT = 30
-
"""Timeout before the battery status reverts."""
+
"""Default timeout (in seconds) before the battery status reverts."""
FIRE_TIMEOUT = 30
-
"""Timeout before the fire status reverts."""
+
"""Default tTimeout (in seconds) before the fire status reverts."""
+
+
# Attributes
+
address = 18
+
"""The keypad address in use by the device."""
+
configbits = 0xFF00
+
"""The configuration bits set on the device."""
+
address_mask = 0xFFFFFFFF
+
"""The address mask configured on the device."""
+
emulate_zone = [False for _ in range(5)]
+
"""List containing the devices zone emulation status."""
+
emulate_relay = [False for _ in range(4)]
+
"""List containing the devices relay emulation status."""
+
emulate_lrr = False
+
"""The status of the devices LRR emulation."""
+
deduplicate = False
+
"""The status of message deduplication as configured on the device."""
def __init__(self, device):
"""
Constructor
-
:param device: The low-level device used for this Alarm Decoder
+
:param device: The low-level device used for this `AlarmDecoder`_
interface.
:type device: Device
"""
@@ -154,9 +177,9 @@
@property
[docs] def id(self):
"""
-
The ID of the Alarm Decoder device.
+
The ID of the `AlarmDecoder`_ device.
-
:returns: The identification string for the device.
+
:returns: identification string for the device
"""
return self._device.id
@@ -165,7 +188,7 @@
"""
Retrieves the timeout for restoring the battery status, in seconds.
-
:returns: The battery status timeout
+
:returns: battery status timeout
"""
return self._battery_timeout
@@ -174,7 +197,7 @@
"""
Sets the timeout for restoring the battery status, in seconds.
-
:param value: The timeout in seconds.
+
:param value: timeout in seconds
:type value: int
"""
self._battery_timeout = value
@@ -184,7 +207,7 @@
"""
Retrieves the timeout for restoring the fire status, in seconds.
-
:returns: The fire status timeout
+
:returns: fire status timeout
"""
return self._fire_timeout
@@ -193,7 +216,7 @@
"""
Sets the timeout for restoring the fire status, in seconds.
-
:param value: The timeout in seconds.
+
:param value: timeout in seconds
:type value: int
"""
self._fire_timeout = value
@@ -202,10 +225,10 @@
"""
Opens the device.
-
:param baudrate: The baudrate used for the device.
+
:param baudrate: baudrate used for the device. Defaults to the lower-level device default.
:type baudrate: int
:param no_reader_thread: Specifies whether or not the automatic reader
-
thread should be started or not
+
thread should be started.
:type no_reader_thread: bool
"""
self._wire_events()
@@ -225,17 +248,18 @@
[docs] def send(self, data):
"""
-
Sends data to the Alarm Decoder device.
+
Sends data to the `AlarmDecoder`_ device.
-
:param data: The data to send.
-
:type data: str
+
:param data: data to send
+
:type data: string
"""
+
if self._device:
-
self._device.write(data)
+
self._device.write(str(data))
[docs] def get_config(self):
"""
-
Retrieves the configuration from the device.
+
Retrieves the configuration from the device. Called automatically by :py:meth:`_on_open`.
"""
self.send("C\r")
@@ -276,9 +300,9 @@
"""
Faults a zone if we are emulating a zone expander.
- :param zone: The zone to fault.
+ :param zone: zone to fault
:type zone: int
- :param simulate_wire_problem: Whether or not to simulate a wire fault.
+ :param simulate_wire_problem: Whether or not to simulate a wire fault
:type simulate_wire_problem: bool
"""
@@ -299,7 +323,7 @@
"""
Clears a zone if we are emulating a zone expander.
- :param zone: The zone to clear.
+ :param zone: zone to clear
:type zone: int
"""
self.send("L{0:02}0\r".format(zone))
@@ -317,29 +341,28 @@
def _handle_message(self, data):
"""
- Parses messages from the panel.
+ Parses keypad messages from the panel.
- :param data: Panel data to parse.
- :type data: str
+ :param data: keypad data to parse
+ :type data: string
- :returns: An object representing the message.
+ :returns: :py:class:`~alarmdecoder.messages.Message`
"""
- if data is None:
+
+ if data is not None:
+ data = data.lstrip('\0')
+
+ if data is None or data == '':
raise InvalidMessageError()
msg = None
header = data[0:4]
- if header[0] != '!' or header == '!KPE':
- msg = Message(data)
-
- if self.address_mask & msg.mask > 0:
- self._update_internal_states(msg)
+ if header[0] != '!' or header == '!KPM':
+ msg = self._handle_keypad_message(data)
elif header == '!EXP' or header == '!REL':
- msg = ExpanderMessage(data)
-
- self._update_internal_states(msg)
+ msg = self._handle_expander_message(data)
elif header == '!RFX':
msg = self._handle_rfx(data)
@@ -353,16 +376,53 @@
elif data.startswith('!CONFIG'):
self._handle_config(data)
+ elif data.startswith('!Sending'):
+ self._handle_sending(data)
+
+ return msg
+
+ def _handle_keypad_message(self, data):
+ """
+ Handle keypad messages.
+
+ :param data: keypad message to parse
+ :type data: string
+
+ :returns: :py:class:`~alarmdecoder.messages.Message`
+ """
+ msg = Message(data)
+
+ if self.address_mask & msg.mask > 0:
+ self._update_internal_states(msg)
+
+ self.on_message(message=msg)
+
+ return msg
+
+ def _handle_expander_message(self, data):
+ """
+ Handle expander messages.
+
+ :param data: expander message to parse
+ :type data: string
+
+ :returns: :py:class:`~alarmdecoder.messages.ExpanderMessage`
+ """
+ msg = ExpanderMessage(data)
+
+ self._update_internal_states(msg)
+ self.on_expander_message(message=msg)
+
return msg
def _handle_rfx(self, data):
"""
Handle RF messages.
- :param data: RF message to parse.
- :type data: str
+ :param data: RF message to parse
+ :type data: string
- :returns: An object representing the RF message.
+ :returns: :py:class:`~alarmdecoder.messages.RFMessage`
"""
msg = RFMessage(data)
@@ -374,10 +434,10 @@
"""
Handle Long Range Radio messages.
- :param data: LRR message to parse.
- :type data: str
+ :param data: LRR message to parse
+ :type data: string
- :returns: An object representing the LRR message.
+ :returns: :py:class:`~alarmdecoder.messages.LRRMessage`
"""
msg = LRRMessage(data)
@@ -398,8 +458,8 @@
"""
Handles received configuration data.
- :param data: Configuration string to parse.
- :type data: str
+ :param data: Configuration string to parse
+ :type data: string
"""
_, config_string = data.split('>')
for setting in config_string.split('&'):
@@ -422,12 +482,28 @@
self.on_config_received()
+ def _handle_sending(self, data):
+ """
+ Handles results of a keypress send.
+
+ :param data: Sending string to parse
+ :type data: string
+ """
+
+ matches = re.match('^!Sending(\.{1,5})done.*', data)
+ if matches is not None:
+ good_send = False
+ if len(matches.group(1)) < 5:
+ good_send = True
+
+ self.on_sending_received(status=good_send, message=data)
+
def _update_internal_states(self, message):
"""
Updates internal device states.
- :param message: Message to update internal states with.
- :type message: Message, ExpanderMessage, LRRMessage, or RFMessage
+ :param message: :py:class:`~alarmdecoder.messages.Message` to update internal states with
+ :type message: :py:class:`~alarmdecoder.messages.Message`, :py:class:`~alarmdecoder.messages.ExpanderMessage`, :py:class:`~alarmdecoder.messages.LRRMessage`, or :py:class:`~alarmdecoder.messages.RFMessage`
"""
if isinstance(message, Message):
self._update_power_status(message)
@@ -446,10 +522,10 @@
"""
Uses the provided message to update the AC power state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: bool indicating the new status
"""
if message.ac_power != self._power_status:
self._power_status, old_status = message.ac_power, self._power_status
@@ -463,10 +539,10 @@
"""
Uses the provided message to update the alarm state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: bool indicating the new status
"""
if message.alarm_sounding != self._alarm_status:
@@ -481,10 +557,10 @@
"""
Uses the provided message to update the zone bypass state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: bool indicating the new status
"""
if message.zone_bypassed != self._bypass_status:
@@ -499,10 +575,10 @@
"""
Uses the provided message to update the armed state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: bool indicating the new status
"""
message_status = message.armed_away | message.armed_home
@@ -521,10 +597,10 @@
"""
Uses the provided message to update the battery state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: boolean indicating the new status
"""
last_status, last_update = self._battery_status
@@ -541,10 +617,10 @@
"""
Uses the provided message to update the fire alarm state.
- :param message: The message to use to update.
- :type message: Message
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.Message`
- :returns: Boolean indicating the new status
+ :returns: boolean indicating the new status
"""
last_status, last_update = self._fire_status
@@ -561,10 +637,10 @@
"""
Uses the provided message to update the expander states.
- :param message: The message to use to update.
- :type message: ExpanderMessage
+ :param message: message to use to update
+ :type message: :py:class:`~alarmdecoder.messages.ExpanderMessage`
- :returns: Boolean indicating the new status
+ :returns: boolean indicating the new status
"""
if message.type == ExpanderMessage.RELAY:
@@ -576,10 +652,10 @@
def _update_zone_tracker(self, message):
"""
- Trigger an update of the zonetracker.
+ Trigger an update of the :py:class:`~alarmdecoder.messages.Zonetracker`.
- :param message: The message to update the zonetracker with.
- :type message: Message, ExpanderMessage, LRRMessage, or RFMessage
+ :param message: message to update the zonetracker with
+ :type message: :py:class:`~alarmdecoder.messages.Message`, :py:class:`~alarmdecoder.messages.ExpanderMessage`, :py:class:`~alarmdecoder.messages.LRRMessage`, or :py:class:`~alarmdecoder.messages.RFMessage`
"""
# Retrieve a list of faults.
@@ -597,29 +673,28 @@
"""
self.get_config()
- self.on_open(args, kwargs)
+ self.on_open()
def _on_close(self, sender, *args, **kwargs):
"""
Internal handler for closing the device.
"""
- self.on_close(args, kwargs)
+ self.on_close()
def _on_read(self, sender, *args, **kwargs):
"""
Internal handler for reading from the device.
"""
- self.on_read(args, kwargs)
+ data = kwargs.get('data', None)
+ self.on_read(data=data)
- msg = self._handle_message(kwargs.get('data', None))
- if msg:
- self.on_message(message=msg)
+ self._handle_message(data)
def _on_write(self, sender, *args, **kwargs):
"""
Internal handler for writing to the device.
"""
- self.on_write(args, kwargs)
+ self.on_write(data=kwargs.get('data', None))
def _on_zone_fault(self, sender, *args, **kwargs):
"""
diff --git a/docs/build/html/_modules/alarmdecoder/devices.html b/docs/build/html/_modules/alarmdecoder/devices.html
index b77c905..c8f1813 100644
--- a/docs/build/html/_modules/alarmdecoder/devices.html
+++ b/docs/build/html/_modules/alarmdecoder/devices.html
@@ -48,7 +48,18 @@
Source code for alarmdecoder.devices
"""
-Contains different types of devices belonging to the Alarm Decoder (AD2) family.
+This module contains different types of devices belonging to the `AlarmDecoder`_ (AD2) family.
+
+* :py:class:`USBDevice`: Interfaces with the `AD2USB`_ device.
+* :py:class:`SerialDevice`: Interfaces with the `AD2USB`_, `AD2SERIAL`_ or `AD2PI`_.
+* :py:class:`SocketDevice`: Interfaces with devices exposed through `ser2sock`_ or another IP to Serial solution.
+ Also supports SSL if using `ser2sock`_.
+
+.. _ser2sock: http://github.com/nutechsoftware/ser2sock
+.. _AlarmDecoder: http://www.alarmdecoder.com
+.. _AD2USB: http://www.alarmdecoder.com
+.. _AD2SERIAL: http://www.alarmdecoder.com
+.. _AD2PI: http://www.alarmdecoder.com
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
@@ -63,20 +74,20 @@
from OpenSSL import SSL, crypto
from pyftdi.pyftdi.ftdi import Ftdi, FtdiError
-from .util import CommError, TimeoutError, NoDeviceError
+from .util import CommError, TimeoutError, NoDeviceError, InvalidMessageError
from .event import event
[docs]class Device(object):
"""
-
Generic parent device to all Alarm Decoder (AD2) products.
+
Base class for all `AlarmDecoder`_ (AD2) device types.
"""
# Generic device events
-
on_open = event.Event('Called when the device has been opened')
-
on_close = event.Event('Called when the device has been closed')
-
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_open = event.Event("This event is called when the device has been opened.\n\n**Callback definition:** *def callback(device)*")
+
on_close = event.Event("This event is called when the device has been closed.\n\n**Callback definition:** def callback(device)*")
+
on_read = event.Event("This event is called when a line has been read from the device.\n\n**Callback definition:** def callback(device, data)*")
+
on_write = event.Event("This event is called when data has been written to the device.\n\n**Callback definition:** def callback(device, data)*")
def __init__(self):
"""
@@ -107,7 +118,7 @@
"""
Retrieve the device ID.
-
:returns: The identification string for the device.
+
:returns: identification string for the device
"""
return self._id
@@ -116,8 +127,8 @@
"""
Sets the device ID.
-
:param value: The device identification.
-
:type value: str
+
:param value: device identification string
+
:type value: string
"""
self._id = value
@@ -125,7 +136,7 @@
"""
Indicates whether or not the reader thread is alive.
- :returns: Whether or not the reader thread is alive.
+ :returns: whether or not the reader thread is alive
"""
return self._read_thread.is_alive()
@@ -161,8 +172,8 @@
"""
Constructor
- :param device: The device used by the reader thread.
- :type device: devices.Device
+ :param device: device used by the reader thread
+ :type device: :py:class:`~alarmdecoder.devices.Device`
"""
threading.Thread.__init__(self)
self._device = device
@@ -187,24 +198,33 @@
except TimeoutError:
pass
- except Exception:
- self._running = False
+ except InvalidMessageError:
+ pass
+
+ except SSL.WantReadError:
+ pass
+
+ except CommError, err:
+ self._device.close()
- time.sleep(0.01)
+ except Exception, err:
+ self._device.close()
+ self._running = False
+ raise
[docs]class USBDevice(Device):
"""
-
AD2USB device exposed with PyFTDI's interface.
+
`AD2USB`_ device utilizing PyFTDI's interface.
"""
# Constants
FTDI_VENDOR_ID = 0x0403
-
"""Vendor ID used to recognize AD2USB devices."""
+
"""Vendor ID used to recognize `AD2USB`_ devices."""
FTDI_PRODUCT_ID = 0x6001
-
"""Product ID used to recognize AD2USB devices."""
+
"""Product ID used to recognize `AD2USB`_ devices."""
BAUDRATE = 115200
-
"""Default baudrate for AD2USB devices."""
+
"""Default baudrate for `AD2USB`_ devices."""
__devices = []
__detect_thread = None
@@ -215,7 +235,7 @@
Returns all FTDI devices matching our vendor and product IDs.
:returns: list of devices
-
:raises: CommError
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
cls.__devices = []
@@ -230,24 +250,24 @@
@classmethod
[docs] def devices(cls):
"""
-
Returns a cached list of AD2USB devices located on the system.
+
Returns a cached list of `AD2USB`_ devices located on the system.
-
:returns: cached list of devices found.
+
:returns: cached list of devices found
"""
return cls.__devices
@classmethod
[docs] def find(cls, device=None):
"""
-
Factory method that returns the requested USBDevice device, or the
+
Factory method that returns the requested :py:class:`USBDevice` device, or the
first device.
:param device: Tuple describing the USB device to open, as returned
by find_all().
:type device: tuple
-
:returns: USBDevice object utilizing the specified device.
-
:raises: NoDeviceError
+
:returns: :py:class:`USBDevice` object utilizing the specified device
+
:raises: :py:class:`~alarmdecoder.util.NoDeviceError`
"""
cls.find_all()
@@ -266,14 +286,18 @@
"""
Starts the device detection thread.
-
:param on_attached: function to be called when a device is attached.
+
:param on_attached: function to be called when a device is attached **Callback definition:** *def callback(thread, device)*
:type on_attached: function
-
:param on_detached: function to be called when a device is detached.
+
:param on_detached: function to be called when a device is detached **Callback definition:** *def callback(thread, device)*
+
:type on_detached: function
"""
cls.__detect_thread = USBDevice.DetectThread(on_attached, on_detached)
-
cls.find_all()
+
try:
+
cls.find_all()
+
except CommError:
+
pass
cls.__detect_thread.start()
@@ -293,7 +317,7 @@
"""
Retrieves the interface used to connect to the device.
-
:returns: the interface used to connect to the device.
+
:returns: the interface used to connect to the device
"""
return self._interface
@@ -302,8 +326,8 @@
"""
Sets the interface used to connect to the device.
-
:param value: May specify either the serial number or the device index.
-
:type value: str or int
+
:param value: may specify either the serial number or the device index
+
:type value: string or int
"""
self._interface = value
if isinstance(value, int):
@@ -316,7 +340,7 @@
"""
Retrieves the serial number of the device.
-
:returns: The serial number of the device.
+
:returns: serial number of the device
"""
return self._serial_number
@@ -326,7 +350,7 @@
"""
Sets the serial number of the device.
-
:param value: The serial number of the device.
+
:param value: serial number of the device
:type value: string
"""
self._serial_number = value
@@ -336,7 +360,7 @@
"""
Retrieves the description of the device.
-
:returns: The description of the device.
+
:returns: description of the device
"""
return self._description
@@ -345,7 +369,7 @@
"""
Sets the description of the device.
-
:param value: The description of the device.
+
:param value: description of the device
:type value: string
"""
self._description = value
@@ -356,7 +380,7 @@
:param interface: May specify either the serial number or the device
index.
-
:type interface: str or int
+
:type interface: string or int
"""
Device.__init__(self)
@@ -376,13 +400,13 @@
"""
Opens the device.
-
:param baudrate: The baudrate to use.
+
:param baudrate: baudrate to use
:type baudrate: int
-
:param no_reader_thread: Whether or not to automatically start the
+
:param no_reader_thread: whether or not to automatically start the
reader thread.
:type no_reader_thread: bool
-
:raises: NoDeviceError
+
:raises: :py:class:`~alarmdecoder.util.NoDeviceError`
"""
# Set up defaults
if baudrate is None:
@@ -429,14 +453,17 @@
except Exception:
pass
+[docs] def fileno(self):
+
raise NotImplementedError('USB devices do not support fileno()')
+
[docs] def write(self, data):
"""
Writes data to the device.
-
:param data: Data to write
-
:type data: str
+
:param data: data to write
+
:type data: string
-
:raises: CommError
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
try:
self._device.write_data(data)
@@ -450,8 +477,8 @@
"""
Reads a single character from the device.
-
:returns: The character read from the device.
-
:raises: CommError
+
:returns: character read from the device
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
ret = None
@@ -467,14 +494,14 @@
"""
Reads a line from the device.
-
:param timeout: The read timeout.
+
:param timeout: read timeout
:type timeout: float
:param purge_buffer: Indicates whether to purge the buffer prior to
reading.
:type purge_buffer: bool
-
:returns: The line that was read.
-
:raises: CommError, TimeoutError
+
:returns: line that was read
+
:raises: :py:class:`~alarmdecoder.util.CommError`, :py:class:`~alarmdecoder.util.TimeoutError`
"""
def timeout_event():
@@ -504,6 +531,8 @@
if len(self._buffer) > 0:
got_line = True
break
+
else:
+
time.sleep(0.01)
except (usb.core.USBError, FtdiError), err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
@@ -526,7 +555,7 @@
"""
Retrieves the FTDI device serial number.
-
:returns: string containing the device serial number.
+
:returns: string containing the device serial number
"""
return usb.util.get_string(self._device.usb_dev, 64, self._device.usb_dev.iSerialNumber)
@@ -534,16 +563,16 @@
"""
Thread that handles detection of added/removed devices.
"""
-
on_attached = event.Event('Called when an AD2USB device has been detected.')
-
on_detached = event.Event('Called when an AD2USB device has been removed.')
+
on_attached = event.Event("This event is called when an `AD2USB`_ device has been detected.\n\n**Callback definition:** def callback(thread, device*")
+
on_detached = event.Event("This event is called when an `AD2USB`_ device has been removed.\n\n**Callback definition:** def callback(thread, device*")
def __init__(self, on_attached=None, on_detached=None):
"""
Constructor
-
:param on_attached: Function to call when a device is attached.
+
:param on_attached: Function to call when a device is attached **Callback definition:** *def callback(thread, device)*
:type on_attached: function
-
:param on_detached: Function to call when a device is detached.
+
:param on_detached: Function to call when a device is detached **Callback definition:** *def callback(thread, device)*
:type on_detached: function
"""
threading.Thread.__init__(self)
@@ -590,7 +619,7 @@
[docs]class SerialDevice(Device):
"""
-
AD2USB or AD2SERIAL device exposed with the pyserial interface.
+
`AD2USB`_, `AD2SERIAL`_ or `AD2PI`_ device utilizing the PySerial interface.
"""
# Constants
@@ -602,11 +631,11 @@
"""
Returns all serial ports present.
-
:param pattern: Pattern to search for when retrieving serial ports.
-
:type pattern: str
+
:param pattern: pattern to search for when retrieving serial ports
+
:type pattern: string
:returns: list of devices
-
:raises: CommError
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
devices = []
@@ -626,7 +655,7 @@
"""
Retrieves the interface used to connect to the device.
-
:returns: the interface used to connect to the device.
+
:returns: interface used to connect to the device
"""
return self._port
@@ -635,7 +664,7 @@
"""
Sets the interface used to connect to the device.
-
:param value: The name of the serial device.
+
:param value: name of the serial device
:type value: string
"""
self._port = value
@@ -644,8 +673,8 @@
"""
Constructor
-
:param interface: The device to open.
-
:type interface: str
+
:param interface: device to open
+
:type interface: string
"""
Device.__init__(self)
@@ -658,13 +687,13 @@
"""
Opens the device.
-
:param baudrate: The baudrate to use with the device.
+
:param baudrate: baudrate to use with the device
:type baudrate: int
-
:param no_reader_thread: Whether or not to automatically start the
+
:param no_reader_thread: whether or not to automatically start the
reader thread.
:type no_reader_thread: bool
-
:raises: NoDeviceError
+
:raises: :py:class:`~alarmdecoder.util.NoDeviceError`
"""
# Set up the defaults
if baudrate is None:
@@ -685,8 +714,8 @@
# all issues with it.
self._device.baudrate = baudrate
-
except (serial.SerialException, ValueError), err:
-
raise NoDeviceError('Error opening device on port {0}.'.format(self._port), err)
+
except (serial.SerialException, ValueError, OSError), err:
+
raise NoDeviceError('Error opening device on {0}.'.format(self._port), err)
else:
self._running = True
@@ -707,14 +736,17 @@
except Exception:
pass
+[docs] def fileno(self):
+
return self._device.fileno()
+
[docs] def write(self, data):
"""
Writes data to the device.
-
:param data: The data to write.
-
:type data: str
+
:param data: data to write
+
:type data: string
-
:raises: CommError
+
:raises: py:class:`~alarmdecoder.util.CommError`
"""
try:
self._device.write(data)
@@ -732,8 +764,8 @@
"""
Reads a single character from the device.
-
:returns: The character read from the device.
-
:raises: CommError
+
:returns: character read from the device
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
ret = None
@@ -749,14 +781,14 @@
"""
Reads a line from the device.
-
:param timeout: The read timeout.
+
:param timeout: read timeout
:type timeout: float
:param purge_buffer: Indicates whether to purge the buffer prior to
reading.
:type purge_buffer: bool
-
:returns: The line that was read.
-
:raises: CommError, TimeoutError
+
:returns: line that was read
+
:raises: :py:class:`~alarmdecoder.util.CommError`, :py:class:`~alarmdecoder.util.TimeoutError`
"""
def timeout_event():
@@ -787,6 +819,8 @@
if len(self._buffer) > 0:
got_line = True
break
+
else:
+
time.sleep(0.01)
except (OSError, serial.SerialException), err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
@@ -808,8 +842,8 @@
[docs]class SocketDevice(Device):
"""
-
Device that supports communication with an Alarm Decoder (AD2) that is
-
exposed via ser2sock or another Serial to IP interface.
+
Device that supports communication with an `AlarmDecoder`_ (AD2) that is
+
exposed via `ser2sock`_ or another Serial to IP interface.
"""
@property
@@ -817,7 +851,7 @@
"""
Retrieves the interface used to connect to the device.
-
:returns: the interface used to connect to the device.
+
:returns: interface used to connect to the device
"""
return (self._host, self._port)
@@ -826,7 +860,7 @@
"""
Sets the interface used to connect to the device.
-
:param value: Tuple containing the host and port to use.
+
:param value: Tuple containing the host and port to use
:type value: tuple
"""
self._host, self._port = value
@@ -836,7 +870,7 @@
"""
Retrieves whether or not the device is using SSL.
-
:returns: Whether or not the device is using SSL.
+
:returns: whether or not the device is using SSL
"""
return self._use_ssl
@@ -845,7 +879,7 @@
"""
Sets whether or not SSL communication is in use.
-
:param value: Whether or not SSL communication is in use.
+
:param value: Whether or not SSL communication is in use
:type value: bool
"""
self._use_ssl = value
@@ -855,7 +889,7 @@
"""
Retrieves the SSL client certificate path used for authentication.
-
:returns: The certificate path
+
:returns: path to the certificate path or :py:class:`OpenSSL.crypto.X509`
"""
return self._ssl_certificate
@@ -864,8 +898,8 @@
"""
Sets the SSL client certificate to use for authentication.
-
:param value: The path to the SSL certificate.
-
:type value: str
+
:param value: path to the SSL certificate or :py:class:`OpenSSL.crypto.X509`
+
:type value: string or :py:class:`OpenSSL.crypto.X509`
"""
self._ssl_certificate = value
@@ -874,7 +908,7 @@
"""
Retrieves the SSL client certificate key used for authentication.
- :returns: The key path
+ :returns: jpath to the SSL key or :py:class:`OpenSSL.crypto.PKey`
"""
return self._ssl_key
@@ -883,8 +917,8 @@
"""
Sets the SSL client certificate key to use for authentication.
- :param value: The path to the SSL key.
- :type value: str
+ :param value: path to the SSL key or :py:class:`OpenSSL.crypto.PKey`
+ :type value: string or :py:class:`OpenSSL.crypto.PKey`
"""
self._ssl_key = value
@@ -894,7 +928,7 @@
Retrieves the SSL Certificate Authority certificate used for
authentication.
- :returns: The CA path
+ :returns: path to the CA certificate or :py:class:`OpenSSL.crypto.X509`
"""
return self._ssl_ca
@@ -903,8 +937,8 @@
"""
Sets the SSL Certificate Authority certificate used for authentication.
- :param value: The path to the SSL CA certificate.
- :type value: str
+ :param value: path to the SSL CA certificate or :py:class:`OpenSSL.crypto.X509`
+ :type value: string or :py:class:`OpenSSL.crypto.X509`
"""
self._ssl_ca = value
@@ -912,7 +946,7 @@
"""
Constructor
- :param interface: Tuple containing the hostname and port of our target.
+ :param interface: Tuple containing the hostname and port of our target
:type interface: tuple
"""
Device.__init__(self)
@@ -927,13 +961,13 @@
"""
Opens the device.
- :param baudrate: The baudrate to use
+ :param baudrate: baudrate to use
:type baudrate: int
- :param no_reader_thread: Whether or not to automatically open the reader
+ :param no_reader_thread: whether or not to automatically open the reader
thread.
:type no_reader_thread: bool
- :raises: NoDeviceError, CommError
+ :raises: :py:class:`~alarmdecoder.util.NoDeviceError`, :py:class:`~alarmdecoder.util.CommError`
"""
try:
@@ -943,9 +977,15 @@
self._init_ssl()
self._device.connect((self._host, self._port))
+ #self._device.setblocking(1)
if self._use_ssl:
- self._device.do_handshake()
+ while True:
+ try:
+ self._device.do_handshake()
+ break
+ except SSL.WantReadError:
+ pass
self._id = '{0}:{1}'.format(self._host, self._port)
@@ -974,20 +1014,23 @@
# Make sure that it closes immediately.
self._device.shutdown(socket.SHUT_RDWR)
- Device.close(self)
-
except Exception:
pass
+
+ Device.close(self)
+
+[docs] def fileno(self):
+
return self._device.fileno()
[docs] def write(self, data):
"""
Writes data to the device.
-
:param data: The data to write.
-
:type data: str
+
:param data: data to write
+
:type data: string
-
:returns: The number of bytes sent.
-
:raises: CommError
+
:returns: number of bytes sent
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
data_sent = None
@@ -1008,8 +1051,8 @@
"""
Reads a single character from the device.
-
:returns: The character read from the device.
-
:raises: CommError
+
:returns: character read from the device
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
data = None
@@ -1025,14 +1068,14 @@
"""
Reads a line from the device.
-
:param timeout: The read timeout.
+
:param timeout: read timeout
:type timeout: float
:param purge_buffer: Indicates whether to purge the buffer prior to
reading.
:type purge_buffer: bool
-
:returns: The line that was read.:
-
:raises: CommError, TimeoutError
+
:returns: line that was read
+
:raises: :py:class:`~alarmdecoder.util.CommError`, :py:class:`~alarmdecoder.util.TimeoutError`
"""
def timeout_event():
@@ -1062,10 +1105,19 @@
if len(self._buffer) > 0:
got_line = True
break
+
else:
+
time.sleep(0.01)
except socket.error, err:
raise CommError('Error reading from device: {0}'.format(str(err)), err)
+
except SSL.SysCallError, err:
+
errno, msg = err
+
raise CommError('SSL error while reading from device: {0} ({1})'.format(msg, errno))
+
+
except Exception:
+
raise
+
else:
if got_line:
ret, self._buffer = self._buffer, ''
@@ -1083,6 +1135,8 @@
def _init_ssl(self):
"""
Initializes our device as an SSL connection.
+
+
:raises: :py:class:`~alarmdecoder.util.CommError`
"""
try:
diff --git a/docs/build/html/_modules/alarmdecoder/event/event.html b/docs/build/html/_modules/alarmdecoder/event/event.html
index e62ec66..050e58f 100644
--- a/docs/build/html/_modules/alarmdecoder/event/event.html
+++ b/docs/build/html/_modules/alarmdecoder/event/event.html
@@ -80,6 +80,9 @@
self.event = event
self.obj = obj
+
def __iter__(self):
+
return iter(self._getfunctionlist())
+
def _getfunctionlist(self):
"""(internal use) """
diff --git a/docs/build/html/_modules/alarmdecoder/messages.html b/docs/build/html/_modules/alarmdecoder/messages.html
index 2645690..a48645a 100644
--- a/docs/build/html/_modules/alarmdecoder/messages.html
+++ b/docs/build/html/_modules/alarmdecoder/messages.html
@@ -48,13 +48,21 @@
Source code for alarmdecoder.messages
"""
-Message representations received from the panel through the Alarm Decoder (AD2)
+Message representations received from the panel through the `AlarmDecoder`_ (AD2)
devices.
+* :py:class:`Message`: The standard and most common message received from a panel.
+* :py:class:`ExpanderMessage`: Messages received from Relay or Zone expander modules.
+* :py:class:`RFMessage`: Message received from an RF receiver module.
+* :py:class:`LRRMessage`: Message received from a long-range radio module.
+
+.. _AlarmDecoder: http://www.alarmdecoder.com
+
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
import re
+import datetime
from .util import InvalidMessageError
@@ -67,11 +75,14 @@
raw = None
"""The raw message text"""
+ timestamp = None
+ """The timestamp of the message"""
+
def __init__(self):
"""
Constructor
"""
- pass
+ self.timestamp = datetime.datetime.now()
def __str__(self):
"""
@@ -79,6 +90,22 @@
"""
return self.raw
+[docs] def dict(self, **kwargs):
+
"""
+
Dictionary representation.
+
"""
+
return dict(
+
time=self.timestamp,
+
mesg=self.raw,
+
**kwargs
+
)
+
+ def __repr__(self):
+ """
+ String representation.
+ """
+ return repr(self.dict())
+
[docs]class Message(BaseMessage):
"""
@@ -86,78 +113,72 @@
"""
ready = False
-
"""Indicates whether or not the panel is in a ready state"""
+
"""Indicates whether or not the panel is in a ready state."""
armed_away = False
-
"""Indicates whether or not the panel is armed away"""
+
"""Indicates whether or not the panel is armed away."""
armed_home = False
-
"""Indicates whether or not the panel is armed home"""
+
"""Indicates whether or not the panel is armed home."""
backlight_on = False
-
"""Indicates whether or not the keypad backlight is on"""
+
"""Indicates whether or not the keypad backlight is on."""
programming_mode = False
-
"""Indicates whether or not we're in programming mode"""
+
"""Indicates whether or not we're in programming mode."""
beeps = -1
-
"""Number of beeps associated with a message"""
+
"""Number of beeps associated with a message."""
zone_bypassed = False
-
"""Indicates whether or not a zone is bypassed"""
+
"""Indicates whether or not a zone is bypassed."""
ac_power = False
-
"""Indicates whether or not the panel is on AC power"""
+
"""Indicates whether or not the panel is on AC power."""
chime_on = False
-
"""Indicates whether or not the chime is enabled"""
+
"""Indicates whether or not the chime is enabled."""
alarm_event_occurred = False
-
"""Indicates whether or not an alarm event has occurred"""
+
"""Indicates whether or not an alarm event has occurred."""
alarm_sounding = False
-
"""Indicates whether or not an alarm is sounding"""
+
"""Indicates whether or not an alarm is sounding."""
battery_low = False
-
"""Indicates whether or not there is a low battery"""
+
"""Indicates whether or not there is a low battery."""
entry_delay_off = False
-
"""Indicates whether or not the entry delay is enabled"""
+
"""Indicates whether or not the entry delay is enabled."""
fire_alarm = False
-
"""Indicates whether or not a fire alarm is sounding"""
+
"""Indicates whether or not a fire alarm is sounding."""
check_zone = False
"""Indicates whether or not there are zones that require attention."""
perimeter_only = False
-
"""Indicates whether or not the perimeter is armed"""
+
"""Indicates whether or not the perimeter is armed."""
numeric_code = None
-
"""The numeric code associated with the message"""
+
"""The numeric code associated with the message."""
text = None
-
"""The human-readable text to be displayed on the panel LCD"""
+
"""The human-readable text to be displayed on the panel LCD."""
cursor_location = -1
-
"""Current cursor location on the keypad"""
+
"""Current cursor location on the keypad."""
mask = None
-
"""Address mask this message is intended for"""
+
"""Address mask this message is intended for."""
bitfield = None
-
"""The bitfield associated with this message"""
+
"""The bitfield associated with this message."""
panel_data = None
-
"""The panel data field associated with this message"""
+
"""The panel data field associated with this message."""
def __init__(self, data=None):
"""
Constructor
-
:param data: Message data to parse.
-
:type data: str
+
:param data: message data to parse
+
:type data: string
"""
BaseMessage.__init__(self)
-
self._regex = re.compile('^(!KPE:){0,1}(\[[a-fA-F0-9\-]+\]),([a-fA-F0-9]+),(\[[a-fA-F0-9]+\]),(".+")$')
+
self._regex = re.compile('^(!KPM:){0,1}(\[[a-fA-F0-9\-]+\]),([a-fA-F0-9]+),(\[[a-fA-F0-9]+\]),(".+")$')
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 message from the device.
-
:param data: The message data.
-
:type data: str
+
:param data: message data
+
:type data: string
-
:raises: InvalidMessageError
+
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
match = self._regex.match(data)
@@ -193,7 +214,38 @@
# Current cursor location on the alpha display.
self.cursor_location = int(self.bitfield[21:23], 16)
-
+
[docs] def dict(self, **kwargs):
+
"""
+
Dictionary representation.
+
"""
+
return dict(
+
time = self.timestamp,
+
bitfield = self.bitfield,
+
numeric_code = self.numeric_code,
+
panel_data = self.panel_data,
+
mask = self.mask,
+
ready = self.ready,
+
armed_away = self.armed_away,
+
armed_home = self.armed_home,
+
backlight_on = self.backlight_on,
+
programming_mode = self.programming_mode,
+
beeps = self.beeps,
+
zone_bypassed = self.zone_bypassed,
+
ac_power = self.ac_power,
+
chime_on = self.chime_on,
+
alarm_event_occurred = self.alarm_event_occurred,
+
alarm_sounding = self.alarm_sounding,
+
battery_low = self.battery_low,
+
entry_delay_off = self.entry_delay_off,
+
fire_alarm = self.fire_alarm,
+
check_zone = self.check_zone,
+
perimeter_only = self.perimeter_only,
+
text = self.text,
+
cursor_location = self.cursor_location,
+
**kwargs
+
)
+
+
[docs]class ExpanderMessage(BaseMessage):
"""
Represents a message from a zone or relay expansion module.
@@ -217,26 +269,22 @@
"""
Constructor
-
:param data: The message data to parse.
-
:type data: str
+
:param data: message data to parse
+
:type data: string
"""
BaseMessage.__init__(self)
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
+
:param data: message data
+
:type data: string
+
+
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
try:
header, values = data.split(':')
@@ -257,47 +305,55 @@
else:
raise InvalidMessageError('Unknown expander message header: {0}'.format(data))
-
+[docs] def dict(self, **kwargs):
+
"""
+
Dictionary representation.
+
"""
+
return dict(
+
time = self.timestamp,
+
address = self.address,
+
channel = self.channel,
+
value = self.value,
+
**kwargs
+
)
+
+
[docs]class RFMessage(BaseMessage):
"""
Represents a message from an RF receiver.
"""
serial_number = None
-
"""Serial number of the RF device"""
+
"""Serial number of the RF device."""
value = -1
-
"""Value associated with this message"""
+
"""Value associated with this message."""
battery = False
-
"""Battery low indication"""
+
"""Low battery indication"""
supervision = False
"""Supervision required indication"""
-
loop = [False for x in range(4)]
+
loop = [False for _ in range(4)]
"""Loop indicators"""
def __init__(self, data=None):
"""
Constructor
-
:param data: The message data to parse
-
:type data: str
+
:param data: message data to parse
+
:type data: string
"""
BaseMessage.__init__(self)
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
+
:param data: message data
+
:type data: string
+
+
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
try:
self.raw = data
@@ -320,7 +376,20 @@
except ValueError:
raise InvalidMessageError('Received invalid message: {0}'.format(data))
-
+[docs] def dict(self, **kwargs):
+
"""
+
Dictionary representation.
+
"""
+
return dict(
+
time = self.timestamp,
+
serial_number = self.serial_number,
+
value = self.value,
+
battery = self.battery,
+
supervision = self.supervision,
+
**kwargs
+
)
+
+
[docs]class LRRMessage(BaseMessage):
"""
Represent a message from a Long Range Radio.
@@ -329,34 +398,30 @@
event_data = None
"""Data associated with the LRR message. Usually user ID or zone."""
partition = -1
-
"""The partition that this message applies to"""
+
"""The partition that this message applies to."""
event_type = None
-
"""The type of the event that occurred"""
+
"""The type of the event that occurred."""
def __init__(self, data=None):
"""
Constructor
-
:param data: The message data to parse.
-
:type data: str
+
:param data: message data to parse
+
:type data: string
"""
BaseMessage.__init__(self)
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
+
:param data: message data to parse
+
:type data: string
+
+
:raises: :py:class:`~alarmdecoder.util.InvalidMessageError`
"""
try:
self.raw = data
@@ -365,7 +430,19 @@
self.event_data, self.partition, self.event_type = values.split(',')
except ValueError:
-
raise InvalidMessageError('Received invalid message: {0}'.format(data))
+ raise InvalidMessageError('Received invalid message: {0}'.format(data))
+
+[docs] def dict(self, **kwargs):
+
"""
+
Dictionary representation.
+
"""
+
return dict(
+
time = self.timestamp,
+
event_data = self.event_data,
+
event_type = self.event_type,
+
partition = self.partition,
+
**kwargs
+
)
diff --git a/docs/build/html/_modules/alarmdecoder/util.html b/docs/build/html/_modules/alarmdecoder/util.html
index 3540201..194f8bd 100644
--- a/docs/build/html/_modules/alarmdecoder/util.html
+++ b/docs/build/html/_modules/alarmdecoder/util.html
@@ -48,7 +48,9 @@
Source code for alarmdecoder.util
"""
-Provides utility classes for the Alarm Decoder (AD2) devices.
+Provides utility classes for the `AlarmDecoder`_ (AD2) devices.
+
+.. _AlarmDecoder: http://www.alarmdecoder.com
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
@@ -87,7 +89,7 @@
[docs]class Firmware(object):
"""
-
Represents firmware for the Alarm Decoder devices.
+
Represents firmware for the `AlarmDecoder`_ devices.
"""
# Constants
@@ -102,14 +104,14 @@
@staticmethod
[docs] def upload(dev, filename, progress_callback=None):
"""
-
Uploads firmware to an Alarm Decoder device.
+
Uploads firmware to an `AlarmDecoder`_ device.
-
:param filename: The firmware filename
-
:type filename: str
-
:param progress_callback: Callback function used to report progress.
+
:param filename: firmware filename
+
:type filename: string
+
:param progress_callback: callback function used to report progress
:type progress_callback: function
-
:raises: NoDeviceError, TimeoutError
+
:raises: :py:class:`~alarmdecoder.util.NoDeviceError`, :py:class:`~alarmdecoder.util.TimeoutError`
"""
def do_upload():
diff --git a/docs/build/html/_modules/alarmdecoder/zonetracking.html b/docs/build/html/_modules/alarmdecoder/zonetracking.html
index b0ed0c1..363a54c 100644
--- a/docs/build/html/_modules/alarmdecoder/zonetracking.html
+++ b/docs/build/html/_modules/alarmdecoder/zonetracking.html
@@ -48,7 +48,9 @@
Source code for alarmdecoder.zonetracking
"""
-Provides zone tracking functionality for the Alarm Decoder (AD2) device family.
+Provides zone tracking functionality for the `AlarmDecoder`_ (AD2) device family.
+
+.. _AlarmDecoder: http://www.alarmdecoder.com
.. moduleauthor:: Scott Petersen <scott@nutech.com>
"""
@@ -65,6 +67,7 @@
Representation of a panel zone.
"""
+ # Constants
CLEAR = 0
"""Status indicating that the zone is cleared."""
FAULT = 1
@@ -74,15 +77,25 @@
STATUS = {CLEAR: 'CLEAR', FAULT: 'FAULT', CHECK: 'CHECK'}
+ # Attributes
+ zone = 0
+ """Zone ID"""
+ name = ''
+ """Zone name"""
+ status = CLEAR
+ """Zone status"""
+ timestamp = None
+ """Timestamp of last update"""
+
def __init__(self, zone=0, name='', status=CLEAR):
"""
Constructor
- :param zone: The zone number.
+ :param zone: zone number
:type zone: int
- :param name: Human readable zone name.
- :type name: str
- :param status: Initial zone state.
+ :param name: Human readable zone name
+ :type name: string
+ :param status: Initial zone state
:type status: int
"""
self.zone = zone
@@ -105,15 +118,53 @@
[docs]class Zonetracker(object):
"""
-
Handles tracking of zone and their statuses.
+
Handles tracking of zones and their statuses.
"""
-
on_fault = event.Event('Called when the device detects a zone fault.')
-
on_restore = event.Event('Called when the device detects that a fault is restored.')
+
on_fault = event.Event("This event is called when the device detects a zone fault.\n\n**Callback definition:** *def callback(device, zone)*")
+
on_restore = event.Event("This event is called when the device detects that a fault is restored.\n\n**Callback definition:** *def callback(device, zone)*")
EXPIRE = 30
"""Zone expiration timeout."""
+
@property
+
def zones(self):
+
"""
+
Returns the current list of zones being tracked.
+
+
:returns: dictionary of :py:class:`Zone` being tracked
+
"""
+
return self._zones
+
+
@zones.setter
+
[docs] def zones(self, value):
+
"""
+
Sets the current list of zones being tracked.
+
+
:param value: new list of zones being tracked
+
:type value: dictionary of :py:class:`Zone` being tracked
+
"""
+
self._zones = value
+
+
@property
+
def faulted(self):
+
"""
+
Retrieves the current list of faulted zones.
+
+
:returns: list of faulted zones
+
"""
+
return self._zones_faulted
+
+
@faulted.setter
+
[docs] def faulted(self, value):
+
"""
+
Sets the current list of faulted zones.
+
+
:param value: new list of faulted zones
+
:type value: list of integers
+
"""
+
self._zones_faulted = value
+
def __init__(self):
"""
Constructor
@@ -126,8 +177,8 @@
"""
Update zone statuses based on the current message.
-
:param message: Message to use to update the zone tracking.
-
:type message: Message or ExpanderMessage
+
:param message: message to use to update the zone tracking
+
:type message: :py:class:`~alarmdecoder.messages.Message` or :py:class:`~alarmdecoder.messages.ExpanderMessage`
"""
if isinstance(message, ExpanderMessage):
if message.type == ExpanderMessage.ZONE:
@@ -208,12 +259,12 @@
"""
Convert an address and channel into a zone number.
-
:param address: The expander address
+
:param address: expander address
:type address: int
-
:param channel: The channel
+
:param channel: channel
:type channel: int
-
:returns: The zone number associated with an address and channel.
+
:returns: zone number associated with an address and channel
"""
# TODO: This is going to need to be reworked to support the larger
@@ -227,7 +278,7 @@
"""
Clear all expired zones from our status list.
-
:param zone: current zone being processed.
+
:param zone: current zone being processed
:type zone: int
"""
cleared_zones = []
@@ -300,11 +351,11 @@
"""
Adds a zone to the internal zone list.
-
:param zone: The zone number.
+
:param zone: zone number
:type zone: int
-
:param name: Human readable zone name.
-
:type name: str
-
:param status: The zone status.
+
:param name: human readable zone name
+
:type name: string
+
:param status: zone status
:type status: int
"""
if not zone in self._zones:
@@ -317,9 +368,9 @@
"""
Updates a zones status.
-
:param zone: The zone number.
+
:param zone: zone number
:type zone: int
-
:param status: The zone status.
+
:param status: zone status
:type status: int
:raises: IndexError
@@ -342,10 +393,10 @@
"""
Determine if a zone is expired or not.
-
:param zone: The zone number.
+
:param zone: zone number
:type zone: int
-
:returns: Whether or not the zone is expired.
+
:returns: whether or not the zone is expired
"""
return time.time() > self._zones[zone].timestamp + Zonetracker.EXPIRE
diff --git a/docs/build/html/alarmdecoder.html b/docs/build/html/alarmdecoder.html
index 5f87dd9..d18d7e8 100644
--- a/docs/build/html/alarmdecoder.html
+++ b/docs/build/html/alarmdecoder.html
@@ -177,6 +177,13 @@
Callback definition: def callback(device, message)
+
+-
+on_sending_received
+This event is called when a !Sending.done message is received from the AlarmDecoder.
+Callback definition: def callback(device, status, message)
+
+
-
on_open
@@ -229,6 +236,12 @@
Represents panel function key #4
+
+-
+KEY_PANIC = u'\x05\x05\x05'
+Represents a panic keypress
+
+
-
BATTERY_TIMEOUT = 30
@@ -255,7 +268,7 @@
-
-address_mask = 0
+address_mask = 4294967295
The address mask configured on the device.
@@ -693,6 +706,11 @@ reader thread.
Closes the device.
+
+-
+fileno()[source]
+
+
-
write(data)[source]
@@ -856,6 +874,11 @@ reader thread.
Closes the device.
+
+-
+fileno()[source]
+
+
-
write(data)[source]
@@ -1020,6 +1043,11 @@ thread.
Closes the device.
+
+-
+fileno()[source]
+
+
-
write(data)[source]
@@ -1103,6 +1131,18 @@ devices.
The raw message text
+
+-
+timestamp = None
+The timestamp of the message
+
+
+
+-
+dict(**kwargs)[source]
+Dictionary representation.
+
+
@@ -1242,6 +1282,12 @@ devices.
The panel data field associated with this message.
+
+-
+dict(**kwargs)[source]
+Dictionary representation.
+
+
@@ -1285,6 +1331,12 @@ devices.
Value associated with the message
+
+-
+dict(**kwargs)[source]
+Dictionary representation.
+
+
@@ -1322,6 +1374,12 @@ devices.
Loop indicators
+
+-
+dict(**kwargs)[source]
+Dictionary representation.
+
+
@@ -1347,6 +1405,12 @@ devices.
The type of the event that occurred.
+
+-
+dict(**kwargs)[source]
+Dictionary representation.
+
+
@@ -1434,7 +1498,7 @@ devices.
-
-zones
+zones[source]
Returns the current list of zones being tracked.
@@ -599,12 +639,12 @@
- on_low_battery (alarmdecoder.decoder.AlarmDecoder attribute)
-
-
- on_lrr_message (alarmdecoder.decoder.AlarmDecoder attribute)
+ |
+
- on_message (alarmdecoder.decoder.AlarmDecoder attribute)
@@ -650,6 +690,10 @@
+ - on_sending_received (alarmdecoder.decoder.AlarmDecoder attribute)
+
+
+
- on_write (alarmdecoder.decoder.AlarmDecoder attribute)
@@ -908,9 +952,15 @@
|
- - timestamp (alarmdecoder.zonetracking.Zone attribute)
+
- timestamp (alarmdecoder.messages.BaseMessage attribute)
+
+
+ - (alarmdecoder.zonetracking.Zone attribute)
+
+
+
- type (alarmdecoder.messages.ExpanderMessage attribute)
diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv
index b32ce89..cd58da7 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 bacf391..aec054a 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,messagesexpandermessag:[],readabl:3,send:3,program:3,x03:3,x02:3,x01:3,sent:3,x04:3,sourc:[0,2,3],string:3,clear_zon:3,fals:3,on_messag:[3,2],perimeter_onli:3,lrr:3,level:3,list:3,upload: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,gener:[],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,aliv:3,invalidmessageerror:3,via:3,vid:3,appli:3,filenam:3,api:2,famili:[3,2],from:[3,2],describ:3,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,indic:[],relai:3,expander_to_zon:3,cach:3,serialdevic:3,must:0,none:[0,3],retriev:[3,2],key_f2:3,on_restor:3,restor:3,dev:3,kwarg:0,can:0,def:[3,2],backlight_on:3,process:3,templat:3,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,low:3,instead:0,panic:3,updat:3,product:3,recogn:3,x509:3,ftdi:3,befor:3,attent:3,mai:2,associ:3,github:[],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],rfx:[],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,thread: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,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,str:[],save_config:3,ani:[],bitfield:3,check_zon:3,dedupl:3,expir:3,"__main__":2,programming_mod:3,also:[0,3],exampl:2,which:3,event_data:3,channel:3,zone_bypass:3,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,on_low_batteri:3,text:3,ssl_kei:3,radio:3,find:[3,2],locat:3,configur:3,solut:3,fault_zon:3,should:3,serial_numb:3,stop:3,ssl:3,"import":2,report:3,requir:[3,2],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,full:[],arg:0,close:3,arm:3,stop_read:3,pyseri:3,statu:3,wire:3,parent:[],pattern:3,written:3,between:3,progress:3,awai:3,kei:3,numer:3,last:3,fault:3,com:[],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],on_fault:3,cursor:3,defin:0,"while":[3,2],stage_upload:3,error:3,loop:3,readi:3,itself:0,ftdi_vendor_id:3,on_zone_fault:3,alarm_sound:3,panel_data:3,author:3,receiv:3,belong:3,handl:[3,2],decod:[],status:3,finish:3,http:[],expans:3,rais:3,user:3,expand:3,lower:3,entri:3,client:3,thi:[3,2],usual:3,when:3,human:3,baudrat:3,expos:3,on_disarm:3,"_on_open":3,except:[3,2],param:[],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,singl:3,page:2,www:[],crypto:3,nutechsoftwar:[],sampl:2,toctre:[],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,usb:[3,2],actual:3,simul:3,stage_start:3,address_mask:3,"float":3,automat:3,chime:3,support:[3,2],on_relay_chang:3,"long":3,start:3,interfac:3,includ:2,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,descript:3,pid:3,repres:3,on_zone_restor:3,exist:0,read_timeout:3,ftdi_product_id:3,check:3,battery_timeout:3,handle_messag:2,obj:0,boot:3,invalid:3,field:3,bool:3,you:0,intend:3,firmwar:3,track:3,on_arm:3,directori:2,mask:3,lrrmessag:3,on_lrr_messag:3,maxdepth:[],time:2},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:exception","5":"py:classmethod","6":"py:staticmethod"},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"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,3,1,""],event_data:[3,3,1,""],event_type:[3,3,1,""]},"alarmdecoder.messages.BaseMessage":{raw:[3,3,1,""]},"alarmdecoder.messages.ExpanderMessage":{RELAY:[3,3,1,""],ZONE:[3,3,1,""],value:[3,3,1,""],address:[3,3,1,""],type:[3,3,1,""],channel:[3,3,1,""]},"alarmdecoder.event.event":{EventHandler:[0,1,1,""],Event:[0,1,1,""]},"alarmdecoder.zonetracking.Zone":{status:[3,3,1,""],STATUS:[3,3,1,""],name:[3,3,1,""],zone:[3,3,1,""],timestamp:[3,3,1,""],CLEAR:[3,3,1,""],FAULT:[3,3,1,""],CHECK:[3,3,1,""]},"alarmdecoder.devices.SerialDevice":{read_line:[3,2,1,""],BAUDRATE:[3,3,1,""],read:[3,2,1,""],write:[3,2,1,""],find_all:[3,6,1,""],"interface":[3,3,1,""],close:[3,2,1,""],open:[3,2,1,""]},"alarmdecoder.zonetracking":{Zonetracker:[3,1,1,""],Zone:[3,1,1,""]},"alarmdecoder.zonetracking.Zonetracker":{faulted:[3,3,1,""],on_restore:[3,3,1,""],update:[3,2,1,""],zones:[3,3,1,""],on_fault:[3,3,1,""],EXPIRE:[3,3,1,""],expander_to_zone:[3,2,1,""]},"alarmdecoder.devices.Device.ReadThread":{READ_TIMEOUT:[3,3,1,""],stop:[3,2,1,""],run:[3,2,1,""]},"alarmdecoder.event":{event:[0,0,1,""]},"alarmdecoder.messages":{Message:[3,1,1,""],LRRMessage:[3,1,1,""],RFMessage:[3,1,1,""],ExpanderMessage:[3,1,1,""],BaseMessage:[3,1,1,""]},"alarmdecoder.devices":{Device:[3,1,1,""],SocketDevice:[3,1,1,""],USBDevice:[3,1,1,""],SerialDevice:[3,1,1,""]},"alarmdecoder.devices.USBDevice.DetectThread":{stop:[3,2,1,""],run:[3,2,1,""],on_attached:[3,3,1,""],on_detached:[3,3,1,""]},alarmdecoder:{zonetracking:[3,0,1,""],messages:[3,0,1,""],devices:[3,0,1,""],util:[3,0,1,""],decoder:[3,0,1,""],panels:[3,0,1,""],event:[0,0,1,""]},"alarmdecoder.decoder.AlarmDecoder":{configbits:[3,3,1,""],on_rfx_message:[3,3,1,""],fault_zone:[3,2,1,""],on_expander_message:[3,3,1,""],on_open:[3,3,1,""],save_config:[3,2,1,""],on_alarm:[3,3,1,""],on_arm:[3,3,1,""],on_boot:[3,3,1,""],fire_timeout:[3,3,1,""],close:[3,2,1,""],open:[3,2,1,""],id:[3,3,1,""],on_power_changed:[3,3,1,""],BATTERY_TIMEOUT:[3,3,1,""],KEY_F1:[3,3,1,""],KEY_F2:[3,3,1,""],KEY_F3:[3,3,1,""],on_message:[3,3,1,""],reboot:[3,2,1,""],send:[3,2,1,""],on_zone_restore:[3,3,1,""],on_disarm:[3,3,1,""],on_fire:[3,3,1,""],on_write:[3,3,1,""],on_read:[3,3,1,""],on_lrr_message:[3,3,1,""],KEY_F4:[3,3,1,""],clear_zone:[3,2,1,""],on_zone_fault:[3,3,1,""],on_config_received:[3,3,1,""],FIRE_TIMEOUT:[3,3,1,""],on_close:[3,3,1,""],on_bypass:[3,3,1,""],address:[3,3,1,""],battery_timeout:[3,3,1,""],on_panic:[3,3,1,""],on_relay_changed:[3,3,1,""],on_low_battery:[3,3,1,""],emulate_lrr:[3,3,1,""],deduplicate:[3,3,1,""],emulate_zone:[3,3,1,""],get_config:[3,2,1,""],address_mask:[3,3,1,""],emulate_relay:[3,3,1,""]},"alarmdecoder.devices.SocketDevice":{ssl_certificate:[3,3,1,""],ssl_key:[3,3,1,""],read:[3,2,1,""],ssl_ca:[3,3,1,""],read_line:[3,2,1,""],ssl:[3,3,1,""],write:[3,2,1,""],"interface":[3,3,1,""],close:[3,2,1,""],open:[3,2,1,""]},"alarmdecoder.devices.USBDevice":{write:[3,2,1,""],BAUDRATE:[3,3,1,""],description:[3,3,1,""],read:[3,2,1,""],DetectThread:[3,1,1,""],stop_detection:[3,5,1,""],devices:[3,5,1,""],start_detection:[3,5,1,""],read_line:[3,2,1,""],find_all:[3,5,1,""],FTDI_VENDOR_ID:[3,3,1,""],serial_number:[3,3,1,""],"interface":[3,3,1,""],close:[3,2,1,""],FTDI_PRODUCT_ID:[3,3,1,""],open:[3,2,1,""],find:[3,5,1,""]},"alarmdecoder.messages.Message":{backlight_on:[3,3,1,""],alarm_event_occurred:[3,3,1,""],programming_mode:[3,3,1,""],text:[3,3,1,""],bitfield:[3,3,1,""],armed_home:[3,3,1,""],alarm_sounding:[3,3,1,""],ready:[3,3,1,""],zone_bypassed:[3,3,1,""],panel_data:[3,3,1,""],check_zone:[3,3,1,""],numeric_code:[3,3,1,""],battery_low:[3,3,1,""],chime_on:[3,3,1,""],entry_delay_off:[3,3,1,""],perimeter_only:[3,3,1,""],fire_alarm:[3,3,1,""],ac_power:[3,3,1,""],beeps:[3,3,1,""],mask:[3,3,1,""],armed_away:[3,3,1,""],cursor_location:[3,3,1,""]},"alarmdecoder.devices.Device":{stop_reader:[3,2,1,""],on_open:[3,3,1,""],on_write:[3,3,1,""],ReadThread:[3,1,1,""],on_close:[3,3,1,""],on_read:[3,3,1,""],close:[3,2,1,""],is_reader_alive:[3,2,1,""],id:[3,3,1,""]},"alarmdecoder.messages.RFMessage":{battery:[3,3,1,""],value:[3,3,1,""],loop:[3,3,1,""],supervision:[3,3,1,""],serial_number:[3,3,1,""]},"alarmdecoder.decoder":{AlarmDecoder:[3,1,1,""]},"alarmdecoder.event.event.EventHandler":{fire:[0,2,1,""],add:[0,2,1,""],remove:[0,2,1,""]},"alarmdecoder.util.Firmware":{STAGE_LOAD:[3,3,1,""],upload:[3,6,1,""],STAGE_BOOT:[3,3,1,""],STAGE_START:[3,3,1,""],STAGE_UPLOADING:[3,3,1,""],STAGE_WAITING:[3,3,1,""],STAGE_DONE:[3,3,1,""]},"alarmdecoder.util":{CommError:[3,4,1,""],Firmware:[3,1,1,""],TimeoutError:[3,4,1,""],NoDeviceError:[3,4,1,""],InvalidMessageError:[3,4,1,""]}},titleterms:{subpackag:[],alarmdecod:[3,1],welcom:2,alarm:2,devic:3,zonetrack:3,util:3,packag:[0,3],decod:[3,2],messag: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:1,all:[1,0],code:[1,3],sleep:3,on_boot:1,stage_don:1,backlight:1,zone:1,readabl:1,send:1,program:1,x03:1,x02:1,x01:1,sent:1,x04:1,sourc:[0,1,3],string:1,clear_zon:1,fals:1,on_messag:[1,3],perimeter_onli:1,lrr:1,level:1,list:1,upload:1,"try":[1,3],emul:1,expandermessag:1,pleas:3,second:1,port:1,supervis:1,ad2seri:[1,3],current:1,"new":0,method:1,can:0,ser2sock:1,perimet:1,timeouterror:1,usbdevic:[1,3],entry_delay_off:1,here:3,on_config_receiv:1,address:1,path:1,valu:1,fire_alarm:1,search:[1,3],sender:[3,0],prior:1,def:[1,3],invalidmessageerror:1,via:1,vid:1,appli:1,filenam:1,api:3,famili:[1,3],key_pan:1,from:[1,3],usb:[1,3],commun:1,is_reader_al:1,handler:[3,0],call:[1,0],type:1,more:3,relat:1,stage_boot:1,pkei:1,flag:1,templat:1,relai:1,actual:1,cach:1,serialdevic:1,must:0,none:[1,0],retriev:[1,3],key_f2:1,on_restor:1,restor:1,dev:1,itself:0,x05:1,aliv:1,backlight_on:1,process:1,indic:1,high:1,cursor_loc:1,serial:1,occur:1,delai:1,progress_callback:1,secur:3,anoth:1,simulate_wire_problem:1,write:1,purg:1,low:1,instead:0,panic:1,updat:1,product:1,recogn:1,x509:1,ftdi:1,befor:1,attent:1,mai:3,data:1,classmethod:1,ssl_ca:1,issu:1,callback:1,"switch":1,ttimeout:1,socketdevic:1,disarm:1,jpath:1,through:1,paramet:1,bypass:1,on_read:1,main:[1,3],"return":1,python:3,timestamp:1,on_bypass:1,detach:1,name:1,revert:1,on_pan:1,authent:1,stage_wait:1,mode:1,timeout:1,found:[1,3],nodeviceerror:1,"static":1,connect:1,our:1,read_lin:1,event:1,ad2pi:[1,3],reboot:1,content:3,reader:1,print:3,factori:1,written:1,standard:1,on_clos:1,base:[1,0],dictionari:1,"byte":1,armed_hom:1,on_detach:1,key_f4:1,key_f1:1,thread:1,key_f3:1,emulate_relai:1,openssl:1,readthread:1,get_config:1,on_rfx_messag:1,find_al:1,ad2usb:[1,3],first:[1,3],oper:0,rang:1,number:1,done:1,on_writ:1,configbit:1,open:[1,3],on_power_chang:1,differ:1,associ:1,interact:3,system:1,wrapper:1,attach:1,start_detect:1,on_open:1,termin:3,battery_low:1,specifi:1,rfmessag:1,on_fir:1,provid:[1,3],remov:[1,0],charact:1,project:3,save_config:1,bitfield:1,raw:[1,3],dedupl:1,expir:1,"__main__":3,programming_mod:1,also:[1,0],exampl:3,which:1,event_data:1,channel:1,thi:[1,3],index:3,buffer:1,object:[1,0],most:1,detect:1,basemessag:1,"class":[1,0],armed_awai:1,doc:0,clear:1,request:1,emulate_lrr:1,on_low_batteri:1,text:1,ssl_kei:1,radio:1,find:[1,3],locat:1,configur:1,solut:1,fault_zon:1,should:1,dict:1,serial_numb:1,stop:1,ssl:1,"import":3,report:1,requir:[1,3],fileno:1,enabl:1,earg:0,whether:1,common:1,partit:1,contain:1,alarm_event_occur:1,certif:1,set:[1,3],keypad:1,ac_pow:1,on_alarm:1,see:3,arg:0,close:1,arm:1,stop_read:1,pyseri:1,statu:1,wire:1,pattern:1,keypress:1,state:1,between:1,progress:1,awai:1,kei:1,numer:1,last:1,fault:1,batteri:1,identif:1,detectthread:1,been:1,beep:1,trigger:1,basic:3,no_reader_thread:1,fire:[1,0],commerror:1,chime_on:1,convert:1,func:0,present:1,sound:1,check_zon:1,on_fault:1,cursor:1,defin:0,"while":[1,3],stage_upload:1,error:1,loop:1,readi:1,kwarg:[1,0],ftdi_vendor_id:1,on_zone_fault:1,alarm_sound:1,panel_data:1,author:1,receiv:1,belong:1,handl:[1,3],status:1,finish:1,expans:1,rais:1,user:1,expand:1,lower:1,entri:1,client:1,zone_bypass:1,usual:1,boot:1,human:1,baudrat:1,expos:1,field:1,"_on_open":1,except:[1,3],on_attach:1,add:0,board:1,match:1,applic:3,vendor:1,around:1,format:1,read:1,numeric_cod:1,lcd:1,bit:1,ad2:[1,3],like:0,singl:1,page:3,crypto:1,sampl:3,fire_timeout:1,home:1,librari:3,definit:1,pyftdi:1,localhost:1,run:1,power:1,event_typ:1,stage_load:1,ssl_certif:1,"__name__":3,describ:1,expander_to_zon:1,simul:1,stage_start:1,address_mask:1,"float":1,automat:1,chime:1,support:[1,3],on_relay_chang:1,"long":1,start:1,interfac:1,includ:3,on_expander_messag:1,stop_detect:1,"function":[1,0],tupl:1,eventhandl:0,line:1,"true":3,emulate_zon:1,"default":1,displai:1,purge_buff:1,below:3,alarm:1,"int":1,descript:1,pid:1,repres:1,on_zone_restor:1,exist:0,read_timeout:1,ftdi_product_id:1,check:1,battery_timeout:1,handle_messag:3,when:1,invalid:1,on_disarm:1,bool:1,you:0,intend:1,firmwar:1,track:1,on_arm:1,on_sending_receiv:1,directori:3,mask:1,lrrmessag:1,on_lrr_messag:1,obj:0,time:3},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:exception","5":"py:classmethod","6":"py:staticmethod"},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","exception","Python exception"],"5":["py","classmethod","Python class method"],"6":["py","staticmethod","Python static method"]},filenames:["alarmdecoder.event","alarmdecoder","modules","index"],titles:["event Package","alarmdecoder Package","alarmdecoder","Welcome to Alarm Decoder’s documentation!"],objects:{"alarmdecoder.messages.LRRMessage":{partition:[1,3,1,""],dict:[1,2,1,""],event_data:[1,3,1,""],event_type:[1,3,1,""]},"alarmdecoder.messages.BaseMessage":{raw:[1,3,1,""],dict:[1,2,1,""],timestamp:[1,3,1,""]},"alarmdecoder.messages.ExpanderMessage":{ZONE:[1,3,1,""],RELAY:[1,3,1,""],value:[1,3,1,""],dict:[1,2,1,""],address:[1,3,1,""],type:[1,3,1,""],channel:[1,3,1,""]},"alarmdecoder.event.event":{EventHandler:[0,1,1,""],Event:[0,1,1,""]},"alarmdecoder.zonetracking.Zone":{status:[1,3,1,""],STATUS:[1,3,1,""],name:[1,3,1,""],zone:[1,3,1,""],timestamp:[1,3,1,""],CLEAR:[1,3,1,""],FAULT:[1,3,1,""],CHECK:[1,3,1,""]},"alarmdecoder.devices.SerialDevice":{fileno:[1,2,1,""],BAUDRATE:[1,3,1,""],read:[1,2,1,""],read_line:[1,2,1,""],write:[1,2,1,""],find_all:[1,6,1,""],"interface":[1,3,1,""],close:[1,2,1,""],open:[1,2,1,""]},"alarmdecoder.zonetracking":{Zonetracker:[1,1,1,""],Zone:[1,1,1,""]},"alarmdecoder.zonetracking.Zonetracker":{faulted:[1,3,1,""],on_restore:[1,3,1,""],update:[1,2,1,""],zones:[1,3,1,""],on_fault:[1,3,1,""],EXPIRE:[1,3,1,""],expander_to_zone:[1,2,1,""]},"alarmdecoder.devices.Device.ReadThread":{READ_TIMEOUT:[1,3,1,""],stop:[1,2,1,""],run:[1,2,1,""]},"alarmdecoder.event":{event:[0,0,1,""]},"alarmdecoder.messages":{Message:[1,1,1,""],LRRMessage:[1,1,1,""],RFMessage:[1,1,1,""],ExpanderMessage:[1,1,1,""],BaseMessage:[1,1,1,""]},"alarmdecoder.devices":{Device:[1,1,1,""],SocketDevice:[1,1,1,""],USBDevice:[1,1,1,""],SerialDevice:[1,1,1,""]},"alarmdecoder.devices.USBDevice.DetectThread":{run:[1,2,1,""],stop:[1,2,1,""],on_attached:[1,3,1,""],on_detached:[1,3,1,""]},alarmdecoder:{zonetracking:[1,0,1,""],messages:[1,0,1,""],devices:[1,0,1,""],util:[1,0,1,""],decoder:[1,0,1,""],panels:[1,0,1,""],event:[0,0,1,""]},"alarmdecoder.decoder.AlarmDecoder":{configbits:[1,3,1,""],on_rfx_message:[1,3,1,""],fault_zone:[1,2,1,""],on_expander_message:[1,3,1,""],on_open:[1,3,1,""],save_config:[1,2,1,""],on_alarm:[1,3,1,""],on_arm:[1,3,1,""],on_sending_received:[1,3,1,""],KEY_PANIC:[1,3,1,""],fire_timeout:[1,3,1,""],close:[1,2,1,""],open:[1,2,1,""],id:[1,3,1,""],on_power_changed:[1,3,1,""],battery_timeout:[1,3,1,""],KEY_F1:[1,3,1,""],KEY_F2:[1,3,1,""],KEY_F3:[1,3,1,""],on_message:[1,3,1,""],reboot:[1,2,1,""],send:[1,2,1,""],on_zone_restore:[1,3,1,""],on_disarm:[1,3,1,""],on_fire:[1,3,1,""],on_write:[1,3,1,""],on_read:[1,3,1,""],on_lrr_message:[1,3,1,""],KEY_F4:[1,3,1,""],clear_zone:[1,2,1,""],on_zone_fault:[1,3,1,""],on_config_received:[1,3,1,""],emulate_relay:[1,3,1,""],on_close:[1,3,1,""],on_bypass:[1,3,1,""],address:[1,3,1,""],BATTERY_TIMEOUT:[1,3,1,""],on_panic:[1,3,1,""],on_relay_changed:[1,3,1,""],on_low_battery:[1,3,1,""],emulate_lrr:[1,3,1,""],deduplicate:[1,3,1,""],emulate_zone:[1,3,1,""],get_config:[1,2,1,""],address_mask:[1,3,1,""],FIRE_TIMEOUT:[1,3,1,""],on_boot:[1,3,1,""]},"alarmdecoder.devices.SocketDevice":{ssl_certificate:[1,3,1,""],ssl_key:[1,3,1,""],fileno:[1,2,1,""],read:[1,2,1,""],ssl_ca:[1,3,1,""],read_line:[1,2,1,""],ssl:[1,3,1,""],write:[1,2,1,""],"interface":[1,3,1,""],close:[1,2,1,""],open:[1,2,1,""]},"alarmdecoder.devices.USBDevice":{fileno:[1,2,1,""],BAUDRATE:[1,3,1,""],description:[1,3,1,""],read:[1,2,1,""],DetectThread:[1,1,1,""],stop_detection:[1,5,1,""],devices:[1,5,1,""],start_detection:[1,5,1,""],read_line:[1,2,1,""],write:[1,2,1,""],find_all:[1,5,1,""],FTDI_VENDOR_ID:[1,3,1,""],serial_number:[1,3,1,""],"interface":[1,3,1,""],close:[1,2,1,""],FTDI_PRODUCT_ID:[1,3,1,""],open:[1,2,1,""],find:[1,5,1,""]},"alarmdecoder.messages.Message":{backlight_on:[1,3,1,""],alarm_event_occurred:[1,3,1,""],programming_mode:[1,3,1,""],text:[1,3,1,""],bitfield:[1,3,1,""],armed_home:[1,3,1,""],alarm_sounding:[1,3,1,""],ready:[1,3,1,""],zone_bypassed:[1,3,1,""],panel_data:[1,3,1,""],check_zone:[1,3,1,""],numeric_code:[1,3,1,""],dict:[1,2,1,""],battery_low:[1,3,1,""],chime_on:[1,3,1,""],entry_delay_off:[1,3,1,""],perimeter_only:[1,3,1,""],fire_alarm:[1,3,1,""],ac_power:[1,3,1,""],beeps:[1,3,1,""],mask:[1,3,1,""],armed_away:[1,3,1,""],cursor_location:[1,3,1,""]},"alarmdecoder.devices.Device":{stop_reader:[1,2,1,""],on_open:[1,3,1,""],on_write:[1,3,1,""],ReadThread:[1,1,1,""],on_close:[1,3,1,""],on_read:[1,3,1,""],close:[1,2,1,""],is_reader_alive:[1,2,1,""],id:[1,3,1,""]},"alarmdecoder.messages.RFMessage":{battery:[1,3,1,""],value:[1,3,1,""],dict:[1,2,1,""],supervision:[1,3,1,""],serial_number:[1,3,1,""],loop:[1,3,1,""]},"alarmdecoder.decoder":{AlarmDecoder:[1,1,1,""]},"alarmdecoder.event.event.EventHandler":{fire:[0,2,1,""],add:[0,2,1,""],remove:[0,2,1,""]},"alarmdecoder.util.Firmware":{STAGE_LOAD:[1,3,1,""],upload:[1,6,1,""],STAGE_BOOT:[1,3,1,""],STAGE_START:[1,3,1,""],STAGE_UPLOADING:[1,3,1,""],STAGE_WAITING:[1,3,1,""],STAGE_DONE:[1,3,1,""]},"alarmdecoder.util":{CommError:[1,4,1,""],Firmware:[1,1,1,""],TimeoutError:[1,4,1,""],NoDeviceError:[1,4,1,""],InvalidMessageError:[1,4,1,""]}},titleterms:{alarmdecod:[1,2],welcom:3,alarm:3,devic:1,messag:1,event:0,util:1,packag:[1,0],decod:[1,3],zonetrack:1,indic:3,tabl:3,document:3,modul:[1,0],panel:1}})
\ No newline at end of file
diff --git a/setup.py b/setup.py
index f8cb474..38a11ba 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@ def readme():
return readme_file.read()
setup(name='alarmdecoder',
- version='0.6',
+ version='0.7',
description='Python interface for the AlarmDecoder (AD2) family '
'of alarm devices which includes the AD2USB, AD2SERIAL and AD2PI.',
long_description=readme(),
|