当蓝牙需要代理时,它会查看 D-Bus 对象路径上的org.bluez.AgentManager1接口,以查找/org/bluez已注册代理的位置。org.bluez.Agent1然后它在该注册对象路径的接口上调用相关方法(/org/bluez/anAgent在您的示例中)。需要为org.bluez.Agent1接口实现的方法记录在:
https ://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/agent-api.txt
无论系统上有多少适配器,都只有一个代理。
问题可能是正在配对的设备与“错误”的适配器相关联吗?
设备 API具有Adapter跟踪设备所属适配器的对象路径的属性。
要查找您创建的代理,使用busctl. Usingbusctl list将列出所有可用的SystemBus服务。由于您没有为代理声明总线名称,因此它将是匿名的,因此格式为:x.xxx. 这可能是一个很长的列表,所以busctl list | grep python我通常会这样做来缩小列表范围。
要反省那里有什么,您可以执行以下操作:
$ busctl introspect :1.174 /org/bluez/anAgent
测试已发布的代理服务:
$ busctl call :1.174 /org/bluez/anAgent org.bluez.Agent1 AuthorizeService os /org/bluez/hci1/dev_12_34_56_78 1234
该服务需要是异步的,因此您需要启动MainLoop事件循环。
pydbus下面是使用D-Bus 绑定创建代理的完整示例。
唯一提到适配器的地方是开始发现的指令。如果您有另一台设备尝试使用代理发现您的设备,那么它将取决于可发现哪个适配器和/或其他设备尝试连接。
import threading
import pydbus
from gi.repository import GLib
BUS_NAME = 'org.bluez'
AGENT_IFACE = 'org.bluez.Agent1'
AGNT_MNGR_IFACE = 'org.bluez.AgentManager1'
ADAPTER_IFACE = 'org.bluez.Adapter1'
AGENT_PATH = '/org/bluez/anAgent'
AGNT_MNGR_PATH = '/org/bluez'
DEVICE_IFACE = 'org.bluez.Device1'
CAPABILITY = 'KeyboardDisplay'
bus = pydbus.SystemBus()
class Agent:
"""
<node>
<interface name="org.bluez.Agent1">
<method name="Release" />
<method name="RequestPinCode">
<arg name="device" direction="in" type="o" />
<arg name="pincode" direction="out" type="s" />
</method>
<method name="DisplayPinCode">
<arg name="device" direction="in" type="o" />
<arg name="pincode" direction="in" type="s" />
</method>
<method name="RequestPasskey">
<arg name="device" direction="in" type="o" />
<arg name="passkey" direction="out" type="u" />
</method>
<method name="DisplayPasskey">
<arg name="device" direction="in" type="o" />
<arg name="passkey" direction="in" type="u" />
<arg name="entered" direction="in" type="q" />
</method>
<method name="RequestConfirmation">
<arg name="device" direction="in" type="o" />
<arg name="passkey" direction="in" type="u" />
</method>
<method name="RequestAuthorization">
<arg name="device" direction="in" type="o" />
</method>
<method name="AuthorizeService">
<arg name="device" direction="in" type="o" />
<arg name="uuid" direction="in" type="s" />
</method>
<method name="Cancel" />
</interface>
</node>
"""
def Release(self):
print('Release')
def RequestPinCode(self, device):
print('RequestPinCode', device)
return '1234'
def DisplayPinCode(self, device, pincode):
print('DisplayPinCode', device, pincode)
def RequestPasskey(self, device):
print('RequestPasskey', device)
return 1234
def DisplayPasskey(self, device, passkey, entered):
print('DisplayPasskey', device, passkey, entered)
def RequestConfirmation(self, device, passkey):
print('RequestConfirmation', device, passkey)
def RequestAuthorization(self, device):
print('RequestAuthorization', device)
def AuthorizeService(self, device, uuid):
print('AuthorizeService', device, uuid)
def Cancel(self):
return
def pair_reply(*args):
print('reply', args)
def pair_error(*args):
print('error', args)
def dbus_path_up(dbus_obj):
return '/'.join(dbus_obj.split('/')[:-1])
def device_found(dbus_obj, properties):
adapter = bus.get(BUS_NAME, dbus_path_up(dbus_obj))
device = bus.get(BUS_NAME, dbus_obj)
print('Stopping discovery')
adapter.StopDiscovery()
if device.Paired:
device.Connect()
else:
print('Pairing procedure starting...')
device.Pair()
def interface_added(path, ifaces):
if DEVICE_IFACE in ifaces.keys():
dev_name = ifaces[DEVICE_IFACE].get('Name')
print('Device found:', dev_name)
if dev_name == 'HC-06':
device_found(path, ifaces[DEVICE_IFACE])
def publish_agent():
bus.register_object(AGENT_PATH, Agent(), None)
aloop = GLib.MainLoop()
aloop.run()
print('Agent Registered')
def create_agent():
thread = threading.Thread(target=publish_agent, daemon=True)
thread.start()
print('Agent running...')
def my_app(hci_idx=0):
adapter_path = f'/org/bluez/hci{hci_idx}'
mngr = bus.get(BUS_NAME, '/')
mngr.onInterfacesAdded = interface_added
create_agent()
agnt_mngr = bus.get(BUS_NAME, AGNT_MNGR_PATH)[AGNT_MNGR_IFACE]
agnt_mngr.RegisterAgent(AGENT_PATH, CAPABILITY)
print('Agent registered...')
adapter = bus.get(BUS_NAME, adapter_path)
# adapter.StartDiscovery()
mainloop = GLib.MainLoop()
try:
mainloop.run()
except KeyboardInterrupt:
mainloop.quit()
adapter.StopDiscovery()
if __name__ == '__main__':
my_app()