蓝牙

来自 Arch Linux 中文维基

蓝牙(Bluetooth)是一个短距离无线通信标准,用于在手机、计算机和其他电子设备之间通信。在 Linux 中,权威的蓝牙协议栈实现是 BlueZ

安装[编辑 | 编辑源代码]

  1. 安装 bluez,这个软件包提供蓝牙协议栈。
  2. 安装 bluez-utils,这个软件包提供 bluetoothctl 实用程序。另外,也可以安装 bluez-deprecated-tools 来获得#弃用的 BlueZ 工具
  3. btusb 内核模块是通用蓝牙驱动。检查模块是否已加载。如果还没有,先加载模块
  4. 启动/启用 bluetooth.service
注意:
  • 蓝牙守护程序默认只会向属于 lp 的用户暴露 bnep0 设备。如果要连接到蓝牙设备的话,需先将用户添加到这个组。可以在 /usr/share/dbus-1/system.d/bluetooth.conf 中修改需要加入的组。
  • 一些蓝牙适配器和无线网卡绑定(例如 Intel Centrino)。这些蓝牙适配器需要先启用无线网卡(在笔记本上通常通过键盘快捷键)才能被内核识别。
  • 一些蓝牙适配器(例如 Broadcom)和网络适配器冲突。因此,需要确保在网络服务启动之前连接蓝牙。
  • 一些工具(例如 hcitool 和 hciconfig)已被上游弃用,并且不再包含在 bluez-utils 中。这些工具将不会被更新,因此建议更新脚本,避免使用它们。如果还是想用,安装 bluez-deprecated-tools。参见 FS#53110Bluez 邮件列表
  • 此 commit 开始, bluez-obexbluez-mesh 已经从 bluez 中独立出来,因此如果要通过蓝牙传输文件,必须安装 bluez-obex

前端[编辑 | 编辑源代码]

控制台[编辑 | 编辑源代码]

  • bluetoothctl — 在 shell 中配对设备是最简单可靠的方法之一。
http://www.bluez.org/ || bluez-utils
  • bluetuith — 为终端界面提供蓝牙管理器,可以方便的配对和管理设备,具有 OBEX 文件传输和鼠标支持。
https://www.github.com/darkhz/bluetuith || bluetuithAUR
提示:要自动化 bluetoothctl 命令,使用 echo -e "command1\ncommand2\n" | bluetoothctlbluetoothctl -- command

图形界面[编辑 | 编辑源代码]

以下软件包提供图形界面来自定义蓝牙。

  • GNOME BluetoothGNOME 的蓝牙工具。
    • gnome-bluetooth-3.0 提供后端(gnome-bluetooth 已过时)
    • gnome-shell 提供状态托盘
    • gnome-control-center 可通过图形界面配置蓝牙。可以在活动预览输入“蓝牙”或者运行 gnome-control-center bluetooth 进行配置。
    • 你还可以直接运行 bluetooth-sendto 命令来把文件发送到远程设备。
    • nautilus-bluetoothAUR 在 Nautilus 右键菜单添加“通过蓝牙发送”
    • 打开蓝牙设置面板来接收文件;只有在蓝牙设置面板打开时才能接收文件。
    • 要在 Thunar 的“发送到”菜单中添加蓝牙选项,请查看这里的指导。(使用 bluetooth-sendto %F 命令)。
https://wiki.gnome.org/Projects/GnomeBluetooth ||
  • BluedevilKDE 的蓝牙工具。如果 Dolphin 和系统托盘里没有蓝牙图标,就在系统托盘选项里启用,或者添加一个挂件。点击图标或在 KDE 系统设置里都可以配置蓝牙。
https://invent.kde.org/plasma/bluedevil || bluedevil
  • Blueberry — Linux Mint 的独立版 GNOME Bluetooth,可在所有桌面环境工作。Blueberry 不支持通过 Obex Object 推送来接收文件。
https://github.com/linuxmint/blueberry || blueberry
  • Blueman — 全功能蓝牙管理器。
https://github.com/blueman-project/blueman || blueman
  • ObexFTP — 用来和启动了 OBEX 的设备传输文件的工具。
http://dev.zuckschwerdt.org/openobex/wiki/ObexFtp || obexftpAUR

配对[编辑 | 编辑源代码]

注意: 使用蓝牙设备之前,先检查它有没有被 rfkill 禁用。

这一小节介绍直接用 bluetoothctl 配置 bluez5 的方法,如果你已经有前端工具(比如 GNOME Bluetooth)的话就不需要了。

实际的步骤取决于设备和它的输入功能。以下是使用 bluetoothctl 配对设备的一般步骤。

运行 bluetoothctl 交互命令。输入 help 来获取帮助。

  1. (可选操作)使用 select MAC_address 选择一个默认的蓝牙接收器。
  2. (可选操作)如果蓝牙设备已经关闭,使用命令 power on 打开蓝牙。蓝牙默认是开启的,请参考#默认电源状态
  3. 使用命令 devices 获得要配对的设备的 MAC 地址。
  4. 如果设备没有出现在上一步的列表中,使用命令 scan on 去搜索发现所有可配对的设备。
  5. 使用命令 agent on 打开代理或者选择一个特定的代理:如果在 agent 命令后按下两次 tab 键,应该就能看到可用代理的列表。蓝牙代理用于管理蓝牙“配对码”。它可以回复外部发来的“配对码”,也可以主动发送。大部分情况下使用 default-agent 应该就足够了。[1]
  6. 使用命令 pair MAC_address 配对设备(可用 tab 键补全 MAC 地址)。
  7. 如果配对设备不需要 PIN,那么你可能需要手动将设备添加到信任列表。使用命令 trust MAC_address
  8. 使用命令 connect MAC_address 建立连接。

以下为一个交互实例:

$ bluetoothctl
[NEW] Controller 00:10:20:30:40:50 hostname [default]
[bluetooth]# agent KeyboardOnly
Agent registered

[bluetooth]# default-agent
Default agent request successful

[bluetooth]# power on
Changing power on succeeded
[CHG] Controller 00:10:20:30:40:50 Powered: yes

[bluetooth]# scan on
Discovery started
[CHG] Controller 00:10:20:30:40:50 Discovering: yes
[NEW] Device 00:12:34:56:78:90 device name
[CHG] Device 00:12:34:56:78:90 LegacyPairing: yes

[bluetooth]# pair 00:12:34:56:78:90
Attempting to pair with 00:12:34:56:78:90
[CHG] Device 00:12:34:56:78:90 Connected: yes
[CHG] Device 00:12:34:56:78:90 Connected: no
[CHG] Device 00:12:34:56:78:90 Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 00:12:34:56:78:90 Paired: yes
Pairing successful
[CHG] Device 00:12:34:56:78:90 Connected: no

[bluetooth]# connect 00:12:34:56:78:90
Attempting to connect to 00:12:34:56:78:90
[CHG] Device 00:12:34:56:78:90 Connected: yes
Connection successful

双系统配对[编辑 | 编辑源代码]

要在双系统中配对设备,需要在 Linux 下手动更改配对密钥,以使其与 Windows 或 macOS 下的密钥保持一致。

这里只介绍手动配置的方法,自动化方法参见 bt-dualboot 等项目。

配置[编辑 | 编辑源代码]

首先,在 Arch Linux 中配对设备。然后重新启动到另一个操作系统,再次配对设备。接下来需要提取配对密钥,但首先要关闭蓝牙设备以防止其尝试重新连接。

注意: 部分罗技产品的 MAC 地址可能会在和新系统配对后自增1,比如 arch:Logitech MX Master 和 Logitech 604 Lightspeed。请检查你的设备是否有这种情况,配置过程中需要考虑这一点。

对于 Windows[编辑 | 编辑源代码]

你可以选择进入 Windows 提取密钥,或是直接在 Linux 下进入 Windows 的系统分区,用 chntpw 工具提取密钥。

在 Windows 上提取密钥[编辑 | 编辑源代码]

首先进入 Windows。

存储配对密钥的注册表项只有 SYSTEM 用户能访问。但是,无法以 SYSTEM 用户的身份登录系统,要以 SYSTEM 的身份运行 regedit.exe,必须借助微软的 Sysinternal 网站提供的 PsExec 工具。

下载 PsTools,然后解压出 PsExec64.exe

在解压出 EXE 的位置,以管理员身份打开命令提示符,启动注册表编辑器:

.\PsExec64.exe -s -i regedit.exe

在regedit中找到下面这一注册表项

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Keys

在此项中存储着每个蓝牙适配器的注册表项,按 MAC 地址列出。如果存在多个项目,可以按照这篇文章找到目标蓝牙适配器对应的 MAC 地址。

在目标适配器的表项中,每个已配对设备(也按照 MAC 地址列出)又各自对应一个二进制值。

对每个准备跨系统使用的设备,右键其整个注册表项,然后导出为 .reg 文件,之后可以从这个文件中复制密钥。

在此文件中,如果只有一个单独的二进制密钥,说明这个设备不是蓝牙 5.1 设备,只需要一个密钥。如果这个设备有多个密钥(比如 LTKIRK),那么这一个蓝牙 5.1 设备,配置方法参见#准备蓝牙 5.1 密钥

最后,重启进入 Linux,然后跳到#完成配置步骤

在 Linux 上提取密钥[编辑 | 编辑源代码]
注意: 如果 Windows 分区启用了 Bitlocker 加密,则无法从 Linux 中使用 chntpw 访问

进入 Arch Linux,安装 chntpw,然后挂载 Windows 系统盘。

$ cd /path/to/windows/system/Windows/System32/config
$ chntpw -e SYSTEM

chntpw 环境中,运行 ls。你可能会看到 CurrentControlSet 或者 ControlSet00X,X 是任意数字。根据看到的名称,执行

> cd CurrentControlSet\Services\BTHPORT\Parameters\Keys

或者

> cd ControlSet00X\Services\BTHPORT\Parameters\Keys

接下来查看电脑蓝牙适配器的 MAC 地址,进入其对应的文件夹:

> ls
> cd your-device's-mac-address

同样,再键入需要在双系统下使用的设备的 MAC 地址,进入其文件夹,如果不是蓝牙 5.1 设备,将只有一个密钥:

> ls
Node has 0 subkeys and 1 values
size  type        value name    [value if type DWORD]
16    REG_BINARY <123456789876>

使用 hex 获取密钥:

> hex 123456789876
:00000 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX (some other chars)

上面若干“XX”表示的就是密钥。记下这个密钥和它对应的 MAC 地址。

如果是蓝牙 5.1 设备,你将看到有多个密钥:

Node has 0 subkeys and 8 values
  size     type              value name             [value if type DWORD]
    16  3 REG_BINARY         <LTK>
     4  4 REG_DWORD          <KeyLength>               16 [0x10]
     8  b REG_QWORD          <ERand>
     4  4 REG_DWORD          <EDIV>                 37520 [0x9290]
    16  3 REG_BINARY         <IRK>
     8  b REG_QWORD          <Address>
     4  4 REG_DWORD          <AddressType>              1 [0x1]
     4  4 REG_DWORD          <AuthReq>                 45 [0x2d]

参考#准备蓝牙 5.1 密钥,用 hex value_name 获取需要的值。

最后,跳到#完成配置将这些密钥导入到 Linux 中。

对于 macOS[编辑 | 编辑源代码]

进入 macOS:

  • 对于macOS Monterey或更高的版本:
    1. 打开“钥匙串”,搜索 Bluetooth。
    2. 按日期排序。
    3. 如果刚刚移除并重连设备,则可以直接选择最新的设备。设备名可能是MobileBluetooth (较旧的蓝牙设备) 或者只是一个UUID (蓝牙5.1+)。
    4. 双击此项,检查MAC地址和你的设备是否一致。
    5. 勾选“显示密码”复选框,然后重复输入两次你的密码。
    6. 复制密码显示区域中的文本,它实际上是个 XML 文件 (⌘+a ⌘+c)
    7. 把文本粘贴到~/bt_keys.txt中。
  • 如果系统版本为 High Sierra 或更高的版本,运行
# defaults read /private/var/root/Library/Preferences/com.apple.bluetoothd.plist LinkKeys > ~/bt_keys.txt
  • 如果系统版本为 Sierra 或更低的版本,运行
# defaults read /private/var/root/Library/Preferences/blued.plist LinkKeys > ~/bt_keys.txt

此时,~/.bt_keys.txt 文件已经包含了所需的密钥。在旧版本的 macOS(High Sierra 和更低的版本)中则需要先反转密钥。例如,将 98 54 2f aa bb cc dd ee ff gg hh ii jj kk ll mm 变为 MM LL KK JJ GG FF EE DD CC BB AA 2F 54 98

注意: 反转可以用这段 Python 代码完成:
>>> Key="98 54 2f aa bb cc dd ee ff gg hh ii jj kk ll mm}"
>>> Key=list(reversed(ERand.strip().split()))

如果这是一个蓝牙 5.1 设备,将会有多个密钥与之对应。参考#准备蓝牙 5.1 密钥使用这些密钥。

最后,将 bt_keys.txt 文件复制到可由 Arch Linux 读取的驱动器。然后重新启动到 Arch Linux,跳到#完成配置小节继续。

准备蓝牙5.1密钥[编辑 | 编辑源代码]

这篇文章的某些内容需要扩充。

原因: We are still working on getting a comprehensive idea of how these work across vendors. For now, documenting specific devices' compatibility with these methods is helpful - especially non-Logitech data points. (在 Talk:Bluetooth#Bluetooth 5.1 Devices 中讨论)

若在#对于 Windows#对于 macOS小节中发现蓝牙5.1密钥,则需在导入Linux系统前对它们的值进行一些转换。在执行#完成配置步骤前,需创建好所需的文件,并填入恰当的内容。本步骤因设备而异,参照下表。一部分值的需要进行特殊操作,相关的实用程序也一并提供在下。

设备 原始密钥与所需的转换 (Windows) 原始密钥与所需的转换 (macOS) 目标密钥文件
Logitech MX Master 3
  • 复制 IRK
  • 删除十六进制字节之间的空格
? IdentityResolvingKey.Key
  • 复制 LTK.
  • 删除十六进制字节之间的空格
? SlaveLongTermKey.KeyPeripheralLongTermKey.Key
ERandEDIV 应为 0 Random NumberEncrypted Diversifier 应为 0.
ThinkPad TrackPoint Keyboard II, Pebble M350 mouse, Logitech G604 Lightspeed mouse
  • 复制 IRK
  • 反转十六进制字节的顺序
  • 复制 Remote IRK
  • 将其从base64转换为十六进制
IdentityResolvingKey.Key
  • 复制 LTK,删除十六进制字节之间的空格
  • 复制 Remote Encryption > Long-term Key.
  • 将其从base64转换为十六进制
LongTermKey.Key
  • 复制 ERand
  • 反转十六进制字节的顺序
  • 整体转换为十进制
  • 复制 Remote Encryption > Random Number
  • 将其从base64转换为十六进制
  • 反转十六进制字节的顺序
LongTermKey.Rand
  • 复制 EDIV
  • 反转十六进制字节的顺序
  • 整体转换为十进制
  • 复制 Remote Encryption > Encrypted Diversifier
  • 将其从base64转换为十六进制
  • 反转十六进制字节的顺序
LongTermKey.EDiv
Logitech M585/M590
  • 复制 IRK
  • 反转十六进制字节的顺序
IdentityResolvingKey.Key
  • 复制 LTK,删除十六进制字节之间的空格
LongTermKey.Key
  • 复制 ERand
  • 反转十六进制字节的顺序
  • 整体转换为十进制
LongTermKey.Rand
  • 复制 EDIV
  • 整体转换为十进制(可直接复制deword的十进制值)
LongTermKey.EDiv
其他设备
  • 复制 LTK
  • 删除16进制字节之间的空格
  • 复制 Remote IRK
  • 将其从base64转换为十六进制
LongTermKey.Key
  • 复制 ERand
  • 反转十六进制字节的顺序
  • 整体转换为十进制
  • 复制 Remote Encryption > Long-term Key
  • 将其从base64转换为十六进制
LongTermKey.Rand
  • 复制 EDIV
  • 删除16进制字节之间的空格
  • 复制 Remote Encryption > Encrypted Diversifier
  • 将其从base64转换为十六进制
  • 反转十六进制字节的顺序
LongTermKey.EDiv
注意:
>>> "key_value".replace(" ", "")
  • 这段Python代码实现了反转字节:
>>> ERand=" 63 02 84 B8 5D 40 44 DF   "
>>> ERand=list(reversed(ERand.strip().split()))
  • 这段Python代码将十六进制数转为十进制:
>>> int("".join(ERand), 16)
16088054540146049635
  • 这段Python代码将base64的值转化为十六进制表示:
binascii.hexlify(base64.decodebytes(b'...')).upper()
  • 这段Python代码完整完成 macOS Encrypted Diversifier 的转换:
struct.unpack('<H', base64.decodebytes(b'...'))
  • 这段Python代码完整完成 macOS Random Number 的转换:
struct.unpack('<H', base64.decodebytes(b'...'))

例如,在通常情况下:

  • LTK48 4D AF CD 0F 92 22 88 0A 52 9A F4 76 DA 8B 94,转换为 LongTermKey.Key 应为 484DAFCD0F9222880A529AF476DA8B94.
  • ERand63 02 84 B8 5D 40 44 DF, 转换为 Rand 应为 16088054540146049635.
  • EDIV37520,转换为EDiv 应为 37520.

完成配置[编辑 | 编辑源代码]

获得密钥后,切换用户为 root,然后输入:

# cd /var/lib/bluetooth/BT-Adapter-MAC-address

在此处可以找到每个已配对蓝牙设备的文件夹。对于要与 Arch 和双启动配对的每个设备,执行以下操作:

# cd device-MAC-address
注意: 若使用的是会在配队后自增MAC地址的设备,请在这一步改成将MAC地址文件夹改成自增后的。可以直接从Windows复制MAC地址过来,也可以手动自增(注意到每个8bit字节都是一个两位十六进制数)。

如果的设备不是蓝牙5.1设备(只有一个密钥),编辑 info 文件,改变 [LinkKey] 中列出的密钥。例如:

info
[LinkKey]
Key=XXXXXXXXXXXXXXX
注意: 确保所有字母都大写,并且删除所有空格。

如果是蓝牙5.1的多个密钥,那么则应将所有的密钥文件复制到对应的MAC地址目录。

然后重新启动 bluetooth.servicepulseaudio(使用 pulseaudio -k && pulseaudio --start)。

现在应该可以连接到你的设备了。

注意: 取决于蓝牙管理器,可能需要完全重启才能重新连接到设备。

配置[编辑 | 编辑源代码]

默认电源状态[编辑 | 编辑源代码]

截至 bluez 5.65, 它的默认行为是在启动服务或从挂起恢复时打开所有蓝牙适配器的电源[2]

如果希望蓝牙在重启后不自动启动(比如要在移动设备中节省电量)。需要将 AutoEnable=false 添加在 /etc/bluetooth/main.conf 底部的 [Policy] 下面:

/etc/bluetooth/main.conf
[Policy]
AutoEnable=false

禁用后可以用 power on 命令开启。

启动后自动可被发现[编辑 | 编辑源代码]

如果设备应该总是可见或者可以直接连接:

/etc/bluetooth/main.conf
[General]
DiscoverableTimeout = 0

从挂起中唤醒[编辑 | 编辑源代码]

允许蓝牙鼠标或者蓝牙键盘将系统从挂起中唤醒。首先,检查bios设置确认从USB中唤醒功能没有被禁止。许多情况下,蓝牙在主板上被看作是USB设备。

获得蓝牙适配器的厂商代码和设备ID。

$ lsusb | grep bluetooth -i
Bus 001 Device 002: ID 8087:0039 Intel Corp. AX200 Bluetooth

针对(上面适配器的)厂商代码和设备ID增加新的udev规则来允许从挂起中唤醒。

/etc/udev/rules.d/91-keyboard-mouse-wakeup.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="8087", ATTRS{idProduct}=="0039" RUN+="/bin/sh -c 'echo enabled > /sys$env{DEVPATH}/../power/wakeup;'"

如果系统唤醒后,要自动重新配置蓝牙键盘,例如,设置不同的键盘布局或者按键重复速度(相关细节,查看Xorg/Keyboard configuration#Adjusting typematic delay and ratexmodmap),可以创建一个可执行脚本:

configure_keyboard.sh
#!/bin/sh
export DISPLAY=:0
xset r rate 220 30
xmodmap /your/path/to/.Xmodmap

然后创建一个像上面一样的额外的udev规则。

/etc/udev/rules.d/92-keyboard-reconfiguration-wakeup.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="8087", ATTRS{idProduct}=="0039" RUN+="/your/path/to/configure_keyboard.sh"

启用实验性功能[编辑 | 编辑源代码]

Bluez 堆栈将新的、有可能出现错误的功能放在 D-Bus 实验性和内核实验性选项后面。这些功能随着时间的推移而变化,因为实验性功能被确定为稳定,不再需要该选项。要启用这些功能,请取消配置中相应行的注释:

/etc/bluetooth/main.conf
...

# Enables D-Bus experimental interfaces
# Possible values: true or false
#Experimental = true

# Enables kernel experimental features, alternatively a list of UUIDs
# can be given.
# Possible values: true,false,<UUID List>
# Possible UUIDS:
...
# Defaults to false.
#KernelExperimental = true

或者说, 你可以编辑 bluetooth.service 来添加 --experimental 或者 --kernel 标识,类似这个 drop-in file:

/etc/systemd/system/bluetooth.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd --experimental

无论是哪种方式,你都必须在之后重启 bluetooth.service

音频[编辑 | 编辑源代码]

通常你需要采取额外的步骤去整合针对蓝牙的音频服务。下面的章节会给出相关细节。

查看蓝牙耳机页面获得更多关于蓝牙音频和蓝牙耳机的信息。

PulseAudio[编辑 | 编辑源代码]

要使用蓝牙耳机或音响的话要先安装 pulseaudio-bluetooth。 要确认重新启动pulseaudio来使得安装生效:pulseaudio -k。默认的PulseAudio配置就可以直接用蓝牙耳机或音响了。[3]

注意: 有时要用 pavucontrol 选择音频的输出设备。

如果你有全局的 PulseAudio 设置,首先确保运行守护进程(一般是 pulse)的用户在 lp 组,并且在 PulseAudio 配置中加载蓝牙模块:

/etc/pulse/system.pa
...
load-module module-bluetooth-policy
load-module module-bluetooth-discover
...

可选的,如果你想要自动切换所有的音频输出到蓝牙设备,增加 load-module module-switch-on-connect

PipeWire[编辑 | 编辑源代码]

PipeWire 版本v0.3.19默认打开对蓝牙的支持。

ALSA[编辑 | 编辑源代码]

注意: Bluez5 已经不再直接集成对 ALSA 的支持,目前只对 PulseAudio 提供支持。如果你不能或者不想使用PulseAudio,请参考下面的命令。

首先,确认你的蓝牙音频设备已经正确配对且已经连接到系统。

然后,安装 bluez-alsa-gitAUR,启动(和使能) bluealsa 服务, 并增加当前用户到 audio 组。

执行下面的命令确认一切是否像预想地那样工作(替换下面的 XX:XX:XX:XX:XX:XXFILE.wav):

$ aplay -D bluealsa:SRV=org.bluealsa,DEV=XX:XX:XX:XX:XX:XX,PROFILE=a2dp FILE.wav

最后,增加下面的配置行到你的 ~/.asoundrc

~/.asoundrc
defaults.bluealsa {
    service "org.bluealsa"
    device "XX:XX:XX:XX:XX:XX"
    profile "a2dp"
}

现在你可以使用bluealsa设备来访问你的蓝牙音频设备。可以使用带有参数 -D bluealsa 的命令 alsamixer 来进行音量管理。

蓝牙串口[编辑 | 编辑源代码]

如果要在Bluetooth-to-Serial模块 (HC-05, HC-06)上进行蓝牙串口通信,需要执行下面的步骤:

使用 bluetoothctl 配对你的蓝牙设备,像上面所描述的那样。

安装 bluez-deprecated-tools,因为它提供了我们需要的特定的功能,这些功能没有被新工具支持。

绑定已经配对的设备的MAC地址到tty终端:

# rfcomm bind rfcomm0 MAC_address_of_Bluetooth_device

现在你可以打开 /dev/rfcomm0 来进行串口通信:

$ picocom /dev/rfcomm0 -b 115200

疑难解答[编辑 | 编辑源代码]

本文内容或本节内容已经过期。

原因: Replace hciconfig with newer commands. (在Talk:蓝牙讨论)

Debugging(排除故障)[编辑 | 编辑源代码]

为了调试,首先停止 bluetooth.service

然后用-d参数:

# /usr/lib/bluetooth/bluetoothd -n -d

另一种选择是用btmon工具。

弃用的 BlueZ 工具[编辑 | 编辑源代码]

八个BlueZ tools已经弃用并从bluez-utils 中移除,尽管并非所有这些都被更新的工具所取代。bluez-deprecated-tools 提供了bluez-utils 的替代版本包,使用了不推荐使用的工具。

不推荐的工具 推荐的替代品
gatttool btgatt-client, D-Bus Gatt API
hciattach btattach
hciconfig btmgmt (and bluetoothctl?)
hcidump btmon (and btsnoop)
hcitool missing, D-Bus Device API available
rfcomm missing, implement with D-Bus Profile1 API?
ciptool
sdptool missing, functionality seems to be scattered over different D-Bus objects: Profile, Advertising, and the UUIDs arrays in device and adapter.

gnome-bluetooth(gnome桌面环境下的蓝牙管理器)[编辑 | 编辑源代码]

如果接收文件时出现以下信息:

Bluetooth OBEX start failed: Invalid path
Bluetooth FTP start failed: Invalid path

确保 XDG user directories 存在。

外置USB蓝牙/2.4GHz接收器[编辑 | 编辑源代码]

如果你在使用外置USB蓝牙/2.4GHz接收器,你要先检查蓝牙接收器是否被识别。插入USB接收器后可通过 journalctl -f 检测(或查看 /var/log/messages.log)。 可能像下面这样:(注意hci):

Feb 20 15:00:24 hostname kernel: [ 2661.349823] usb 4-1: new full-speed USB device number 3 using uhci_hcd
Feb 20 15:00:24 hostname bluetoothd[4568]: HCI dev 0 registered
Feb 20 15:00:24 hostname bluetoothd[4568]: Listening for HCI events on hci0
Feb 20 15:00:25 hostname bluetoothd[4568]: HCI dev 0 up
Feb 20 15:00:25 hostname bluetoothd[4568]: Adapter /org/bluez/4568/hci0 has been enabled

如果只有前两行,说明系统找到了设备而只需要启动它。 例:

hciconfig -a hci0
hci0:	Type: USB
	BD Address: 00:00:00:00:00:00 ACL MTU: 0:0 SCO MTU: 0:0
	DOWN 
	RX bytes:0 acl:0 sco:0 events:0 errors:0
        TX bytes:0 acl:0 sco:0 commands:0 errors:
# hciconfig hci0 up
hciconfig -a hci0
hci0:	Type: USB
	BD Address: 00:02:72:C4:7C:06 ACL MTU: 377:10 SCO MTU: 64:8
	UP RUNNING 
	RX bytes:348 acl:0 sco:0 events:11 errors:0
        TX bytes:38 acl:0 sco:0 commands:11 errors:0

bluez-utils 里的 hcitool 检查设备是否被检测到。 要获取可用设备和他们的标识和MAC地址可以输入:

$ hcitool dev
Devices:
        hci0	00:1B:DC:0F:DB:40

设备的详细信息可以用hciconfig获取 :

$ hciconfig -a hci0
hci0:   Type: USB
        BD Address: 00:1B:DC:0F:DB:40 ACL MTU: 310:10 SCO MTU: 64:8
        UP RUNNING PSCAN ISCAN
        RX bytes:1226 acl:0 sco:0 events:27 errors:0
        TX bytes:351 acl:0 sco:0 commands:26 errors:0
        Features: 0xff 0xff 0x8f 0xfe 0x9b 0xf9 0x00 0x80
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
        Link policy: RSWITCH HOLD SNIFF PARK
        Link mode: SLAVE ACCEPT 
        Name: 'BlueZ (0)'
        Class: 0x000100
        Service Classes: Unspecified
        Device Class: Computer, Uncategorized
        HCI Ver: 2.0 (0x3) HCI Rev: 0xc5c LMP Ver: 2.0 (0x3) LMP Subver: 0xc5c
        Manufacturer: Cambridge Silicon Radio (10)

音频设备开始在离USB接收器较近的距离来回切换[编辑 | 编辑源代码]

如果有其他设备(和当前设备)共用同一个USB主机,它们可能会中断与音频设备的通信。 确保它是唯一连接到其总线的设备。例如:

$ lsusb
Bus 002 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 004: ID 048d:1345 Integrated Technology Express, Inc. Multi Cardreader
Bus 001 Device 003: ID 0424:a700 Standard Microsystems Corp. 2 Port Hub
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

CSR 接收器 0a12:0001[编辑 | 编辑源代码]

该设备 ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) 有一个回归错误[1], 目前仅适用于5.17和<6.0版本的内核。若想获得更多相关信息,请参阅Kernel Bug 60824.

罗技双模外置蓝牙/2.4GHz可切换USB接收器[编辑 | 编辑源代码]

罗技的外置USB接收器 (例如罗技MX5000)可以在两种模式下运行:2.4GHz接收器模式(模拟USB模式)和HCI(蓝牙模式)。在2.4GHz接收器模式下,接收器模拟了USB设备,所以在您的计算机上,您就像在用普通的USB有线鼠标/键盘一样。

如果您按住接收器上的红色小按钮,它会启用其他模式。按住接收器上的红色按钮并将其插入计算机,按住按钮3-5秒后,将以蓝牙模式接入设备。蓝牙图标会出现在系统托盘里。讨论

或者,您可以安装bluez-hid2hci当您连接罗技的接收器时,它可以自动切换模式。

hcitool扫描:找不到设备[编辑 | 编辑源代码]

  • 在一些戴尔笔记本电脑(例如Studio 15)上,您必须将蓝牙模式从HID切换到HCI。安装bluez-hid2hci,那么udev应该会自动执行此操作。或者,您可以运行此命令手动切换到HCI:
# /usr/lib/udev/hid2hci
  • 如果设备没有显示,并且您的计算机上有Windows系统,请尝试引导它并从Windows启用蓝牙适配器。
  • 有时,如下这个简单的命令能帮到您:
# hciconfig hci0 up

bluetoothctl: No default controller available(没有可用的默认控件)[编辑 | 编辑源代码]

一些主板蓝牙控件出现错误。要查看这是否是问题所在,请运行journalctl|grep-hci。如果出现“Command tx timeout”或“Failed to read Intel version command”之类的报错,请关闭电脑电源,并拔下电源线几秒钟。这会强制控件重新加载固件(而标准重新启动不会)。请参阅此处的错误报告。

确保设备没有被rfkill阻止。

蓝牙服务(软件)无法正确识别一些英特尔设备(硬件)(如8260)也可能发生这种情况。在某些情况下,使用不推荐使用的bluez utils compataAUR来代替bluez utils据报道已经解决了这个问题。

这也可能是由电源策略[2]引起的,在这种情况下,添加内核参数btusb.enable_autosuspend=n是一个潜在的解决方案。另请参阅Red Hat Bugzilla–Bug 1573562

有时,在没有选项的情况下重新加载btusb有助于恢复控件:

# modprobe -r btusb
# modprobe btusb

当接收器是CSR克隆时也可能发生这种情况

systemd: Condition check resulted in Bluetooth service being skipped(条件检查导致跳过蓝牙服务)[编辑 | 编辑源代码]

bluetooth.service只需要存在于/sys/class/bluetooth 目录即可,该目录应由内核模块 bluetooth创建,只有当 systemd-udev 真正找到一个工作的蓝牙硬件设备时,它才会自动加载。

如果您的/sys/class/bluetooth 不存在,请检查您的内核蓝牙模块是否由lsmod加载。如果没有, 并且您很确定自己有蓝牙设备, 您可以尝试通过加载蓝牙模块重新启动bluetooth.service,来重新启动这些服务。

在加载bluetooth模块时,您还应该加载相应的内核蓝牙驱动程序,一般用btusb,但是也可以用btrtl,btintel,btbcm,bnep,btusb 等。

检查bluetooth.serviceunit status (单元状态),看看它是否启动。

另请参阅 Debian Bug report logs - #853207.

如果 bluetooth.service 成功启动,但有可能您仍然无法正常使用蓝牙(例如, bluetoothctl 在您scan on时显示类似org.Bluez.Error.NotReady )。如果发生这种情况,请尝试重新启动计算机,并仔细检查:目录/sys/class/bluetooth 是否存在; lsmod 是否包括正确的蓝牙模块;在 journal中记录的信息; 等。 systemd-udev 应该自动检测出您的蓝牙硬件,而无需再次手动更改。

rfkill unblock:不能unblock[编辑 | 编辑源代码]

如果你的设备unblock后依然是soft blocked,试试:

$ connmanctl enable bluetooth

电脑蓝牙不可见[编辑 | 编辑源代码]

手机蓝牙扫描不到电脑?启动PSCAN和ISCAN:

# enable PSCAN and ISCAN
$ hciconfig hci0 piscan 
# check it worked
$ hciconfig
hci0:   Type: USB
        BD Address: 00:12:34:56:78:9A ACL MTU: 192:8 SCO MTU: 64:8
        UP RUNNING PSCAN ISCAN
        RX bytes:20425 acl:115 sco:0 events:526 errors:0
        TX bytes:5543 acl:84 sco:0 commands:340 errors:0
注意:/etc/bluetooth/main.conf 检查设备可见超时和配对超时

尝试在 /etc/bluetooth/main.conf 中更改设备类,如下所示:

# Default device class. Only the major and minor device class bits are
# considered.
#Class = 0x000100 (from default config)
Class = 0x100100

这是让我的电脑对我的手机可见的唯一解决方案。

Foxconn / Hon Hai / Lite-On Broadcom device(富士康/鸿海/光宝/博通 设备)[编辑 | 编辑源代码]

其中一些设备需要在启动时将固件闪存到设备中。没有提供固件,但可以使用hex2hcd(与bluez utils一起安装)将Microsoft Windows.hex文件转换为.hcd包)。

为了获得正确的.hex文件,请尝试搜索设备供应商:使用lsusb获得的产品代码,例如:

   ...
   Bus 002 Device 004: ID 04ca:2006 Lite-On Technology Corp. Broadcom BCM43142A0 Bluetooth Device
   ...

or

   Bus 004 Device 004: Id 0489:e031 Foxconn / Hon Hai

或者,启动到Windows(安装虚拟机即可),并从设备管理器获取固件名称。如果你想知道你的设备的型号,但在lsusb中看不到,你能作为iProductlsusb-v看到它。

也可以从下载的Windows驱动程序中提取.hex文件,而无需为其运行Windows。下载合适的驱动程序,例如 Bluetooth Widcomm ( 在为Lifebook P771[失效链接 2022-09-17 ⓘ] 提供的驱动中有列出),其中包含许多Broadcomm设备的驱动程序。在蓝牙Widcomm的情况下,驱动程序是一个自提取的RAR档案,因此可以使用unrar提取包 x。T要找出众多.hex文件中哪一个最适合您,请查找文件Win32/bcbtums-win7x86-brcm.inf并搜索[RAMUSBE031.CopyList],其中E031 应替换为大写的设备的产品代码(lsusb中的第二个十六进制数)。在下面,您应该看到正确的.hex文件的文件名。

您有了.hcd文件,就把它复制到/lib/firmware/brcm/BCM.hcd 中——这个文件名是dmesg建议的,在您的情况下可能会更改,所以请检查您的dmesg 输出以进行验证。然后重新加载btusb模块:

# rmmod btusb
# modprobe btusb

在某些情况下(使用较旧的内核?),您必须使用brcm_patchram_plus utility来闪存.hcd文件,该实用程序由brcm_patchram_plus-gitAUR[损坏的链接:package not found] 提供。首先,确保dmesg 中的设备被btusb识别为蓝牙设备。然后,运行以下操作(用您的供应商产品替换04ca 2006):

# echo '04ca 2006' > /sys/bus/usb/drivers/btusb/new_id
    

启用设备:

# hciconfig hci0 up

写入固件

# brcm_patchram_plus_usb --patchram fw-04ca_2006.hcd hci0

该设备现在应该可用。请参阅 BBS#162688 ,了解有关使这些更改持久化的信息。

Intel combined WiFi and Bluetooth cards(英特尔集成式WIFI和蓝牙)[编辑 | 编辑源代码]

请参阅Wireless network configuration#Bluetooth coexistence.

设备配对成功,一段时间后意外断开[编辑 | 编辑源代码]

如果运行 journalctl有以下结果,并且你的设备配对后过一会儿又断开:

bluetoothd: Unable to get connect data for Headset Voice gateway: getpeername: Transport endpoint is not connected (107)
bluetoothd: connect error: Connection refused (111)

这可能是因为你在其它操作系统中用同样的蓝牙适配器配对了这个设备(比如双启动)。有的设备不能在MAC地址和多个设备联系的情况下工作。你可以先移除设配再重新配对:

$ bluetoothctl
[bluetooth]# devices
Device XX:XX:XX:XX:XX:XX My Device
[bluetooth]# remove XX:XX:XX:XX:XX:XX

重启 bluetooth.service,打开蓝牙适配器,让设备可见,重新扫描配对。因为蓝牙管理器不一样,有时需要重启系统。

扫描不到设备[编辑 | 编辑源代码]

有的节能蓝牙设备用bluetoothctl扫描不到,比如某些蓝牙鼠标(如Logitech MX Master)。可以尝试使用transport le来扫描设备:

# bluetoothctl
[bluetooth]# menu scan
[bluetooth]# transport le
[bluetooth]# back
[bluetooth]# scan on
[bluetooth]# devices
...
Device XX:XX:XX:XX:XX:XX device name <---- 这个就是你的设备

另一种方法是安装 bluez-deprecated-tools启动 bluetooth.service 再输入:

# bluetoothctl
[NEW] Controller (MAC) myhostname [default]
[bluetooth]# power on
[CHG] Controller (MAC) Class: 0x0c010c
Changing power on succeeded
[CHG] Controller (MAC) Powered: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller (MAC) Discovering: yes

在另一个终端里输入:

# hcitool lescan

等待你的设备出现,再按 Ctrl+C。 bluetoothctl 就可以获取你的设备并正常配对了。

Cannot receive transferred files due to symlink(由于符号链接,无法接收传输的文件)[编辑 | 编辑源代码]

如果在功能正常的蓝牙连接上传入文件传输失败,则问题可能是由于文件传输路径中的符号链接造成的。日志中会显示这样的日志:

Jun 18 11:18:13 ember obexd[3338969]: open(/home/me/.cache/obexd/MOC740): Operation not permitted (1)

如果错误消息中显示的路径包含符号链接,则obexd默认情况下不会接受它。初始化时可以使用obex.service用户服务Drop-in file覆盖该行为:

~/.config/systemd/user/obex.service.d/10-symlink.conf
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/obexd --symlinks

然后重新加载调用用户的systemd管理器配置,并重新启动obex.service用户单元。

耳机和鼠标之间的干扰[编辑 | 编辑源代码]

如果您在同时使用蓝牙鼠标和键盘时遇到音频断断续续的问题,您可以尝试以下#23中提到的方法 https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/424215

# hciconfig hci0 lm ACCEPT,MASTER
# hciconfig hci0 lp HOLD,SNIFF,PARK

蓝牙鼠标动作延迟[编辑 | 编辑源代码]

尝试编辑文件 /var/lib/bluetooth/XX:XX:XX:XX:XX:XX/YY:YY:YY:YY:YY:YY/info (XX:XX:XX:XX:XX:XX-您的蓝牙适配器MAC地址,YY:YY:YY:YY:YY:YY -您的鼠标MAC地址),并添加以下行:

[ConnectionParameters]
MinInterval=6
MaxInterval=9
Latency=44
Timeout=216

您可以通过运行hcitool dev命令查看本地适配器的MAC地址。您可以通过执行hcitool con命令查看当前连接的远程设备的MAC地址。

挂起/休眠后适配器消失[编辑 | 编辑源代码]

首先,查找适配器的供应商和产品ID。例如:

$ lsusb -tv
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    ...
    |__ Port 3: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M
        ID 8087:0025 Intel Corp. 
    |__ Port 3: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M
        ID 8087:0025 Intel Corp. 
    ...

在以上的例子中,供应商ID是8087,产品ID是0025。

然后,使用 usb_modeswitch重置你指定的适配器:

# usb_modeswitch -R -v vendor_ID -p product_ID

Problems with all BLE devices on kernel (5.9+内核版本5.9以上所有BLE设备的问题)[编辑 | 编辑源代码]

从v5.9开始,内核蓝牙堆栈尝试在BLE连接上使用链路层隐私。如果设备在配对后工作,但无法在重新启动或挂起后继续运行,可能是因为这个原因。

要解决[3]此问题,请打开/var/lib/bluetooth/adapter_mac/device_mac/info删除以下行,然后重新启动bluetooth.service:

[IdentityResolvingKey]
Key=...

请参阅Arch论坛上的相关讨论

Bluetooth immediately waking up suspend-to-idle devices(蓝牙突然唤醒挂起的空闲设备)[编辑 | 编辑源代码]

在能够挂起到空闲 suspend-to-idle/S2idle/S0ix/Modern Standby的系统上,蓝牙控件将在睡眠期间保持启用状态。如果连接了蓝牙设备,这通常会导致系统在进入睡眠状态后立即唤醒

为了防止这种情况,你可以在启用睡眠模式前完全禁用蓝牙——安装T bluez-utils 并创建此文件:

/etc/systemd/system/bluetooth-disable-before-sleep.service
[Unit]
Description=Disable Bluetooth before going to sleep
Before=sleep.target
Before=suspend.target
Before=hybrid-sleep.target
Before=suspend-then-hibernate.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes

ExecStart=/usr/bin/bluetoothctl power off
ExecStop=/usr/bin/bluetoothctl power on

[Install]
WantedBy=sleep.target
WantedBy=suspend.target
WantedBy=hybrid-sleep.target
WantedBy=suspend-then-hibernate.target

启用此服务并检查蓝牙设备在进入睡眠状态时是否断开连接,以及在唤醒系统后蓝牙何时恢复连接。

如果使用此解决方法,则使用蓝牙鼠标/键盘唤醒系统将不起作用。

持续连接/断开与TP-LINK UB400和Xbox手柄的连接[编辑 | 编辑源代码]

使用以下设置:

/etc/bluetooth/main.conf
...
[General
JustWorksRepairing = always
FastConnectable = true
Class = 0x000100
...
[GATT]
ReconnectIntervals=1,1,2,3,5,8,13,21,34,55
AutoEnable=true
...

然后重新启用bluetooth.service.

你可以参阅discussion on xpadneo 但不需要xpadneo驱动程序

Mediatek MT7921或MT7961在带有windows的双启动系统上[编辑 | 编辑源代码]

在双启动系统上,如果Windows和Linux的蓝牙固件版本不同,则蓝牙适配器在重新启动到Windows后无法工作。

防止这种情况的最佳方法是为每个操作系统更新最新版本的蓝牙驱动程序(尤其是固件)。

如果找不到Windows的最新版本驱动程序(或固件),可以从Arch Linux复制最新的固件文件/usr/lib/firmware/mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin.xz 并提取到Windows(例如C:\WINDOWS\system32\DRIVERS\,可以在Windows上的设备管理器中找到固件文件路径)。

  1. 在软件开发中,回归错误是指在新版本或新功能中引入的错误,这导致现有功能或已修复的错误再次出现。 回归错误可能是由于代码更改、库更新、配置更改等原因导致的。它们通常表现为程序中的错误、异常、崩溃或数据不一致。
  2. 比如省电模式,可能导致蓝牙服务默认关闭
  3. https://lkml.kernel.org/lkml/D577711C-4AF5-4E82-8A17-E766B64E15A9@holtmann.org/