brought solar app up-to-date with the UR api
This commit is contained in:
parent
fc0a0ca2bb
commit
ebe8320f2e
|
@ -1,2 +1,4 @@
|
||||||
*.so
|
*.so
|
||||||
*.pyc
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.log
|
||||||
|
|
|
@ -274,7 +274,7 @@ def get_device_firmware(handle, device, features_array=None):
|
||||||
str((ord(fw_info[5]) & 0xF0) >> 4) +
|
str((ord(fw_info[5]) & 0xF0) >> 4) +
|
||||||
str(ord(fw_info[5]) & 0x0F))
|
str(ord(fw_info[5]) & 0x0F))
|
||||||
name = prefix + ' ' + version
|
name = prefix + ' ' + version
|
||||||
build = 256 * ord(fw_info[6]) + ord(fw_info[7])
|
build = (ord(fw_info[6]) << 8) + ord(fw_info[7])
|
||||||
if build:
|
if build:
|
||||||
name += ' b' + str(build)
|
name += ' b' + str(build)
|
||||||
extras = fw_info[9:].rstrip('\x00')
|
extras = fw_info[9:].rstrip('\x00')
|
||||||
|
@ -324,8 +324,11 @@ def get_device_name(handle, device, features_array=None):
|
||||||
_l.log(_LOG_LEVEL, "(%d,%d) device name %s", handle, device, d_name)
|
_l.log(_LOG_LEVEL, "(%d,%d) device name %s", handle, device, d_name)
|
||||||
return d_name
|
return d_name
|
||||||
|
|
||||||
|
|
||||||
def get_device_battery_level(handle, device, features_array=None):
|
def get_device_battery_level(handle, device, features_array=None):
|
||||||
"""Reads a device's battery level.
|
"""Reads a device's battery level.
|
||||||
|
|
||||||
|
:raises FeatureNotSupported: if the device does not support this feature.
|
||||||
"""
|
"""
|
||||||
battery = request(handle, device, FEATURE.BATTERY, features_array=features_array)
|
battery = request(handle, device, FEATURE.BATTERY, features_array=features_array)
|
||||||
if battery:
|
if battery:
|
||||||
|
|
|
@ -150,6 +150,7 @@ def write(handle, device, data):
|
||||||
_l.warn("(%d:%d) <= w[%s] call packet too long: %d bytes", handle, device, wdata.encode('hex'), len(wdata))
|
_l.warn("(%d:%d) <= w[%s] call packet too long: %d bytes", handle, device, wdata.encode('hex'), len(wdata))
|
||||||
if not _hid.write(handle, wdata):
|
if not _hid.write(handle, wdata):
|
||||||
_l.warn("(%d,%d) write failed, assuming receiver no longer available", handle, device)
|
_l.warn("(%d,%d) write failed, assuming receiver no longer available", handle, device)
|
||||||
|
close(handle)
|
||||||
raise NoReceiver()
|
raise NoReceiver()
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,7 +211,7 @@ def request(handle, device, feature_index_function, params=b'', features_array=N
|
||||||
|
|
||||||
if reply_device != device:
|
if reply_device != device:
|
||||||
# this message not for the device we're interested in
|
# this message not for the device we're interested in
|
||||||
_l.log(_LOG_LEVEL, "(%d,%d) request got reply for unexpected device %d: [%s]", handle, device, reply_device, reply.encode('hex'))
|
_l.log(_LOG_LEVEL, "(%d,%d) request got reply for unexpected device %d: [%s]", handle, device, reply_device, reply_data.encode('hex'))
|
||||||
# worst case scenario, this is a reply for a concurrent request
|
# worst case scenario, this is a reply for a concurrent request
|
||||||
# on this receiver
|
# on this receiver
|
||||||
_unhandled._publish(reply_code, reply_device, reply_data)
|
_unhandled._publish(reply_code, reply_device, reply_data)
|
||||||
|
@ -229,7 +230,7 @@ def request(handle, device, feature_index_function, params=b'', features_array=N
|
||||||
if reply_code == 0x11 and reply_data[0] == b'\xFF' and reply_data[1:3] == feature_index_function:
|
if reply_code == 0x11 and reply_data[0] == b'\xFF' and reply_data[1:3] == feature_index_function:
|
||||||
# an error returned from the device
|
# an error returned from the device
|
||||||
error_code = ord(reply_data[3])
|
error_code = ord(reply_data[3])
|
||||||
_l.warn("(%d,%d) request feature call error %d = %s: %s", handle, device, error, _ERROR_NAME(error_code), reply_data.encode('hex'))
|
_l.warn("(%d,%d) request feature call error %d = %s: %s", handle, device, error_code, ERROR_NAME(error_code), reply_data.encode('hex'))
|
||||||
feature_index = ord(feature_index_function[0])
|
feature_index = ord(feature_index_function[0])
|
||||||
feature_function = feature_index_function[1].encode('hex')
|
feature_function = feature_index_function[1].encode('hex')
|
||||||
feature = None if features_array is None else features_array[feature_index]
|
feature = None if features_array is None else features_array[feature_index]
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cd `dirname "$0"`
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$PWD/lib
|
||||||
|
export PYTHONPATH=$PWD/lib
|
||||||
|
export PYTHONWARNINGS=all
|
||||||
|
|
||||||
|
exec python -OO -tt -u -3 solar.py "$@"
|
107
solar.py
107
solar.py
|
@ -1,28 +1,35 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(level=1)
|
||||||
|
logging.captureWarnings(True)
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import subprocess
|
import subprocess
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import gobject
|
from gi.repository import GObject
|
||||||
import pygtk
|
from gi.repository import Gtk
|
||||||
pygtk.require('2.0')
|
|
||||||
import gtk
|
|
||||||
|
|
||||||
from logitech import unifying_receiver as ur
|
from logitech.unifying_receiver import api as ur
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# A few constants
|
||||||
|
#
|
||||||
|
|
||||||
KEYBOARD_NAME = 'Wireless Solar Keyboard K750'
|
KEYBOARD_NAME = 'Wireless Solar Keyboard K750'
|
||||||
TITLE = 'Solar [K750]'
|
TITLE = 'Solar [K750]'
|
||||||
|
|
||||||
NOTIFY_DESKTOP = True
|
NOTIFY_DESKTOP = True
|
||||||
BLINK_ICON = 3
|
|
||||||
|
|
||||||
OK = 0
|
OK = 0
|
||||||
NO_RECEIVER = 1
|
NO_RECEIVER = 1
|
||||||
NO_K750 = 2
|
NO_K750 = 2
|
||||||
NO_STATUS = 3
|
NO_STATUS = 3
|
||||||
|
|
||||||
SLEEP = (10, 30, 25, 15)
|
SLEEP = (10, 5, 5, 15)
|
||||||
TEXT = ('K750 keyboard connected',
|
TEXT = ('K750 keyboard connected',
|
||||||
'Logitech Unifying Receiver not detected',
|
'Logitech Unifying Receiver not detected',
|
||||||
'K750 keyboard not detected',
|
'K750 keyboard not detected',
|
||||||
|
@ -38,17 +45,39 @@ K750_Status = namedtuple('K750_Status',
|
||||||
['receiver', 'device', 'status', 'charge', 'lux'])
|
['receiver', 'device', 'status', 'charge', 'lux'])
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# _unhandled_queue = []
|
||||||
|
|
||||||
|
# def unhandled_messages_hook(code, device, data):
|
||||||
|
# if len(_unhandled_queue) > 32:
|
||||||
|
# del _unhandled_queue[:]
|
||||||
|
# _unhandled_queue.append((code, device, data))
|
||||||
|
|
||||||
|
# from logitech.unifying_receiver import unhandled
|
||||||
|
# unhandled.set_unhandled_hook(unhandled_messages_hook)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
def notify_desktop(status_code, text):
|
def notify_desktop(status_code, text):
|
||||||
global NOTIFY_DESKTOP
|
global NOTIFY_DESKTOP
|
||||||
if NOTIFY_DESKTOP:
|
if NOTIFY_DESKTOP:
|
||||||
try:
|
try:
|
||||||
program = ('/usr/bin/notify-send', '-u', 'low', TITLE, text)
|
subprocess.call(('notify-send', '-u', 'low', TITLE, text))
|
||||||
subprocess.Popen(program, close_fds=True)
|
|
||||||
except OSError:
|
except OSError:
|
||||||
NOTIFY_DESKTOP = False
|
NOTIFY_DESKTOP = False
|
||||||
|
|
||||||
|
|
||||||
def update_status_icon(status_icon, status_changed, k750):
|
def update_status_icon(status_icon, status_changed, k750):
|
||||||
|
print "update status", status_changed, k750
|
||||||
|
|
||||||
text = TEXT[k750.status]
|
text = TEXT[k750.status]
|
||||||
if k750.status == OK:
|
if k750.status == OK:
|
||||||
text += '\n' + (CHARGE_LUX_TEXT % (k750.charge, k750.lux))
|
text += '\n' + (CHARGE_LUX_TEXT % (k750.charge, k750.lux))
|
||||||
|
@ -57,10 +86,6 @@ def update_status_icon(status_icon, status_changed, k750):
|
||||||
|
|
||||||
if status_changed:
|
if status_changed:
|
||||||
notify_desktop(k750.status, text)
|
notify_desktop(k750.status, text)
|
||||||
if BLINK_ICON:
|
|
||||||
status_icon.set_blinking(True)
|
|
||||||
time.sleep(BLINK_ICON)
|
|
||||||
status_icon.set_blinking(False)
|
|
||||||
|
|
||||||
|
|
||||||
def read_charge(receiver, device):
|
def read_charge(receiver, device):
|
||||||
|
@ -72,26 +97,47 @@ def read_charge(receiver, device):
|
||||||
|
|
||||||
if receiver and not device:
|
if receiver and not device:
|
||||||
try:
|
try:
|
||||||
device = ur.find_device(receiver, "keyboard", KEYBOARD_NAME)
|
device = ur.find_device_by_name(receiver, KEYBOARD_NAME)
|
||||||
except ur.NoReceiver:
|
except ur.NoReceiver:
|
||||||
ur.close(receiver)
|
|
||||||
receiver = None
|
receiver = None
|
||||||
|
|
||||||
if receiver:
|
if receiver and device:
|
||||||
if device:
|
feature_solar_index = device.features_array.index(ur.FEATURE.SOLAR_CHARGE)
|
||||||
|
|
||||||
|
event = None
|
||||||
|
for i in range(0, 20):
|
||||||
|
next_event = ur.base.read(receiver, ur.base.DEFAULT_TIMEOUT * 2 // i if i > 0 else ur.base.DEFAULT_TIMEOUT * 3)
|
||||||
|
if not next_event:
|
||||||
|
break
|
||||||
|
if next_event[1] == device.number:
|
||||||
|
if next_event[0] == 0x10 and next_event[2][0] == b'\x8F':
|
||||||
|
event = next_event
|
||||||
|
elif next_event[0] == 0x11 and next_event[2][0] == chr(feature_solar_index) and next_event[2][7:11] == b'GOOD':
|
||||||
|
if next_event[2][1] == b'\x10':
|
||||||
|
event = next_event
|
||||||
|
elif next_event[2][1] == b'\x00' or next_event[2][1] == b'\x20':
|
||||||
|
event = next_event
|
||||||
|
|
||||||
|
if event is None:
|
||||||
try:
|
try:
|
||||||
charge_lux = ur.get_solar_charge(receiver, device)
|
reply = ur.request(receiver, device.number, ur.FEATURE.SOLAR_CHARGE, function=b'\x03', params=b'\x78\x01', features_array=device.features_array)
|
||||||
if charge_lux is None:
|
if reply is None:
|
||||||
|
status = NO_K750
|
||||||
device = None
|
device = None
|
||||||
status = NO_STATUS
|
|
||||||
else:
|
else:
|
||||||
charge, lux = charge_lux
|
return read_charge(receiver, device)
|
||||||
status = OK
|
|
||||||
except ur.NoReceiver:
|
except ur.NoReceiver:
|
||||||
ur.close(receiver)
|
|
||||||
receiver = None
|
receiver = None
|
||||||
|
device = None
|
||||||
else:
|
else:
|
||||||
status = NO_K750
|
if event[1] == 0x10:
|
||||||
|
status = NO_K750
|
||||||
|
device = None
|
||||||
|
else:
|
||||||
|
status = OK
|
||||||
|
charge = ord(event[2][2])
|
||||||
|
if event[2][1] == b'\x10':
|
||||||
|
lux = (ord(event[2][3]) << 8) + ord(event[2][4])
|
||||||
|
|
||||||
return K750_Status(receiver, device, status, charge, lux)
|
return K750_Status(receiver, device, status, charge, lux)
|
||||||
|
|
||||||
|
@ -109,17 +155,18 @@ class StatusThread(threading.Thread):
|
||||||
while True:
|
while True:
|
||||||
k750 = read_charge(k750.receiver, k750.device)
|
k750 = read_charge(k750.receiver, k750.device)
|
||||||
status_changed = k750.status != last_status
|
status_changed = k750.status != last_status
|
||||||
gobject.idle_add(update_status_icon, self.status_icon, status_changed, k750)
|
GObject.idle_add(update_status_icon, self.status_icon, status_changed, k750)
|
||||||
last_status = k750.status
|
last_status = k750.status
|
||||||
time.sleep(SLEEP[k750.status])
|
time.sleep(SLEEP[k750.status])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
status_icon = gtk.status_icon_new_from_file('images/icon.png')
|
status_icon = Gtk.StatusIcon.new_from_file('images/icon.png')
|
||||||
status_icon.set_title('Solar')
|
status_icon.set_title(TITLE)
|
||||||
|
status_icon.set_name(TITLE)
|
||||||
status_icon.set_tooltip_text('Initializing...')
|
status_icon.set_tooltip_text('Initializing...')
|
||||||
status_icon.connect("popup_menu", gtk.main_quit)
|
status_icon.connect("popup_menu", Gtk.main_quit)
|
||||||
|
|
||||||
gobject.threads_init()
|
GObject.threads_init()
|
||||||
StatusThread(status_icon).start()
|
StatusThread(status_icon).start()
|
||||||
gtk.main()
|
Gtk.main()
|
||||||
|
|
|
@ -7,4 +7,4 @@ export PYTHONPATH=$PWD/lib
|
||||||
export PYTHONDONTWRITEBYTECODE=true
|
export PYTHONDONTWRITEBYTECODE=true
|
||||||
export PYTHONWARNINGS=all
|
export PYTHONWARNINGS=all
|
||||||
|
|
||||||
python -m unittest discover -v "$@"
|
exec python -m unittest discover -v "$@"
|
||||||
|
|
Loading…
Reference in New Issue