在访问蓝牙的 Python 应用程序中,我可以使用以下命令查询属于已连接设备的所有属性:
object_manager = dbus.Interface(
bus.get_object("org.bluez", "/"),
"org.freedesktop.DBus.ObjectManager")
managed_objects = object_manager.GetManagedObjects()
这可行,但它返回 BlueZ 拥有的所有托管对象,包括许多我不关心的对象。 因此,如果我想将其限制为属于特定设备的对象(例如
/org/bluez/hci0/dev_00_11_22_33_44_55
),我需要显式过滤输出:
for path, ifaces in managed_objects.items():
if path.startswith(device_path):
....
有更好的方法吗? 理想情况下,我想将设备路径传递给对象管理器,并且只接收其下方的路径,但是
GetManagedObjects
方法不接受任何参数,而且我没有看到任何其他方法来获取必要的信息.
我知道我可以为
InterfacesAdded
信号注册一个接收器,这效果很好,但前提是 BlueZ 查询远程设备。 如果数据已经缓存,我需要从 ObjectManager 显式读取它。
您可以通过以设备对象路径为起点,递归调用org.freedesktop.DBus.Properties
界面中的
Introspect方法来获取所有对象路径。
生成的内省数据采用 XML 格式。根内省元素始终是节点元素。它可能有一个 name 属性,表示接口内省的(绝对)对象路径。它还包含该对象路径中公开的所有接口、信号、方法以及子对象路径(节点)。
使用该接口很简单,您只需定义它并调用方法,然后解析 XML 响应即可:
introspect_interface = dbus.Interface(
bus.get_object("org.bluez", object_path),
"org.freedesktop.DBus.Introspectable"
)
xml_data = introspect_interface.Introspect()
parsed_data = ET.fromstring(xml_data)
nodes = [node.get('name') for node in parsed_data.findall('node')]
interfaces = [iface.get('name') for iface in parsed_data.findall('interface')]
下一步是调用该对象路径的
GetAll()
接口中的 org.freedesktop.DBus.Properties
方法,该方法需要一个字符串参数,这是接口名称,我们为该对象路径上的所有接口获取它,不包括 org.freedesktop.DBus.Introspectable, org.freedesktop.DBus.Properties
接口。可以这样做:
properties_interface = dbus.Interface(
bus.get_object("org.bluez", object_path),
"org.freedesktop.DBus.Properties"
)
properties = properties_interface.GetAll(interface)
将所有内容放在一起,最终代码将是:
import dbus
import xml.etree.ElementTree as ET
common_interfaces = ["org.freedesktop.DBus.Properties", "org.freedesktop.DBus.Introspectable"]
bus = dbus.SystemBus()
def introspect_object_path(object_path):
print(f"Introspecting: {object_path}")
introspect_interface = dbus.Interface(
bus.get_object("org.bluez", object_path),
"org.freedesktop.DBus.Introspectable"
)
properties_interface = dbus.Interface(
bus.get_object("org.bluez", object_path),
"org.freedesktop.DBus.Properties"
)
xml_data = introspect_interface.Introspect()
parsed_data = ET.fromstring(xml_data)
nodes = [node.get('name') for node in parsed_data.findall('node')]
interfaces = [iface.get('name') for iface in parsed_data.findall('interface')]
for interface in interfaces:
if interface in common_interfaces:
continue
print(f"Getting properties for interface: {interface}")
properties = properties_interface.GetAll(interface)
# Handle properties...
print(properties)
for node in nodes:
introspect_object_path(object_path + f"/{node}")
base_object_path = "/org/bluez/hci0/dev_00_11_22_33_44_55"
introspect_object_path(base_object_path)