如何使用蓝牙批处理脚本自动配对 RPi 和 Android
How can I automate pairing RPi and Android with bluetooth Batch script
我正在进行一个将 Android 设备与 Raspberry Pi 设备连接的项目。 RPi 需要被视为用户永远不需要触摸的可部署设备。出于这个原因,我正在尝试在 RPi 上编写一个启动批处理脚本,允许用户将他们的 Android 与 PI 配对。
我的想法是,当您启动时,此脚本将 运行,他们 phone 上的用户将尝试连接到 RPi,RPi 将自动接受此连接。
这是我目前所拥有的
#!/bin/bash
bluetoothctl -- discoverable on
bluetoothctl -- pairable on
bluetoothctl -- agent on
bluetoothctl -- default-agent
问题是,当我这样做时,我没有进入 [bluetoothctl]
提示我需要与 Android.
进行通信
当我 运行 这些命令(没有批处理脚本)并尝试与我的 Android 配对时,我得到
Request confirmation
[agent] Confirm passkey 861797 (yes/no): yes
从这里我只需要输入 yes 来实例化连接。我看到的问题是 1:我不知道如何留在命令行中的 [bluetoothctl]
提示符中与设备通信,以及 2:我不知道如何将“是”发送到提示。
同样,对我来说重要的是,除了为了部署目的而启动 RPi 之外,用户永远不需要对 RPi 做任何事情。是否有解决我的问题的方法,或者有更好的方法一起解决吗?
对于那些感兴趣的人,蓝牙启动连接已经到位,这样我就可以将网络信息发送到 RPi,它可以自动连接到网络,这样主应用程序通信就会以这种方式进行。
这是我能够手动完成的脚本的预期结果。
以这种方式使用 bluetoothctl
可能会出现问题,因为它并非设计为以这种方式进行交互。正如您将 Python 作为标签之一,从 Python (和其他语言)访问此功能的预期方式是通过 D-Bus API.
这些记录在:https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
还有示例:https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test
确认是agent API. You can also set discoverable and pairable with the adapter API中的RequestConfirmation
。使用 API 还可以让您停止可发现超时。
phone 连接后,您通常希望将其标记为可信,这样就不需要再次配对。这是通过 device API.
完成的
下面是使用 Python 在适配器上设置这些属性的示例。尽管只使用了 RequestConfirmation
,但我保留了所有代理函数。我已将其设置为始终同意发送的任何代码,这是您在问题中要求的。
此示例 Python 脚本将替换您的批处理脚本
import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
BUS_NAME = 'org.bluez'
ADAPTER_IFACE = 'org.bluez.Adapter1'
ADAPTER_ROOT = '/org/bluez/hci'
AGENT_IFACE = 'org.bluez.Agent1'
AGNT_MNGR_IFACE = 'org.bluez.AgentManager1'
AGENT_PATH = '/my/app/agent'
AGNT_MNGR_PATH = '/org/bluez'
CAPABILITY = 'KeyboardDisplay'
DEVICE_IFACE = 'org.bluez.Device1'
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
def set_trusted(path):
props = dbus.Interface(bus.get_object(BUS_NAME, path), dbus.PROPERTIES_IFACE)
props.Set(DEVICE_IFACE, "Trusted", True)
class Agent(dbus.service.Object):
@dbus.service.method(AGENT_IFACE,
in_signature="", out_signature="")
def Release(self):
print("Release")
@dbus.service.method(AGENT_IFACE,
in_signature='o', out_signature='s')
def RequestPinCode(self, device):
print(f'RequestPinCode {device}')
return '0000'
@dbus.service.method(AGENT_IFACE,
in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
print("RequestConfirmation (%s, %06d)" % (device, passkey))
set_trusted(device)
return
@dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="")
def RequestAuthorization(self, device):
print("RequestAuthorization (%s)" % (device))
auth = input("Authorize? (yes/no): ")
if (auth == "yes"):
return
raise Rejected("Pairing rejected")
@dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="u")
def RequestPasskey(self, device):
print("RequestPasskey (%s)" % (device))
set_trusted(device)
passkey = input("Enter passkey: ")
return dbus.UInt32(passkey)
@dbus.service.method(AGENT_IFACE,
in_signature="ouq", out_signature="")
def DisplayPasskey(self, device, passkey, entered):
print("DisplayPasskey (%s, %06u entered %u)" %
(device, passkey, entered))
@dbus.service.method(AGENT_IFACE,
in_signature="os", out_signature="")
def DisplayPinCode(self, device, pincode):
print("DisplayPinCode (%s, %s)" % (device, pincode))
class Adapter:
def __init__(self, idx=0):
bus = dbus.SystemBus()
self.path = f'{ADAPTER_ROOT}{idx}'
self.adapter_object = bus.get_object(BUS_NAME, self.path)
self.adapter_props = dbus.Interface(self.adapter_object,
dbus.PROPERTIES_IFACE)
self.adapter_props.Set(ADAPTER_IFACE,
'DiscoverableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Discoverable', True)
self.adapter_props.Set(ADAPTER_IFACE,
'PairableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Pairable', True)
if __name__ == '__main__':
agent = Agent(bus, AGENT_PATH)
agnt_mngr = dbus.Interface(bus.get_object(BUS_NAME, AGNT_MNGR_PATH),
AGNT_MNGR_IFACE)
agnt_mngr.RegisterAgent(AGENT_PATH, CAPABILITY)
agnt_mngr.RequestDefaultAgent(AGENT_PATH)
adapter = Adapter()
mainloop = GLib.MainLoop()
try:
mainloop.run()
except KeyboardInterrupt:
agnt_mngr.UnregisterAgent(AGENT_PATH)
mainloop.quit()
我正在进行一个将 Android 设备与 Raspberry Pi 设备连接的项目。 RPi 需要被视为用户永远不需要触摸的可部署设备。出于这个原因,我正在尝试在 RPi 上编写一个启动批处理脚本,允许用户将他们的 Android 与 PI 配对。
我的想法是,当您启动时,此脚本将 运行,他们 phone 上的用户将尝试连接到 RPi,RPi 将自动接受此连接。
这是我目前所拥有的
#!/bin/bash
bluetoothctl -- discoverable on
bluetoothctl -- pairable on
bluetoothctl -- agent on
bluetoothctl -- default-agent
问题是,当我这样做时,我没有进入 [bluetoothctl]
提示我需要与 Android.
当我 运行 这些命令(没有批处理脚本)并尝试与我的 Android 配对时,我得到
Request confirmation
[agent] Confirm passkey 861797 (yes/no): yes
从这里我只需要输入 yes 来实例化连接。我看到的问题是 1:我不知道如何留在命令行中的 [bluetoothctl]
提示符中与设备通信,以及 2:我不知道如何将“是”发送到提示。
同样,对我来说重要的是,除了为了部署目的而启动 RPi 之外,用户永远不需要对 RPi 做任何事情。是否有解决我的问题的方法,或者有更好的方法一起解决吗?
对于那些感兴趣的人,蓝牙启动连接已经到位,这样我就可以将网络信息发送到 RPi,它可以自动连接到网络,这样主应用程序通信就会以这种方式进行。
这是我能够手动完成的脚本的预期结果。
以这种方式使用 bluetoothctl
可能会出现问题,因为它并非设计为以这种方式进行交互。正如您将 Python 作为标签之一,从 Python (和其他语言)访问此功能的预期方式是通过 D-Bus API.
这些记录在:https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
还有示例:https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test
确认是agent API. You can also set discoverable and pairable with the adapter API中的RequestConfirmation
。使用 API 还可以让您停止可发现超时。
phone 连接后,您通常希望将其标记为可信,这样就不需要再次配对。这是通过 device API.
完成的下面是使用 Python 在适配器上设置这些属性的示例。尽管只使用了 RequestConfirmation
,但我保留了所有代理函数。我已将其设置为始终同意发送的任何代码,这是您在问题中要求的。
此示例 Python 脚本将替换您的批处理脚本
import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
BUS_NAME = 'org.bluez'
ADAPTER_IFACE = 'org.bluez.Adapter1'
ADAPTER_ROOT = '/org/bluez/hci'
AGENT_IFACE = 'org.bluez.Agent1'
AGNT_MNGR_IFACE = 'org.bluez.AgentManager1'
AGENT_PATH = '/my/app/agent'
AGNT_MNGR_PATH = '/org/bluez'
CAPABILITY = 'KeyboardDisplay'
DEVICE_IFACE = 'org.bluez.Device1'
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
def set_trusted(path):
props = dbus.Interface(bus.get_object(BUS_NAME, path), dbus.PROPERTIES_IFACE)
props.Set(DEVICE_IFACE, "Trusted", True)
class Agent(dbus.service.Object):
@dbus.service.method(AGENT_IFACE,
in_signature="", out_signature="")
def Release(self):
print("Release")
@dbus.service.method(AGENT_IFACE,
in_signature='o', out_signature='s')
def RequestPinCode(self, device):
print(f'RequestPinCode {device}')
return '0000'
@dbus.service.method(AGENT_IFACE,
in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
print("RequestConfirmation (%s, %06d)" % (device, passkey))
set_trusted(device)
return
@dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="")
def RequestAuthorization(self, device):
print("RequestAuthorization (%s)" % (device))
auth = input("Authorize? (yes/no): ")
if (auth == "yes"):
return
raise Rejected("Pairing rejected")
@dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="u")
def RequestPasskey(self, device):
print("RequestPasskey (%s)" % (device))
set_trusted(device)
passkey = input("Enter passkey: ")
return dbus.UInt32(passkey)
@dbus.service.method(AGENT_IFACE,
in_signature="ouq", out_signature="")
def DisplayPasskey(self, device, passkey, entered):
print("DisplayPasskey (%s, %06u entered %u)" %
(device, passkey, entered))
@dbus.service.method(AGENT_IFACE,
in_signature="os", out_signature="")
def DisplayPinCode(self, device, pincode):
print("DisplayPinCode (%s, %s)" % (device, pincode))
class Adapter:
def __init__(self, idx=0):
bus = dbus.SystemBus()
self.path = f'{ADAPTER_ROOT}{idx}'
self.adapter_object = bus.get_object(BUS_NAME, self.path)
self.adapter_props = dbus.Interface(self.adapter_object,
dbus.PROPERTIES_IFACE)
self.adapter_props.Set(ADAPTER_IFACE,
'DiscoverableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Discoverable', True)
self.adapter_props.Set(ADAPTER_IFACE,
'PairableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Pairable', True)
if __name__ == '__main__':
agent = Agent(bus, AGENT_PATH)
agnt_mngr = dbus.Interface(bus.get_object(BUS_NAME, AGNT_MNGR_PATH),
AGNT_MNGR_IFACE)
agnt_mngr.RegisterAgent(AGENT_PATH, CAPABILITY)
agnt_mngr.RequestDefaultAgent(AGENT_PATH)
adapter = Adapter()
mainloop = GLib.MainLoop()
try:
mainloop.run()
except KeyboardInterrupt:
agnt_mngr.UnregisterAgent(AGENT_PATH)
mainloop.quit()