diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle index b2d6160..e34f4ac 100644 Binary files a/docs/_build/doctrees/environment.pickle and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree index 60cc750..98e13cf 100644 Binary files a/docs/_build/doctrees/index.doctree and b/docs/_build/doctrees/index.doctree differ diff --git a/docs/_build/doctrees/modules.doctree b/docs/_build/doctrees/modules.doctree index 00ae235..2472e03 100644 Binary files a/docs/_build/doctrees/modules.doctree and b/docs/_build/doctrees/modules.doctree differ diff --git a/docs/_build/doctrees/pyad2usb.doctree b/docs/_build/doctrees/pyad2usb.doctree index e0bbc01..fe0d0e8 100644 Binary files a/docs/_build/doctrees/pyad2usb.doctree and b/docs/_build/doctrees/pyad2usb.doctree differ diff --git a/docs/_build/doctrees/pyad2usb.event.doctree b/docs/_build/doctrees/pyad2usb.event.doctree index 2233ef5..450e6de 100644 Binary files a/docs/_build/doctrees/pyad2usb.event.doctree and b/docs/_build/doctrees/pyad2usb.event.doctree differ diff --git a/docs/_build/html/_modules/index.html b/docs/_build/html/_modules/index.html index 5f6a0ea..b4d2a4d 100644 --- a/docs/_build/html/_modules/index.html +++ b/docs/_build/html/_modules/index.html @@ -48,7 +48,9 @@ diff --git a/docs/_build/html/_modules/pyad2usb/messages.html b/docs/_build/html/_modules/pyad2usb/messages.html new file mode 100644 index 0000000..ba68f3c --- /dev/null +++ b/docs/_build/html/_modules/pyad2usb/messages.html @@ -0,0 +1,289 @@ + + + + + + + + pyad2usb.messages — pyad2usb documentation + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for pyad2usb.messages

+"""
+Message representations received from the panel through the AD2USB.
+"""
+
+import re
+
+
[docs]class Message(object): + """ + Represents a message from the alarm panel. + """ + + def __init__(self, data=None): + """ + Constructor + """ + self.ready = False + self.armed_away = False + self.armed_home = False + self.backlight_on = False + self.programming_mode = False + self.beeps = -1 + self.zone_bypassed = False + self.ac_power = False + self.chime_on = False + self.alarm_event_occurred = False + self.alarm_sounding = False + self.battery_low = False + self.entry_delay_off = False + self.fire_alarm = False + self.check_zone = False + self.perimeter_only = False + self.numeric_code = "" + self.text = "" + self.cursor_location = -1 + self.data = "" + self.mask = "" + self.bitfield = "" + self.panel_data = "" + + self._regex = re.compile('("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*),("(?:[^"]|"")*"|[^,]*)') + + if data is not None: + self._parse_message(data) + + def _parse_message(self, data): + """ + Parse the message from the device. + """ + m = self._regex.match(data) + + if m is None: + raise util.InvalidMessageError('Received invalid message: {0}'.format(data)) + + self.bitfield, self.numeric_code, self.panel_data, alpha = m.group(1, 2, 3, 4) + self.mask = int(self.panel_data[3:3+8], 16) + + self.data = data + self.ready = not self.bitfield[1:2] == "0" + self.armed_away = not self.bitfield[2:3] == "0" + self.armed_home = not self.bitfield[3:4] == "0" + self.backlight_on = not self.bitfield[4:5] == "0" + self.programming_mode = not self.bitfield[5:6] == "0" + self.beeps = int(self.bitfield[6:7], 16) + self.zone_bypassed = not self.bitfield[7:8] == "0" + self.ac_power = not self.bitfield[8:9] == "0" + self.chime_on = not self.bitfield[9:10] == "0" + self.alarm_event_occurred = not self.bitfield[10:11] == "0" + self.alarm_sounding = not self.bitfield[11:12] == "0" + self.battery_low = not self.bitfield[12:13] == "0" + self.entry_delay_off = not self.bitfield[13:14] == "0" + self.fire_alarm = not self.bitfield[14:15] == "0" + self.check_zone = not self.bitfield[15:16] == "0" + self.perimeter_only = not self.bitfield[16:17] == "0" + # bits 17-20 unused. + self.text = alpha.strip('"') + + if int(self.panel_data[19:21], 16) & 0x01 > 0: + self.cursor_location = int(self.bitfield[21:23], 16) # Alpha character index that the cursor is on. + + def __str__(self): + """ + String conversion operator. + """ + return 'msg > {0:0<9} [{1}{2}{3}] -- ({4}) {5}'.format(hex(self.mask), 1 if self.ready else 0, 1 if self.armed_away else 0, 1 if self.armed_home else 0, self.numeric_code, self.text) +
+
[docs]class ExpanderMessage(object): + """ + Represents a message from a zone or relay expansion module. + """ + + ZONE = 0 + RELAY = 1 + + def __init__(self, data=None): + """ + Constructor + """ + self.type = None + self.address = None + self.channel = None + self.value = None + self.raw = None + + if data is not None: + self._parse_message(data) + + def __str__(self): + """ + String conversion operator. + """ + expander_type = 'UNKWN' + if self.type == ExpanderMessage.ZONE: + expander_type = 'ZONE' + elif self.type == ExpanderMessage.RELAY: + expander_type = 'RELAY' + + return 'exp > [{0: <5}] {1}/{2} -- {3}'.format(expander_type, self.address, self.channel, self.value) + + def _parse_message(self, data): + """ + Parse the raw message from the device. + """ + header, values = data.split(':') + address, channel, value = values.split(',') + + self.raw = data + self.address = address + self.channel = channel + self.value = value + + if header == '!EXP': + self.type = ExpanderMessage.ZONE + elif header == '!REL': + self.type = ExpanderMessage.RELAY +
+
[docs]class RFMessage(object): + """ + Represents a message from an RF receiver. + """ + + def __init__(self, data=None): + """ + Constructor + """ + self.raw = None + self.serial_number = None + self.value = None + + if data is not None: + self._parse_message(data) + + def __str__(self): + """ + String conversion operator. + """ + return 'rf > {0}: {1}'.format(self.serial_number, self.value) + + def _parse_message(self, data): + """ + Parses the raw message from the device. + """ + self.raw = data + + _, values = data.split(':') + self.serial_number, self.value = values.split(',') +
+
[docs]class LRRMessage(object): + """ + Represent a message from a Long Range Radio. + """ + + def __init__(self, data=None): + """ + Constructor + """ + self.raw = None + self._event_data = None + self._partition = None + self._event_type = None + + if data is not None: + self._parse_message(data) + + def __str__(self): + """ + String conversion operator. + """ + return 'lrr > {0} @ {1} -- {2}'.format() + + def _parse_message(self, data): + """ + Parses the raw message from the device. + """ + self.raw = data + + _, values = data.split(':') + self._event_data, self._partition, self._event_type = values.split(',')
+
+ +
+
+
+
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/pyad2usb/zonetracking.html b/docs/_build/html/_modules/pyad2usb/zonetracking.html new file mode 100644 index 0000000..f9e8e3b --- /dev/null +++ b/docs/_build/html/_modules/pyad2usb/zonetracking.html @@ -0,0 +1,368 @@ + + + + + + + + pyad2usb.zonetracking — pyad2usb documentation + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for pyad2usb.zonetracking

+"""
+Provides zone tracking functionality for the AD2USB device family.
+"""
+
+import time
+from .event import event
+from . import messages
+
+
[docs]class Zone(object): + """ + Representation of a panel zone. + """ + + CLEAR = 0 + """Status indicating that the zone is cleared.""" + FAULT = 1 + """Status indicating that the zone is faulted.""" + CHECK = 2 # Wire fault + """Status indicating that there is a wiring issue with the zone.""" + + STATUS = { CLEAR: 'CLEAR', FAULT: 'FAULT', CHECK: 'CHECK' } + + def __init__(self, zone=0, name='', status=CLEAR): + """ + Constructor + + :param zone: The zone number. + :type zone: int + :param name: Human readable zone name. + :type name: str + :param status: Initial zone state. + :type status: int + """ + self.zone = zone + self.name = name + self.status = status + self.timestamp = time.time() + + def __str__(self): + """ + String conversion operator. + """ + return 'Zone {0} {1}'.format(self.zone, self.name) + + def __repr__(self): + """ + Human readable representation operator. + """ + return 'Zone({0}, {1}, ts {2})'.format(self.zone, Zone.STATUS[self.status], self.timestamp) +
+
[docs]class Zonetracker(object): + """ + Handles tracking of zone and their statuses. + """ + + on_fault = event.Event('Called when the device detects a zone fault.') + on_restore = event.Event('Called when the device detects that a fault is restored.') + + EXPIRE = 30 + """Zone expiration timeout.""" + + def __init__(self): + """ + Constructor + """ + self._zones = {} + self._zones_faulted = [] + self._last_zone_fault = 0 + +
[docs] def update(self, message): + """ + Update zone statuses based on the current message. + + :param message: Message to use to update the zone tracking. + :type message: Message or ExpanderMessage + """ + zone = -1 + + if isinstance(message, messages.ExpanderMessage): + if message.type == messages.ExpanderMessage.ZONE: + zone = self._expander_to_zone(int(message.address), int(message.channel)) + + status = Zone.CLEAR + if int(message.value) == 1: + status = Zone.FAULT + elif int(message.value) == 2: + status = Zone.CHECK + + try: + self._update_zone(zone, status=status) + except IndexError: + self._add_zone(zone, status=status) + + else: + # Panel is ready, restore all zones. + if message.ready: + for idx, z in enumerate(self._zones_faulted): + self._update_zone(z, Zone.CLEAR) + + self._last_zone_fault = 0 + + # Process fault + elif "FAULT" in message.text or message.check_zone: + # Apparently this representation can be both base 10 + # or base 16, depending on where the message came + # from. + try: + zone = int(message.numeric_code) + except ValueError: + zone = int(message.numeric_code, 16) + + # Add new zones and clear expired ones. + if zone in self._zones_faulted: + self._update_zone(zone) + self._clear_zones(zone) + else: + status = Zone.FAULT + if message.check_zone: + status = Zone.CHECK + + self._add_zone(zone, status=status) + self._zones_faulted.append(zone) + self._zones_faulted.sort() + + # Save our spot for the next message. + self._last_zone_fault = zone + + self._clear_expired_zones() +
+ def _clear_zones(self, zone): + """ + Clear all expired zones from our status list. + + :param zone: current zone being processed. + :type zone: int + """ + cleared_zones = [] + found_last = found_new = at_end = False + + # First pass: Find our start spot. + it = iter(self._zones_faulted) + try: + while not found_last: + z = it.next() + + if z == self._last_zone_fault: + found_last = True + break + + except StopIteration: + at_end = True + + # Continue until we find our end point and add zones in + # between to our clear list. + try: + while not at_end and not found_new: + z = it.next() + + if z == zone: + found_new = True + break + else: + cleared_zones += [z] + + except StopIteration: + pass + + # Second pass: roll through the list again if we didn't find + # our end point and remove everything until we do. + if not found_new: + it = iter(self._zones_faulted) + + try: + while not found_new: + z = it.next() + + if z == zone: + found_new = True + break + else: + cleared_zones += [z] + + except StopIteration: + pass + + # Actually remove the zones and trigger the restores. + for idx, z in enumerate(cleared_zones): + self._update_zone(z, Zone.CLEAR) + + def _clear_expired_zones(self): + """ + Update zone status for all expired zones. + """ + zones = [] + + for z in self._zones.keys(): + zones += [z] + + for z in zones: + if self._zones[z].status != Zone.CLEAR and self._zone_expired(z): + self._update_zone(z, Zone.CLEAR) + + def _add_zone(self, zone, name='', status=Zone.CLEAR): + """ + Adds a zone to the internal zone list. + + :param zone: The zone number. + :type zone: int + :param name: Human readable zone name. + :type name: str + :param status: The zone status. + :type status: int + """ + if not zone in self._zones: + self._zones[zone] = Zone(zone=zone, name=name, status=status) + + if status != Zone.CLEAR: + self.on_fault(zone) + + def _update_zone(self, zone, status=None): + """ + Updates a zones status. + + :param zone: The zone number. + :type zone: int + :param status: The zone status. + :type status: int + + :raises: IndexError + """ + if not zone in self._zones: + raise IndexError('Zone does not exist and cannot be updated: %d', zone) + + if status is not None: + self._zones[zone].status = status + + self._zones[zone].timestamp = time.time() + + if status == Zone.CLEAR: + if zone in self._zones_faulted: + self._zones_faulted.remove(zone) + + self.on_restore(zone) + + def _zone_expired(self, zone): + """ + Determine if a zone is expired or not. + + :param zone: The zone number. + :type zone: int + + :returns: Whether or not the zone is expired. + """ + if time.time() > self._zones[zone].timestamp + Zonetracker.EXPIRE: + return True + + return False + + def _expander_to_zone(self, address, channel): + """ + Convert an address and channel into a zone number. + + :param address: The expander address + :type address: int + :param channel: The channel + :type channel: int + + :returns: The zone number associated with an address and channel. + """ + + # TODO: This is going to need to be reworked to support the larger + # panels without fixed addressing on the expanders. + + idx = address - 7 # Expanders start at address 7. + + return address + channel + (idx * 7) + 1
+
+ +
+
+
+
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_sources/pyad2usb.txt b/docs/_build/html/_sources/pyad2usb.txt index 08dfd6b..2e8b746 100644 --- a/docs/_build/html/_sources/pyad2usb.txt +++ b/docs/_build/html/_sources/pyad2usb.txt @@ -1,14 +1,6 @@ pyad2usb Package ================ -:mod:`pyad2usb` Package ------------------------ - -.. automodule:: pyad2usb.__init__ - :members: - :undoc-members: - :show-inheritance: - :mod:`ad2usb` Module -------------------- @@ -33,6 +25,30 @@ pyad2usb Package :undoc-members: :show-inheritance: +:mod:`zonetracking` Module +-------------------------- + +.. automodule:: pyad2usb.zonetracking + :members: + :undoc-members: + :show-inheritance: + +:mod:`panels` Module +-------------------- + +.. automodule:: pyad2usb.panels + :members: + :undoc-members: + :show-inheritance: + +:mod:`messages` Module +---------------------- + +.. automodule:: pyad2usb.messages + :members: + :undoc-members: + :show-inheritance: + Subpackages ----------- diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html index e28beaf..3a840cb 100644 --- a/docs/_build/html/genindex.html +++ b/docs/_build/html/genindex.html @@ -90,6 +90,12 @@ +
+
BATTERY_TIMEOUT (pyad2usb.ad2usb.AD2USB attribute) +
+ +
+
BAUDRATE (pyad2usb.devices.SerialDevice attribute)
@@ -106,6 +112,20 @@ + - @@ -200,6 +222,16 @@ +
FAULT (pyad2usb.zonetracking.Zone attribute) +
+ + +
fault_zone() (pyad2usb.ad2usb.AD2USB method) +
+ + + -
+
CHECK (pyad2usb.zonetracking.Zone attribute) +
+ + +
CLEAR (pyad2usb.zonetracking.Zone attribute) +
+ + +
clear_zone() (pyad2usb.ad2usb.AD2USB method) +
+ +
+
close() (pyad2usb.ad2usb.AD2USB method)
@@ -131,8 +151,6 @@
CommError
-
create() (pyad2usb.ad2usb.Overseer class method)
@@ -174,7 +192,11 @@
-
ExpanderMessage (class in pyad2usb.ad2usb) +
ExpanderMessage (class in pyad2usb.messages) +
+ + +
EXPIRE (pyad2usb.zonetracking.Zonetracker attribute)
+
find_all() (pyad2usb.ad2usb.Overseer class method)
@@ -213,13 +245,15 @@
-
fire() (pyad2usb.event.event.EventHandler method)
+
FIRE_TIMEOUT (pyad2usb.ad2usb.AD2USB attribute) +
+ +
Firmware (class in pyad2usb.util)
@@ -280,7 +314,7 @@ @@ -290,7 +324,7 @@
-
LRRMessage (class in pyad2usb.ad2usb) +
LRRMessage (class in pyad2usb.messages)
@@ -314,6 +348,10 @@ +
on_arm (pyad2usb.ad2usb.AD2USB attribute) +
+ +
on_attached (pyad2usb.ad2usb.Overseer attribute)
@@ -344,12 +382,32 @@ -
on_message (pyad2usb.ad2usb.AD2USB attribute) +
on_disarm (pyad2usb.ad2usb.AD2USB attribute) +
+ + +
on_fault (pyad2usb.zonetracking.Zonetracker attribute) +
+ + +
on_fire (pyad2usb.ad2usb.AD2USB attribute) +
+ + +
on_low_battery (pyad2usb.ad2usb.AD2USB attribute) +
+ + +
on_lrr_message (pyad2usb.ad2usb.AD2USB attribute)
-
Message (class in pyad2usb.ad2usb) +
Message (class in pyad2usb.messages)
+
on_message (pyad2usb.ad2usb.AD2USB attribute) +
+ +
on_open (pyad2usb.ad2usb.AD2USB attribute)
@@ -360,6 +418,10 @@
+
on_panic (pyad2usb.ad2usb.AD2USB attribute) +
+ +
on_power_changed (pyad2usb.ad2usb.AD2USB attribute)
@@ -374,7 +436,7 @@ -
on_status_changed (pyad2usb.ad2usb.AD2USB attribute) +
on_restore (pyad2usb.zonetracking.Zonetracker attribute)
@@ -388,6 +450,14 @@ +
on_zone_fault (pyad2usb.ad2usb.AD2USB attribute) +
+ + +
on_zone_restore (pyad2usb.ad2usb.AD2USB attribute) +
+ +
open() (pyad2usb.ad2usb.AD2USB method)
@@ -420,31 +490,39 @@
-
pyad2usb.__init__ (module) +
pyad2usb.ad2usb (module)
-
pyad2usb.ad2usb (module) +
pyad2usb.devices (module)
-
pyad2usb.devices (module) +
pyad2usb.event (module) +
+ + +
pyad2usb.event.event (module)
-
pyad2usb.event (module) +
pyad2usb.messages (module)
-
pyad2usb.event.event (module) +
pyad2usb.panels (module)
pyad2usb.util (module)
+ +
pyad2usb.zonetracking (module) +
+
@@ -490,7 +568,7 @@
-
RELAY (pyad2usb.ad2usb.ExpanderMessage attribute) +
RELAY (pyad2usb.messages.ExpanderMessage attribute)
@@ -498,7 +576,7 @@ -
RFMessage (class in pyad2usb.ad2usb) +
RFMessage (class in pyad2usb.messages)
@@ -518,11 +596,11 @@ - +
-
SerialDevice (class in pyad2usb.devices) +
save_config() (pyad2usb.ad2usb.AD2USB method)
-
set_config() (pyad2usb.ad2usb.AD2USB method) +
SerialDevice (class in pyad2usb.devices)
@@ -541,12 +619,12 @@
STAGE_LOAD (pyad2usb.util.Firmware attribute)
-
STAGE_START (pyad2usb.util.Firmware attribute)
+
STAGE_UPLOADING (pyad2usb.util.Firmware attribute)
@@ -560,6 +638,10 @@ +
STATUS (pyad2usb.zonetracking.Zone attribute) +
+ +
stop() (pyad2usb.ad2usb.Overseer method)
@@ -594,6 +676,10 @@
+
update() (pyad2usb.zonetracking.Zonetracker method) +
+ +
upload() (pyad2usb.util.Firmware static method)
@@ -630,7 +716,17 @@ + diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html index ffdf6a7..8e5c95b 100644 --- a/docs/_build/html/index.html +++ b/docs/_build/html/index.html @@ -54,10 +54,12 @@
- - - + + + + + + + + +
-
ZONE (pyad2usb.ad2usb.ExpanderMessage attribute) +
Zone (class in pyad2usb.zonetracking) +
+ + +
ZONE (pyad2usb.messages.ExpanderMessage attribute) +
+ +
+ +
Zonetracker (class in pyad2usb.zonetracking)
pyad2usb
    - pyad2usb.__init__ -
    @@ -89,11 +84,26 @@     pyad2usb.event.event
    + pyad2usb.messages +
    + pyad2usb.panels +
    pyad2usb.util
    + pyad2usb.zonetracking +
diff --git a/docs/_build/html/pyad2usb.event.html b/docs/_build/html/pyad2usb.event.html index a4ede97..a729413 100644 --- a/docs/_build/html/pyad2usb.event.html +++ b/docs/_build/html/pyad2usb.event.html @@ -75,6 +75,13 @@ You can add handler also by using ‘+=’ operator.

+
+
+remove(func)[source]
+

Remove existing event handler function.

+

You can remove handler also by using ‘-=’ operator.

+
+
fire(earg=None)[source]
@@ -83,13 +90,6 @@ You can add handler also by using ‘+=’ operator.

e.fire(earg).

-
-
-remove(func)[source]
-

Remove existing event handler function.

-

You can remove handler also by using ‘-=’ operator.

-
- diff --git a/docs/_build/html/pyad2usb.html b/docs/_build/html/pyad2usb.html index 2989540..f6ea00a 100644 --- a/docs/_build/html/pyad2usb.html +++ b/docs/_build/html/pyad2usb.html @@ -54,54 +54,149 @@

pyad2usb Package

-
-

pyad2usb Package

-

The PyAD2USB module.

-

ad2usb Module

Provides the full AD2USB class and factory.

-
-class pyad2usb.ad2usb.AD2USB(device)[source]
+
+class pyad2usb.ad2usb.Overseer(attached_event=None, detached_event=None)[source]

Bases: object

-

High-level wrapper around AD2USB/AD2SERIAL devices.

+

Factory for creation of AD2USB devices as well as provide4s attach/detach events.”

-
-F1 = u'\x01\x01\x01'
-
+
+on_attached
+

Called when an AD2USB device has been detected.

+
-
-F2 = u'\x02\x02\x02'
-
+
+on_detached
+

Called when an AD2USB device has been removed.

+
-
-
-F3 = u'\x03\x03\x03'
-
+
+
+classmethod find_all()[source]
+

Returns all AD2USB devices located on the system.

+ +++ + + + + + +
Returns:list of devices found
Raises :util.CommError
+
-
-
-F4 = u'\x04\x04\x04'
-
+
+
+classmethod devices()[source]
+

Returns a cached list of AD2USB devices located on the system.

+ +++ + + + +
Returns:cached list of devices found.
+
+ +
+
+classmethod create(device=None)[source]
+

Factory method that returns the requested AD2USB device, or the first device.

+ +++ + + + + + + + +
Parameters:device (tuple) – Tuple describing the USB device to open, as returned by find_all().
Returns:AD2USB object utilizing the specified device.
Raises :util.NoDeviceError
+
-
-close()[source]
-

Closes the device.

+
+close()[source]
+

Clean up and shut down.

-
-get_config()[source]
-

Retrieves the configuration from the device.

+
+start()[source]
+

Starts the detection thread, if not already running.

+
+
+stop()[source]
+

Stops the detection thread.

+
+ +
+
+get_device(device=None)[source]
+

Factory method that returns the requested AD2USB device, or the first device.

+ +++ + + + +
Parameters:device (tuple) – Tuple describing the USB device to open, as returned by find_all().
+
+ +
+
+class DetectThread(overseer)[source]
+

Bases: threading.Thread

+

Thread that handles detection of added/removed devices.

+
+
+stop()[source]
+

Stops the thread.

+
+ +
+
+run()[source]
+

The actual detection process.

+
+ +
+ + + +
+
+class pyad2usb.ad2usb.AD2USB(device)[source]
+

Bases: object

+

High-level wrapper around AD2USB/AD2SERIAL devices.

-
-id[source]
-
+
+on_arm
+

Called when the panel is armed.

+
+ +
+
+on_disarm
+

Called when the panel is disarmed.

+
+ +
+
+on_power_changed
+

Called when panel power switches between AC and DC.

+
@@ -110,9 +205,9 @@
-
-on_boot
-

Called when the device finishes bootings.

+
+on_fire
+

Called when a fire is detected.

@@ -122,9 +217,9 @@
-
-on_close
-

Called when the device has been closed.

+
+on_boot
+

Called when the device finishes bootings.

@@ -133,12 +228,42 @@

Called when the device receives its configuration.

+
+
+on_zone_fault
+

Called when the device detects a zone fault.

+
+ +
+
+on_zone_restore
+

Called when the device detects that a fault is restored.

+
+ +
+
+on_low_battery
+

Called when the device detects a low battery.

+
+ +
+
+on_panic
+

Called when the device detects a panic.

+
+
on_message

Called when a message has been received from the device.

+
+
+on_lrr_message
+

Called when an LRR message is received.

+
+
on_open
@@ -146,9 +271,9 @@
-
-on_power_changed
-

Called when panel power switches between AC and DC.

+
+on_close
+

Called when the device has been closed.

@@ -157,165 +282,207 @@

Called when a line has been read from the device.

-
-
-on_status_changed
-

Called when the panel status changes.

-
-
on_write

Called when data has been written to the device.

-
-
-open(baudrate=None, interface=None, index=None, no_reader_thread=False)[source]
-

Opens the device.

+
+
+F1 = u'\x01\x01\x01'
+

Represents panel function key #1

-
-
-reboot()[source]
-

Reboots the device.

+
+
+F2 = u'\x02\x02\x02'
+

Represents panel function key #2

-
-
-set_config(settings)[source]
-

Sets configuration entries on the device.

+
+
+F3 = u'\x03\x03\x03'
+

Represents panel function key #3

+
+
+F4 = u'\x04\x04\x04'
+

Represents panel function key #4

-
-
-class pyad2usb.ad2usb.ExpanderMessage(data=None)[source]
-

Bases: object

-

Represents a message from a zone or relay expansion module.

-
-RELAY = 1
-
+
+BATTERY_TIMEOUT = 30
+

Timeout before the battery status reverts.

+
-
-ZONE = 0
-
- +
+FIRE_TIMEOUT = 30
+

Timeout before the fire status reverts.

-
-
-class pyad2usb.ad2usb.LRRMessage(data=None)[source]
-

Bases: object

-

Represent a message from a Long Range Radio.

+
+
+id[source]
+

The ID of the AD2USB device.

+ +++ + + + +
Returns:The identification string for the device.
-
-
-class pyad2usb.ad2usb.Message(data=None)[source]
-

Bases: object

-

Represents a message from the alarm panel.

+
+
+open(baudrate=None, interface=None, index=None, no_reader_thread=False)[source]
+

Opens the device.

+ +++ + + + +
Parameters:
    +
  • baudrate (int) – The baudrate used for the device.
  • +
  • interface (varies depends on device type.. FIXME) – The interface used for the device.
  • +
  • index (int) – Interface index.. can probably remove. FIXME
  • +
  • no_reader_thread (bool) – Specifies whether or not the automatic reader thread should be started or not
  • +
+
-
-
-class pyad2usb.ad2usb.Overseer(attached_event=None, detached_event=None)[source]
-

Bases: object

-

Factory for creation of AD2USB devices as well as provide4s attach/detach events.”

-
-
-class DetectThread(overseer)[source]
-

Bases: threading.Thread

-

Thread that handles detection of added/removed devices.

-
-run()[source]
-

The actual detection process.

+
+close()[source]
+

Closes the device.

-
-stop()[source]
-

Stops the thread.

+
+get_config()[source]
+

Retrieves the configuration from the device.

+
+
+save_config()
+

Sets configuration entries on the device.

-
-Overseer.close()[source]
-

Clean up and shut down.

+
+reboot()[source]
+

Reboots the device.

-
-
-classmethod Overseer.create(device=None)[source]
-

Factory method that returns the requested AD2USB device, or the first device.

+
+
+fault_zone(zone, simulate_wire_problem=False)
+

Faults a zone if we are emulating a zone expander.

+ +++ + + + +
Parameters:
    +
  • zone (int) – The zone to fault.
  • +
  • simulate_wire_problem (bool) – Whether or not to simulate a wire fault.
  • +
+
-
-
-classmethod Overseer.devices()[source]
-

Returns a cached list of AD2USB devices located on the system.

+
+
+clear_zone(zone)
+

Clears a zone if we are emulating a zone expander.

+ +++ + + + +
Parameters:zone (int) – The zone to clear.
-
-
-classmethod Overseer.find_all()[source]
-

Returns all AD2USB devices located on the system.

-
-
-Overseer.get_device(device=None)[source]
-

Factory method that returns the requested AD2USB device, or the first device.

+
+
+

devices Module

+

Contains different types of devices belonging to the AD2USB family.

+
+
+class pyad2usb.devices.Device[source]
+

Bases: object

+

Generic parent device to all AD2USB products.

+
+
+on_open
+

Called when the device has been opened

-
-Overseer.on_attached
-

Called when an AD2USB device has been detected.

+
+on_close
+

Called when the device has been closed

-
-Overseer.on_detached
-

Called when an AD2USB device has been removed.

+
+on_read
+

Called when a line has been read from the device

-
-
-Overseer.start()[source]
-

Starts the detection thread, if not already running.

+
+
+on_write
+

Called when data has been written to the device

-
-
-Overseer.stop()[source]
-

Stops the detection thread.

+
+
+id[source]
+

Retrieve the device ID.

+ +++ + + + +
Returns:The identification string for the device.
+
+
+is_reader_alive()[source]
+

Indicates whether or not the reader thread is alive.

+ +++ + + + +
Returns:Whether or not the reader thread is alive.
-
-
-class pyad2usb.ad2usb.RFMessage(data=None)[source]
-

Bases: object

-

Represents a message from an RF receiver.

+
+
+stop_reader()[source]
+

Stops the reader thread.

-
-
-

devices Module

-

Contains different types of devices belonging to the AD2USB family.

-
-
-class pyad2usb.devices.Device[source]
-

Bases: object

-

Generic parent device to all AD2USB products.

class ReadThread(device)[source]
@@ -324,7 +491,14 @@
READ_TIMEOUT = 10
-
+

Timeout for the reader thread.

+
+ +
+
+stop()[source]
+

Stops the running thread.

+
@@ -332,53 +506,131 @@

The actual read process.

-
-
-stop()[source]
-

Stops the running thread.

+
+
+class pyad2usb.devices.USBDevice(vid=1027, pid=24577, serial=None, description=None, interface=0)[source]
+

Bases: pyad2usb.devices.Device

+

AD2USB device exposed with PyFTDI’s interface.

+
+
+FTDI_VENDOR_ID = 1027
+

Vendor ID used to recognize AD2USB devices.

+
+ +
+
+FTDI_PRODUCT_ID = 24577
+

Product ID used to recognize AD2USB devices.

+
+
-
-Device.id[source]
-
+
+BAUDRATE = 115200
+

Default baudrate for AD2USB devices.

+
-
-
-Device.is_reader_alive()[source]
-

Indicates whether or not the reader thread is alive.

+
+
+static find_all()[source]
+

Returns all FTDI devices matching our vendor and product IDs.

+ +++ + + + + + +
Returns:list of devices
Raises :util.CommError
-
-
-Device.on_close
-

Called when the device has been closed

+
+
+open(baudrate=115200, interface=None, index=0, no_reader_thread=False)[source]
+

Opens the device.

+ +++ + + + + + +
Parameters:
    +
  • baudrate (int) – The baudrate to use.
  • +
  • interface (int) – The interface to use.
  • +
  • no_reader_thread (bool) – Whether or not to automatically start the reader thread.
  • +
+
Raises :

util.NoDeviceError

+
-
-
-Device.on_open
-

Called when the device has been opened

+
+
+close()[source]
+

Closes the device.

-
-
-Device.on_read
-

Called when a line has been read from the device

+
+
+write(data)[source]
+

Writes data to the device.

+ +++ + + + + + +
Parameters:data (str) – Data to write
Raises :util.CommError
-
-
-Device.on_write
-

Called when data has been written to the device

+
+
+read()[source]
+

Reads a single character from the device.

+ +++ + + + + + +
Returns:The character read from the device.
Raises :util.CommError
-
-Device.stop_reader()[source]
-

Stops the reader thread.

+
+read_line(timeout=0.0, purge_buffer=False)[source]
+

Reads a line from the device.

+ +++ + + + + + + + +
Parameters:
    +
  • timeout (float) – Read timeout
  • +
  • purge_buffer (bool) – Indicates whether to purge the buffer prior to reading.
  • +
+
Returns:

The line that was read.

+
Raises :

util.CommError, util.TimeoutError

+
@@ -391,42 +643,110 @@
BAUDRATE = 19200
-
- -
-
-close()[source]
-

Closes the device.

+

Default baudrate for Serial devices.

static find_all(pattern=None)[source]

Returns all serial ports present.

+ +++ + + + + + + + +
Parameters:pattern (str) – Pattern to search for when retrieving serial ports.
Returns:list of devices
Raises :util.CommError
open(baudrate=19200, interface=None, index=None, no_reader_thread=False)[source]

Opens the device.

+ +++ + + + + + +
Parameters:
    +
  • baudrate (int) – The baudrate to use with the device.
  • +
  • interface (str) – The device to open.
  • +
  • index (int) – Unused.
  • +
  • no_reader_thread (bool) – Whether or not to automatically start the reader thread.
  • +
+
Raises :

util.NoDeviceError

+
+
+ +
+
+close()[source]
+

Closes the device.

+
+ +
+
+write(data)[source]
+

Writes data to the device.

+ +++ + + + + + +
Parameters:data (str) – The data to write.
Raises :util.CommError
read()[source]

Reads a single character from the device.

+ +++ + + + + + +
Returns:The character read from the device.
Raises :util.CommError
-read_line(timeout=0.0)[source]
+read_line(timeout=0.0, purge_buffer=False)[source]

Reads a line from the device.

-
- -
-
-write(data)[source]
-

Writes data to the device.

+ +++ + + + + + + + +
Parameters:
    +
  • timeout (float) – The read timeout.
  • +
  • purge_buffer (bool) – Indicates whether to purge the buffer prior to reading.
  • +
+
Returns:

The line read.

+
Raises :

util.CommError, util.TimeoutError

+
@@ -437,92 +757,91 @@

Bases: pyad2usb.devices.Device

Device that supports communication with an AD2USB that is exposed via ser2sock or another Serial to IP interface.

-
-
-close()[source]
-

Closes the device.

-
-
open(baudrate=None, interface=None, index=0, no_reader_thread=False)[source]

Opens the device.

+ +++ + + + + + +
Parameters:
    +
  • baudrate (int) – The baudrate to use
  • +
  • interface (tuple) – The hostname and port to connect to.
  • +
  • index (int) – Unused
  • +
  • no_reader_thread (bool) – Whether or not to automatically open the reader thread.
  • +
+
Raises :

util.NoDeviceError

+
-
-read()[source]
-

Reads a single character from the device.

-
- -
-
-read_line(timeout=0.0)[source]
-

Reads a line from the device.

+
+close()[source]
+

Closes the device.

write(data)[source]

Writes data to the device.

-
- -
- -
-
-class pyad2usb.devices.USBDevice(vid=1027, pid=24577, serial=None, description=None, interface=0)[source]
-

Bases: pyad2usb.devices.Device

-

AD2USB device exposed with PyFTDI’s interface.

-
-
-BAUDRATE = 115200
-
- -
-
-FTDI_PRODUCT_ID = 24577
-
- -
-
-FTDI_VENDOR_ID = 1027
-
- -
-
-close()[source]
-

Closes the device.

-
- -
-
-static find_all()[source]
-

Returns all FTDI devices matching our vendor and product IDs.

-
- -
-
-open(baudrate=115200, interface=None, index=0, no_reader_thread=False)[source]
-

Opens the device.

+ +++ + + + + + + + +
Parameters:data (str) – The data to write.
Returns:The number of bytes sent.
Raises :util.CommError
-
-read()[source]
+
+read()[source]

Reads a single character from the device.

+ +++ + + + + + +
Returns:The character read from the device.
Raises :util.CommError
-
-read_line(timeout=0.0)[source]
+
+read_line(timeout=0.0, purge_buffer=False)[source]

Reads a line from the device.

-
- -
-
-write(data)[source]
-

Writes data to the device.

+ +++ + + + + + + + +
Parameters:
    +
  • timeout (float) – The read timeout.
  • +
  • purge_buffer (bool) – Indicates whether to purge the buffer prior to reading.
  • +
+
Returns:

The line read from the device.

+
Raises :

util.CommError, util.TimeoutError

+
@@ -531,6 +850,13 @@ Serial to IP interface.

util Module

Provides utility classes for the AD2USB devices.

+
+
+exception pyad2usb.util.NoDeviceError[source]
+

Bases: exceptions.Exception

+

No devices found.

+
+
exception pyad2usb.util.CommError[source]
@@ -538,29 +864,43 @@ Serial to IP interface.

There was an error communicating with the device.

+
+
+exception pyad2usb.util.TimeoutError[source]
+

Bases: exceptions.Exception

+

There was a timeout while trying to communicate with the device.

+
+ +
+
+exception pyad2usb.util.InvalidMessageError[source]
+

Bases: exceptions.Exception

+

The format of the panel message was invalid.

+
+
class pyad2usb.util.Firmware[source]

Bases: object

Represents firmware for the AD2USB/AD2SERIAL devices.

-
-STAGE_BOOT = 2
+
+STAGE_START = 0
-
-STAGE_DONE = 5
+
+STAGE_WAITING = 1
-
-STAGE_LOAD = 3
+
+STAGE_BOOT = 2
-
-STAGE_START = 0
+
+STAGE_LOAD = 3
@@ -569,37 +909,150 @@ Serial to IP interface.

-
-STAGE_WAITING = 1
+
+STAGE_DONE = 5
static upload(dev, filename, progress_callback=None)[source]

Uploads firmware to an AD2USB/AD2SERIAL device.

+ +++ + + + + + +
Parameters:
    +
  • filename (str) – The firmware filename
  • +
  • progress_callback (function) – Callback function used to report progress.
  • +
+
Raises :

util.NoDeviceError, util.TimeoutError

+
-
-
-exception pyad2usb.util.InvalidMessageError[source]
-

Bases: exceptions.Exception

-

The format of the panel message was invalid.

+
+
+

zonetracking Module

+

Provides zone tracking functionality for the AD2USB device family.

+
+
+class pyad2usb.zonetracking.Zone(zone=0, name='', status=0)[source]
+

Bases: object

+

Representation of a panel zone.

+
+
+CLEAR = 0
+

Status indicating that the zone is cleared.

-
-
-exception pyad2usb.util.NoDeviceError[source]
-

Bases: exceptions.Exception

-

No devices found.

+
+
+FAULT = 1
+

Status indicating that the zone is faulted.

-
-
-exception pyad2usb.util.TimeoutError[source]
-

Bases: exceptions.Exception

-

There was a timeout while trying to communicate with the device.

+
+
+CHECK = 2
+

Status indicating that there is a wiring issue with the zone.

+
+ +
+
+STATUS = {0: 'CLEAR', 1: 'FAULT', 2: 'CHECK'}
+
+ +
+ +
+
+class pyad2usb.zonetracking.Zonetracker[source]
+

Bases: object

+

Handles tracking of zone and their statuses.

+
+
+on_fault
+

Called when the device detects a zone fault.

+
+ +
+
+on_restore
+

Called when the device detects that a fault is restored.

+
+ +
+
+EXPIRE = 30
+

Zone expiration timeout.

+
+ +
+
+update(message)[source]
+

Update zone statuses based on the current message.

+ +++ + + + +
Parameters:message (Message or ExpanderMessage) – Message to use to update the zone tracking.
+
+ +
+ +
+
+

panels Module

+

Representations of Panels and their templates.

+
+
+

messages Module

+

Message representations received from the panel through the AD2USB.

+
+
+class pyad2usb.messages.Message(data=None)[source]
+

Bases: object

+

Represents a message from the alarm panel.

+
+ +
+
+class pyad2usb.messages.ExpanderMessage(data=None)[source]
+

Bases: object

+

Represents a message from a zone or relay expansion module.

+
+
+ZONE = 0
+
+ +
+
+RELAY = 1
+
+ +
+ +
+
+class pyad2usb.messages.RFMessage(data=None)[source]
+

Bases: object

+

Represents a message from an RF receiver.

+
+ +
+
+class pyad2usb.messages.LRRMessage(data=None)[source]
+

Bases: object

+

Represent a message from a Long Range Radio.

@@ -626,10 +1079,12 @@ Serial to IP interface.

Table Of Contents

  • pyad2usb Package
      -
    • pyad2usb Package
    • ad2usb Module
    • devices Module
    • util Module
    • +
    • zonetracking Module
    • +
    • panels Module
    • +
    • messages Module
    • Subpackages
    • diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js index 07d020d..7ab97e2 100644 --- a/docs/_build/html/searchindex.js +++ b/docs/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:42,terms:{all:[1,3],socketdevic:1,func:3,boot:1,radio:1,on_boot:1,stage_don:1,baudrat:1,locat:1,zone:1,also:3,configur:1,except:1,on_attach:1,add:3,present:1,bypass:1,x03:1,on_read:1,x01:1,match:1,x04:1,sourc:[1,3],"return":1,around:1,format:1,fals:1,on_messag:1,stop:1,util:[],on_bypass:1,detach:1,like:3,level:1,earg:3,list:1,upload:1,method:1,"try":1,whether:1,stage_wait:1,timeout:1,contain:1,found:1,expandermessag:1,page:0,set:1,nodeviceerror:1,on_open:1,creation:1,"static":1,close:1,read_lin:1,event:[],stop_read:1,pyseri:1,index:[0,1],statu:1,detect:1,parent:1,pattern:1,ad2seri:1,reboot:1,content:0,written:1,between:1,"new":3,factori:1,localhost:1,can:3,ser2sock:1,shut:1,full:1,run:1,timeouterror:1,power:1,detached_ev:1,gener:1,usbdevic:1,on_clos:1,base:[1,3],on_config_receiv:1,on_status_chang:1,on_detach:1,panel:1,search:0,actual:1,expos:1,thread:1,readthread:1,set_config:1,stage_start:1,provide4:1,descript:1,chang:1,find_al:1,ad2usb:[],first:1,oper:3,rang:1,via:1,vid:1,attached_ev:1,modul:[],down:1,filenam:1,alreadi:1,messag:1,famili:1,on_writ:1,open:1,on_power_chang:1,differ:1,"long":1,from:1,commun:1,detectthread:1,support:1,devic:[],system:1,been:1,get_devic:1,trigger:1,call:[1,3],interfac:1,type:1,start:1,"function":3,wrapper:1,no_reader_thread:1,stage_load:1,fire:3,handler:3,commerror:1,stage_boot:1,rfmessag:1,relai:1,x02:1,obj:3,line:1,cach:1,serialdevic:1,must:3,none:[1,3],sender:3,retriev:1,provid:1,remov:[1,3],on_alarm:1,dev:1,charact:1,defin:3,"while":1,doc:3,stage_upload:1,error:1,aliv:1,creat:1,process:1,request:1,pid:1,reader:1,repres:1,high:1,packag:[],itself:3,exist:3,ftdi_vendor_id:1,our:1,read_timeout:1,vendor:1,ftdi_product_id:1,attach:1,progress_callback:1,receiv:1,anoth:1,belong:1,when:1,invalid:1,port:1,write:1,handl:1,read:1,which:1,instead:3,you:3,singl:1,product:1,finish:1,firmwar:1,pyftdi:1,expans:1,object:[1,3],ftdi:1,get_config:1,eventhandl:3,data:1,"class":[1,3],serial:1,subpackag:[],classmethod:1,entri:1,alarm:1,well:1,lrrmessag:1,"switch":1,is_reader_al:1,clean:1,invalidmessageerror:1,overs:1},objtypes:{"0":"py:module","1":"py:method","2":"py:attribute","3":"py:class","4":"py:staticmethod","5":"py:exception","6":"py:classmethod"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"],"3":["py","class","Python class"],"4":["py","staticmethod","Python static method"],"5":["py","exception","Python exception"],"6":["py","classmethod","Python class method"]},filenames:["index","pyad2usb","modules","pyad2usb.event"],titles:["Welcome to pyad2usb’s documentation!","pyad2usb Package","pyad2usb","event Package"],objects:{"pyad2usb.devices":{Device:[1,3,1,""],SocketDevice:[1,3,1,""],USBDevice:[1,3,1,""],SerialDevice:[1,3,1,""]},"pyad2usb.util.Firmware":{STAGE_LOAD:[1,2,1,""],upload:[1,4,1,""],STAGE_BOOT:[1,2,1,""],STAGE_START:[1,2,1,""],STAGE_UPLOADING:[1,2,1,""],STAGE_WAITING:[1,2,1,""],STAGE_DONE:[1,2,1,""]},"pyad2usb.devices.SerialDevice":{write:[1,1,1,""],BAUDRATE:[1,2,1,""],read:[1,1,1,""],read_line:[1,1,1,""],find_all:[1,4,1,""],close:[1,1,1,""],open:[1,1,1,""]},"pyad2usb.ad2usb.Overseer.DetectThread":{run:[1,1,1,""],stop:[1,1,1,""]},"pyad2usb.devices.Device":{on_open:[1,2,1,""],on_write:[1,2,1,""],ReadThread:[1,3,1,""],on_close:[1,2,1,""],on_read:[1,2,1,""],stop_reader:[1,1,1,""],is_reader_alive:[1,1,1,""],id:[1,2,1,""]},pyad2usb:{util:[1,0,1,""],"__init__":[1,0,1,""],ad2usb:[1,0,1,""],devices:[1,0,1,""],event:[3,0,1,""]},"pyad2usb.ad2usb":{RFMessage:[1,3,1,""],LRRMessage:[1,3,1,""],ExpanderMessage:[1,3,1,""],Overseer:[1,3,1,""],Message:[1,3,1,""],AD2USB:[1,3,1,""]},"pyad2usb.event":{event:[3,0,1,""]},"pyad2usb.devices.Device.ReadThread":{READ_TIMEOUT:[1,2,1,""],run:[1,1,1,""],stop:[1,1,1,""]},"pyad2usb.util":{CommError:[1,5,1,""],Firmware:[1,3,1,""],TimeoutError:[1,5,1,""],NoDeviceError:[1,5,1,""],InvalidMessageError:[1,5,1,""]},"pyad2usb.ad2usb.AD2USB":{on_power_changed:[1,2,1,""],F1:[1,2,1,""],F2:[1,2,1,""],F3:[1,2,1,""],F4:[1,2,1,""],on_message:[1,2,1,""],on_config_received:[1,2,1,""],on_open:[1,2,1,""],on_status_changed:[1,2,1,""],on_alarm:[1,2,1,""],get_config:[1,1,1,""],set_config:[1,1,1,""],on_close:[1,2,1,""],on_bypass:[1,2,1,""],reboot:[1,1,1,""],on_boot:[1,2,1,""],on_write:[1,2,1,""],close:[1,1,1,""],on_read:[1,2,1,""],open:[1,1,1,""],id:[1,2,1,""]},"pyad2usb.ad2usb.ExpanderMessage":{RELAY:[1,2,1,""],ZONE:[1,2,1,""]},"pyad2usb.event.event.EventHandler":{fire:[3,1,1,""],add:[3,1,1,""],remove:[3,1,1,""]},"pyad2usb.event.event":{EventHandler:[3,3,1,""],Event:[3,3,1,""]},"pyad2usb.ad2usb.Overseer":{on_attached:[1,2,1,""],get_device:[1,1,1,""],DetectThread:[1,3,1,""],create:[1,6,1,""],stop:[1,1,1,""],devices:[1,6,1,""],on_detached:[1,2,1,""],start:[1,1,1,""],find_all:[1,6,1,""],close:[1,1,1,""]},"pyad2usb.devices.SocketDevice":{read_line:[1,1,1,""],read:[1,1,1,""],write:[1,1,1,""],open:[1,1,1,""],close:[1,1,1,""]},"pyad2usb.devices.USBDevice":{read_line:[1,1,1,""],BAUDRATE:[1,2,1,""],read:[1,1,1,""],write:[1,1,1,""],find_all:[1,4,1,""],FTDI_VENDOR_ID:[1,2,1,""],close:[1,1,1,""],FTDI_PRODUCT_ID:[1,2,1,""],open:[1,1,1,""]}},titleterms:{subpackag:1,welcom:0,pyad2usb:[0,1,2],devic:1,indic:0,event:3,util:1,packag:[1,3],tabl:0,modul:[1,3],document:0,ad2usb:1}}) \ No newline at end of file +Search.setIndex({envversion:42,terms:{represent:1,all:[1,3],socketdevic:1,func:3,boot:1,sent:1,disarm:1,arm:1,scott:[],on_boot:1,stage_don:1,simulate_wire_problem:1,vari:1,paramet:1,current:1,baudrat:1,locat:1,zone:1,on_disarm:1,configur:1,except:1,should:1,on_attach:1,whether:1,add:3,present:1,bypass:1,x03:1,on_read:1,x01:1,match:1,x04:1,sourc:[1,3],"return":1,string:1,clear_zon:1,format:1,read:1,on_messag:1,stop:1,util:[],on_bypass:1,automat:1,"new":3,report:1,detach:1,name:1,like:3,level:1,earg:3,list:1,upload:1,method:1,"try":1,emul:1,stage_wait:1,timeout:1,contain:1,found:1,expandermessag:1,page:0,set:1,detect:1,nodeviceerror:1,on_open:1,creation:1,on_pan:1,"static":1,connect:1,fire_timeout:1,close:1,read_lin:1,event:[],stop_read:1,firmwar:1,pyseri:1,index:[0,1],statu:1,wire:1,parent:1,defin:3,pattern:1,ad2seri:1,reboot:1,callback:1,content:0,buffer:1,written:1,com:[],between:1,progress:1,factori:1,localhost:1,ser2sock:1,shut:1,full:1,run:1,timeouterror:1,power:1,detached_ev:1,gener:1,usbdevic:1,lrr:1,on_clos:1,base:[1,3],on_config_receiv:1,depend:1,"byte":1,on_status_chang:[],on_detach:1,panel:[],search:[0,1],actual:1,expos:1,thread:1,fault:1,fixm:1,through:1,set_config:[],stage_start:1,provide4:1,"int":1,get_config:1,aliv:1,fals:1,chang:[],find_al:1,ad2usb:[],first:1,oper:3,revert:1,rang:1,via:1,vid:1,attached_ev:1,modul:[],"float":1,number:1,zonetrack:[],fault_zon:1,down:1,filenam:1,alreadi:1,"long":1,famili:1,batteri:1,on_writ:1,open:1,on_power_chang:1,kei:1,identif:1,differ:1,from:1,usb:1,messag:[],commun:1,detectthread:1,support:1,devic:[],system:1,been:1,get_devic:1,trigger:1,call:[1,3],low:1,handl:1,interfac:1,stage_upload:1,type:1,start:1,"function":[1,3],wrapper:1,no_reader_thread:1,stage_load:1,fire:[1,3],handler:3,commerror:1,specifi:1,stage_boot:1,rfmessag:1,serial:1,relai:1,x02:1,obj:3,line:1,on_fir:1,cach:1,serialdevic:1,must:3,descript:1,on_zone_restor:1,none:[1,3],sender:3,retriev:1,describ:1,on_restor:1,restor:1,provid:1,remov:[1,3],purg:1,on_alarm:1,dev:1,charact:1,purge_buff:1,"while":1,can:[1,3],str:1,doc:3,petersen:[],clear:1,radio:1,expir:1,creat:1,process:1,request:1,save_config:1,pid:1,reader:1,templat:1,repres:1,high:1,packag:[],on_fault:1,itself:3,exist:3,readthread:1,ftdi_vendor_id:1,our:1,read_timeout:1,vendor:1,ftdi_product_id:1,simul:1,attach:1,around:1,progress_callback:1,moduleauthor:[],prior:1,receiv:1,anoth:1,belong:1,when:1,"switch":1,invalid:1,port:1,write:1,also:3,bool:1,on_zone_fault:1,tupl:1,instead:3,you:3,probabl:1,panic:1,singl:1,updat:1,status:1,product:1,finish:1,recogn:1,hostnam:1,"default":1,pyftdi:1,expans:1,object:[1,3],unus:1,ftdi:1,befor:1,rais:1,track:1,battery_timeout:1,on_arm:1,eventhandl:3,data:1,"class":[1,3],expand:1,nutech:[],subpackag:[],classmethod:1,entri:1,alarm:1,well:1,issu:1,lrrmessag:1,which:1,is_reader_al:1,on_lrr_messag:1,error:1,clean:1,check:1,invalidmessageerror:1,overs:1,on_low_batteri:1},objtypes:{"0":"py:module","1":"py:attribute","2":"py:method","3":"py:class","4":"py:staticmethod","5":"py:exception","6":"py:classmethod"},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","method","Python method"],"3":["py","class","Python class"],"4":["py","staticmethod","Python static method"],"5":["py","exception","Python exception"],"6":["py","classmethod","Python class method"]},filenames:["index","pyad2usb","modules","pyad2usb.event"],titles:["Welcome to pyad2usb’s documentation!","pyad2usb Package","pyad2usb","event Package"],objects:{"pyad2usb.devices":{Device:[1,3,1,""],SocketDevice:[1,3,1,""],USBDevice:[1,3,1,""],SerialDevice:[1,3,1,""]},"pyad2usb.util.Firmware":{STAGE_LOAD:[1,1,1,""],upload:[1,4,1,""],STAGE_BOOT:[1,1,1,""],STAGE_START:[1,1,1,""],STAGE_UPLOADING:[1,1,1,""],STAGE_WAITING:[1,1,1,""],STAGE_DONE:[1,1,1,""]},"pyad2usb.zonetracking":{Zonetracker:[1,3,1,""],Zone:[1,3,1,""]},"pyad2usb.devices.SerialDevice":{write:[1,2,1,""],BAUDRATE:[1,1,1,""],read:[1,2,1,""],read_line:[1,2,1,""],find_all:[1,4,1,""],close:[1,2,1,""],open:[1,2,1,""]},"pyad2usb.zonetracking.Zonetracker":{on_restore:[1,1,1,""],EXPIRE:[1,1,1,""],update:[1,2,1,""],on_fault:[1,1,1,""]},"pyad2usb.ad2usb.Overseer.DetectThread":{run:[1,2,1,""],stop:[1,2,1,""]},"pyad2usb.devices.Device":{on_open:[1,1,1,""],on_write:[1,1,1,""],ReadThread:[1,3,1,""],on_close:[1,1,1,""],on_read:[1,1,1,""],stop_reader:[1,2,1,""],is_reader_alive:[1,2,1,""],id:[1,1,1,""]},pyad2usb:{zonetracking:[1,0,1,""],messages:[1,0,1,""],devices:[1,0,1,""],ad2usb:[1,0,1,""],util:[1,0,1,""],panels:[1,0,1,""],event:[3,0,1,""]},"pyad2usb.ad2usb":{AD2USB:[1,3,1,""],Overseer:[1,3,1,""]},"pyad2usb.messages":{Message:[1,3,1,""],RFMessage:[1,3,1,""],ExpanderMessage:[1,3,1,""],LRRMessage:[1,3,1,""]},"pyad2usb.event":{event:[3,0,1,""]},"pyad2usb.devices.Device.ReadThread":{READ_TIMEOUT:[1,1,1,""],run:[1,2,1,""],stop:[1,2,1,""]},"pyad2usb.util":{CommError:[1,5,1,""],Firmware:[1,3,1,""],TimeoutError:[1,5,1,""],NoDeviceError:[1,5,1,""],InvalidMessageError:[1,5,1,""]},"pyad2usb.ad2usb.AD2USB":{fault_zone:[1,2,1,""],on_open:[1,1,1,""],save_config:[1,2,1,""],on_boot:[1,1,1,""],close:[1,2,1,""],open:[1,2,1,""],id:[1,1,1,""],on_power_changed:[1,1,1,""],BATTERY_TIMEOUT:[1,1,1,""],on_message:[1,1,1,""],reboot:[1,2,1,""],get_config:[1,2,1,""],on_zone_restore:[1,1,1,""],on_disarm:[1,1,1,""],on_fire:[1,1,1,""],on_write:[1,1,1,""],on_read:[1,1,1,""],on_lrr_message:[1,1,1,""],clear_zone:[1,2,1,""],on_zone_fault:[1,1,1,""],on_config_received:[1,1,1,""],on_close:[1,1,1,""],on_panic:[1,1,1,""],on_low_battery:[1,1,1,""],on_arm:[1,1,1,""],F1:[1,1,1,""],F2:[1,1,1,""],F3:[1,1,1,""],F4:[1,1,1,""],on_alarm:[1,1,1,""],on_bypass:[1,1,1,""],FIRE_TIMEOUT:[1,1,1,""]},"pyad2usb.messages.ExpanderMessage":{ZONE:[1,1,1,""],RELAY:[1,1,1,""]},"pyad2usb.event.event.EventHandler":{fire:[3,2,1,""],add:[3,2,1,""],remove:[3,2,1,""]},"pyad2usb.event.event":{EventHandler:[3,3,1,""],Event:[3,3,1,""]},"pyad2usb.ad2usb.Overseer":{on_attached:[1,1,1,""],get_device:[1,2,1,""],DetectThread:[1,3,1,""],create:[1,6,1,""],stop:[1,2,1,""],devices:[1,6,1,""],on_detached:[1,1,1,""],start:[1,2,1,""],find_all:[1,6,1,""],close:[1,2,1,""]},"pyad2usb.zonetracking.Zone":{STATUS:[1,1,1,""],FAULT:[1,1,1,""],CLEAR:[1,1,1,""],CHECK:[1,1,1,""]},"pyad2usb.devices.SocketDevice":{read_line:[1,2,1,""],read:[1,2,1,""],write:[1,2,1,""],open:[1,2,1,""],close:[1,2,1,""]},"pyad2usb.devices.USBDevice":{read_line:[1,2,1,""],BAUDRATE:[1,1,1,""],read:[1,2,1,""],write:[1,2,1,""],find_all:[1,4,1,""],FTDI_VENDOR_ID:[1,1,1,""],close:[1,2,1,""],FTDI_PRODUCT_ID:[1,1,1,""],open:[1,2,1,""]}},titleterms:{subpackag:1,welcom:0,pyad2usb:[0,1,2],devic:1,messag:1,event:3,util:1,packag:[1,3],zonetrack:1,indic:0,tabl:0,modul:[1,3],document:0,ad2usb:1,panel:1}}) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 5bfd805..f92113e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -304,3 +304,5 @@ epub_copyright = u'2013, Author' # If false, no index is generated. #epub_use_index = True + +autodoc_member_order = 'bysource' diff --git a/docs/pyad2usb.rst b/docs/pyad2usb.rst index 08dfd6b..2e8b746 100644 --- a/docs/pyad2usb.rst +++ b/docs/pyad2usb.rst @@ -1,14 +1,6 @@ pyad2usb Package ================ -:mod:`pyad2usb` Package ------------------------ - -.. automodule:: pyad2usb.__init__ - :members: - :undoc-members: - :show-inheritance: - :mod:`ad2usb` Module -------------------- @@ -33,6 +25,30 @@ pyad2usb Package :undoc-members: :show-inheritance: +:mod:`zonetracking` Module +-------------------------- + +.. automodule:: pyad2usb.zonetracking + :members: + :undoc-members: + :show-inheritance: + +:mod:`panels` Module +-------------------- + +.. automodule:: pyad2usb.panels + :members: + :undoc-members: + :show-inheritance: + +:mod:`messages` Module +---------------------- + +.. automodule:: pyad2usb.messages + :members: + :undoc-members: + :show-inheritance: + Subpackages ----------- diff --git a/pyad2usb/__init__.py b/pyad2usb/__init__.py index 6937a83..4db13b1 100644 --- a/pyad2usb/__init__.py +++ b/pyad2usb/__init__.py @@ -1,5 +1 @@ -""" -The PyAD2USB module. -""" - __all__ = ['ad2usb', 'devices', 'util'] diff --git a/pyad2usb/ad2usb.py b/pyad2usb/ad2usb.py index ea6c717..617645a 100644 --- a/pyad2usb/ad2usb.py +++ b/pyad2usb/ad2usb.py @@ -1,5 +1,9 @@ """ + Provides the full AD2USB class and factory. + +.. moduleauthor:: Scott Petersen + """ import time @@ -28,6 +32,9 @@ class Overseer(object): def find_all(cls): """ Returns all AD2USB devices located on the system. + + :returns: list of devices found + :raises: util.CommError """ cls.__devices = devices.USBDevice.find_all() @@ -37,6 +44,8 @@ class Overseer(object): def devices(cls): """ Returns a cached list of AD2USB devices located on the system. + + :returns: cached list of devices found. """ return cls.__devices @@ -44,6 +53,12 @@ class Overseer(object): def create(cls, device=None): """ Factory method that returns the requested AD2USB device, or the first device. + + :param device: Tuple describing the USB device to open, as returned by find_all(). + :type device: tuple + + :returns: AD2USB object utilizing the specified device. + :raises: util.NoDeviceError """ cls.find_all() @@ -61,6 +76,11 @@ class Overseer(object): def __init__(self, attached_event=None, detached_event=None): """ Constructor + + :param attached_event: Event to trigger when a device is attached. + :type attached_event: function + :param detached_event: Event to trigger when a device is detached. + :type detached_event: function """ self._detect_thread = Overseer.DetectThread(self) @@ -96,6 +116,9 @@ class Overseer(object): def get_device(self, device=None): """ Factory method that returns the requested AD2USB device, or the first device. + + :param device: Tuple describing the USB device to open, as returned by find_all(). + :type device: tuple """ return Overseer.create(device) @@ -106,6 +129,9 @@ class Overseer(object): def __init__(self, overseer): """ Constructor + + :param overseer: Overseer object to use with the thread. + :type overseer: Overseer """ threading.Thread.__init__(self) @@ -178,16 +204,25 @@ class AD2USB(object): # Constants F1 = unichr(1) + unichr(1) + unichr(1) + """Represents panel function key #1""" F2 = unichr(2) + unichr(2) + unichr(2) + """Represents panel function key #2""" F3 = unichr(3) + unichr(3) + unichr(3) + """Represents panel function key #3""" F4 = unichr(4) + unichr(4) + unichr(4) + """Represents panel function key #4""" BATTERY_TIMEOUT = 30 + """Timeout before the battery status reverts.""" FIRE_TIMEOUT = 30 + """Timeout before the fire status reverts.""" def __init__(self, device): """ Constructor + + :param device: The low-level device used for this AD2USB interface. + :type device: devices.Device """ self._device = device self._zonetracker = zonetracking.Zonetracker() @@ -212,12 +247,23 @@ class AD2USB(object): def id(self): """ The ID of the AD2USB device. + + :returns: The identification string for the device. """ return self._device.id def open(self, baudrate=None, interface=None, index=None, no_reader_thread=False): """ Opens the device. + + :param baudrate: The baudrate used for the device. + :type baudrate: int + :param interface: The interface used for the device. + :type interface: varies depends on device type.. FIXME + :param index: Interface index.. can probably remove. FIXME + :type index: int + :param no_reader_thread: Specifies whether or not the automatic reader thread should be started or not + :type no_reader_thread: bool """ self._wire_events() self._device.open(baudrate=baudrate, interface=interface, index=index, no_reader_thread=no_reader_thread) @@ -274,6 +320,11 @@ class AD2USB(object): def fault_zone(self, zone, simulate_wire_problem=False): """ Faults a zone if we are emulating a zone expander. + + :param zone: The zone to fault. + :type zone: int + :param simulate_wire_problem: Whether or not to simulate a wire fault. + :type simulate_wire_problem: bool """ # Allow ourselves to also be passed an address/channel combination # for zone expanders. @@ -289,6 +340,9 @@ class AD2USB(object): def clear_zone(self, zone): """ Clears a zone if we are emulating a zone expander. + + :param zone: The zone to clear. + :type zone: int """ self._device.write("L{0:02}0\r".format(zone)) @@ -306,6 +360,11 @@ class AD2USB(object): def _handle_message(self, data): """ Parses messages from the panel. + + :param data: Panel data to parse. + :type data: str + + :returns: An object representing the message. """ if data is None: return None @@ -338,6 +397,11 @@ class AD2USB(object): def _handle_lrr(self, data): """ Handle Long Range Radio messages. + + :param data: LRR message to parse. + :type data: str + + :returns: An object representing the LRR message. """ msg = messages.LRRMessage(data) @@ -358,6 +422,9 @@ class AD2USB(object): def _handle_config(self, data): """ Handles received configuration data. + + :param data: Configuration string to parse. + :type data: str """ _, config_string = data.split('>') for setting in config_string.split('&'): @@ -385,6 +452,9 @@ class AD2USB(object): def _update_internal_states(self, message): """ Updates internal device states. + + :param message: Message to update internal states with. + :type message: Message, ExpanderMessage, LRRMessage, or RFMessage """ if isinstance(message, messages.Message): if message.ac_power != self._power_status: @@ -447,6 +517,9 @@ class AD2USB(object): def _update_zone_tracker(self, message): """ Trigger an update of the zonetracker. + + :param message: The message to update the zonetracker with. + :type message: Message, ExpanderMessage, LRRMessage, or RFMessage """ # Retrieve a list of faults. diff --git a/pyad2usb/devices.py b/pyad2usb/devices.py index 458c9b1..897896a 100644 --- a/pyad2usb/devices.py +++ b/pyad2usb/devices.py @@ -1,5 +1,7 @@ """ Contains different types of devices belonging to the AD2USB family. + +.. moduleauthor:: Scott Petersen """ import usb.core @@ -40,6 +42,8 @@ class Device(object): def id(self): """ Retrieve the device ID. + + :returns: The identification string for the device. """ return self._id @@ -47,12 +51,17 @@ class Device(object): def id(self, value): """ Sets the device ID. + + :param value: The device identification. + :type value: str """ self._id = value def is_reader_alive(self): """ Indicates whether or not the reader thread is alive. + + :returns: Whether or not the reader thread is alive. """ return self._read_thread.is_alive() @@ -68,10 +77,14 @@ class Device(object): """ READ_TIMEOUT = 10 + """Timeout for the reader thread.""" def __init__(self, device): """ Constructor + + :param device: The device used by the reader thread. + :type device: devices.Device """ threading.Thread.__init__(self) self._device = device @@ -105,13 +118,19 @@ class USBDevice(Device): # Constants FTDI_VENDOR_ID = 0x0403 + """Vendor ID used to recognize AD2USB devices.""" FTDI_PRODUCT_ID = 0x6001 + """Product ID used to recognize AD2USB devices.""" BAUDRATE = 115200 + """Default baudrate for AD2USB devices.""" @staticmethod def find_all(): """ Returns all FTDI devices matching our vendor and product IDs. + + :returns: list of devices + :raises: util.CommError """ devices = [] @@ -126,6 +145,17 @@ class USBDevice(Device): def __init__(self, vid=FTDI_VENDOR_ID, pid=FTDI_PRODUCT_ID, serial=None, description=None, interface=0): """ Constructor + + :param vid: Vendor ID + :type vid: int + :param pid: Product ID + :type pid: int + :param serial: The serial number + :type serial: str + :param description: Description of the device. + :type description: str + :param interface: The interface to use + :type interface: int """ Device.__init__(self) @@ -139,6 +169,15 @@ class USBDevice(Device): def open(self, baudrate=BAUDRATE, interface=None, index=0, no_reader_thread=False): """ Opens the device. + + :param baudrate: The baudrate to use. + :type baudrate: int + :param interface: The interface to use. + :type interface: int + :param no_reader_thread: Whether or not to automatically start the reader thread. + :type no_reader_thread: bool + + :raises: util.NoDeviceError """ # Set up defaults if baudrate is None: @@ -197,6 +236,11 @@ class USBDevice(Device): def write(self, data): """ Writes data to the device. + + :param data: Data to write + :type data: str + + :raises: util.CommError """ try: self._device.write_data(data) @@ -208,6 +252,9 @@ class USBDevice(Device): def read(self): """ Reads a single character from the device. + + :returns: The character read from the device. + :raises: util.CommError """ ret = None @@ -222,6 +269,14 @@ class USBDevice(Device): def read_line(self, timeout=0.0, purge_buffer=False): """ Reads a line from the device. + + :param timeout: Read timeout + :type timeout: float + :param purge_buffer: Indicates whether to purge the buffer prior to reading. + :type purge_buffer: bool + + :returns: The line that was read. + :raises: util.CommError, util.TimeoutError """ if purge_buffer: @@ -287,11 +342,18 @@ class SerialDevice(Device): # Constants BAUDRATE = 19200 + """Default baudrate for Serial devices.""" @staticmethod def find_all(pattern=None): """ Returns all serial ports present. + + :param pattern: Pattern to search for when retrieving serial ports. + :type pattern: str + + :returns: list of devices + :raises: util.CommError """ devices = [] @@ -309,6 +371,9 @@ class SerialDevice(Device): def __init__(self, interface=None): """ Constructor + + :param interface: The device to open. + :type interface: str """ Device.__init__(self) @@ -319,6 +384,17 @@ class SerialDevice(Device): def open(self, baudrate=BAUDRATE, interface=None, index=None, no_reader_thread=False): """ Opens the device. + + :param baudrate: The baudrate to use with the device. + :type baudrate: int + :param interface: The device to open. + :type interface: str + :param index: Unused. + :type index: int + :param no_reader_thread: Whether or not to automatically start the reader thread. + :type no_reader_thread: bool + + :raises: util.NoDeviceError """ # Set up the defaults if baudrate is None: @@ -370,6 +446,11 @@ class SerialDevice(Device): def write(self, data): """ Writes data to the device. + + :param data: The data to write. + :type data: str + + :raises: util.CommError """ try: self._device.write(data) @@ -386,6 +467,9 @@ class SerialDevice(Device): def read(self): """ Reads a single character from the device. + + :returns: The character read from the device. + :raises: util.CommError """ ret = None @@ -400,6 +484,14 @@ class SerialDevice(Device): def read_line(self, timeout=0.0, purge_buffer=False): """ Reads a line from the device. + + :param timeout: The read timeout. + :type timeout: float + :param purge_buffer: Indicates whether to purge the buffer prior to reading. + :type purge_buffer: bool + + :returns: The line read. + :raises: util.CommError, util.TimeoutError """ def timeout_event(): timeout_event.reading = False @@ -471,6 +563,17 @@ class SocketDevice(Device): def open(self, baudrate=None, interface=None, index=0, no_reader_thread=False): """ Opens the device. + + :param baudrate: The baudrate to use + :type baudrate: int + :param interface: The hostname and port to connect to. + :type interface: tuple + :param index: Unused + :type index: int + :param no_reader_thread: Whether or not to automatically open the reader thread. + :type no_reader_thread: bool + + :raises: util.NoDeviceError """ if interface is not None: self._interface = interface @@ -512,6 +615,12 @@ class SocketDevice(Device): def write(self, data): """ Writes data to the device. + + :param data: The data to write. + :type data: str + + :returns: The number of bytes sent. + :raises: util.CommError """ data_sent = None @@ -531,6 +640,9 @@ class SocketDevice(Device): def read(self): """ Reads a single character from the device. + + :returns: The character read from the device. + :raises: util.CommError """ data = None @@ -545,6 +657,14 @@ class SocketDevice(Device): def read_line(self, timeout=0.0, purge_buffer=False): """ Reads a line from the device. + + :param timeout: The read timeout. + :type timeout: float + :param purge_buffer: Indicates whether to purge the buffer prior to reading. + :type purge_buffer: bool + + :returns: The line read from the device. + :raises: util.CommError, util.TimeoutError """ if purge_buffer: diff --git a/pyad2usb/messages.py b/pyad2usb/messages.py index 86e6e54..e5f4ca8 100644 --- a/pyad2usb/messages.py +++ b/pyad2usb/messages.py @@ -12,6 +12,9 @@ class Message(object): def __init__(self, data=None): """ Constructor + + :param data: Message data to parse. + :type data: str """ self.ready = False self.armed_away = False @@ -45,6 +48,11 @@ class Message(object): def _parse_message(self, data): """ Parse the message from the device. + + :param data: The message data. + :type data: str + + :raises: util.InvalidMessageError """ m = self._regex.match(data) @@ -94,6 +102,9 @@ class ExpanderMessage(object): def __init__(self, data=None): """ Constructor + + :param data: The message data to parse. + :type data: str """ self.type = None self.address = None @@ -119,6 +130,9 @@ class ExpanderMessage(object): def _parse_message(self, data): """ Parse the raw message from the device. + + :param data: The message data + :type data: str """ header, values = data.split(':') address, channel, value = values.split(',') @@ -141,6 +155,9 @@ class RFMessage(object): def __init__(self, data=None): """ Constructor + + :param data: The message data to parse + :type data: str """ self.raw = None self.serial_number = None @@ -158,6 +175,9 @@ class RFMessage(object): def _parse_message(self, data): """ Parses the raw message from the device. + + :param data: The message data. + :type data: str """ self.raw = data @@ -172,6 +192,9 @@ class LRRMessage(object): def __init__(self, data=None): """ Constructor + + :param data: The message data to parse. + :type data: str """ self.raw = None self._event_data = None @@ -190,6 +213,9 @@ class LRRMessage(object): def _parse_message(self, data): """ Parses the raw message from the device. + + :param data: The message data. + :type data: str """ self.raw = data diff --git a/pyad2usb/util.py b/pyad2usb/util.py index 4e55a4e..5f6aa83 100644 --- a/pyad2usb/util.py +++ b/pyad2usb/util.py @@ -48,6 +48,13 @@ class Firmware(object): def upload(dev, filename, progress_callback=None): """ Uploads firmware to an AD2USB/AD2SERIAL device. + + :param filename: The firmware filename + :type filename: str + :param progress_callback: Callback function used to report progress. + :type progress_callback: function + + :raises: util.NoDeviceError, util.TimeoutError """ def do_upload(): diff --git a/pyad2usb/zonetracking.py b/pyad2usb/zonetracking.py index 3878658..45d3224 100644 --- a/pyad2usb/zonetracking.py +++ b/pyad2usb/zonetracking.py @@ -12,21 +12,40 @@ class Zone(object): """ CLEAR = 0 + """Status indicating that the zone is cleared.""" FAULT = 1 + """Status indicating that the zone is faulted.""" CHECK = 2 # Wire fault + """Status indicating that there is a wiring issue with the zone.""" STATUS = { CLEAR: 'CLEAR', FAULT: 'FAULT', CHECK: 'CHECK' } def __init__(self, zone=0, name='', status=CLEAR): + """ + Constructor + + :param zone: The zone number. + :type zone: int + :param name: Human readable zone name. + :type name: str + :param status: Initial zone state. + :type status: int + """ self.zone = zone self.name = name self.status = status self.timestamp = time.time() def __str__(self): + """ + String conversion operator. + """ return 'Zone {0} {1}'.format(self.zone, self.name) def __repr__(self): + """ + Human readable representation operator. + """ return 'Zone({0}, {1}, ts {2})'.format(self.zone, Zone.STATUS[self.status], self.timestamp) class Zonetracker(object): @@ -38,6 +57,7 @@ class Zonetracker(object): on_restore = event.Event('Called when the device detects that a fault is restored.') EXPIRE = 30 + """Zone expiration timeout.""" def __init__(self): """ @@ -50,6 +70,9 @@ class Zonetracker(object): def update(self, message): """ Update zone statuses based on the current message. + + :param message: Message to use to update the zone tracking. + :type message: Message or ExpanderMessage """ zone = -1 @@ -107,6 +130,9 @@ class Zonetracker(object): def _clear_zones(self, zone): """ Clear all expired zones from our status list. + + :param zone: current zone being processed. + :type zone: int """ cleared_zones = [] found_last = found_new = at_end = False @@ -177,6 +203,13 @@ class Zonetracker(object): def _add_zone(self, zone, name='', status=Zone.CLEAR): """ Adds a zone to the internal zone list. + + :param zone: The zone number. + :type zone: int + :param name: Human readable zone name. + :type name: str + :param status: The zone status. + :type status: int """ if not zone in self._zones: self._zones[zone] = Zone(zone=zone, name=name, status=status) @@ -187,6 +220,13 @@ class Zonetracker(object): def _update_zone(self, zone, status=None): """ Updates a zones status. + + :param zone: The zone number. + :type zone: int + :param status: The zone status. + :type status: int + + :raises: IndexError """ if not zone in self._zones: raise IndexError('Zone does not exist and cannot be updated: %d', zone) @@ -205,6 +245,11 @@ class Zonetracker(object): def _zone_expired(self, zone): """ Determine if a zone is expired or not. + + :param zone: The zone number. + :type zone: int + + :returns: Whether or not the zone is expired. """ if time.time() > self._zones[zone].timestamp + Zonetracker.EXPIRE: return True @@ -214,6 +259,13 @@ class Zonetracker(object): def _expander_to_zone(self, address, channel): """ Convert an address and channel into a zone number. + + :param address: The expander address + :type address: int + :param channel: The channel + :type channel: int + + :returns: The zone number associated with an address and channel. """ # TODO: This is going to need to be reworked to support the larger