dom
dom

Reputation: 35

Blocking DBus call from python API

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.

Upvotes: 1

Views: 859

Answers (2)

dom
dom

Reputation: 35

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
)

Upvotes: 1

ukBaz
ukBaz

Reputation: 8014

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)

Upvotes: 1

Related Questions