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 The physical dimensions (width, height) in µm
Read-only 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) Property: DrawingsAvailable (at)
An array of timestamps of the available drawings. The timestamp of An array of timestamps of the available drawings. The timestamp of
each drawing can be used as argument to GetJSONData(). Timestamps are each drawing can be used as argument to GetJSONData(). Timestamps are

View File

@ -163,6 +163,14 @@ class TuhiKeteDevice(_DBusObject):
def drawings_available(self): def drawings_available(self):
return self.property('DrawingsAvailable') 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): def pair(self):
logger.debug(f'{self}: Pairing') logger.debug(f'{self}: Pairing')
# FIXME: Pair() doesn't return anything useful yet, so we wait until # FIXME: Pair() doesn't return anything useful yet, so we wait until
@ -199,6 +207,10 @@ class TuhiKeteDevice(_DBusObject):
self.notify('drawings-available') self.notify('drawings-available')
elif 'Listening' in changed_props: elif 'Listening' in changed_props:
self.notify('listening') self.notify('listening')
elif 'BatteryPercent' in changed_props:
self.notify('battery-percent')
elif 'BatteryState' in changed_props:
self.notify('battery-state')
def __repr__(self): def __repr__(self):
return f'{self.address} - {self.name}' return f'{self.address} - {self.name}'
@ -923,6 +935,16 @@ class TuhiKeteShell(cmd.Cmd):
for device in self._manager.devices: for device in self._manager.devices:
if parsed_args.address is None or parsed_args.address == device.address: if parsed_args.address is None or parsed_args.address == device.address:
print(device) 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:') print('\tAvailable drawings:')
for d in device.drawings_available: for d in device.drawings_available:
t = time.localtime(d) t = time.localtime(d)

View File

@ -12,6 +12,7 @@
# #
import argparse import argparse
import enum
import logging import logging
import sys import sys
from gi.repository import GObject from gi.repository import GObject
@ -34,6 +35,12 @@ class TuhiDevice(GObject.Object):
real device) with the frontend DBusServer object that exports the device real device) with the frontend DBusServer object that exports the device
over Tuhi's DBus interface over Tuhi's DBus interface
''' '''
class BatteryState(enum.Enum):
UNKNOWN = 0
CHARGING = 1
DISCHARGING = 2
__gsignals__ = { __gsignals__ = {
# Signal sent when an error occurs on the device itself. # Signal sent when an error occurs on the device itself.
# Argument is a Wacom*Exception # Argument is a Wacom*Exception
@ -49,6 +56,8 @@ class TuhiDevice(GObject.Object):
assert uuid is not None or paired is False assert uuid is not None or paired is False
self.paired = paired self.paired = paired
self._uuid = uuid 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('connected', self._on_bluez_device_connected)
bluez_device.connect('disconnected', self._on_bluez_device_disconnected) bluez_device.connect('disconnected', self._on_bluez_device_disconnected)
@ -93,6 +102,23 @@ class TuhiDevice(GObject.Object):
def listening(self): def listening(self):
return self._tuhi_dbus_device.listening 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): def connect_device(self):
self._bluez_device.connect_device() 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('done', self._on_fetching_finished, bluez_device)
self._wacom_device.connect('button-press-required', self._on_button_press_required) 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('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._wacom_device.start(not self.paired)
self.pairing_mode = False self.pairing_mode = False
@ -138,6 +165,13 @@ class TuhiDevice(GObject.Object):
def _on_listening_updated(self, dbus_device, pspec): def _on_listening_updated(self, dbus_device, pspec):
self.notify('listening') 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): class Tuhi(GObject.Object):
__gsignals__ = { __gsignals__ = {

View File

@ -53,6 +53,12 @@ INTROSPECTION_XML = '''
<property type='b' name='Listening' access='read'> <property type='b' name='Listening' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/> <annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property> </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'> <property type='at' name='DrawingsAvailable' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/> <annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property> </property>
@ -146,7 +152,11 @@ class TuhiDBusDevice(_TuhiDBus):
self._listening = False self._listening = False
self._listening_client = None self._listening_client = None
self._dbusid = self._register_object(connection) 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::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) device.connect('device-error', self._on_device_error)
@GObject.Property @GObject.Property
@ -169,6 +179,30 @@ class TuhiDBusDevice(_TuhiDBus):
def paired(self, paired): def paired(self, paired):
self._paired = 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): def remove(self):
self.connection.unregister_object(self._dbusid) self.connection.unregister_object(self._dbusid)
self._dbusid = None self._dbusid = None
@ -221,6 +255,10 @@ class TuhiDBusDevice(_TuhiDBus):
return ts return ts
elif propname == 'Listening': elif propname == 'Listening':
return GLib.Variant.new_boolean(self.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 return None
@ -235,6 +273,12 @@ class TuhiDBusDevice(_TuhiDBus):
return return
self.paired = device.paired 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): def _on_device_error(self, device, exception):
logger.info('An error occured while synching the device') logger.info('An error occured while synching the device')
if self.listening: if self.listening:

View File

@ -106,6 +106,9 @@ class WacomDevice(GObject.Object):
(GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT, )), (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT, )),
'button-press-required': 'button-press-required':
(GObject.SIGNAL_RUN_FIRST, None, ()), (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): 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}%') logger.debug(f'device is plugged in and charged at {battery}%')
else: else:
logger.debug(f'device is discharging: {battery}%') logger.debug(f'device is discharging: {battery}%')
self.emit('battery-status', battery, charging)
if self.is_slate(): if self.is_slate():
self.width = w = self.get_dimensions('width') self.width = w = self.get_dimensions('width')
self.height = h = self.get_dimensions('height') self.height = h = self.get_dimensions('height')