BLE 客户端
ble_client 组件用于连接蓝牙低功耗设备,以便查询和控制它们。该组件本身不暴露任何传感器或输出组件,只是管理连接以供其他组件使用。
NOTE
由于 ESP32 BLE 栈的限制,最多支持三个设备。如果您希望连接更多设备,请使用额外的 ESP32 开发板。
该组件支持需要 6 位 PIN 码进行认证的设备。
目前,通过客户端连接的设备无法被基于ESP32 BLE 跟踪器的其他组件支持,因为它们监听的是广播消息,而只有没有活动连接的设备才会发送广播。
尽管有上面最后一点说明,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 地址): 要连接的 BLE 设备的 MAC 地址。
- auto_connect (可选, 布尔值): 如果为 true,当ESP32 BLE 跟踪器发现设备时将自动连接。默认为 true。
- id (必需, ID): 用于代码生成和被依赖组件引用的 ID。
自动化:
-
on_connect (可选, 自动化): 当客户端连接到设备时执行的自动化。参见
on_connect。 -
on_disconnect (可选, 自动化): 当客户端与设备断开连接时执行的自动化。参见
on_disconnect。 -
on_passkey_request (可选, 自动化): 用于输入另一个 BLE 设备所需的密钥的自动化。参见
on_passkey_request。 -
on_passkey_notification (可选, 自动化): 用于向用户显示密钥的自动化。参见
on_passkey_notification。 -
on_numeric_comparison_request (可选, 自动化): 用于比较两个 BLE 设备上显示的密钥的自动化。参见
on_numeric_comparison_request。
BLE 客户端自动化
Section titled “BLE 客户端自动化”on_connect
Section titled “on_connect”当客户端连接到 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");on_disconnect
Section titled “on_disconnect”当客户端与 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");on_passkey_request
Section titled “on_passkey_request”当 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: 123456on_passkey_notification
Section titled “on_passkey_notification”当从 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 ]on_numeric_comparison_request
Section titled “on_numeric_comparison_request”当 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: Trueble_client.connect 动作
Section titled “ble_client.connect 动作”此动作仅适用于设置了 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.disconnect 动作
Section titled “ble_client.disconnect 动作”此动作断开通过 ble_client.connect 动作连接的设备。
自动化块序列的执行将在断开连接完成后继续。
ble_client.ble_write 动作
Section titled “ble_client.ble_write 动作”此动作触发向指定 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 # 要写入的字节列表。 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 # 返回 std::vector<uint8_t> 的 lambda。 value: !lambda |- return {0x13, 0x37};- id (必需, ID): 关联的 BLE 客户端的 ID。
- service_uuid (必需, UUID): 要写入的服务的 UUID。
- characteristic_uuid (必需, UUID): 要写入的服务特征值的 UUID。
- value (必需, 字节数组或 lambda): 要写入的值。
ble_client.passkey_reply 动作
Section titled “ble_client.passkey_reply 动作”此动作使用指定的 passkey 触发认证尝试。
示例用法:
on_...: then: - ble_client.passkey_reply: id: my_ble_client passkey: 123456- id (必需, ID): 关联的 BLE 客户端的 ID。
- passkey (必需, 整数): 6 位密钥。
ble_client.numeric_comparison_reply 动作
Section titled “ble_client.numeric_comparison_reply 动作”此动作在数值比较后触发认证尝试。
示例用法:
on_...: then: - ble_client.numeric_comparison_reply: id: my_ble_client accept: True- id (必需, ID): 关联的 BLE 客户端的 ID。
- accept (必需, 布尔值): 如果两个 BLE 设备上显示的密钥匹配,则应为
true。
ble_client.remove_bond 动作
Section titled “ble_client.remove_bond 动作”此动作从安全数据库中移除设备并管理取消配对。
示例用法:
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。
BLE 概述
Section titled “BLE 概述”本节简要介绍蓝牙 LE 架构,以帮助理解此组件和相关组件。网上有许多更详细的参考资料。
BLE 使用服务器和客户端的概念。简单来说,服务器在提供服务的设备上实现,通常是心率监测器、标签、气象站等设备。客户端连接到服务器并使用其服务。客户端通常是手机上的应用程序,或者在 ESPHome 的情况下,是 ESP32 设备。
当客户端连接到服务器时,客户端会查询服务器提供的服务。服务暴露服务器上的功能类别。这些可能是定义明确且受支持的服务,如电池电量服务、设备信息或心率。或者它们可能是专门为该设备设计的自定义服务。例如,廉价 iTag 上的按钮使用自定义服务。
每个服务然后定义一个或多个特征值,通常是该服务的离散值。例如,环境传感器服务暴露的特征值包括风速、湿度和降雨量。根据其功能,每个特征值可能是只读或读写的。
特征值还可能暴露一个或多个描述符,携带有关特征值的更多信息。这可能是单位、有效范围以及是否启用了通知(见下文)等内容。
BLE 还支持通知。客户端持续轮询更新可能会消耗大量电力,这对于设计为低能耗的协议来说是不可取的。相反,服务器可以仅在值更改时将更新推送给客户端。根据其目的和设计,特征值可能允许发送通知。然后,客户端可以通过设置特征值的配置描述符来启用通知。
每个服务、特征值和描述符都由一个唯一标识符(UUID)标识,长度可能在 16 到 128 位之间。客户端通常会根据 UUID 识别设备的功能。
一旦建立连接,通过完整的 UUID 引用每个服务/特征值/描述符将占用小型(约 23 字节)数据包的相当大一部分。因此,特征值和描述符还提供了一个小型 2 字节句柄(别名),以最大化可用数据空间。
虽然该组件可以连接大多数 BLE 设备,但有用的功能只能通过依赖组件获得,例如BLE 客户端传感器。 有关设置特定设备的详细信息,请参阅这些组件的文档。
要使用 ble_client 组件,您需要启用ESP32 BLE 跟踪器组件。这也将允许您发现设备的 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 客户端传感器组件使用。
使用固定密钥的安全连接:
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"