fixes to polling receiver/device status

This commit is contained in:
Daniel Pavel 2013-06-08 16:16:12 +02:00
parent 2e351bfc78
commit ed5ce48f65
3 changed files with 49 additions and 18 deletions

View File

@ -40,6 +40,7 @@ class _ThreadedHandle(object):
self._listener = listener
self.path = path
self._local = _threading.local()
# take over the current handle for the thread doing the replacement
self._local.handle = handle
self._handles = [handle]
@ -104,7 +105,8 @@ class _ThreadedHandle(object):
_EVENT_READ_TIMEOUT = 500
# After this many reads that did not produce a packet, call the tick() method.
_IDLE_READS = 4
# This only happens if tick_period is enabled (>0) for the Listener instance.
_IDLE_READS = 5
class EventsListener(_threading.Thread):
@ -113,7 +115,7 @@ class EventsListener(_threading.Thread):
Incoming packets will be passed to the callback function in sequence.
"""
def __init__(self, receiver, notifications_callback):
super(EventsListener, self).__init__(name=self.__class__.__name__)
super(EventsListener, self).__init__(name=self.__class__.__name__ + ':' + receiver.path)
self.daemon = True
self._active = False
@ -128,14 +130,17 @@ class EventsListener(_threading.Thread):
self._active = True
# replace the handle with a threaded one
ihandle = int(self.receiver.handle)
self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle)
# get the right low-level handle for this thead
ihandle = int(self.receiver.handle)
_log.info("started with %s (%d)", self.receiver, ihandle)
self.has_started()
last_tick = 0
idle_reads = _IDLE_READS * 10
# the first idle read -- delay it a bit, and make sure to stagger
# idle reads for multiple receivers
idle_reads = _IDLE_READS + (ihandle % 3) * 2
while self._active:
if self._queued_notifications.empty():

View File

@ -79,6 +79,16 @@ class ReceiverStatus(dict):
# self.updated = _timestamp()
self._changed_callback(self._receiver, alert=alert, reason=reason)
def poll(self, timestamp):
r = self._receiver
assert r
if _log.isEnabledFor(_DEBUG):
_log.debug("polling status of %s", r)
# make sure to read some stuff that may be read later by the UI
r.serial, r.firmware, None
def process_notification(self, n):
if n.sub_id == 0x4A:
self.lock_open = bool(n.address & 0x01)
@ -227,16 +237,16 @@ class DeviceStatus(dict):
if _log.isEnabledFor(_DEBUG):
_log.debug("polling status of %s", d)
# read these from the device in case they haven't been read already
d.protocol, d.serial, d.firmware
# read these from the device, the UI may need them later
d.protocol, d.firmware, d.kind, d.name, d.settings, None
# make sure we know all the features of the device
# if d.features:
# d.features[:]
if BATTERY_LEVEL not in self:
self.read_battery(timestamp)
# make sure we know all the features of the device
if d.features:
d.features[:]
elif len(self) > 0 and timestamp - self.updated > _STATUS_TIMEOUT:
# if the device has been inactive for too long, clear out any known
# properties, they are most likely obsolete anyway

View File

@ -32,7 +32,7 @@ def _ghost(device):
# how often to poll devices that haven't updated their statuses on their own
# (through notifications)
_POLL_TICK = 100 # seconds
_POLL_TICK = 3 * 60 # seconds
class ReceiverListener(_listener.EventsListener):
@ -41,7 +41,7 @@ class ReceiverListener(_listener.EventsListener):
def __init__(self, receiver, status_changed_callback):
super(ReceiverListener, self).__init__(receiver, self._notifications_handler)
# no reason to enable polling yet
# self.tick_period = _POLL_TICK
self.tick_period = _POLL_TICK
self._last_tick = 0
assert status_changed_callback
@ -58,7 +58,8 @@ class ReceiverListener(_listener.EventsListener):
r, self.receiver = self.receiver, None
assert r is not None
_log.info("%s: notifications listener has stopped", r)
r.status = 'The device was unplugged.'
r.status = 'The receiver was unplugged.'
if r:
try:
pass
@ -75,8 +76,12 @@ class ReceiverListener(_listener.EventsListener):
# configuration.save()
def tick(self, timestamp):
# if _log.isEnabledFor(_DEBUG):
# _log.debug("%s: polling status: %s", self.receiver, list(iter(self.receiver)))
if not self.tick_period:
raise Exception("tick() should not be called without a tick_period: %s", self)
if not self.receiver:
# just in case the receiver was just removed
return
# not necessary anymore, we're now using udev monitor to watch for receiver status
# if self._last_tick > 0 and timestamp - self._last_tick > _POLL_TICK * 2:
@ -94,9 +99,20 @@ class ReceiverListener(_listener.EventsListener):
# don't mess with stuff while pairing
return
for dev in self.receiver:
if dev.status is not None:
dev.status.poll(timestamp)
self.receiver.status.poll(timestamp)
# Iterating directly through the reciver would unnecessarily probe
# all possible devices, even unpaired ones.
# Checking for each device number in turn makes sure only already
# known devices are polled.
# This is okay because we should have already known about them all
# long before the first poll() happents, through notifications.
for number in range(1, 6):
if number in self.receiver:
dev = self.receiver[number]
assert dev
if dev.status is not None:
dev.status.poll(timestamp)
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
assert device is not None