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