1

I am programming a BLE device and therefore need to get some information from the org.freedesktop.DBus.Properties interface, but can't get it to work from dbus python API. From the console this is no problem. For example, from dbus-send I can invoke following method call successfully (with correct mac address of course):

$ dbus-send --system --dest=org.bluez --print-reply "/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX" org.freedesktop.DBus.Properties.Get string:'org.bluez.Device1' string:'Paired'

>> method return time=1645780543.222377 sender=:1.7 -> destination=:1.329 serial=1113 reply_serial=2
   variant       boolean true

Now, what I'm trying to do is actually something like this:

import dbus
bus = dbus.SystemBus()

connected = bus.call_blocking(
    'org.bluez',                             #bus_name
    '/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX', #object_path
    'org.freedesktop.DBus.Properties',       #dbus_interface
    'Get',                                   #method
    signature='(ss)',                        #signature
    args=['org.bluez.Device1', 'Connected'], #args
)
print(connected)

which gives me the error: ERROR:dbus.connection:Unable to set arguments ['org.bluez.Device1', 'Paired'] according to signature '(ss)': <class 'TypeError'>: Fewer items found in struct's D-Bus signature than in Python arguments

I tried also with no signature with no success. And I also found a similar question here, but for C-API. So I tried to adapt it to the python dbus API, but still can't get it to work. Moreover, the official documentation isn't very helpful as well, as there is no clear statement on how the argument mechanism works here or a reference to such an explanation. This is pretty annoying, since I can invoke a blocking call for instance on the GetManagedObjects method from org.freedesktop.DBus.ObjectManager interface that way, but that one takes no arguments of course...

Any help appreciated.

dom
  • 35
  • 5

2 Answers2

1

There are more Pythonic libraries for D-Bus such as pydbus

device_path = "/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX"

bus = pydbus.SystemBus()

device = bus.get('org.bluez', device_path)
print(device.Connected)

If you did want to do it with the deprecated python-dbus library then I have always done it this way:

BLUEZ_SERVICE_NAME = 'org.bluez'
DEVICE_INTERFACE = 'org.bluez.Device1'
remote_device_path = device_path
remote_device_obj = self.bus.get_object(BLUEZ_SERVICE_NAME,
                                        remote_device_path)
remote_device_props = dbus.Interface(remote_device_obj,
                                     dbus.PROPERTIES_IFACE)
print(remote_device_props.Get(DEVICE_INTERFACE, 'Connected'))

If you want to do it with PyGObject library then an example of that is:

from gi.repository import Gio, GLib

bus_type = Gio.BusType.SYSTEM
bus_name = 'org.bluez'
object_path = '/org/bluez/hci0'
prop_iface = 'org.freedesktop.DBus.Properties'
adapter_iface = 'org.bluez.Adapter1'


adapter_props_proxy = Gio.DBusProxy.new_for_bus_sync(
            bus_type=bus_type,
            flags=Gio.DBusProxyFlags.NONE,
            info=None,
            name=bus_name,
            object_path=object_path,
            interface_name=prop_iface,
            cancellable=None)

all_props = adapter_props_proxy.GetAll('(s)', adapter_iface)
print(all_props)
powered = adapter_props_proxy.Get('(ss)', adapter_iface, 'Powered')
print(powered)
ukBaz
  • 6,985
  • 2
  • 8
  • 31
  • I did not know, that the python-dbus lib was deprecated. I started using it, cause the official bluez examples were using it. I'm still new to this whole DBus stuff. The pydbus implementation seems fairly simple. Would have saved me from some trouble I guess... That aside, in the meanwhile I found also a direct answer to what I was trying with call_blocking(). I will post it, but mark yours as the correct one, since this is the more elaborate answer. Thanks! – dom Feb 25 '22 at 11:51
  • 1
    At the bottom of the page is the information about python-dbus https://www.freedesktop.org/wiki/Software/DBusBindings/ – ukBaz Feb 25 '22 at 12:02
  • But then it puzzles me even more why they don't update the official examples, like that one: https://github.com/bluez/bluez/blob/master/test/example-gatt-server – dom Feb 25 '22 at 12:13
1

Just for completeness and if someone stumble upon this:

You can get the deprecated API call to work if you change the signature to just ss instead of (ss) for some reason. This seems not to be consistent with other dbus APIs, which must have the signature as tuple.

connected = bus.call_blocking(
    'org.bluez',                             #bus_name
    '/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX', #object_path
    'org.freedesktop.DBus.Properties',       #dbus_interface
    'Get',                                   #method
    signature='ss',                          #signature
    args=['org.bluez.Device1', 'Connected'], #args
)
dom
  • 35
  • 5