跳转到内容

BLE 客户端

ble_client 组件用于连接蓝牙低功耗设备,以便查询和控制它们。该组件本身不暴露任何传感器或输出组件,而只是管理与其他组件的连接。

WARNING

ESP32 上的 BLE 软件栈会消耗设备上相当多的 RAM。

如果您的设备配置中包含太多额外组件,很可能会发生崩溃。 内存密集型组件,如 Voice Assistant 和其他音频组件,最有可能引起问题。

NOTE

由于 ESP32 BLE 协议栈的限制,最多支持三个设备。如果您希望连接更多设备,请使用额外的 ESP32 开发板。

此组件支持需要 6 位 PIN 码用于身份验证的设备。

目前,已连接客户端的设备无法被基于 Esp32 Ble Tracker 的其他组件支持,因为它们监听只由没有活动连接的设备发送的广播。

尽管有上面最后一点,ble_client 组件仍需要 esp32_ble_tracker 组件来发现可用的客户端设备。

esp32_ble_tracker:
ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: itag_black
auto_connect: true
  • mac_address (必填, MAC Address):要连接的 BLE 设备的 MAC 地址。
  • auto_connect (可选, boolean):如果为 true,当设备被 Esp32 Ble Tracker 发现时将自动连接。默认为 true。
  • id (必填, ID):用于代码生成以及供依赖组件引用的 ID。

自动化:

当客户端连接到 BLE 设备时触发此自动化。

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: ble_itag
on_connect:
then:
- lambda: |-
ESP_LOGD("ble_client_lambda", "Connected to BLE device");

当客户端断开与 BLE 设备的连接时触发此自动化。

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: ble_itag
on_disconnect:
then:
- lambda: |-
ESP_LOGD("ble_client_lambda", "Disconnected from BLE device");

当 BLE 设备请求验证密钥进行身份验证时触发此自动化。

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: ble_itag
on_passkey_request:
then:
- ble_client.passkey_reply:
id: ble_itag
passkey: 123456

当从 BLE 设备收到验证密钥时触发此自动化。

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: ble_itag
on_passkey_notification:
then:
- logger.log:
format: "Enter this passkey on your BLE device: %06d"
args: [ passkey ]

当 BLE 设备请求进行数字比较时触发此自动化。

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: ble_itag
on_numeric_comparison_request:
then:
- logger.log:
format: "Compare this passkey with the one on your BLE device: %06d"
args: [ passkey ]
- ble_client.numeric_comparison_reply:
id: ble_itag
accept: True

此操作仅对 auto_connect: false 的设备有用,允许从自动化内部建立连接。连接后,可以使用其他操作,如 ble_write。这在对 BLE 服务器只需要偶尔交互时很有用,因此不需要保持持续连接。

以下示例每小时更新一次小米 MHO-C303 时钟的时间。请注意,在连接尝试期间必须停止 BLE 跟踪器,并在之后重新启动。如果跟踪器设置了 continuous: false,则不需要这样做。在此示例场景中,还有另一个 BLE 设备确实需要扫描器保持开启,因此在连接期间需要停止和启动扫描。

ble_client:
- id: ble_clock
mac_address: XX:XX:XX:XX:XX:XX
auto_connect: false
- id: other_device
mac_address: XX:XX:XX:XX:XX:XX
interval:
- interval: 60min
then:
- esp32_ble_tracker.stop_scan:
- ble_client.connect: ble_clock
- ble_client.ble_write:
id: ble_clock
service_uuid: EBE0CCB0-7A0A-4B0C-8A1A-6FF2997DA3A6
characteristic_uuid: EBE0CCB7-7A0A-4B0C-8A1A-6FF2997DA3A6
value: !lambda |-
uint32_t t = id(sntp_time).now().timestamp + ESPTime::timezone_offset();
return {(uint8_t)t, (uint8_t)(t >> 8), (uint8_t)(t >> 16), (uint8_t)(t >> 24), 0};
- ble_client.disconnect: ble_clock
- esp32_ble_tracker.start_scan:

connect 操作之后的任何操作都只在连接成功后才继续执行。如果连接失败,自动化块中的后续操作将不会执行。如果扫描已停止,应考虑这一点——可能需要另一种机制来重新启动扫描。

此操作断开使用 ble_client.connect 操作连接的设备。断开连接完成后,自动化块序列的执行将继续。

此操作触发对指定 BLE 特性的写入。写入以尽力而为的方式进行尝试,并且只有在 ble_client 的连接已建立且外设公开了预期的 BLE 服务和特性的情况下才会成功。写入完成后,自动化块序列的执行将继续。写入失败将不会停止后续操作的执行(例如,这允许执行断开连接。)

示例用法:

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: my_ble_client
switch:
- platform: template
name: "My Switch"
turn_on_action:
- ble_client.ble_write:
id: my_ble_client
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
# List of bytes to write.
value: [0x01, 0xab, 0xff]
- ble_client.ble_write:
id: my_ble_client
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
# A lambda returning an std::vector<uint8_t>.
value: !lambda |-
return {0x13, 0x37};
  • id (必填, ID):关联 BLE 客户端的 ID。
  • service_uuid (必填, UUID):要写入的服务的 UUID。
  • characteristic_uuid (必填, UUID):要写入的服务特性的 UUID。
  • value (必填, bytes 列表, 可模板化):要写入的值。

此操作使用指定的 passkey 触发身份验证尝试。

示例用法:

on_...:
then:
- ble_client.passkey_reply:
id: my_ble_client
passkey: 123456
  • id (必填, ID):关联 BLE 客户端的 ID。
  • passkey (必填, int, 可模板化):6 位验证密钥。

ble_client.numeric_comparison_reply Action

Section titled “ble_client.numeric_comparison_reply Action”

此操作在数字比较后触发身份验证尝试。

示例用法:

on_...:
then:
- ble_client.numeric_comparison_reply:
id: my_ble_client
accept: True
  • id (必填, ID):关联 BLE 客户端的 ID。
  • accept (必填, boolean, 可模板化):如果两个 BLE 设备上显示的验证密钥匹配,则应为 true。

此操作从安全数据库中移除设备并管理取消配对。

示例用法:

ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: my_ble_client
on_connect:
then:
- ble_client.remove_bond:
id: my_ble_client
  • id (必填, ID):关联 BLE 客户端的 ID。

本节简要概述蓝牙 LE 架构,以帮助理解此组件及相关组件。网上有很多更详细的参考资料。

BLE 使用服务器和客户端的概念。简而言之,服务器实现在提供服务的设备上,通常是诸如心脏监测器、标签、气象站等设备。客户端连接到服务器并使用其服务。客户端通常是手机上的应用,或者在 ESPHome 的情况下,是 ESP32 设备。

当客户端连接到服务器时,客户端会查询服务器提供的服务。服务在服务器上公开类别的功能。这些可能是定义明确且受支持的服务,例如电池电量服务、设备信息或心率。也可能是为该设备专门设计的自定义服务。例如,廉价 iTag 上的按钮使用自定义服务。

每个服务然后定义一个或多个特征,这些特征通常是该服务的离散值。例如,对于环境传感器服务,公开的特征包括风速、湿度和降雨量。根据它们的功能,这些特征可能只读或可读写。

一个特征还可以公开一个或多个描述符,这些描述符携带有关该特征的更多信息。这可能是单位、有效范围以及是否启用通知(见下文)等内容。

BLE 还支持通知。客户端持续轮询更新可能会消耗大量电力,这对于设计为低功耗的协议来说是不可取的。相反,服务器可以仅在更新发生变化时将更新推送给客户端。根据其用途和设计,特征可能允许发送通知。然后,客户端可以通过设置该特征的配置描述符来启用通知。

每个服务、特征和描述符都由一个唯一标识符(UUID)标识,长度可能在 16 到 128 位之间。客户端通常会根据 UUID 来识别设备的功能。

一旦连接建立,使用完整的 UUID 引用每个服务/特征/描述符将占用小小的(约 23 字节)数据包的相当大一部分。因此,特征和描述符还提供了一个小的 2 字节句柄(别名)来最大限度地增加可用数据空间。

虽然该组件可以连接到大多数 BLE 设备,但只有通过依赖组件才能获得有用的功能,例如 Ble Client。有关设置特定设备的详细信息,请参阅这些组件的文档。

要使用 ble_client 组件,您需要启用 Esp32 Ble Tracker 组件。这还将允许您发现设备的 MAC 地址。

当您发现设备的 MAC 地址后,可以将其添加到 ble_client 配置块中。

然后,如果您构建并上传此配置,ESP 将侦听该设备,并在发现它时尝试连接。然后,该组件将查询设备的所有可用服务和特性并显示在日志中:

[18:24:56][D][ble_client:043]: Found device at MAC address [XX:XX:XX:XX:XX:XX]
[18:24:56][I][ble_client:072]: Attempting BLE connection to XX:XX:XX:XX:XX:XX
[18:24:56][I][ble_client:097]: [XX:XX:XX:XX:XX:XX] ESP_GATTC_OPEN_EVT
[18:24:57][I][ble_client:143]: Service UUID: 0x1800
[18:24:57][I][ble_client:144]: start_handle: 0x1 end_handle: 0x5
[18:24:57][I][ble_client:305]: characteristic 0x2A00, handle 0x3, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A01, handle 0x5, properties 0x2
[18:24:57][I][ble_client:143]: Service UUID: 0x1801
[18:24:57][I][ble_client:144]: start_handle: 0x6 end_handle: 0x6
[18:24:57][I][ble_client:143]: Service UUID: 0x180A
[18:24:57][I][ble_client:144]: start_handle: 0x7 end_handle: 0x19
[18:24:57][I][ble_client:305]: characteristic 0x2A29, handle 0x9, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A24, handle 0xb, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A25, handle 0xd, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A27, handle 0xf, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A26, handle 0x11, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A28, handle 0x13, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A23, handle 0x15, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A2A, handle 0x17, properties 0x2
[18:24:57][I][ble_client:305]: characteristic 0x2A50, handle 0x19, properties 0x2
[18:24:57][I][ble_client:143]: Service UUID: F000FFC0045140-00B0-0000-0000-000000
[18:24:57][I][ble_client:144]: start_handle: 0x1a end_handle: 0x22
[18:24:57][I][ble_client:305]: characteristic F000FFC1045140-00B0-0000-0000-000000, handle 0x1c, properties 0x1c
[18:24:57][I][ble_client:343]: descriptor 0x2902, handle 0x1d
[18:24:57][I][ble_client:343]: descriptor 0x2901, handle 0x1e
[18:24:57][I][ble_client:305]: characteristic F000FFC2045140-00B0-0000-0000-000000, handle 0x20, properties 0x1c
[18:24:57][I][ble_client:343]: descriptor 0x2902, handle 0x21
[18:24:57][I][ble_client:343]: descriptor 0x2901, handle 0x22
[18:24:57][I][ble_client:143]: Service UUID: 0xFFE0
[18:24:57][I][ble_client:144]: start_handle: 0x23 end_handle: 0x26
[18:24:57][I][ble_client:305]: characteristic 0xFFE1, handle 0x25, properties 0x10
[18:24:57][I][ble_client:343]: descriptor 0x2902, handle 0x26
[18:24:57][I][ble_client:143]: Service UUID: 0x1802
[18:24:57][I][ble_client:144]: start_handle: 0x27 end_handle: 0x29
[18:24:57][I][ble_client:305]: characteristic 0x2A06, handle 0x29, properties 0x4

发现的服务随后可用于启用和配置其他 ESPHome 组件,例如服务 UUID 0xFFE0 用于 iTag 式钥匙串按钮事件,由 Ble Client 组件使用。

使用固定验证密钥的安全连接:

esp32_ble:
io_capability: keyboard_only
esp32_ble_tracker:
ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: pvvx_ble_display
on_passkey_request:
then:
- logger.log: "Authenticating with passkey"
- ble_client.passkey_reply:
id: pvvx_ble_display
passkey: 123456

使用动态生成的验证密钥的安全连接:

api:
actions:
- action: passkey_reply
variables:
passkey: int
then:
- logger.log: "Authenticating with passkey"
- ble_client.passkey_reply:
id: my_ble_client
passkey: !lambda return passkey;
- action: numeric_comparison_reply
variables:
accept: bool
then:
- logger.log: "Authenticating with numeric comparison"
- ble_client.numeric_comparison_reply:
id: my_ble_client
accept: !lambda return accept;
esp32_ble:
io_capability: keyboard_display
esp32_ble_tracker:
ble_client:
- mac_address: XX:XX:XX:XX:XX:XX
id: my_ble_client
on_passkey_request:
then:
- logger.log: "Enter the passkey displayed on your BLE device"
- logger.log: " Go to https://my.home-assistant.io/redirect/developer_services/ and select passkey_reply"
on_passkey_notification:
then:
- logger.log:
format: "Enter this passkey on your BLE device: %06d"
args: [ passkey ]
on_numeric_comparison_request:
then:
- logger.log:
format: "Compare this passkey with the one on your BLE device: %06d"
args: [ passkey ]
- logger.log: " Go to https://my.home-assistant.io/redirect/developer_services/ and select numeric_comparison_reply"
on_connect:
then:
- logger.log: "Connected"