diff --git a/pyad2/ad2.py b/pyad2/ad2.py index c767437..9cc2cb4 100644 --- a/pyad2/ad2.py +++ b/pyad2/ad2.py @@ -6,12 +6,11 @@ Provides the full AD2 class and factory. import time import threading -import re from .event import event -from . import devices -from . import util -from . import messages -from . import zonetracking +from .devices import USBDevice +from .util import CommError, NoDeviceError +from .messages import Message, ExpanderMessage, RFMessage, LRRMessage +from .zonetracking import Zonetracker class Overseer(object): """ @@ -30,9 +29,9 @@ class Overseer(object): Returns all AD2USB devices located on the system. :returns: list of devices found - :raises: util.CommError + :raises: CommError """ - cls.__devices = devices.USBDevice.find_all() + cls.__devices = USBDevice.find_all() return cls.__devices @@ -54,18 +53,18 @@ class Overseer(object): :type device: tuple :returns: AD2USB object utilizing the specified device. - :raises: util.NoDeviceError + :raises: NoDeviceError """ cls.find_all() if len(cls.__devices) == 0: - raise util.NoDeviceError('No AD2USB devices present.') + raise NoDeviceError('No AD2USB devices present.') if device is None: device = cls.__devices[0] vendor, product, sernum, ifcount, description = device - device = devices.USBDevice((sernum, ifcount - 1)) + device = USBDevice((sernum, ifcount - 1)) return AD2(device) @@ -163,7 +162,7 @@ class Overseer(object): for d in removed_devices: self._overseer.on_detached(d) - except util.CommError, err: + except CommError, err: pass time.sleep(0.25) @@ -220,10 +219,10 @@ class AD2(object): Constructor :param device: The low-level device used for this AD2 interface. - :type device: devices.Device + :type device: Device """ self._device = device - self._zonetracker = zonetracking.Zonetracker() + self._zonetracker = Zonetracker() self._power_status = None self._alarm_status = None @@ -271,7 +270,9 @@ class AD2(object): """ Closes the device. """ - self._device.close() + if self._device: + self._device.close() + del self._device self._device = None @@ -283,7 +284,7 @@ class AD2(object): """ Retrieves the configuration from the device. """ - self._device.write("C\r") + self.send("C\r") def save_config(self): """ @@ -312,13 +313,13 @@ class AD2(object): config_string = '&'.join(['='.join(t) for t in config_entries]) - self._device.write("C{0}\r".format(config_string)) + self.send("C{0}\r".format(config_string)) def reboot(self): """ Reboots the device. """ - self._device.write('=') + self.send('=') def fault_zone(self, zone, simulate_wire_problem=False): """ @@ -339,7 +340,7 @@ class AD2(object): status = 2 if simulate_wire_problem else 1 - self._device.write("L{0:02}{1}\r".format(zone, status)) + self.send("L{0:02}{1}\r".format(zone, status)) def clear_zone(self, zone): """ @@ -348,7 +349,7 @@ class AD2(object): :param zone: The zone to clear. :type zone: int """ - self._device.write("L{0:02}0\r".format(zone)) + self.send("L{0:02}0\r".format(zone)) def _wire_events(self): """ @@ -371,19 +372,19 @@ class AD2(object): :returns: An object representing the message. """ if data is None: - return None + raise InvalidMessageError() msg = None header = data[0:4] if header[0] != '!' or header == '!KPE': - msg = messages.Message(data) + msg = Message(data) if self.address_mask & msg.mask > 0: self._update_internal_states(msg) elif header == '!EXP' or header == '!REL': - msg = messages.ExpanderMessage(data) + msg = ExpanderMessage(data) self._update_internal_states(msg) @@ -402,7 +403,7 @@ class AD2(object): return msg def _handle_rfx(self, data): - msg = messages.RFMessage(data) + msg = RFMessage(data) self.on_rfx_message(msg) @@ -417,7 +418,7 @@ class AD2(object): :returns: An object representing the LRR message. """ - msg = messages.LRRMessage(data) + msg = LRRMessage(data) if msg.event_type == 'ALARM_PANIC': self._panic_status = True @@ -469,7 +470,7 @@ class AD2(object): :param message: Message to update internal states with. :type message: Message, ExpanderMessage, LRRMessage, or RFMessage """ - if isinstance(message, messages.Message): + if isinstance(message, Message): if message.ac_power != self._power_status: self._power_status, old_status = message.ac_power, self._power_status @@ -511,8 +512,8 @@ class AD2(object): self._fire_status = (message.fire_alarm, time.time()) self.on_fire(self._fire_status) - elif isinstance(message, messages.ExpanderMessage): - if message.type == messages.ExpanderMessage.RELAY: + elif isinstance(message, ExpanderMessage): + if message.type == ExpanderMessage.RELAY: self._relay_status[(message.address, message.channel)] = message.value self.on_relay_changed(message) @@ -529,9 +530,9 @@ class AD2(object): # Retrieve a list of faults. # NOTE: This only happens on first boot or after exiting programming mode. - if isinstance(message, messages.Message): + if isinstance(message, Message): if not message.ready and "Hit * for faults" in message.text: - self._device.write('*') + self.send('*') return self._zonetracker.update(message)