蓝牙 - Arch Linux 中文维基

跳转到内容

# 蓝牙

来自 Arch Linux 中文维基

相关文章

- 蓝牙鼠标
- 蓝牙耳机

翻译状态：

- 本文（或部分内容）译自 Bluetooth，最近一次同步于 2022-12-31，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

蓝牙（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#53110 和 Bluez 邮件列表。
- 从此 commit 开始， bluez-obex包 和 bluez-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" | bluetoothctl` 或 `bluetoothctl -- command`。

#### 图形界面

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

- GNOME Bluetooth — GNOME 的蓝牙工具。
  - 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 ||

- Bluedevil — KDE 的蓝牙工具。如果 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包

- Bluetooth Manager Sidebar — 适用于 Wayland 会话的 GTK4/libadwaita 蓝牙管理器，以侧边栏形式打开，支持设备配对、OBEX 文件传输和音频配置文件切换。

  https://github.com/Relz/bluetooth-manager-sidebar || bm-sidebarAUR

- 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 系统的情况，仅需确保 `/var/lib/bluetooth/BT-Adapter-MAC-address` 下的所有文件在两个系统中相同即可。既可以复制，也可以通过链接实现。

而对于 Windows 或 MacOS，需要在 Linux 下手动更改配对密钥，以使其与 Windows 或 macOS 下的密钥保持一致。

这里只介绍手动配置的方法，自动化方法参见 bt-dualboot 等项目。如果需要半自动化工具，考虑使用 bluetooth-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 设备，只需要一个密钥。如果这个设备有多个密钥（比如 `LTK` 或 `IRK`），那么这是一个蓝牙 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

如果该环境下没有 `CurrentControlSet`，但存在 `ControlSet00X`，那么执行

    > cd ControlSet00X\Services\BTHPORT\Parameters\Keys

这里可能仅有一个以蓝牙适配器的 MAC 地址为名的子密钥。 使用 `ls` 查看并 `cd` 进去：

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

该适配器下的子密钥名就是适配器配对的设备的 MAC 地址。 使用 `ls`查看，并 `cd` 进入所有你想要在双系统下配对的设备：

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

如果不是蓝牙 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"
    >>> " ".join(reversed(key.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 Anywhere 3S Logitech MX Master 3 Logitech MX Master 3S Logitech MX Keys Logitech MX Keys Mini Logitech MX Mechanical Xbox One S Wireless Controller | 复制 `IRK` 删除十六进制字节之间的空格 | ? | `IdentityResolvingKey.Key`
复制 `LTK`. 删除十六进制字节之间的空格 | ? | `SlaveLongTermKey.Key` 与 `PeripheralLongTermKey.Key`
`ERand` 和 `EDIV` 应为 `0` | Random Number 与 Encrypted Diversifier 应为 `0`. | –
Logitech MX Anywhere 2S | Copy `IRK`. Remove the spaces between the hex octets. | ? | `IdentityResolvingKey.Key`
Copy `CSRK`. Remove the spaces between the hex octets. | ? | `LocalSignatureKey.Key`
Copy `LTK`. Remove the spaces between the hex octets. | ? | `LongTermKey.Key`
Copy `KeyLength`. Convert the whole number to decimal. | ? | `LongTermKey.EncSize`
Copy `EDIV`. Convert the whole number to decimal. | ? | `LongTermKey.EDiv`
Copy `ERand`. Reverse the order of the octets. Convert the whole number to decimal. | ? | `LongTermKey.Rand`
Royal Kludge F68 keyboard is like the Logitech MX Anywhere 2S | Also copy `CSRKInbound` too. Remove the spaces between the hex octets. | ? | `RemoteSignatureKey.Key`
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转换为小端十进制数字（参见下方 Python 脚本） | `LongTermKey.Rand`
复制 `EDIV` 反转十六进制字节的顺序 整体转换为十进制 | 复制 Remote Encryption > Encrypted Diversifier 将其从base64转换为小端十进制数字（参见下方 Python 脚本） | `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`
Xbox wireless controller | Copy `LTK`. Remove the spaces between the hex octets. | ? | `SlaveLongTermKey.Key`

注意：

- 删除十六进制字节间的空格，可使用 这一在线工具 或这段 Python 代码:

    >>> "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('<Q', base64.decodebytes(b'...'))

例如，在通常情况下:

- `LTK` 为 `48 4D AF CD 0F 92 22 88 0A 52 9A F4 76 DA 8B 94`，转换为 `LongTermKey.Key` 应为 `484DAFCD0F9222880A529AF476DA8B94`.
- `ERand` 为 `63 02 84 B8 5D 40 44 DF`， 转换为 `Rand` 应为 `16088054540146049635`.
- `EDIV` 为 `37520`，转换为`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 的密钥，编辑 `info` 文件并将所有适用的密钥替换为记录的值。例如，对于 Xbox One S 无线手柄：

    info

    [IdentityResolvingKey]
    Key=<IdentityResolvingKey.Key>

    [PeripheralLongTermKey]
    Key=<PeripheralLongTermKey.Key>

    [SlaveLongTermKey]
    Key=<SlaveLongTermKey.Key>

然后重新启动 `bluetooth.service` 和 `pulseaudio`（使用 `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 rate 和 xmodmap），可以创建一个可执行脚本：

    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:XX` 和 `FILE.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.service`的 unit 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中看不到，你能作为`iProduct`用lsusb-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/

分类：​

- 蓝牙
- 使用“模板:过时”标记的页面或章节
- 包含失效链接的页面
- 包含损坏的软件包链接的页面

蓝牙
添加话题