Export the battery level/charge state

pull/48/head
Peter Hutterer 2018-01-29 13:44:02 +10:00
parent 0dc3cb5f3a
commit e647e20426
5 changed files with 124 additions and 0 deletions

View File

@ -155,6 +155,26 @@ org.freedesktop.tuhi1.Device
The physical dimensions (width, height) in µm
Read-only
Property: BatteryPercent (u)
The last known battery charge level in percent. This charge level is
only valid when the BatteryState is other than Unknown.
Read-only
Property: BatteryState (u)
An enum describing the battery state. Permitted enum values are
0: Unknown
1: Charging
2: Discharging
'Unknown' may refer to a state that could not be read, a state
that has not yet been updated, or a state that has not updated within
a daemon-internal time period. Thus, a device that is connected but
does not regularly send battery updates may eventually switch to
'Unknown'.
Read-only
Property: DrawingsAvailable (at)
An array of timestamps of the available drawings. The timestamp of
each drawing can be used as argument to GetJSONData(). Timestamps are

View File

@ -163,6 +163,14 @@ class TuhiKeteDevice(_DBusObject):
def drawings_available(self):
return self.property('DrawingsAvailable')
@GObject.Property
def battery_percent(self):
return self.property('BatteryPercent')
@GObject.Property
def battery_state(self):
return self.property('BatteryState')
def pair(self):
logger.debug(f'{self}: Pairing')
# FIXME: Pair() doesn't return anything useful yet, so we wait until
@ -199,6 +207,10 @@ class TuhiKeteDevice(_DBusObject):
self.notify('drawings-available')
elif 'Listening' in changed_props:
self.notify('listening')
elif 'BatteryPercent' in changed_props:
self.notify('battery-percent')
elif 'BatteryState' in changed_props:
self.notify('battery-state')
def __repr__(self):
return f'{self.address} - {self.name}'
@ -923,6 +935,16 @@ class TuhiKeteShell(cmd.Cmd):
for device in self._manager.devices:
if parsed_args.address is None or parsed_args.address == device.address:
print(device)
charge_strs = {
0: 'unknown',
1: 'charging',
2: 'discharging'
}
try:
charge_str = charge_strs[device.battery_state]
except KeyError:
charge_str = 'invalid'
print(f'\tBattery level: {device.battery_percent}%, {charge_str}')
print('\tAvailable drawings:')
for d in device.drawings_available:
t = time.localtime(d)

View File

@ -12,6 +12,7 @@
#
import argparse
import enum
import logging
import sys
from gi.repository import GObject
@ -34,6 +35,12 @@ class TuhiDevice(GObject.Object):
real device) with the frontend DBusServer object that exports the device
over Tuhi's DBus interface
'''
class BatteryState(enum.Enum):
UNKNOWN = 0
CHARGING = 1
DISCHARGING = 2
__gsignals__ = {
# Signal sent when an error occurs on the device itself.
# Argument is a Wacom*Exception
@ -49,6 +56,8 @@ class TuhiDevice(GObject.Object):
assert uuid is not None or paired is False
self.paired = paired
self._uuid = uuid
self._battery_state = TuhiDevice.BatteryState.UNKNOWN
self._battery_percent = 0
bluez_device.connect('connected', self._on_bluez_device_connected)
bluez_device.connect('disconnected', self._on_bluez_device_disconnected)
@ -93,6 +102,23 @@ class TuhiDevice(GObject.Object):
def listening(self):
return self._tuhi_dbus_device.listening
@GObject.Property
def battery_percent(self):
return self._battery_percent
@battery_percent.setter
def battery_percent(self, value):
self._battery_percent = value
@GObject.Property
def battery_state(self):
return self._battery_state
@battery_state.setter
def battery_state(self, value):
print('setting battery state on tuhidevice')
self._battery_state = value
def connect_device(self):
self._bluez_device.connect_device()
@ -104,6 +130,7 @@ class TuhiDevice(GObject.Object):
self._wacom_device.connect('done', self._on_fetching_finished, bluez_device)
self._wacom_device.connect('button-press-required', self._on_button_press_required)
self._wacom_device.connect('notify::uuid', self._on_uuid_updated, bluez_device)
self._wacom_device.connect('battery-status', self._on_battery_status, bluez_device)
self._wacom_device.start(not self.paired)
self.pairing_mode = False
@ -138,6 +165,13 @@ class TuhiDevice(GObject.Object):
def _on_listening_updated(self, dbus_device, pspec):
self.notify('listening')
def _on_battery_status(self, wacom_device, percent, is_charging, bluez_device):
if is_charging:
self.battery_state = TuhiDevice.BatteryState.CHARGING
else:
self.battery_state = TuhiDevice.BatteryState.DISCHARGING
self.battery_percent = percent
class Tuhi(GObject.Object):
__gsignals__ = {

View File

@ -53,6 +53,12 @@ INTROSPECTION_XML = '''
<property type='b' name='Listening' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property>
<property type='u' name='BatteryPercent' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property>
<property type='b' name='BatteryState' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property>
<property type='at' name='DrawingsAvailable' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property>
@ -146,7 +152,11 @@ class TuhiDBusDevice(_TuhiDBus):
self._listening = False
self._listening_client = None
self._dbusid = self._register_object(connection)
self._battery_percent = 0
self._battery_state = device.battery_state
device.connect('notify::paired', self._on_device_paired)
device.connect('notify::battery-percent', self._on_battery_percent)
device.connect('notify::battery-state', self._on_battery_state)
device.connect('device-error', self._on_device_error)
@GObject.Property
@ -169,6 +179,30 @@ class TuhiDBusDevice(_TuhiDBus):
def paired(self, paired):
self._paired = paired
@GObject.Property
def battery_percent(self):
return self._battery_percent
@battery_percent.setter
def battery_percent(self, value):
if self._battery_percent == value:
return
self._battery_percent = value
self.properties_changed({'BatteryPercent': GLib.Variant.new_uint32(value)})
@GObject.Property
def battery_state(self):
return self._battery_state
@battery_state.setter
def battery_state(self, value):
if self._battery_state == value:
return
self._battery_state = value
self.properties_changed({'BatteryState': GLib.Variant.new_uint32(value.value)})
def remove(self):
self.connection.unregister_object(self._dbusid)
self._dbusid = None
@ -221,6 +255,10 @@ class TuhiDBusDevice(_TuhiDBus):
return ts
elif propname == 'Listening':
return GLib.Variant.new_boolean(self.listening)
elif propname == 'BatteryPercent':
return GLib.Variant.new_uint32(self.battery_percent)
elif propname == 'BatteryState':
return GLib.Variant.new_uint32(self.battery_state.value)
return None
@ -235,6 +273,12 @@ class TuhiDBusDevice(_TuhiDBus):
return
self.paired = device.paired
def _on_battery_percent(self, device, pspec):
self.battery_percent = device.battery_percent
def _on_battery_state(self, device, pspec):
self.battery_state = device.battery_state
def _on_device_error(self, device, exception):
logger.info('An error occured while synching the device')
if self.listening:

View File

@ -106,6 +106,9 @@ class WacomDevice(GObject.Object):
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT, )),
'button-press-required':
(GObject.SIGNAL_RUN_FIRST, None, ()),
# battery level in %, boolean for is-charging
"battery-status":
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_INT, GObject.TYPE_BOOLEAN)),
}
def __init__(self, device, uuid=None):
@ -544,6 +547,7 @@ class WacomDevice(GObject.Object):
logger.debug(f'device is plugged in and charged at {battery}%')
else:
logger.debug(f'device is discharging: {battery}%')
self.emit('battery-status', battery, charging)
if self.is_slate():
self.width = w = self.get_dimensions('width')
self.height = h = self.get_dimensions('height')