阻止来自 python API 的 DBus 调用

Blocking DBus call from python API

我正在对 BLE 设备进行编程,因此需要从 org.freedesktop.DBus.Properties 接口获取一些信息,但无法从 dbus python API 获取它。从控制台这没有问题。例如,从 dbus-send 我可以成功调用以下方法调用(当然有正确的 mac 地址):

$ 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

现在,我要做的实际上是这样的:

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)

这给了我错误: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

我也尝试过没有签名但没有成功。而且我还发现一个类似的问题 , 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 也不是很有帮助,因为这里没有关于参数机制如何工作的明确说明或对此类解释的引用。这很烦人,因为我可以通过这种方式从 org.freedesktop.DBus.ObjectManager 接口调用 GetManagedObjects 方法的阻塞调用,但是那个方法当然不需要任何参数...

感谢任何帮助。

D-Bus 还有更多 Pythonic 库,例如 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)

如果您确实想使用已弃用的 python-dbus 库,那么我一直都是这样做的:

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'))

如果你想用 PyGObject 库来做,那么一个例子是:

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)

只是为了完整性,如果有人偶然发现了这个:

如果出于某种原因将签名更改为 ss 而不是 (ss),则可以使已弃用的 API 调用生效。这似乎与其他dbus APIs 不一致,它必须具有元组的签名。

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
)