diff --git a/alarmdecoder/devices.py b/alarmdecoder/devices.py index 9462926..e3acd8b 100644 --- a/alarmdecoder/devices.py +++ b/alarmdecoder/devices.py @@ -15,19 +15,35 @@ This module contains different types of devices belonging to the `AlarmDecoder`_ .. moduleauthor:: Scott Petersen """ -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) diff --git a/examples/alarm_email.py b/examples/alarm_email.py index 573d174..999c073 100644 --- a/examples/alarm_email.py +++ b/examples/alarm_email.py @@ -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) diff --git a/examples/lrr_example.py b/examples/lrr_example.py index ba1b627..6a2f424 100644 --- a/examples/lrr_example.py +++ b/examples/lrr_example.py @@ -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) diff --git a/examples/rf_device.py b/examples/rf_device.py index a5faaae..6e2f8fb 100644 --- a/examples/rf_device.py +++ b/examples/rf_device.py @@ -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) diff --git a/examples/detection.py b/examples/usb_detection.py similarity index 100% rename from examples/detection.py rename to examples/usb_detection.py diff --git a/examples/basics.py b/examples/usb_device.py similarity index 100% rename from examples/basics.py rename to examples/usb_device.py diff --git a/examples/virtual_zone_expander.py b/examples/virtual_zone_expander.py index e5da53b..42ac1c1 100644 --- a/examples/virtual_zone_expander.py +++ b/examples/virtual_zone_expander.py @@ -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: diff --git a/requirements.txt b/requirements.txt index 09a946a..8313187 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/setup.py b/setup.py index 0e9d527..b5e733c 100644 --- a/setup.py +++ b/setup.py @@ -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'],