| @@ -1,31 +1,31 @@ | |||
| pyAD2 - Python library for the AD2 device family | |||
| ================================================ | |||
| alarmdecoder - Python library for the Alarm Decoder (AD2) device family | |||
| ======================================================================= | |||
| This Python module aims to provide a consistent interface for all of the AD2 | |||
| product line, including the AD2USB, AD2SERIAL and AD2PI devices. This also | |||
| includes devices that have been exposed via [ser2sock](http://github.com/nutechsoftware/ser2sock) and supports encryption | |||
| via SSL/TLS. | |||
| This Python module aims to provide a consistent interface for all of the Alarm | |||
| Decoder product line, including the AD2USB, AD2SERIAL and AD2PI devices. This | |||
| also includes devices that have been exposed via [ser2sock](http://github.com/nutechsoftware/ser2sock) and supports | |||
| encryption via SSL/TLS. | |||
| Installation | |||
| ------------ | |||
| pyAD2 can be installed through pip: | |||
| pip install pyad2 | |||
| alarmdecoder can be installed through pip: | |||
| pip install alarmdecoder | |||
| or from source: | |||
| python setup.py install | |||
| Requirements | |||
| ------------ | |||
| * [pyopenssl](https://launchpad.net/pyopenssl) | |||
| * [pyftdi](https://github.com/eblot/pyftdi) >= 0.9.0 | |||
| * [pyusb](http://sourceforge.net/apps/trac/pyusb/) >= 1.0.0b1 | |||
| * [pyserial](http://pyserial.sourceforge.net/) >= 2.7 | |||
| * [pyftdi](https://github.com/eblot/pyftdi) >= 0.9.0 | |||
| * [pyopenssl](https://launchpad.net/pyopenssl) | |||
| Documentation | |||
| ------------- | |||
| API documentation can be found [here](http://github.com/nutechsoftware/pyad2/tree/master/docs/_build/html). | |||
| API documentation can be found [here](http://github.com/nutechsoftware/alarmdecoder/tree/master/docs/_build/html). | |||
| Examples | |||
| -------- | |||
| @@ -36,4 +36,4 @@ Basic usage: | |||
| ``` | |||
| Please see the [examples](http://github.com/nutechsoftware/pyad2/tree/master/examples) directory for more. | |||
| Please see the [examples](http://github.com/nutechsoftware/alarmdecoder/tree/master/examples) directory for more. | |||
| @@ -1,25 +1,25 @@ | |||
| #!/usr/bin/env python | |||
| import sys, time | |||
| import pyad2 | |||
| import alarmdecoder | |||
| def handle_firmware(stage): | |||
| if stage == pyad2.util.Firmware.STAGE_START: | |||
| if stage == alarmdecoder.util.Firmware.STAGE_START: | |||
| handle_firmware.wait_tick = 0 | |||
| handle_firmware.upload_tick = 0 | |||
| elif stage == pyad2.util.Firmware.STAGE_WAITING: | |||
| elif stage == alarmdecoder.util.Firmware.STAGE_WAITING: | |||
| if handle_firmware.wait_tick == 0: | |||
| sys.stdout.write('Waiting for device.') | |||
| handle_firmware.wait_tick += 1 | |||
| sys.stdout.write('.') | |||
| sys.stdout.flush() | |||
| elif stage == pyad2.util.Firmware.STAGE_BOOT: | |||
| elif stage == alarmdecoder.util.Firmware.STAGE_BOOT: | |||
| if handle_firmware.wait_tick > 0: print "" | |||
| print "Rebooting device.." | |||
| elif stage == pyad2.util.Firmware.STAGE_LOAD: | |||
| elif stage == alarmdecoder.util.Firmware.STAGE_LOAD: | |||
| print 'Waiting for boot loader..' | |||
| elif stage == pyad2.util.Firmware.STAGE_UPLOADING: | |||
| elif stage == alarmdecoder.util.Firmware.STAGE_UPLOADING: | |||
| if handle_firmware.upload_tick == 0: | |||
| sys.stdout.write('Uploading firmware.') | |||
| @@ -28,7 +28,7 @@ def handle_firmware(stage): | |||
| if handle_firmware.upload_tick % 30 == 0: | |||
| sys.stdout.write('.') | |||
| sys.stdout.flush() | |||
| elif stage == pyad2.util.Firmware.STAGE_DONE: | |||
| elif stage == alarmdecoder.util.Firmware.STAGE_DONE: | |||
| print "\r\nDone!" | |||
| def main(): | |||
| @@ -45,11 +45,11 @@ def main(): | |||
| print "Flashing device: {0}\r\nFirmware: {1}".format(device, firmware) | |||
| dev = pyad2.devices.SerialDevice(interface=device) | |||
| dev = alarmdecoder.devices.SerialDevice(interface=device) | |||
| dev.open(baudrate=19200) | |||
| time.sleep(3) | |||
| pyad2.util.Firmware.upload(dev, firmware, handle_firmware) | |||
| alarmdecoder.util.Firmware.upload(dev, firmware, handle_firmware) | |||
| dev.close() | |||
| @@ -1,6 +1,6 @@ | |||
| #!/usr/bin/env python | |||
| import pyad2 | |||
| import alarmdecoder | |||
| import sys, select | |||
| import termios, tty | |||
| import time | |||
| @@ -23,7 +23,7 @@ def main(): | |||
| try: | |||
| print "Opening connection to {0}:{1}\r".format(host, port) | |||
| dev = pyad2.devices.SocketDevice(interface=(host, int(port))) | |||
| dev = alarmdecoder.devices.SocketDevice(interface=(host, int(port))) | |||
| dev.ssl = True | |||
| dev.ssl_certificate = client_cert | |||
| dev.ssl_key = client_key | |||
| @@ -85,17 +85,17 @@ qthelp: | |||
| @echo | |||
| @echo "Build finished; now you can run "qcollectiongenerator" with the" \ | |||
| ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | |||
| @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyad2.qhcp" | |||
| @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/alarmdecoder.qhcp" | |||
| @echo "To view the help file:" | |||
| @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyad2.qhc" | |||
| @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/alarmdecoder.qhc" | |||
| devhelp: | |||
| $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | |||
| @echo | |||
| @echo "Build finished." | |||
| @echo "To view the help file:" | |||
| @echo "# mkdir -p $$HOME/.local/share/devhelp/pyad2" | |||
| @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyad2" | |||
| @echo "# mkdir -p $$HOME/.local/share/devhelp/alarmdecoder" | |||
| @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/alarmdecoder" | |||
| @echo "# devhelp" | |||
| epub: | |||
| @@ -1,6 +1,6 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # pyad2 documentation build configuration file, created by | |||
| # alarmdecoder documentation build configuration file, created by | |||
| # sphinx-quickstart on Sat Jun 8 14:38:46 2013. | |||
| # | |||
| # This file is execfile()d with the current directory set to its containing dir. | |||
| @@ -40,8 +40,8 @@ source_suffix = '.rst' | |||
| master_doc = 'index' | |||
| # General information about the project. | |||
| project = u'pyad2' | |||
| copyright = u'2013, Author' | |||
| project = u'alarmdecoder' | |||
| copyright = u'2013, Nu Tech Software Solutions, Inc.' | |||
| # The version info for the project you're documenting, acts as replacement for | |||
| # |version| and |release|, also used in various other places throughout the | |||
| @@ -167,7 +167,7 @@ html_static_path = ['_static'] | |||
| #html_file_suffix = None | |||
| # Output file base name for HTML help builder. | |||
| htmlhelp_basename = 'pyad2doc' | |||
| htmlhelp_basename = 'alarmdecoderdoc' | |||
| # -- Options for LaTeX output -------------------------------------------------- | |||
| @@ -186,8 +186,8 @@ latex_elements = { | |||
| # Grouping the document tree into LaTeX files. List of tuples | |||
| # (source start file, target name, title, author, documentclass [howto/manual]). | |||
| latex_documents = [ | |||
| ('index', 'pyad2.tex', u'pyad2 Documentation', | |||
| u'Author', 'manual'), | |||
| ('index', 'alarmdecoder.tex', u'AlarmDecoder Documentation', | |||
| u'Nu Tech Software Solutions, Inc.', 'manual'), | |||
| ] | |||
| # The name of an image file (relative to this directory) to place at the top of | |||
| @@ -216,8 +216,8 @@ latex_documents = [ | |||
| # One entry per manual page. List of tuples | |||
| # (source start file, name, description, authors, manual section). | |||
| man_pages = [ | |||
| ('index', 'pyad2', u'pyad2 Documentation', | |||
| [u'Author'], 1) | |||
| ('index', 'alarmdecoder', u'AlarmDecoder Documentation', | |||
| [u'Nu Tech Software Solutions, Inc.'], 1) | |||
| ] | |||
| # If true, show URL addresses after external links. | |||
| @@ -230,8 +230,8 @@ man_pages = [ | |||
| # (source start file, target name, title, author, | |||
| # dir menu entry, description, category) | |||
| texinfo_documents = [ | |||
| ('index', 'pyad2', u'pyad2 Documentation', | |||
| u'Author', 'pyad2', 'One line description of project.', | |||
| ('index', 'alarmdecoder', u'AlarmDecoder Documentation', | |||
| u'Nu Tech Software Solutions, Inc.', 'alarmdecoder', 'Python library for the Alarm Decoder (AD2) device family.', | |||
| 'Miscellaneous'), | |||
| ] | |||
| @@ -251,10 +251,10 @@ texinfo_documents = [ | |||
| # -- Options for Epub output --------------------------------------------------- | |||
| # Bibliographic Dublin Core info. | |||
| epub_title = u'pyad2' | |||
| epub_author = u'Author' | |||
| epub_publisher = u'Author' | |||
| epub_copyright = u'2013, Author' | |||
| epub_title = u'alarmdecoder' | |||
| epub_author = u'Nu Tech Software Solutions, Inc.' | |||
| epub_publisher = u'Nu Tech Software Solutions, Inc.' | |||
| epub_copyright = u'2013, Nu Tech Software Solutions, Inc.' | |||
| # The language of the text. It defaults to the language option | |||
| # or en if the language is not set. | |||
| @@ -1,9 +1,9 @@ | |||
| .. pyad2 documentation master file, created by | |||
| .. alarmdecoder documentation master file, created by | |||
| sphinx-quickstart on Sat Jun 8 14:38:46 2013. | |||
| You can adapt this file completely to your liking, but it should at least | |||
| contain the root `toctree` directive. | |||
| Welcome to pyad2's documentation! | |||
| Welcome to alarmdecoder's documentation! | |||
| ==================================== | |||
| Contents: | |||
| @@ -11,7 +11,7 @@ Contents: | |||
| .. toctree:: | |||
| :maxdepth: 4 | |||
| pyad2 | |||
| alarmdecoder | |||
| Indices and tables | |||
| @@ -115,9 +115,9 @@ if "%1" == "qthelp" ( | |||
| echo. | |||
| echo.Build finished; now you can run "qcollectiongenerator" with the ^ | |||
| .qhcp project file in %BUILDDIR%/qthelp, like this: | |||
| echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyad2.qhcp | |||
| echo.^> qcollectiongenerator %BUILDDIR%\qthelp\alarmdecoder.qhcp | |||
| echo.To view the help file: | |||
| echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyad2.ghc | |||
| echo.^> assistant -collectionFile %BUILDDIR%\qthelp\alarmdecoder.ghc | |||
| goto end | |||
| ) | |||
| @@ -1,7 +1,7 @@ | |||
| pyad2 | |||
| ======== | |||
| alarmdecoder | |||
| ============ | |||
| .. toctree:: | |||
| :maxdepth: 4 | |||
| pyad2 | |||
| alarmdecoder | |||
| @@ -4,7 +4,7 @@ event Package | |||
| :mod:`event` Package | |||
| -------------------- | |||
| .. automodule:: pyad2.event | |||
| .. automodule:: alarmdecoder.event | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -12,7 +12,7 @@ event Package | |||
| :mod:`event` Module | |||
| ------------------- | |||
| .. automodule:: pyad2.event.event | |||
| .. automodule:: alarmdecoder.event.event | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -1,10 +1,10 @@ | |||
| pyad2 Package | |||
| alarmdecoder Package | |||
| ================ | |||
| :mod:`ad2` Module | |||
| :mod:`alarmdecoder` Module | |||
| -------------------- | |||
| .. automodule:: pyad2.ad2 | |||
| .. automodule:: alarmdecoder.alarmdecoder | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -12,7 +12,7 @@ pyad2 Package | |||
| :mod:`devices` Module | |||
| --------------------- | |||
| .. automodule:: pyad2.devices | |||
| .. automodule:: alarmdecoder.devices | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -20,7 +20,7 @@ pyad2 Package | |||
| :mod:`util` Module | |||
| ------------------ | |||
| .. automodule:: pyad2.util | |||
| .. automodule:: alarmdecoder.util | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -28,7 +28,7 @@ pyad2 Package | |||
| :mod:`zonetracking` Module | |||
| -------------------------- | |||
| .. automodule:: pyad2.zonetracking | |||
| .. automodule:: alarmdecoder.zonetracking | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -36,7 +36,7 @@ pyad2 Package | |||
| :mod:`panels` Module | |||
| -------------------- | |||
| .. automodule:: pyad2.panels | |||
| .. automodule:: alarmdecoder.panels | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -44,7 +44,7 @@ pyad2 Package | |||
| :mod:`messages` Module | |||
| ---------------------- | |||
| .. automodule:: pyad2.messages | |||
| .. automodule:: alarmdecoder.messages | |||
| :members: | |||
| :undoc-members: | |||
| :show-inheritance: | |||
| @@ -54,5 +54,5 @@ Subpackages | |||
| .. toctree:: | |||
| pyad2.event | |||
| alarmdecoder.event | |||
| @@ -1,8 +1,8 @@ | |||
| import time | |||
| import smtplib | |||
| from email.mime.text import MIMEText | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import USBDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import USBDevice | |||
| # Configuration values | |||
| SUBJECT = "Alarm Decoder - ALARM" | |||
| @@ -20,7 +20,7 @@ def main(): | |||
| """ | |||
| try: | |||
| # Retrieve the first USB device | |||
| device = AD2(USBDevice.find()) | |||
| device = AlarmDecoder(USBDevice.find()) | |||
| # Set up an event handler and open the device | |||
| device.on_alarm += handle_alarm | |||
| @@ -33,7 +33,7 @@ def main(): | |||
| def handle_alarm(sender, *args, **kwargs): | |||
| """ | |||
| Handles alarm events from the AD2. | |||
| Handles alarm events from the AlarmDecoder. | |||
| """ | |||
| status = kwargs['status'] | |||
| text = "Alarm status: {0}".format(status) | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import USBDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import USBDevice | |||
| def main(): | |||
| """ | |||
| @@ -8,7 +8,7 @@ def main(): | |||
| """ | |||
| try: | |||
| # Retrieve the first USB device | |||
| device = AD2(USBDevice.find()) | |||
| device = AlarmDecoder(USBDevice.find()) | |||
| # Set up an event handler and open the device | |||
| device.on_message += handle_message | |||
| @@ -21,7 +21,7 @@ def main(): | |||
| def handle_message(sender, *args, **kwargs): | |||
| """ | |||
| Handles message events from the AD2. | |||
| Handles message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import USBDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import USBDevice | |||
| __devices = {} | |||
| @@ -33,12 +33,12 @@ def main(): | |||
| def create_device(device_args): | |||
| """ | |||
| Creates an AD2 from the specified USB device arguments. | |||
| Creates an AlarmDecoder from the specified USB device arguments. | |||
| :param device_args: Tuple containing information on the USB device to open. | |||
| :type device_args: Tuple (vid, pid, serialnumber, interface_count, description) | |||
| """ | |||
| device = AD2(USBDevice.find(device_args)) | |||
| device = AlarmDecoder(USBDevice.find(device_args)) | |||
| device.on_message += handle_message | |||
| device.open() | |||
| @@ -46,7 +46,7 @@ def create_device(device_args): | |||
| def handle_message(sender, *args, **kwargs): | |||
| """ | |||
| Handles message events from the AD2. | |||
| Handles message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import USBDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import USBDevice | |||
| RF_DEVICE_SERIAL_NUMBER = '0252254' | |||
| @@ -18,7 +18,7 @@ def main(): | |||
| """ | |||
| try: | |||
| # Retrieve the first USB device | |||
| device = AD2(USBDevice.find()) | |||
| device = AlarmDecoder(USBDevice.find()) | |||
| # Set up an event handler and open the device | |||
| device.on_rfx_message += handle_rfx | |||
| @@ -31,7 +31,7 @@ def main(): | |||
| def handle_rfx(sender, *args, **kwargs): | |||
| """ | |||
| Handles RF message events from the AD2. | |||
| Handles RF message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import SerialDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import SerialDevice | |||
| # Configuration values | |||
| SERIAL_DEVICE = '/dev/ttyUSB0' | |||
| @@ -12,7 +12,7 @@ def main(): | |||
| """ | |||
| try: | |||
| # Retrieve the specified serial device. | |||
| device = AD2(SerialDevice(interface=SERIAL_DEVICE)) | |||
| device = AlarmDecoder(SerialDevice(interface=SERIAL_DEVICE)) | |||
| # Set up an event handler and open the device | |||
| device.on_message += handle_message | |||
| @@ -28,7 +28,7 @@ def main(): | |||
| def handle_message(sender, *args, **kwargs): | |||
| """ | |||
| Handles message events from the AD2. | |||
| Handles message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import SocketDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import SocketDevice | |||
| # Configuration values | |||
| HOSTNAME = 'localhost' | |||
| @@ -13,7 +13,7 @@ def main(): | |||
| """ | |||
| try: | |||
| # Retrieve an AD2 device that has been exposed with ser2sock on localhost:10000. | |||
| device = AD2(SocketDevice(interface=(HOSTNAME, PORT))) | |||
| device = AlarmDecoder(SocketDevice(interface=(HOSTNAME, PORT))) | |||
| # Set up an event handler and open the device | |||
| device.on_message += handle_message | |||
| @@ -26,7 +26,7 @@ def main(): | |||
| def handle_message(sender, *args, **kwargs): | |||
| """ | |||
| Handles message events from the AD2. | |||
| Handles message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import SocketDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import SocketDevice | |||
| # Configuration values | |||
| HOSTNAME = 'localhost' | |||
| @@ -27,7 +27,7 @@ def main(): | |||
| ssl_device.ssl_key = SSL_KEY # Client private key | |||
| ssl_device.ssl_certificate = SSL_CERT # Client certificate | |||
| device = AD2(ssl_device) | |||
| device = AlarmDecoder(ssl_device) | |||
| # Set up an event handler and open the device | |||
| device.on_message += handle_message | |||
| @@ -40,7 +40,7 @@ def main(): | |||
| def handle_message(sender, *args, **kwargs): | |||
| """ | |||
| Handles message events from the AD2. | |||
| Handles message events from the AlarmDecoder. | |||
| """ | |||
| msg = kwargs['message'] | |||
| @@ -1,6 +1,6 @@ | |||
| import time | |||
| from pyad2 import AD2 | |||
| from pyad2.devices import USBDevice | |||
| from alarmdecoder import AlarmDecoder | |||
| from alarmdecoder.devices import USBDevice | |||
| # Configuration values | |||
| TARGET_ZONE = 41 | |||
| @@ -12,23 +12,23 @@ def main(): | |||
| restores it. | |||
| This is an advanced feature that allows you to emulate a virtual zone. When | |||
| the AD2 is configured to emulate a relay expander we can fault and restore | |||
| those zones programmatically at will. These events can also be seen by others, | |||
| such as home automation platforms which allows you to connect other devices or | |||
| services and monitor them as you would any pyhysical zone. | |||
| the Alarm Decoder is configured to emulate a relay expander we can fault and | |||
| restore those zones programmatically at will. These events can also be seen by | |||
| others, such as home automation platforms which allows you to connect other | |||
| devices or services and monitor them as you would any pyhysical zone. | |||
| For example, you could connect a ZigBee device and receiver and fault or | |||
| restore it's zone(s) based on the data received. | |||
| In order for this to happen you need to perform a couple configuration steps: | |||
| 1. Enable zone expander emulation on your AD2 device by hitting '!' in a | |||
| terminal and going through the prompts. | |||
| 1. Enable zone expander emulation on your Alarm Decoder device by hitting '!' | |||
| in a terminal and going through the prompts. | |||
| 2. Enable the zone expander in your panel programming. | |||
| """ | |||
| try: | |||
| # Retrieve the first USB device | |||
| device = AD2(USBDevice.find()) | |||
| device = AlarmDecoder(USBDevice.find()) | |||
| # Set up an event handlers and open the device | |||
| device.on_zone_fault += handle_zone_fault | |||
| @@ -1,7 +1,7 @@ | |||
| from ad2 import AD2 | |||
| from decoder import AlarmDecoder | |||
| import devices | |||
| import util | |||
| import messages | |||
| import zonetracking | |||
| __all__ = ['ad2', 'devices', 'util', 'messages', 'zonetracking'] | |||
| __all__ = ['decoder', 'devices', 'util', 'messages', 'zonetracking'] | |||
| @@ -1,5 +1,5 @@ | |||
| """ | |||
| Provides the full AD2 class and factory. | |||
| Provides the full AlarmDecoder class. | |||
| .. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
| """ | |||
| @@ -12,9 +12,9 @@ from .util import CommError, NoDeviceError | |||
| from .messages import Message, ExpanderMessage, RFMessage, LRRMessage | |||
| from .zonetracking import Zonetracker | |||
| class AD2(object): | |||
| class AlarmDecoder(object): | |||
| """ | |||
| High-level wrapper around AD2 devices. | |||
| High-level wrapper around Alarm Decoder (AD2) devices. | |||
| """ | |||
| # High-level Events | |||
| @@ -62,7 +62,7 @@ class AD2(object): | |||
| """ | |||
| Constructor | |||
| :param device: The low-level device used for this AD2 interface. | |||
| :param device: The low-level device used for this Alarm Decoder interface. | |||
| :type device: Device | |||
| """ | |||
| self._device = device | |||
| @@ -102,7 +102,7 @@ class AD2(object): | |||
| @property | |||
| def id(self): | |||
| """ | |||
| The ID of the AD2 device. | |||
| The ID of the Alarm Decoder device. | |||
| :returns: The identification string for the device. | |||
| """ | |||
| @@ -134,7 +134,7 @@ class AD2(object): | |||
| def send(self, data): | |||
| """ | |||
| Sends data to the AD2 device. | |||
| Sends data to the Alarm Decoder device. | |||
| :param data: The data to send. | |||
| :type data: str | |||
| @@ -371,14 +371,14 @@ class AD2(object): | |||
| if message.battery_low == self._battery_status[0]: | |||
| self._battery_status = (self._battery_status[0], time.time()) | |||
| else: | |||
| if message.battery_low == True or time.time() > self._battery_status[1] + AD2.BATTERY_TIMEOUT: | |||
| if message.battery_low == True or time.time() > self._battery_status[1] + AlarmDecoder.BATTERY_TIMEOUT: | |||
| self._battery_status = (message.battery_low, time.time()) | |||
| self.on_low_battery(status=self._battery_status) | |||
| if message.fire_alarm == self._fire_status[0]: | |||
| self._fire_status = (self._fire_status[0], time.time()) | |||
| else: | |||
| if message.fire_alarm == True or time.time() > self._fire_status[1] + AD2.FIRE_TIMEOUT: | |||
| if message.fire_alarm == True or time.time() > self._fire_status[1] + AlarmDecoder.FIRE_TIMEOUT: | |||
| self._fire_status = (message.fire_alarm, time.time()) | |||
| self.on_fire(status=self._fire_status) | |||
| @@ -1,5 +1,5 @@ | |||
| """ | |||
| Contains different types of devices belonging to the AD2 family. | |||
| Contains different types of devices belonging to the Alarm Decoder (AD2) family. | |||
| .. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
| """ | |||
| @@ -18,7 +18,7 @@ from .event import event | |||
| class Device(object): | |||
| """ | |||
| Generic parent device to all AD2 products. | |||
| Generic parent device to all Alarm Decoder (AD2) products. | |||
| """ | |||
| # Generic device events | |||
| @@ -494,8 +494,10 @@ class USBDevice(Device): | |||
| """ | |||
| Constructor | |||
| :param factory: AD2Factory object to use with the thread. | |||
| :type factory: AD2Factory | |||
| :param on_attached: Function to call when a device is attached. | |||
| :type on_attached: function | |||
| :param on_detached: Function to call when a device is detached. | |||
| :type on_detached: function | |||
| """ | |||
| threading.Thread.__init__(self) | |||
| @@ -763,8 +765,8 @@ class SerialDevice(Device): | |||
| class SocketDevice(Device): | |||
| """ | |||
| Device that supports communication with an AD2 that is exposed via ser2sock or another | |||
| Serial to IP interface. | |||
| Device that supports communication with an Alarm Decoder (AD2) that is | |||
| exposed via ser2sock or another Serial to IP interface. | |||
| """ | |||
| @property | |||
| @@ -1,5 +1,6 @@ | |||
| """ | |||
| Message representations received from the panel through the AD2 devices. | |||
| Message representations received from the panel through the Alarm Decoder (AD2) | |||
| devices. | |||
| .. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
| """ | |||
| @@ -3,13 +3,13 @@ import time | |||
| from unittest import TestCase | |||
| from mock import Mock, MagicMock, patch | |||
| from ..ad2 import AD2 | |||
| from ..decoder import AlarmDecoder | |||
| from ..devices import USBDevice | |||
| from ..messages import Message, RFMessage, LRRMessage, ExpanderMessage | |||
| from ..event.event import Event, EventHandler | |||
| from ..zonetracking import Zonetracker | |||
| class TestAD2(TestCase): | |||
| class TestAlarmDecoder(TestCase): | |||
| def setUp(self): | |||
| self._panicked = False | |||
| self._relay_changed = False | |||
| @@ -30,28 +30,28 @@ class TestAD2(TestCase): | |||
| self._device.on_read = EventHandler(Event(), self._device) | |||
| self._device.on_write = EventHandler(Event(), self._device) | |||
| self._ad2 = AD2(self._device) | |||
| self._ad2._zonetracker = Mock(spec=Zonetracker) | |||
| self._ad2._zonetracker.on_fault = EventHandler(Event(), self._ad2._zonetracker) | |||
| self._ad2._zonetracker.on_restore = EventHandler(Event(), self._ad2._zonetracker) | |||
| self._ad2.on_panic += self.on_panic | |||
| self._ad2.on_relay_changed += self.on_relay_changed | |||
| self._ad2.on_power_changed += self.on_power_changed | |||
| self._ad2.on_alarm += self.on_alarm | |||
| self._ad2.on_bypass += self.on_bypass | |||
| self._ad2.on_low_battery += self.on_battery | |||
| self._ad2.on_fire += self.on_fire | |||
| self._ad2.on_arm += self.on_arm | |||
| self._ad2.on_disarm += self.on_disarm | |||
| self._ad2.on_config_received += self.on_config | |||
| self._ad2.on_message += self.on_message | |||
| self._ad2.on_rfx_message += self.on_rfx_message | |||
| self._ad2.on_lrr_message += self.on_lrr_message | |||
| self._ad2.address_mask = int('ffffffff', 16) | |||
| self._ad2.open() | |||
| self._decoder = AlarmDecoder(self._device) | |||
| self._decoder._zonetracker = Mock(spec=Zonetracker) | |||
| self._decoder._zonetracker.on_fault = EventHandler(Event(), self._decoder._zonetracker) | |||
| self._decoder._zonetracker.on_restore = EventHandler(Event(), self._decoder._zonetracker) | |||
| self._decoder.on_panic += self.on_panic | |||
| self._decoder.on_relay_changed += self.on_relay_changed | |||
| self._decoder.on_power_changed += self.on_power_changed | |||
| self._decoder.on_alarm += self.on_alarm | |||
| self._decoder.on_bypass += self.on_bypass | |||
| self._decoder.on_low_battery += self.on_battery | |||
| self._decoder.on_fire += self.on_fire | |||
| self._decoder.on_arm += self.on_arm | |||
| self._decoder.on_disarm += self.on_disarm | |||
| self._decoder.on_config_received += self.on_config | |||
| self._decoder.on_message += self.on_message | |||
| self._decoder.on_rfx_message += self.on_rfx_message | |||
| self._decoder.on_lrr_message += self.on_lrr_message | |||
| self._decoder.address_mask = int('ffffffff', 16) | |||
| self._decoder.open() | |||
| def tearDown(self): | |||
| pass | |||
| @@ -96,170 +96,170 @@ class TestAD2(TestCase): | |||
| self._lrr_message_received = True | |||
| def test_open(self): | |||
| self._ad2.open() | |||
| self._decoder.open() | |||
| self._device.open.assert_any_calls() | |||
| def test_close(self): | |||
| self._ad2.open() | |||
| self._decoder.open() | |||
| self._ad2.close() | |||
| self._decoder.close() | |||
| self._device.close.assert_any_calls() | |||
| def test_send(self): | |||
| self._ad2.send('test') | |||
| self._decoder.send('test') | |||
| self._device.write.assert_called_with('test') | |||
| def test_get_config(self): | |||
| self._ad2.get_config() | |||
| self._decoder.get_config() | |||
| self._device.write.assert_called_with("C\r") | |||
| def test_save_config(self): | |||
| self._ad2.save_config() | |||
| self._decoder.save_config() | |||
| self._device.write.assert_any_calls() | |||
| def test_reboot(self): | |||
| self._ad2.reboot() | |||
| self._decoder.reboot() | |||
| self._device.write.assert_called_with('=') | |||
| def test_fault(self): | |||
| self._ad2.fault_zone(1) | |||
| self._decoder.fault_zone(1) | |||
| self._device.write.assert_called_with("L{0:02}{1}\r".format(1, 1)) | |||
| def test_fault_wireproblem(self): | |||
| self._ad2.fault_zone(1, simulate_wire_problem=True) | |||
| self._decoder.fault_zone(1, simulate_wire_problem=True) | |||
| self._device.write.assert_called_with("L{0:02}{1}\r".format(1, 2)) | |||
| def test_clear_zone(self): | |||
| self._ad2.clear_zone(1) | |||
| self._decoder.clear_zone(1) | |||
| self._device.write.assert_called_with("L{0:02}0\r".format(1)) | |||
| def test_message(self): | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertIsInstance(msg, Message) | |||
| self._ad2._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self._decoder._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertTrue(self._message_received) | |||
| def test_message_kpe(self): | |||
| msg = self._ad2._handle_message('!KPE:[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('!KPE:[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertIsInstance(msg, Message) | |||
| self._ad2._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self._decoder._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertTrue(self._message_received) | |||
| def test_expander_message(self): | |||
| msg = self._ad2._handle_message('!EXP:07,01,01') | |||
| msg = self._decoder._handle_message('!EXP:07,01,01') | |||
| self.assertIsInstance(msg, ExpanderMessage) | |||
| def test_relay_message(self): | |||
| self._ad2.open() | |||
| msg = self._ad2._handle_message('!REL:12,01,01') | |||
| self._decoder.open() | |||
| msg = self._decoder._handle_message('!REL:12,01,01') | |||
| self.assertIsInstance(msg, ExpanderMessage) | |||
| self.assertEquals(self._relay_changed, True) | |||
| def test_rfx_message(self): | |||
| msg = self._ad2._handle_message('!RFX:0180036,80') | |||
| msg = self._decoder._handle_message('!RFX:0180036,80') | |||
| self.assertIsInstance(msg, RFMessage) | |||
| self.assertTrue(self._rfx_message_received) | |||
| def test_panic(self): | |||
| self._ad2.open() | |||
| self._decoder.open() | |||
| msg = self._ad2._handle_message('!LRR:012,1,ALARM_PANIC') | |||
| msg = self._decoder._handle_message('!LRR:012,1,ALARM_PANIC') | |||
| self.assertEquals(self._panicked, True) | |||
| msg = self._ad2._handle_message('!LRR:012,1,CANCEL') | |||
| msg = self._decoder._handle_message('!LRR:012,1,CANCEL') | |||
| self.assertEquals(self._panicked, False) | |||
| self.assertIsInstance(msg, LRRMessage) | |||
| def test_config_message(self): | |||
| self._ad2.open() | |||
| self._decoder.open() | |||
| msg = self._ad2._handle_message('!CONFIG>ADDRESS=18&CONFIGBITS=ff00&LRR=N&EXP=NNNNN&REL=NNNN&MASK=ffffffff&DEDUPLICATE=N') | |||
| self.assertEquals(self._ad2.address, 18) | |||
| self.assertEquals(self._ad2.configbits, int('ff00', 16)) | |||
| self.assertEquals(self._ad2.address_mask, int('ffffffff', 16)) | |||
| self.assertEquals(self._ad2.emulate_zone, [False for x in range(5)]) | |||
| self.assertEquals(self._ad2.emulate_relay, [False for x in range(4)]) | |||
| self.assertEquals(self._ad2.emulate_lrr, False) | |||
| self.assertEquals(self._ad2.deduplicate, False) | |||
| msg = self._decoder._handle_message('!CONFIG>ADDRESS=18&CONFIGBITS=ff00&LRR=N&EXP=NNNNN&REL=NNNN&MASK=ffffffff&DEDUPLICATE=N') | |||
| self.assertEquals(self._decoder.address, 18) | |||
| self.assertEquals(self._decoder.configbits, int('ff00', 16)) | |||
| self.assertEquals(self._decoder.address_mask, int('ffffffff', 16)) | |||
| self.assertEquals(self._decoder.emulate_zone, [False for x in range(5)]) | |||
| self.assertEquals(self._decoder.emulate_relay, [False for x in range(4)]) | |||
| self.assertEquals(self._decoder.emulate_lrr, False) | |||
| self.assertEquals(self._decoder.deduplicate, False) | |||
| self.assertEquals(self._got_config, True) | |||
| def test_power_changed_event(self): | |||
| msg = self._ad2._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._power_changed, False) # Not set first time we hit it. | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._power_changed, False) | |||
| msg = self._ad2._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._power_changed, True) | |||
| def test_alarm_event(self): | |||
| msg = self._ad2._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._alarmed, False) # Not set first time we hit it. | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._alarmed, False) | |||
| msg = self._ad2._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._alarmed, True) | |||
| def test_zone_bypassed_event(self): | |||
| msg = self._ad2._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._bypassed, False) # Not set first time we hit it. | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._bypassed, False) | |||
| msg = self._ad2._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._bypassed, True) | |||
| def test_armed_away_event(self): | |||
| msg = self._ad2._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, False) # Not set first time we hit it. | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, False) | |||
| msg = self._ad2._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, True) | |||
| self._armed = False | |||
| msg = self._ad2._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, False) # Not set first time we hit it. | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, False) | |||
| msg = self._ad2._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._armed, True) | |||
| def test_battery_low_event(self): | |||
| msg = self._ad2._handle_message('[0000000000010000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000010000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._battery[0], True) | |||
| # force the timeout to expire. | |||
| with patch.object(time, 'time', return_value=self._battery[1] + 35): | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._battery[0], False) | |||
| def test_fire_alarm_event(self): | |||
| msg = self._ad2._handle_message('[0000000000000100----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000100----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._fire[0], True) | |||
| # force the timeout to expire. | |||
| with patch.object(time, 'time', return_value=self._fire[1] + 35): | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self.assertEquals(self._fire[0], False) | |||
| def test_hit_for_faults(self): | |||
| self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000],"Hit * for faults "') | |||
| self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000],"Hit * for faults "') | |||
| self._ad2._device.write.assert_called_with('*') | |||
| self._decoder._device.write.assert_called_with('*') | |||
| def test_zonetracker_update(self): | |||
| msg = self._ad2._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self._ad2._zonetracker.update.assert_called_with(msg) | |||
| msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "') | |||
| self._decoder._zonetracker.update.assert_called_with(msg) | |||
| @@ -1,10 +1,9 @@ | |||
| """ | |||
| Provides utility classes for the AD2 devices. | |||
| Provides utility classes for the Alarm Decoder (AD2) devices. | |||
| .. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
| """ | |||
| import ad2 | |||
| import time | |||
| import threading | |||
| @@ -34,7 +33,7 @@ class InvalidMessageError(Exception): | |||
| class Firmware(object): | |||
| """ | |||
| Represents firmware for the AD2 devices. | |||
| Represents firmware for the Alarm Decoder devices. | |||
| """ | |||
| # Constants | |||
| @@ -48,14 +47,14 @@ class Firmware(object): | |||
| @staticmethod | |||
| def upload(dev, filename, progress_callback=None): | |||
| """ | |||
| Uploads firmware to an AD2 device. | |||
| Uploads firmware to an Alarm Decoder device. | |||
| :param filename: The firmware filename | |||
| :type filename: str | |||
| :param progress_callback: Callback function used to report progress. | |||
| :type progress_callback: function | |||
| :raises: util.NoDeviceError, util.TimeoutError | |||
| :raises: NoDeviceError, TimeoutError | |||
| """ | |||
| def do_upload(): | |||
| @@ -1,5 +1,5 @@ | |||
| """ | |||
| Provides zone tracking functionality for the AD2 device family. | |||
| Provides zone tracking functionality for the Alarm Decoder (AD2) device family. | |||
| .. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
| """ | |||
| @@ -4,9 +4,9 @@ def readme(): | |||
| with open('README.md') as f: | |||
| return f.read() | |||
| setup(name='pyad2', | |||
| setup(name='alarmdecoder', | |||
| version='0.5', | |||
| description='Python interface library for the AD2 family of alarm devices.', | |||
| description='Python interface library for the Alarm Decoder (AD2) family of alarm devices, including: the AD2USB, AD2SERIAL and AD2PI.', | |||
| long_description=readme(), | |||
| classifiers=[ | |||
| 'Development Status :: 4 - Beta', | |||
| @@ -17,12 +17,12 @@ setup(name='pyad2', | |||
| 'Topic :: Home Automation', | |||
| 'Topic :: Security', | |||
| ], | |||
| keywords='alarm data ad2 ad2usb ad2serial ad2pi security ademco dsc', | |||
| url='http://github.com/nutechsoftware/pyad2', | |||
| keywords='alarmdecoder alarm decoder ad2 ad2usb ad2serial ad2pi security ademco dsc', | |||
| url='http://github.com/nutechsoftware/alarmdecoder', | |||
| author='Nu Tech Software Solutions, Inc.', | |||
| author_email='general@support.nutech.com', | |||
| license='MIT', | |||
| packages=['pyad2', 'pyad2.event'], | |||
| packages=['alarmdecoder', 'alarmdecoder.event'], | |||
| install_requires=[ | |||
| 'pyopenssl', | |||
| 'pyusb>=1.0.0b1', | |||