@@ -15,19 +15,35 @@ This module contains different types of devices belonging to the `AlarmDecoder`_ | |||
.. moduleauthor:: Scott Petersen <scott@nutech.com> | |||
""" | |||
import usb.core | |||
import usb.util | |||
import time | |||
import threading | |||
import serial | |||
import serial.tools.list_ports | |||
import socket | |||
from OpenSSL import SSL, crypto | |||
from pyftdi.pyftdi.ftdi import Ftdi, FtdiError | |||
from .util import CommError, TimeoutError, NoDeviceError, InvalidMessageError | |||
from .event import event | |||
try: | |||
from pyftdi.pyftdi.ftdi import Ftdi, FtdiError | |||
import usb.core | |||
import usb.util | |||
have_pyftdi = True | |||
except ImportError: | |||
have_pyftdi = False | |||
try: | |||
from OpenSSL import SSL, crypto | |||
have_openssl = True | |||
except ImportError: | |||
from collections import namedtuple | |||
SSL = namedtuple('SSL', ['Error', 'WantReadError', 'SysCallError']) | |||
have_openssl = False | |||
class Device(object): | |||
""" | |||
@@ -198,6 +214,9 @@ class USBDevice(Device): | |||
:returns: list of devices | |||
:raises: :py:class:`~alarmdecoder.util.CommError` | |||
""" | |||
if not have_pyftdi: | |||
raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.') | |||
cls.__devices = [] | |||
query = cls.PRODUCT_IDS | |||
@@ -234,6 +253,9 @@ class USBDevice(Device): | |||
:returns: :py:class:`USBDevice` object utilizing the specified device | |||
:raises: :py:class:`~alarmdecoder.util.NoDeviceError` | |||
""" | |||
if not have_pyftdi: | |||
raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.') | |||
cls.find_all() | |||
if len(cls.__devices) == 0: | |||
@@ -257,6 +279,9 @@ class USBDevice(Device): | |||
:type on_detached: function | |||
""" | |||
if not have_pyftdi: | |||
raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.') | |||
cls.__detect_thread = USBDevice.DetectThread(on_attached, on_detached) | |||
try: | |||
@@ -271,6 +296,9 @@ class USBDevice(Device): | |||
""" | |||
Stops the device detection thread. | |||
""" | |||
if not have_pyftdi: | |||
raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.') | |||
try: | |||
cls.__detect_thread.stop() | |||
@@ -347,6 +375,9 @@ class USBDevice(Device): | |||
index. | |||
:type interface: string or int | |||
""" | |||
if not have_pyftdi: | |||
raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.') | |||
Device.__init__(self) | |||
self._device = Ftdi() | |||
@@ -1120,6 +1151,9 @@ class SocketDevice(Device): | |||
:raises: :py:class:`~alarmdecoder.util.CommError` | |||
""" | |||
if not have_openssl: | |||
raise ImportError('SSL sockets have been disabled due to missing requirement: pyopenssl.') | |||
try: | |||
ctx = SSL.Context(SSL.TLSv1_METHOD) | |||
@@ -2,7 +2,7 @@ import time | |||
import smtplib | |||
from email.mime.text import MIMEText | |||
from alarmdecoder import AlarmDecoder | |||
from alarmdecoder.devices import USBDevice | |||
from alarmdecoder.devices import SerialDevice | |||
# Configuration values | |||
SUBJECT = "AlarmDecoder - ALARM" | |||
@@ -13,6 +13,9 @@ SMTP_SERVER = "localhost" | |||
SMTP_USERNAME = None | |||
SMTP_PASSWORD = None | |||
SERIAL_DEVICE = '/dev/ttyUSB0' | |||
BAUDRATE = 115200 | |||
def main(): | |||
""" | |||
Example application that sends an email when an alarm event is | |||
@@ -20,11 +23,11 @@ def main(): | |||
""" | |||
try: | |||
# Retrieve the first USB device | |||
device = AlarmDecoder(USBDevice.find()) | |||
device = AlarmDecoder(SerialDevice(interface=SERIAL_DEVICE)) | |||
# Set up an event handler and open the device | |||
device.on_alarm += handle_alarm | |||
with device.open(): | |||
with device.open(baudrate=BAUDRATE): | |||
while True: | |||
time.sleep(1) | |||
@@ -1,6 +1,9 @@ | |||
import time | |||
from alarmdecoder import AlarmDecoder | |||
from alarmdecoder.devices import USBDevice | |||
from alarmdecoder.devices import SerialDevice | |||
SERIAL_DEVICE = '/dev/ttyUSB0' | |||
BAUDRATE = 115200 | |||
def main(): | |||
""" | |||
@@ -8,11 +11,11 @@ def main(): | |||
""" | |||
try: | |||
# Retrieve the first USB device | |||
device = AlarmDecoder(USBDevice.find()) | |||
device = AlarmDecoder(SerialDevice(interface=SERIAL_DEVICE)) | |||
# Set up an event handler and open the device | |||
device.on_lrr_message += handle_lrr_message | |||
with device.open(): | |||
with device.open(baudrate=BAUDRATE): | |||
while True: | |||
time.sleep(1) | |||
@@ -1,9 +1,12 @@ | |||
import time | |||
from alarmdecoder import AlarmDecoder | |||
from alarmdecoder.devices import USBDevice | |||
from alarmdecoder.devices import SerialDevice | |||
RF_DEVICE_SERIAL_NUMBER = '0252254' | |||
SERIAL_DEVICE = '/dev/ttyUSB0' | |||
BAUDRATE = 115200 | |||
def main(): | |||
""" | |||
Example application that watches for an event from a specific RF device. | |||
@@ -18,11 +21,11 @@ def main(): | |||
""" | |||
try: | |||
# Retrieve the first USB device | |||
device = AlarmDecoder(USBDevice.find()) | |||
device = AlarmDecoder(SerialDevice(interface=SERIAL_DEVICE)) | |||
# Set up an event handler and open the device | |||
device.on_rfx_message += handle_rfx | |||
with device.open(): | |||
with device.open(baudrate=BAUDRATE): | |||
while True: | |||
time.sleep(1) | |||
@@ -1,11 +1,14 @@ | |||
import time | |||
from alarmdecoder import AlarmDecoder | |||
from alarmdecoder.devices import USBDevice | |||
from alarmdecoder.devices import SerialDevice | |||
# Configuration values | |||
TARGET_ZONE = 41 | |||
WAIT_TIME = 10 | |||
SERIAL_DEVICE = '/dev/ttyUSB0' | |||
BAUDRATE = 115200 | |||
def main(): | |||
""" | |||
Example application that periodically faults a virtual zone and then | |||
@@ -15,7 +18,7 @@ def main(): | |||
the AlarmDecoder is configured to emulate a zone 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. | |||
devices or services and monitor them as you would any physical zone. | |||
For example, you could connect a ZigBee device and receiver and fault or | |||
restore it's zone(s) based on the data received. | |||
@@ -28,13 +31,13 @@ def main(): | |||
""" | |||
try: | |||
# Retrieve the first USB device | |||
device = AlarmDecoder(USBDevice.find()) | |||
device = AlarmDecoder(SerialDevice(interface=SERIAL_DEVICE)) | |||
# Set up an event handlers and open the device | |||
device.on_zone_fault += handle_zone_fault | |||
device.on_zone_restore += handle_zone_restore | |||
with device.open(): | |||
with device.open(baudrate=BAUDRATE): | |||
last_update = time.time() | |||
while True: | |||
if time.time() - last_update > WAIT_TIME: | |||
@@ -1,16 +1 @@ | |||
Jinja2==2.7.2 | |||
MarkupSafe==0.21 | |||
Pygments==1.6 | |||
Sphinx==1.2.2 | |||
argparse==1.2.1 | |||
cffi==0.8.2 | |||
cryptography==0.3 | |||
distribute==0.7.3 | |||
docutils==0.11 | |||
pyOpenSSL==0.14 | |||
pycparser==2.10 | |||
pyftdi==0.9.0 | |||
pyserial==2.7 | |||
pyusb==1.0.0b1 | |||
six==1.6.1 | |||
wsgiref==0.1.2 |
@@ -30,13 +30,7 @@ setup(name='alarmdecoder', | |||
license='MIT', | |||
packages=['alarmdecoder', 'alarmdecoder.event'], | |||
install_requires=[ | |||
'pyopenssl', | |||
'pyusb>=1.0.0b1', | |||
'pyserial>=2.7', | |||
'pyftdi>=0.9.0', | |||
], | |||
dependency_links=[ | |||
'https://github.com/eblot/pyftdi/archive/v0.9.0.tar.gz#egg=pyftdi-0.9.0' | |||
], | |||
test_suite='nose.collector', | |||
tests_require=['nose', 'mock'], | |||