load the configuration when the device is detected
and apply it every time the device comes online
This commit is contained in:
parent
1d438f098f
commit
8d5718178f
|
@ -33,6 +33,7 @@ class _Setting(object):
|
||||||
self.persister = None
|
self.persister = None
|
||||||
|
|
||||||
def __call__(self, device):
|
def __call__(self, device):
|
||||||
|
assert not hasattr(self, '_value')
|
||||||
o = _copy(self)
|
o = _copy(self)
|
||||||
o._value = None
|
o._value = None
|
||||||
o._device = device # _proxy(device)
|
o._device = device # _proxy(device)
|
||||||
|
@ -43,12 +44,15 @@ class _Setting(object):
|
||||||
return self._validator.choices if self._validator.kind & KIND.choice else None
|
return self._validator.choices if self._validator.kind & KIND.choice else None
|
||||||
|
|
||||||
def read(self, cached=True):
|
def read(self, cached=True):
|
||||||
|
if self._value is None and self.persister:
|
||||||
|
self._value = self.persister.get(self.name)
|
||||||
|
|
||||||
if cached and self._value is not None:
|
if cached and self._value is not None:
|
||||||
if self.persister and self.name not in self.persister:
|
if self.persister and self.name not in self.persister:
|
||||||
self.persister[self.name] = self._value
|
self.persister[self.name] = self._value
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
if self._device:
|
if self._device.online:
|
||||||
reply = self._rw.read(self._device)
|
reply = self._rw.read(self._device)
|
||||||
if reply:
|
if reply:
|
||||||
self._value = self._validator.validate_read(reply)
|
self._value = self._validator.validate_read(reply)
|
||||||
|
@ -66,6 +70,10 @@ class _Setting(object):
|
||||||
self.persister[self.name] = self._value
|
self.persister[self.name] = self._value
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
if self._value is not None:
|
||||||
|
self.write(self._value)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if hasattr(self, '_value'):
|
if hasattr(self, '_value'):
|
||||||
assert hasattr(self, '_device')
|
assert hasattr(self, '_device')
|
||||||
|
@ -73,6 +81,9 @@ class _Setting(object):
|
||||||
return '<Setting([%s:%s] %s)>' % (self._rw.kind, self._validator.kind, self.name)
|
return '<Setting([%s:%s] %s)>' % (self._rw.kind, self._validator.kind, self.name)
|
||||||
__unicode__ = __repr__ = __str__
|
__unicode__ = __repr__ = __str__
|
||||||
|
|
||||||
|
#
|
||||||
|
# read/write low-level operators
|
||||||
|
#
|
||||||
|
|
||||||
class _RegisterRW(object):
|
class _RegisterRW(object):
|
||||||
__slots__ = ['register']
|
__slots__ = ['register']
|
||||||
|
@ -111,6 +122,10 @@ class _FeatureRW(object):
|
||||||
assert self.feature is not None
|
assert self.feature is not None
|
||||||
return device.feature_request(self.feature, self.write_fnid, data_bytes)
|
return device.feature_request(self.feature, self.write_fnid, data_bytes)
|
||||||
|
|
||||||
|
#
|
||||||
|
# value validators
|
||||||
|
# handle the conversion from read bytes, to setting value, and back
|
||||||
|
#
|
||||||
|
|
||||||
class _BooleanValidator(object):
|
class _BooleanValidator(object):
|
||||||
__slots__ = ['true_value', 'false_value', 'mask', 'write_returns_value']
|
__slots__ = ['true_value', 'false_value', 'mask', 'write_returns_value']
|
||||||
|
@ -118,6 +133,7 @@ class _BooleanValidator(object):
|
||||||
kind = KIND.toggle
|
kind = KIND.toggle
|
||||||
default_true = 0x01
|
default_true = 0x01
|
||||||
default_false = 0x00
|
default_false = 0x00
|
||||||
|
# mask specifies all the affected bits in the value
|
||||||
default_mask = 0xFF
|
default_mask = 0xFF
|
||||||
|
|
||||||
def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask, write_returns_value=False):
|
def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask, write_returns_value=False):
|
||||||
|
@ -191,7 +207,7 @@ class _ChoicesValidator(object):
|
||||||
return self.choices[value]
|
return self.choices[value]
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
# pre-defined basic setting descriptors
|
||||||
#
|
#
|
||||||
|
|
||||||
def register_toggle(name, register,
|
def register_toggle(name, register,
|
||||||
|
|
|
@ -136,9 +136,6 @@ class DeviceStatus(dict):
|
||||||
# timestamp of when this status object was last updated
|
# timestamp of when this status object was last updated
|
||||||
self.updated = 0
|
self.updated = 0
|
||||||
|
|
||||||
# optional object able to persist device settings
|
|
||||||
self.configuration = None
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
def _item(name, format):
|
def _item(name, format):
|
||||||
value = self.get(name)
|
value = self.get(name)
|
||||||
|
@ -242,8 +239,11 @@ class DeviceStatus(dict):
|
||||||
# get cleared when the device is turned off (but not when the device
|
# get cleared when the device is turned off (but not when the device
|
||||||
# goes idle, and we can't tell the difference right now).
|
# goes idle, and we can't tell the difference right now).
|
||||||
self[KEYS.NOTIFICATION_FLAGS] = d.enable_notifications()
|
self[KEYS.NOTIFICATION_FLAGS] = d.enable_notifications()
|
||||||
if self.configuration:
|
|
||||||
self.configuration.attach_to(d)
|
# Devices lose configuration when they are turned off,
|
||||||
|
# make sure they're up-to-date.
|
||||||
|
for s in self._device.settings:
|
||||||
|
s.apply()
|
||||||
else:
|
else:
|
||||||
if was_active:
|
if was_active:
|
||||||
battery = self.get(KEYS.BATTERY_LEVEL)
|
battery = self.get(KEYS.BATTERY_LEVEL)
|
||||||
|
|
|
@ -105,7 +105,3 @@ def attach_to(device):
|
||||||
if s.persister is None:
|
if s.persister is None:
|
||||||
s.persister = persister
|
s.persister = persister
|
||||||
assert s.persister == persister
|
assert s.persister == persister
|
||||||
if s.name in persister:
|
|
||||||
s.write(persister[s.name])
|
|
||||||
else:
|
|
||||||
persister[s.name] = s.read(cached=False)
|
|
||||||
|
|
|
@ -171,8 +171,10 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
|
|
||||||
if not already_known:
|
if not already_known:
|
||||||
_log.info("%s triggered new device %s (%s)", n, dev, dev.kind)
|
_log.info("%s triggered new device %s (%s)", n, dev, dev.kind)
|
||||||
|
# If there are saved configs, bring the device's settings up-to-date.
|
||||||
|
# They will be applied when the device is marked as online.
|
||||||
|
configuration.attach_to(dev)
|
||||||
dev.status = _status.DeviceStatus(dev, self._status_changed)
|
dev.status = _status.DeviceStatus(dev, self._status_changed)
|
||||||
dev.status.configuration = configuration
|
|
||||||
# the receiver changed status as well
|
# the receiver changed status as well
|
||||||
self._status_changed(self.receiver)
|
self._status_changed(self.receiver)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ from gi.repository import Gtk, GLib
|
||||||
from logitech.unifying_receiver import settings as _settings
|
from logitech.unifying_receiver import settings as _settings
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
# a separate thread is used to read/write from the device
|
||||||
|
# so as not to block the main (GUI) thread
|
||||||
#
|
#
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -29,15 +30,16 @@ def _process_apply_queue():
|
||||||
while True:
|
while True:
|
||||||
task = _apply_queue.get()
|
task = _apply_queue.get()
|
||||||
assert isinstance(task, tuple)
|
assert isinstance(task, tuple)
|
||||||
|
device_is_online = True
|
||||||
# print ("task", *task)
|
# print ("task", *task)
|
||||||
if task[0] == 'write':
|
if task[0] == 'write':
|
||||||
_, setting, value, sbox = task
|
_, setting, value, sbox = task
|
||||||
GLib.idle_add(_write_start, sbox, priority=0)
|
GLib.idle_add(_write_start, sbox, priority=0)
|
||||||
value = setting.write(value)
|
value = setting.write(value)
|
||||||
elif task[0] == 'read':
|
elif task[0] == 'read':
|
||||||
_, setting, force_read, sbox = task
|
_, setting, force_read, sbox, device_is_online = task
|
||||||
value = setting.read(not force_read)
|
value = setting.read(not force_read)
|
||||||
GLib.idle_add(_update_setting_item, sbox, value, priority=99)
|
GLib.idle_add(_update_setting_item, sbox, value, device_is_online, priority=99)
|
||||||
|
|
||||||
from threading import Thread as _Thread
|
from threading import Thread as _Thread
|
||||||
_queue_processor = _Thread(name='SettingsProcessor', target=_process_apply_queue)
|
_queue_processor = _Thread(name='SettingsProcessor', target=_process_apply_queue)
|
||||||
|
@ -190,10 +192,7 @@ def update(device, is_online=None):
|
||||||
sbox = _items[k] = _create_sbox(s)
|
sbox = _items[k] = _create_sbox(s)
|
||||||
_box.pack_start(sbox, False, False, 0)
|
_box.pack_start(sbox, False, False, 0)
|
||||||
|
|
||||||
if is_online:
|
_apply_queue.put(('read', s, False, sbox, is_online))
|
||||||
_apply_queue.put(('read', s, False, sbox))
|
|
||||||
else:
|
|
||||||
_update_setting_item(sbox, None, False)
|
|
||||||
|
|
||||||
_box.set_visible(True)
|
_box.set_visible(True)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue