expanded devices database, commented out some unnecessary logging
This commit is contained in:
parent
bc9f39873e
commit
5da2d43b1c
|
@ -18,11 +18,6 @@ from watcher import Watcher
|
|||
APP_TITLE = 'Solaar'
|
||||
|
||||
|
||||
def _notify(status_code, title, text=''):
|
||||
if text:
|
||||
ui.notify.show(status_code, title, text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
arg_parser = argparse.ArgumentParser(prog=APP_TITLE)
|
||||
|
@ -41,7 +36,7 @@ if __name__ == '__main__':
|
|||
|
||||
GObject.threads_init()
|
||||
|
||||
args.notifications = args.notifications and args.systray
|
||||
args.notifications &= args.systray
|
||||
if args.notifications:
|
||||
ui.notify.init(APP_TITLE)
|
||||
|
||||
|
@ -57,7 +52,7 @@ if __name__ == '__main__':
|
|||
if window:
|
||||
GObject.idle_add(ui.window.update, window, rstatus, devices, icon_name)
|
||||
|
||||
watcher = Watcher(_status_changed, _notify if args.notifications else None)
|
||||
watcher = Watcher(_status_changed, ui.notify.show if args.notifications else None)
|
||||
watcher.start()
|
||||
|
||||
window = ui.window.create(APP_TITLE, watcher.rstatus, args.systray)
|
||||
|
|
|
@ -72,7 +72,7 @@ try:
|
|||
n.update(title, text, icon or title)
|
||||
n.timestamp = timestamp()
|
||||
try:
|
||||
logging.debug("showing notification %s", n)
|
||||
# logging.debug("showing notification %s", n)
|
||||
n.show()
|
||||
except Exception:
|
||||
logging.exception("showing notification %s", n)
|
||||
|
|
|
@ -104,7 +104,6 @@ class Watcher(Thread):
|
|||
|
||||
if self.listener:
|
||||
self.listener.stop()
|
||||
api.close(self.listener.receiver)
|
||||
self.listener = None
|
||||
|
||||
def stop(self):
|
||||
|
|
|
@ -9,22 +9,53 @@ from . import constants as C
|
|||
|
||||
from ..unifying_receiver import api as _api
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
_REQUEST_STATUS_FUNCTIONS = {
|
||||
C.NAME.K750: k750.request_status,
|
||||
}
|
||||
|
||||
_PROCESS_EVENT_FUNCTIONS = {
|
||||
C.NAME.K750: k750.process_event,
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def ping(devinfo, listener=None):
|
||||
if listener is None:
|
||||
reply = _api.ping(devinfo.number)
|
||||
elif listener:
|
||||
reply = listener.request(_api.ping, devinfo.number)
|
||||
else:
|
||||
return None
|
||||
|
||||
def ping(devinfo, listener):
|
||||
reply = listener.request(_api.ping, devinfo.number)
|
||||
return C.STATUS.CONNECTED if reply else C.STATUS.UNAVAILABLE
|
||||
|
||||
|
||||
def default_request_status(devinfo, listener):
|
||||
def default_request_status(devinfo, listener=None):
|
||||
if _api.C.FEATURE.BATTERY in devinfo.features:
|
||||
reply = listener.request(_api.get_device_battery_level, devinfo.number, features=devinfo.features)
|
||||
if listener is None:
|
||||
reply = _api.get_device_battery_level(devinfo.handle, devinfo.number, features=devinfo.features)
|
||||
elif listener:
|
||||
reply = listener.request(_api.get_device_battery_level, devinfo.number, features=devinfo.features)
|
||||
else:
|
||||
reply = None
|
||||
|
||||
if reply:
|
||||
discharge, dischargeNext, status = reply
|
||||
return C.STATUS.CONNECTED, {C.PROPS.BATTERY_LEVEL: discharge}
|
||||
|
||||
|
||||
def default_process_event(devinfo, data):
|
||||
def default_process_event(devinfo, data, listener=None):
|
||||
feature_index = ord(data[0:1])
|
||||
if feature_index >= len(devinfo.features):
|
||||
logging.warn("mistery event %s for %s", repr(data), devinfo)
|
||||
return None
|
||||
|
||||
feature = devinfo.features[feature_index]
|
||||
feature_function = ord(data[1:2]) & 0xF0
|
||||
|
||||
|
@ -48,39 +79,27 @@ def default_process_event(devinfo, data):
|
|||
# ?
|
||||
|
||||
|
||||
_REQUEST_STATUS_FUNCTIONS = {
|
||||
k750.NAME: k750.request_status
|
||||
}
|
||||
|
||||
def request_status(devinfo, listener):
|
||||
def request_status(devinfo, listener=None):
|
||||
"""Trigger a status request for a device.
|
||||
|
||||
:param devinfo: the device info tuple.
|
||||
:param listener: the EventsListener that will be used to send the request,
|
||||
and which will receive the status events from the device.
|
||||
"""
|
||||
if listener:
|
||||
if devinfo.name in _REQUEST_STATUS_FUNCTIONS:
|
||||
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener)
|
||||
return default_request_status(devinfo, listener) or ping(devinfo, listener)
|
||||
if devinfo.name in _REQUEST_STATUS_FUNCTIONS:
|
||||
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener)
|
||||
return default_request_status(devinfo, listener) or ping(devinfo, listener)
|
||||
|
||||
|
||||
_PROCESS_EVENT_FUNCTIONS = {
|
||||
k750.NAME: k750.process_event
|
||||
}
|
||||
|
||||
def process_event(devinfo, data):
|
||||
def process_event(devinfo, data, listener=None):
|
||||
"""Process an event received for a device.
|
||||
|
||||
When using an EventsListener, it is assumed this event was received through
|
||||
its callback, where you may call LUR APIs directly.
|
||||
|
||||
:param devinfo: the device info tuple.
|
||||
:param data: the event data (event packet sans the first two bytes: reply code and device number)
|
||||
"""
|
||||
default_result = default_process_event(devinfo, data)
|
||||
default_result = default_process_event(devinfo, data, listener)
|
||||
if default_result is not None:
|
||||
return default_result
|
||||
|
||||
if devinfo.name in _PROCESS_EVENT_FUNCTIONS:
|
||||
return _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, data)
|
||||
return _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, data, listener)
|
||||
|
|
|
@ -24,3 +24,34 @@ PROPS = type('PROPS', (),
|
|||
BATTERY_STATUS='battery_status',
|
||||
LIGHT_LEVEL='light_level',
|
||||
))
|
||||
|
||||
|
||||
NAME = type('NAME', (),
|
||||
dict(
|
||||
M315='Wireless Mouse M315',
|
||||
M325='Wireless Mouse M325',
|
||||
M510='Wireless Mouse M510',
|
||||
M515='Couch Mouse M515',
|
||||
M570='Wireless Trackball M570',
|
||||
K270='Wireless Keyboard K270',
|
||||
K350='Wireless Keyboard K350',
|
||||
K750='Wireless Solar Keyboard K750',
|
||||
K800='Wireless Illuminated Keyboard K800',
|
||||
))
|
||||
|
||||
from ..unifying_receiver.common import FallbackDict
|
||||
|
||||
FULL_NAME = FallbackDict(lambda x: x,
|
||||
dict(
|
||||
M315=NAME.M315,
|
||||
M325=NAME.M325,
|
||||
M510=NAME.M510,
|
||||
M515=NAME.M515,
|
||||
M570=NAME.M570,
|
||||
K270=NAME.K270,
|
||||
K350=NAME.K350,
|
||||
K750=NAME.K750,
|
||||
K800=NAME.K800,
|
||||
))
|
||||
|
||||
del FallbackDict
|
||||
|
|
|
@ -12,18 +12,6 @@ from . import constants as C
|
|||
#
|
||||
#
|
||||
|
||||
NAME = 'Wireless Solar Keyboard K750'
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def _trigger_solar_charge_events(handle, devinfo):
|
||||
return _api.request(handle, devinfo.number,
|
||||
feature=_api.C.FEATURE.SOLAR_CHARGE, function=b'\x03', params=b'\x78\x01',
|
||||
features=devinfo.features)
|
||||
|
||||
|
||||
def _charge_status(data, hasLux=False):
|
||||
charge, lux = _unpack('!BH', data[2:5])
|
||||
|
||||
|
@ -47,16 +35,25 @@ def _charge_status(data, hasLux=False):
|
|||
return 0x10 << charge_index, d
|
||||
|
||||
|
||||
def request_status(devinfo, listener):
|
||||
if listener:
|
||||
def request_status(devinfo, listener=None):
|
||||
def _trigger_solar_charge_events(handle, devinfo):
|
||||
return _api.request(handle, devinfo.number,
|
||||
feature=_api.C.FEATURE.SOLAR_CHARGE, function=b'\x03', params=b'\x78\x01',
|
||||
features=devinfo.features)
|
||||
if listener is None:
|
||||
reply = _trigger_solar_charge_events(devinfo.handle, devinfo)
|
||||
elif listener:
|
||||
reply = listener.request(_trigger_solar_charge_events, devinfo)
|
||||
if reply is None:
|
||||
return C.STATUS.UNAVAILABLE
|
||||
else:
|
||||
reply = 0
|
||||
|
||||
if reply is None:
|
||||
return C.STATUS.UNAVAILABLE
|
||||
|
||||
|
||||
def process_event(devinfo, data):
|
||||
def process_event(devinfo, data, listener=None):
|
||||
if data[:2] == b'\x09\x00' and data[7:11] == b'GOOD':
|
||||
# usually sent after the keyboard is turned on
|
||||
# usually sent after the keyboard is turned on or just connected
|
||||
return _charge_status(data)
|
||||
|
||||
if data[:2] == b'\x09\x10' and data[7:11] == b'GOOD':
|
||||
|
@ -65,9 +62,7 @@ def process_event(devinfo, data):
|
|||
|
||||
if data[:2] == b'\x09\x20' and data[7:11] == b'GOOD':
|
||||
logging.debug("Solar key pressed")
|
||||
if _trigger_solar_charge_events(devinfo.handle, devinfo) is None:
|
||||
return C.STATUS.UNAVAILABLE
|
||||
return _charge_status(data)
|
||||
return request_status(devinfo, listener) or _charge_status(data)
|
||||
|
||||
if data[:2] == b'\x05\x00':
|
||||
# wireless device status
|
||||
|
|
|
@ -254,7 +254,7 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None
|
|||
|
||||
if reply_devnumber != devnumber:
|
||||
# this message not for the device we're interested in
|
||||
_l.log(_LOG_LEVEL, "(%d) request got reply for unexpected device %d: [%s]", devnumber, reply_devnumber, _hexlify(reply_data))
|
||||
# _l.log(_LOG_LEVEL, "(%d) request got reply for unexpected device %d: [%s]", devnumber, reply_devnumber, _hexlify(reply_data))
|
||||
# worst case scenario, this is a reply for a concurrent request
|
||||
# on this receiver
|
||||
if unhandled_hook:
|
||||
|
@ -290,6 +290,6 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None
|
|||
# _l.log(_LOG_LEVEL, "(%d) matched reply with feature-index-function [%s]", devnumber, _hexlify(reply_data[2:]))
|
||||
return reply_data[2:]
|
||||
|
||||
_l.log(_LOG_LEVEL, "(%d) unmatched reply {%s} (expected {%s})", devnumber, _hexlify(reply_data[:2]), _hexlify(feature_index_function))
|
||||
# _l.log(_LOG_LEVEL, "(%d) unmatched reply {%s} (expected {%s})", devnumber, _hexlify(reply_data[:2]), _hexlify(feature_index_function))
|
||||
if unhandled_hook:
|
||||
unhandled_hook(reply_code, reply_devnumber, reply_data)
|
||||
|
|
|
@ -20,16 +20,15 @@ _LOG_LEVEL = 4
|
|||
_l = _Logger('lur.listener')
|
||||
|
||||
|
||||
_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT / 4) # ms
|
||||
_IDLE_SLEEP = _base.DEFAULT_TIMEOUT / 4 # ms
|
||||
_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT / 5) # ms
|
||||
_IDLE_SLEEP = _base.DEFAULT_TIMEOUT / 5 # ms
|
||||
|
||||
|
||||
def _callback_caller(listener, callback):
|
||||
# _l.log(_LOG_LEVEL, "%s starting callback caller", listener)
|
||||
while listener._active:
|
||||
event = listener.events.get()
|
||||
if _l.isEnabledFor(_LOG_LEVEL):
|
||||
_l.log(_LOG_LEVEL, "%s delivering event %s", listener, event)
|
||||
_l.log(_LOG_LEVEL, "%s delivering event %s", listener, event)
|
||||
try:
|
||||
callback.__call__(*event)
|
||||
except:
|
||||
|
@ -41,12 +40,11 @@ class EventsListener(Thread):
|
|||
"""Listener thread for events from the Unifying Receiver.
|
||||
|
||||
Incoming events (reply_code, devnumber, data) will be passed to the callback
|
||||
function. The callback is called in a separate thread.
|
||||
function in sequence, by a separate thread.
|
||||
|
||||
While this listener is running, you should use the request() method to make
|
||||
regular UR API calls, otherwise the replies are very likely to be captured
|
||||
by the listener and delivered as events to the callback. As an exception,
|
||||
you can make API calls in the events callback.
|
||||
regular UR API calls, otherwise the expected API replies are most likely to
|
||||
be captured by the listener and delivered as events to the callback.
|
||||
"""
|
||||
def __init__(self, receiver, events_callback):
|
||||
super(EventsListener, self).__init__(group='Unifying Receiver', name='Events-%x' % receiver)
|
||||
|
@ -97,6 +95,7 @@ class EventsListener(Thread):
|
|||
self.task_reply = self._make_request(*self.task)
|
||||
self.task_done.set()
|
||||
|
||||
_base.close(self.receiver)
|
||||
self.__str_cached = 'Events(%x)' % self.receiver
|
||||
|
||||
_base.unhandled_hook = last_hook
|
||||
|
@ -113,8 +112,7 @@ class EventsListener(Thread):
|
|||
The api_function must have a receiver handle as a first agument, all
|
||||
other passed args and kwargs will follow.
|
||||
"""
|
||||
# if _l.isEnabledFor(_LOG_LEVEL):
|
||||
# _l.log(_LOG_LEVEL, "%s request '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
|
||||
# _l.log(_LOG_LEVEL, "%s request '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
|
||||
|
||||
self.task_processing.acquire()
|
||||
self.task_done.clear()
|
||||
|
@ -125,15 +123,13 @@ class EventsListener(Thread):
|
|||
self.task = self.task_reply = None
|
||||
self.task_processing.release()
|
||||
|
||||
# if _l.isEnabledFor(_LOG_LEVEL):
|
||||
# _l.log(_LOG_LEVEL, "%s request '%s.%s' => %s", self, api_function.__module__, api_function.__name__, repr(reply))
|
||||
# _l.log(_LOG_LEVEL, "%s request '%s.%s' => %s", self, api_function.__module__, api_function.__name__, repr(reply))
|
||||
if isinstance(reply, Exception):
|
||||
raise reply
|
||||
return reply
|
||||
|
||||
def _make_request(self, api_function, args, kwargs):
|
||||
if _l.isEnabledFor(_LOG_LEVEL):
|
||||
_l.log(_LOG_LEVEL, "%s calling '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
|
||||
_l.log(_LOG_LEVEL, "%s calling '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
|
||||
try:
|
||||
return api_function.__call__(self.receiver, *args, **kwargs)
|
||||
except E.NoReceiver as nr:
|
||||
|
|
Loading…
Reference in New Issue