Browse Source

Import consistency. Refactored Overseer as AD2Factory.

pyserial_fix
Scott Petersen 11 years ago
parent
commit
805efa32c3
5 changed files with 68 additions and 66 deletions
  1. +12
    -12
      pyad2/ad2.py
  2. +37
    -36
      pyad2/devices.py
  3. +1
    -0
      pyad2/messages.py
  4. +15
    -15
      pyad2/tests/test_ad2.py
  5. +3
    -3
      pyad2/zonetracking.py

+ 12
- 12
pyad2/ad2.py View File

@@ -12,7 +12,7 @@ from .util import CommError, NoDeviceError
from .messages import Message, ExpanderMessage, RFMessage, LRRMessage
from .zonetracking import Zonetracker

class Overseer(object):
class AD2Factory(object):
"""
Factory for creation of AD2USB devices as well as provides attach/detach events."
"""
@@ -77,7 +77,7 @@ class Overseer(object):
:param detached_event: Event to trigger when a device is detached.
:type detached_event: function
"""
self._detect_thread = Overseer.DetectThread(self)
self._detect_thread = AD2Factory.DetectThread(self)

if attached_event:
self.on_attached += attached_event
@@ -85,7 +85,7 @@ class Overseer(object):
if detached_event:
self.on_detached += detached_event

Overseer.find_all()
AD2Factory.find_all()

self.start()

@@ -115,22 +115,22 @@ class Overseer(object):
:param device: Tuple describing the USB device to open, as returned by find_all().
:type device: tuple
"""
return Overseer.create(device)
return AD2Factory.create(device)

class DetectThread(threading.Thread):
"""
Thread that handles detection of added/removed devices.
"""
def __init__(self, overseer):
def __init__(self, factory):
"""
Constructor

:param overseer: Overseer object to use with the thread.
:type overseer: Overseer
:param factory: AD2Factory object to use with the thread.
:type factory: AD2Factory
"""
threading.Thread.__init__(self)

self._overseer = overseer
self._factory = factory
self._running = False

def stop(self):
@@ -149,18 +149,18 @@ class Overseer(object):

while self._running:
try:
Overseer.find_all()
AD2Factory.find_all()

current_devices = set(Overseer.devices())
current_devices = set(AD2Factory.devices())
new_devices = [d for d in current_devices if d not in last_devices]
removed_devices = [d for d in last_devices if d not in current_devices]
last_devices = current_devices

for d in new_devices:
self._overseer.on_attached(d)
self._factory.on_attached(d)

for d in removed_devices:
self._overseer.on_detached(d)
self._factory.on_detached(d)

except CommError, err:
pass


+ 37
- 36
pyad2/devices.py View File

@@ -9,10 +9,11 @@ import time
import threading
import serial, serial.tools.list_ports
import socket

from OpenSSL import SSL, crypto
from pyftdi.pyftdi.ftdi import *
from pyftdi.pyftdi.usbtools import *
from . import util
from .util import CommError, TimeoutError, NoDeviceError
from .event import event

class Device(object):
@@ -118,7 +119,7 @@ class Device(object):
try:
self._device.read_line(timeout=self.READ_TIMEOUT)

except util.TimeoutError, err:
except TimeoutError, err:
pass

except Exception, err:
@@ -147,7 +148,7 @@ class USBDevice(Device):
Returns all FTDI devices matching our vendor and product IDs.

:returns: list of devices
:raises: util.CommError
:raises: CommError
"""
devices = []

@@ -155,7 +156,7 @@ class USBDevice(Device):
devices = Ftdi.find_all([(USBDevice.FTDI_VENDOR_ID, USBDevice.FTDI_PRODUCT_ID)], nocache=True)

except (usb.core.USBError, FtdiError), err:
raise util.CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)
raise CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)

return devices

@@ -244,7 +245,7 @@ class USBDevice(Device):
:param no_reader_thread: Whether or not to automatically start the reader thread.
:type no_reader_thread: bool

:raises: util.NoDeviceError
:raises: NoDeviceError
"""
# Set up defaults
if baudrate is None:
@@ -264,7 +265,7 @@ class USBDevice(Device):
self._id = 'USB {0}:{1}'.format(self._device.usb_dev.bus, self._device.usb_dev.address)

except (usb.core.USBError, FtdiError), err:
raise util.NoDeviceError('Error opening device: {0}'.format(str(err)), err)
raise NoDeviceError('Error opening device: {0}'.format(str(err)), err)

else:
self._running = True
@@ -293,7 +294,7 @@ class USBDevice(Device):
:param data: Data to write
:type data: str

:raises: util.CommError
:raises: CommError
"""
try:
self._device.write_data(data)
@@ -301,14 +302,14 @@ class USBDevice(Device):
self.on_write(data)

except FtdiError, err:
raise util.CommError('Error writing to device: {0}'.format(str(err)), err)
raise CommError('Error writing to device: {0}'.format(str(err)), err)

def read(self):
"""
Reads a single character from the device.

:returns: The character read from the device.
:raises: util.CommError
:raises: CommError
"""
ret = None

@@ -316,7 +317,7 @@ class USBDevice(Device):
ret = self._device.read_data(1)

except (usb.core.USBError, FtdiError), err:
raise util.CommError('Error reading from device: {0}'.format(str(err)), err)
raise CommError('Error reading from device: {0}'.format(str(err)), err)

return ret

@@ -330,7 +331,7 @@ class USBDevice(Device):
:type purge_buffer: bool

:returns: The line that was read.
:raises: util.CommError, util.TimeoutError
:raises: CommError, TimeoutError
"""

if purge_buffer:
@@ -372,7 +373,7 @@ class USBDevice(Device):
if timer:
timer.cancel()

raise util.CommError('Error reading from device: {0}'.format(str(err)), err)
raise CommError('Error reading from device: {0}'.format(str(err)), err)

else:
if got_line:
@@ -385,7 +386,7 @@ class USBDevice(Device):
if timer.is_alive():
timer.cancel()
else:
raise util.TimeoutError('Timeout while waiting for line terminator.')
raise TimeoutError('Timeout while waiting for line terminator.')

return ret

@@ -408,7 +409,7 @@ class SerialDevice(Device):
:type pattern: str

:returns: list of devices
:raises: util.CommError
:raises: CommError
"""
devices = []

@@ -419,7 +420,7 @@ class SerialDevice(Device):
devices = serial.tools.list_ports.comports()

except SerialException, err:
raise util.CommError('Error enumerating serial devices: {0}'.format(str(err)), err)
raise CommError('Error enumerating serial devices: {0}'.format(str(err)), err)

return devices

@@ -464,14 +465,14 @@ class SerialDevice(Device):
:param no_reader_thread: Whether or not to automatically start the reader thread.
:type no_reader_thread: bool

:raises: util.NoDeviceError
:raises: NoDeviceError
"""
# Set up the defaults
if baudrate is None:
baudrate = SerialDevice.BAUDRATE

if self._port is None:
raise util.NoDeviceError('No device interface specified.')
raise NoDeviceError('No device interface specified.')

self._device.port = self._port

@@ -486,7 +487,7 @@ class SerialDevice(Device):
# all issues with it.

except (serial.SerialException, ValueError), err:
raise util.NoDeviceError('Error opening device on port {0}.'.format(self._port), err)
raise NoDeviceError('Error opening device on port {0}.'.format(self._port), err)

else:
self._running = True
@@ -512,7 +513,7 @@ class SerialDevice(Device):
:param data: The data to write.
:type data: str

:raises: util.CommError
:raises: CommError
"""
try:
self._device.write(data)
@@ -521,7 +522,7 @@ class SerialDevice(Device):
pass

except serial.SerialException, err:
raise util.CommError('Error writing to device.', err)
raise CommError('Error writing to device.', err)

else:
self.on_write(data)
@@ -531,7 +532,7 @@ class SerialDevice(Device):
Reads a single character from the device.

:returns: The character read from the device.
:raises: util.CommError
:raises: CommError
"""
ret = None

@@ -539,7 +540,7 @@ class SerialDevice(Device):
ret = self._device.read(1)

except serial.SerialException, err:
raise util.CommError('Error reading from device: {0}'.format(str(err)), err)
raise CommError('Error reading from device: {0}'.format(str(err)), err)

return ret

@@ -553,7 +554,7 @@ class SerialDevice(Device):
:type purge_buffer: bool

:returns: The line read.
:raises: util.CommError, util.TimeoutError
:raises: CommError, TimeoutError
"""
def timeout_event():
timeout_event.reading = False
@@ -591,7 +592,7 @@ class SerialDevice(Device):
if timer:
timer.cancel()

raise util.CommError('Error reading from device: {0}'.format(str(err)), err)
raise CommError('Error reading from device: {0}'.format(str(err)), err)

else:
if got_line:
@@ -604,7 +605,7 @@ class SerialDevice(Device):
if timer.is_alive():
timer.cancel()
else:
raise util.TimeoutError('Timeout while waiting for line terminator.')
raise TimeoutError('Timeout while waiting for line terminator.')

return ret

@@ -734,7 +735,7 @@ class SocketDevice(Device):
:param no_reader_thread: Whether or not to automatically open the reader thread.
:type no_reader_thread: bool

:raises: util.NoDeviceError, util.CommError
:raises: NoDeviceError, CommError
"""

try:
@@ -748,7 +749,7 @@ class SocketDevice(Device):
self._id = '{0}:{1}'.format(self._host, self._port)

except socket.error, err:
raise util.NoDeviceError('Error opening device at {0}:{1}'.format(self._host, self._port), err)
raise NoDeviceError('Error opening device at {0}:{1}'.format(self._host, self._port), err)

else:
self._running = True
@@ -781,7 +782,7 @@ class SocketDevice(Device):
:type data: str

:returns: The number of bytes sent.
:raises: util.CommError
:raises: CommError
"""
data_sent = None

@@ -789,12 +790,12 @@ class SocketDevice(Device):
data_sent = self._device.send(data)

if data_sent == 0:
raise util.CommError('Error writing to device.')
raise CommError('Error writing to device.')

self.on_write(data)

except (SSL.Error, socket.error), err:
raise util.CommError('Error writing to device.', err)
raise CommError('Error writing to device.', err)

return data_sent

@@ -803,7 +804,7 @@ class SocketDevice(Device):
Reads a single character from the device.

:returns: The character read from the device.
:raises: util.CommError
:raises: CommError
"""
data = None

@@ -811,7 +812,7 @@ class SocketDevice(Device):
data = self._device.recv(1)

except socket.error, err:
raise util.CommError('Error while reading from device: {0}'.format(str(err)), err)
raise CommError('Error while reading from device: {0}'.format(str(err)), err)

return data

@@ -825,7 +826,7 @@ class SocketDevice(Device):
:type purge_buffer: bool

:returns: The line read from the device.
:raises: util.CommError, util.TimeoutError
:raises: CommError, TimeoutError
"""

if purge_buffer:
@@ -867,7 +868,7 @@ class SocketDevice(Device):
if timer:
timer.cancel()

raise util.CommError('Error reading from device: {0}'.format(str(err)), err)
raise CommError('Error reading from device: {0}'.format(str(err)), err)

else:
if got_line:
@@ -880,7 +881,7 @@ class SocketDevice(Device):
if timer.is_alive():
timer.cancel()
else:
raise util.TimeoutError('Timeout while waiting for line terminator.')
raise TimeoutError('Timeout while waiting for line terminator.')

return ret

@@ -909,7 +910,7 @@ class SocketDevice(Device):
self._device = SSL.Connection(ctx, self._device)

except SSL.Error, err:
raise util.CommError('Error setting up SSL connection.', err)
raise CommError('Error setting up SSL connection.', err)

def _verify_ssl_callback(self, connection, x509, errnum, errdepth, ok):
return ok

+ 1
- 0
pyad2/messages.py View File

@@ -5,6 +5,7 @@ Message representations received from the panel through the AD2 devices.
"""

import re

from .util import InvalidMessageError

class BaseMessage(object):


+ 15
- 15
pyad2/tests/test_ad2.py View File

@@ -3,22 +3,22 @@ import time
from unittest import TestCase
from mock import Mock, MagicMock, patch

from ..ad2 import Overseer, AD2
from ..ad2 import AD2Factory, AD2
from ..devices import USBDevice
from ..messages import Message, RFMessage, LRRMessage, ExpanderMessage
from ..event.event import Event, EventHandler
from ..zonetracking import Zonetracker

class TestOverseer(TestCase):
class TestAD2Factory(TestCase):
def setUp(self):
self._attached = False
self._detached = False

with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2', 1, 'AD2')]):
self._overseer = Overseer()
self._factory = AD2Factory()

def tearDown(self):
self._overseer.stop()
self._factory.stop()

def attached_event(self, sender, args):
self._attached = True
@@ -28,22 +28,22 @@ class TestOverseer(TestCase):

def test_find_all(self):
with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2', 1, 'AD2')]):
devices = Overseer.find_all()
devices = AD2Factory.find_all()

self.assertEquals(devices[0][2], 'AD2')

def test_create_default_param(self):
with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2', 1, 'AD2')]):
device = Overseer.create()
device = AD2Factory.create()

self.assertEquals(device._device.interface, ('AD2', 0))

def test_create_with_param(self):
with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2-1', 1, 'AD2'), (0, 0, 'AD2-2', 1, 'AD2')]):
device = Overseer.create((0, 0, 'AD2-1', 1, 'AD2'))
device = AD2Factory.create((0, 0, 'AD2-1', 1, 'AD2'))
self.assertEquals(device._device.interface, ('AD2-1', 0))

device = Overseer.create((0, 0, 'AD2-2', 1, 'AD2'))
device = AD2Factory.create((0, 0, 'AD2-2', 1, 'AD2'))
self.assertEquals(device._device.interface, ('AD2-2', 0))

def test_events(self):
@@ -51,18 +51,18 @@ class TestOverseer(TestCase):
self.assertEquals(self._detached, False)

# this is ugly, but it works.
self._overseer.stop()
self._overseer._detect_thread = Overseer.DetectThread(self._overseer)
self._overseer.on_attached += self.attached_event
self._overseer.on_detached += self.detached_event
self._factory.stop()
self._factory._detect_thread = AD2Factory.DetectThread(self._factory)
self._factory.on_attached += self.attached_event
self._factory.on_detached += self.detached_event

with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2-1', 1, 'AD2'), (0, 0, 'AD2-2', 1, 'AD2')]):
self._overseer.start()
self._factory.start()

with patch.object(USBDevice, 'find_all', return_value=[(0, 0, 'AD2-2', 1, 'AD2')]):
Overseer.find_all()
AD2Factory.find_all()
time.sleep(1)
self._overseer.stop()
self._factory.stop()

self.assertEquals(self._attached, True)
self.assertEquals(self._detached, True)


+ 3
- 3
pyad2/zonetracking.py View File

@@ -8,7 +8,7 @@ import re
import time

from .event import event
from . import messages
from .messages import ExpanderMessage

class Zone(object):
"""
@@ -78,8 +78,8 @@ class Zonetracker(object):
:param message: Message to use to update the zone tracking.
:type message: Message or ExpanderMessage
"""
if isinstance(message, messages.ExpanderMessage):
if message.type == messages.ExpanderMessage.ZONE:
if isinstance(message, ExpanderMessage):
if message.type == ExpanderMessage.ZONE:
zone = self._expander_to_zone(message.address, message.channel)

status = Zone.CLEAR


Loading…
Cancel
Save