0

On my laptop:

gdbus introspect --system --dest org.freedesktop.UPower --object-path /org/freedesktop/UPower/devices/DisplayDevice

returns a set of properties:

   properties:
      readonly s NativePath = '';
      readonly s Vendor = '';
      readonly s Model = '';
      readonly s Serial = '';
      readonly t UpdateTime = 1669341757;
      readonly u Type = 2;
      readonly b PowerSupply = true;
      readonly b HasHistory = false;
      readonly b HasStatistics = false;
      readonly b Online = false;
      readonly d Energy = 32.719999999999999;
      readonly d EnergyEmpty = 0.0;
      readonly d EnergyFull = 58.990000000000002;
      readonly d EnergyFullDesign = 0.0;
      readonly d EnergyRate = 6.2569999999999997;
      readonly d Voltage = 0.0;
      readonly i ChargeCycles = 0;
      readonly d Luminosity = 0.0;
      readonly x TimeToEmpty = 18825;
      readonly x TimeToFull = 0;
      readonly d Percentage = 55.0;
      readonly d Temperature = 0.0;
      readonly b IsPresent = true;
      readonly u State = 2;
      readonly b IsRechargeable = false;
      readonly d Capacity = 0.0;
      readonly u Technology = 0;
      readonly u WarningLevel = 1;
      readonly u BatteryLevel = 1;
      readonly s IconName = 'battery-good-symbolic';

I am trying to modify a gnome shell extension.

when initalising the extension, it does this:

const BUS_NAME = 'org.freedesktop.UPower';
const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice';

const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device'); // see https://upower.freedesktop.org/docs/UPower.html
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);

...

 this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,

...

the existing code accesses a couple of properties like this:

    let chargingState = this._proxy.State === UPower.DeviceState.CHARGING
        ? '-charging' : '';
    let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);

According to the documentation, there is another property EnergyRate (https://upower.freedesktop.org/docs/UPower.html)

and the gdbus call (above) returns a value for many properties, including EnergyRate.

Yet when I do:

global.log("Energy: " + this._proxy.EnergyRate);  

the value of the property EnergyRate is undefined. This happens for other defined properties too, such as Energy

Why can't I access all of the properties?

Tim Richardson
  • 6,608
  • 6
  • 44
  • 71
  • Is that property in the XML definition with the correct type signature? – andy.holmes Nov 25 '22 at 03:39
  • Assuming this is the xml: https://github.com/freedesktop/upower/blob/master/dbus/org.freedesktop.UPower.Device.xml, the properties are defined in lowercase format, like you see from upower -d; "energy-rate" is defined. The existing code refers to properties LikeThis, e.g. TimeToFull, yet in the xml that is 'time-to-full', so some step is mapping the xml names to CamelCase and maybe that is where the problem is? – Tim Richardson Nov 25 '22 at 04:25
  • ah, I was completely on the wrong track. https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/92d3c6e051958b31151bf9538205a71cab6f70d7/data/dbus-interfaces/org.freedesktop.UPower.Device.xml is the correct XML, and it is devoid of most properties. I wonder why. – Tim Richardson Nov 25 '22 at 04:32
  • 1
    You could always `let value = proxy.get_cached_property('EnergyRate')?.unpack() || 0;`. – andy.holmes Nov 25 '22 at 04:49
  • 1
    I copied the XML into a string, added the missing EnergyRate, loaded it instead of the path in the existing code, and it just worked. If it really actually keeps working I will post it as an answer. Other extensions go to much more effort to get this data. I emailed Florian Mueller asking why so much is missing from gnome xml. The last commit was in 2015. I did this before seeing your comment immediately above – Tim Richardson Nov 25 '22 at 04:53
  • @andy.holmes your method works as well. So from complete consternation to two solutions. Very good. I will post an answer, the world needs to know. – Tim Richardson Nov 25 '22 at 05:00
  • @andy.holmes post your answer and I will accept it. – Tim Richardson Nov 25 '22 at 05:23

1 Answers1

1

I am new at this, which means this will be an "explain it like I'm five" because that's my mental age with respect to this.

Primitive solution

I came up with one solution which required only rudimentary knowledge of the gnome libraries, and @andy.holmes contributed an expert answer via comments.

The existing code sets up access to the dbus "address"/endpoint in two steps:

const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device');

and

const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);

the first line refers to XML which is part of the gnome runtime. The fragment is here https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/92d3c6e051958b31151bf9538205a71cab6f70d7/data/dbus-interfaces/org.freedesktop.UPower.Device.xml

and it has only a small subset of the properties of the dbus address. Missing is energy-rate.

So I made a string, copying the gnome runtime XML and adding one line:

const UPowerInterface = '<node>\n' +
    '  <interface name="org.freedesktop.UPower.Device">\n' +
    '    <property name="Type" type="u" access="read"/>\n' +
    '    <property name="State" type="u" access="read"/>\n' +
    '    <property name="Percentage" type="d" access="read"/>\n' +
    '    <property name="EnergyRate" type="d" access="read"/>\n' +
    '    <property name="TimeToEmpty" type="x" access="read"/>\n' +
    '    <property name="TimeToFull" type="x" access="read"/>\n' +
    '    <property name="IsPresent" type="b" access="read"/>\n' +
    '    <property name="IconName" type="s" access="read"/>\n' +
    '  </interface>\n' +
    '</node>\n'

and did this:

const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerInterface);

and now I have a property EnergyRate. I don't know why these properties are missing, there may be a very good reason. I have asked Florian Mueller.

Expert Solution

@andy.holmes suggested a one-line alternative which does not need new XML nor any other changes:

let value = this._proxy.get_cached_property('EnergyRate')?.unpack() || 0;

and it works and it is less effort.

Tim Richardson
  • 6,608
  • 6
  • 44
  • 71