Rust蓝牙开发库bluez-async的使用:异步支持Linux蓝牙协议栈的高效通信
Rust蓝牙开发库bluez-async的使用:异步支持Linux蓝牙协议栈的高效通信
bluez-async
是一个围绕 BlueZ(Linux 蓝牙守护进程)D-Bus 接口的异步封装库。它提供了类型安全的接口来访问 BlueZ 暴露的蓝牙客户端(即中心设备,在蓝牙术语中)接口的子集,主要关注蓝牙低功耗 (BLE) 的通用属性配置文件 (GATT)。
使用示例
以下是使用 bluez-async 的基本示例代码:
// 创建新会话。这会建立与 BlueZ 通信的 D-Bus 连接。
// 这里我们忽略 join handle,因为我们不打算无限期运行。
let (_, session) = BluetoothSession::new().await?;
// 开始扫描蓝牙设备,并等待几秒钟以发现一些设备。
session.start_discovery().await?;
time::sleep(Duration::from_secs(5)).await;
session.stop_discovery().await?;
// 获取当前已知的设备列表。
let devices = session.get_devices().await?;
// 找到我们关心的设备。
let device = devices
.into_iter()
.find(|device| device.name.as_deref() == Some("My device"))
.unwrap();
// 连接到该设备。
session.connect(&device.id).await?;
// 通过短 UUID 查找 GATT 服务和特征。
let service = session
.get_service_by_uuid(&device.id, uuid_from_u16(0x1234))
.await?;
let characteristic = session
.get_characteristic_by_uuid(&service.id, uuid_from_u32(0x1235))
.await?;
// 读取特征值并写入新值。
println!(
"Value: {:?}",
session
.read_characteristic_value(&characteristic.id)
.await?
);
session
.write_characteristic_value(&characteristic.id, vec![1, 2, 3])
.await?;
// 订阅特征的通知并打印出来。
let mut events = session
.characteristic_event_stream(&characteristic.id)
.await?;
session.start_notify(&characteristic.id).await?;
while let Some(event) = events.next().await {
if let BluetoothEvent::Characteristic {
id,
event: CharacteristicEvent::Value { value },
} = event
{
println!("Update from {}: {:?}", id, value);
}
}
完整示例代码
以下是一个更完整的示例,展示了如何使用 bluez-async 进行蓝牙设备扫描、连接和通信:
use bluez_async::{
BluetoothEvent, BluetoothSession, CharacteristicEvent, MacAddress, Uuid,
};
use futures::StreamExt;
use std::time::Duration;
use tokio::time;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建蓝牙会话
let (_, session) = BluetoothSession::new().await?;
// 2. 开始设备发现
println!("开始扫描蓝牙设备...");
session.start_discovery().await?;
time::sleep(Duration::from_secs(10)).await;
session.stop_discovery().await?;
println!("扫描完成");
// 3. 获取设备列表
let devices = session.get_devices().await?;
println!("发现 {} 个设备", devices.len());
// 4. 筛选目标设备 (这里假设我们要连接名为"MyDevice"的设备)
let target_device = devices
.into_iter()
.find(|d| d.name.as_deref() == Some("MyDevice"))
.ok_or("未找到目标设备")?;
println!("找到设备: {:?}", target_device);
// 5. 连接到设备
println!("连接到设备...");
session.connect(&target_device.id).await?;
println!("连接成功");
// 6. 发现服务 (假设服务UUID为0x1234)
let service_uuid = Uuid::from_u16(0x1234);
println!("查找服务: {}", service_uuid);
let service = session
.get_service_by_uuid(&target_device.id, service_uuid)
.await?;
// 7. 发现特征 (假设特征UUID为0x1235)
let char_uuid = Uuid::from_u16(0x1235);
println!("查找特征: {}", char_uuid);
let characteristic = session
.get_characteristic_by_uuid(&service.id, char_uuid)
.await?;
// 8. 读取特征值
let value = session.read_characteristic_value(&characteristic.id).await?;
println!("特征值: {:?}", value);
// 9. 写入特征值
let new_value = vec![0x01, 0x02, 0x03];
println!("写入新值: {:?}", new_value);
session
.write_characteristic_value(&characteristic.id, new_value)
.await?;
// 10. 订阅通知
println!("订阅通知...");
let mut events = session.characteristic_event_stream(&characteristic.id).await?;
session.start_notify(&characteristic.id).await?;
println!("等待通知 (按Ctrl+C退出)...");
while let Some(event) = events.next().await {
match event {
BluetoothEvent::Characteristic {
id,
event: CharacteristicEvent::Value { value },
} => {
println!("收到通知 from {}: {:?}", id, value);
}
_ => {}
}
}
Ok(())
}
功能说明
- 设备发现:通过
start_discovery()
和stop_discovery()
方法扫描周围的蓝牙设备。 - 设备连接:使用
connect()
方法连接到特定设备。 - 服务发现:通过 UUID 查找设备提供的服务。
- 特征操作:
- 读取特征值 (
read_characteristic_value
) - 写入特征值 (
write_characteristic_value
) - 订阅通知 (
start_notify
+characteristic_event_stream
)
- 读取特征值 (
依赖项
要使用 bluez-async,需要在 Cargo.toml 中添加以下依赖:
[dependencies]
bluez-async = "0.8.2"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"
许可证
bluez-async 采用双重许可:
- Apache License, Version 2.0
- MIT license
您可以根据需要选择其中一种许可证。
1 回复
Rust蓝牙开发库bluez-async使用指南
简介
bluez-async是一个Rust库,提供了对Linux蓝牙协议栈(BlueZ)的异步支持,使开发者能够高效地进行蓝牙通信开发。它基于Tokio异步运行时,提供了简洁的API来与BlueZ的DBus接口交互。
主要特性
- 完全异步支持(Tokio)
- 类型安全的DBus接口
- 自动处理DBus对象路径和信号
- 支持蓝牙设备发现、连接、服务发现等操作
安装
在Cargo.toml中添加依赖:
[dependencies]
bluez-async = "0.3"
tokio = { version = "1.0", features = ["full"] }
基本使用方法
初始化蓝牙适配器
use bluez_async::BluetoothSession;
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
// 创建蓝牙会话
let (_, session) = BluetoothSession::new().await?;
// 获取默认适配器
let adapter = session.get_default_adapter().await?;
println!("使用适配器: {}", adapter.id);
Ok(())
}
扫描蓝牙设备
use bluez_async::{BluetoothEvent, BluetoothSession};
use futures::stream::StreamExt;
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
let (sender, session) = BluetoothSession::new().await?;
let adapter = session.get_default_adapter().await?;
// 开始扫描
session.start_discovery(&adapter.id).await?;
// 监听设备发现事件
let mut events = sender.incoming();
while let Some(event) = events.next().await {
match event {
BluetoothEvent::Device { id, address, rssi, .. } => {
println!("发现设备: {} (地址: {}), 信号强度: {:?}", id, address, rssi);
}
_ => {}
}
}
Ok(())
}
连接设备并发现服务
use bluez_async::{BluetoothSession, MacAddress};
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
let (_, session) = BluetoothSession::new().await?;
// 设备MAC地址
let device_addr = MacAddress::from([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
// 连接设备
let device = session.get_device_by_address(device_addr).await?;
session.connect(&device.id).await?;
// 发现服务
let services = session.get_services(&device.id).await?;
for service in services {
println!("服务 UUID: {}", service.uuid);
}
Ok(())
}
高级用法
读取特征值
use bluez_async::{BluetoothSession, MacAddress, Uuid};
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
let (_, session) = BluetoothSession::new().await?;
let device_addr = MacAddress::from([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
let device = session.get_device_by_address(device_addr).await?;
// 假设我们已经知道特征UUID
let char_uuid = Uuid::parse_str("00002a00-0000-1000-8000-00805f9b34fb")?;
// 获取特征
let characteristic = session.get_characteristic_by_uuid(&device.id, char_uuid).await?;
// 读取特征值
let value = session.read_value(&characteristic.id).await?;
println!("特征值: {:?}", value);
Ok(())
}
写入特征值
use bluez_async::{BluetoothSession, MacAddress, Uuid};
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
let (_, session) = BluetoothSession::new().await?;
let device_addr = MacAddress::from([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
let device = session.get_device_by_address(device_addr).await?;
let char_uuid = Uuid::parse_str("00002a01-0000-1000-8000-00805f9b34fb")?;
let characteristic = session.get_characteristic_by_uuid(&device.id, char_uuid).await?;
// 写入特征值
let data = vec![0x01, 0x02, 0x03];
session.write_value(&characteristic.id, data).await?;
Ok(())
}
完整示例
下面是一个完整的蓝牙设备扫描和连接示例:
use bluez_async::{BluetoothEvent, BluetoothSession, MacAddress};
use futures::stream::StreamExt;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> Result<(), eyre::Report> {
// 1. 初始化蓝牙会话
let (sender, session) = BluetoothSession::new().await?;
let adapter = session.get_default_adapter().await?;
println!("默认蓝牙适配器: {}", adapter.id);
// 2. 开始扫描设备
session.start_discovery(&adapter.id).await?;
println!("开始扫描蓝牙设备...");
// 3. 监听设备发现事件
let mut events = sender.incoming();
let mut target_device = None;
// 扫描10秒
tokio::select! {
_ = async {
sleep(Duration::from_secs(10)).await;
println!("扫描结束");
} => {}
device = async {
while let Some(event) = events.next().await {
if let BluetoothEvent::Device { id, address, name, rssi, .. } = event {
println!("发现设备: {} (地址: {}), 名称: {:?}, 信号强度: {:?}",
id, address, name, rssi);
// 假设我们要连接名为"MyDevice"的设备
if name.as_deref() == Some("MyDevice") {
target_device = Some((id, address));
break;
}
}
}
} => {}
}
// 4. 停止扫描
session.stop_discovery(&adapter.id).await?;
// 5. 连接目标设备
if let Some((device_id, address)) = target_device {
println!("尝试连接设备: {}", address);
// 连接设备
session.connect(&device_id).await?;
println!("设备已连接");
// 发现服务
let services = session.get_services(&device_id).await?;
println!("发现{}个服务:", services.len());
for service in services {
println!("服务 UUID: {}", service.uuid);
}
} else {
println!("未找到目标设备");
}
Ok(())
}
注意事项
- 需要Linux系统和BlueZ蓝牙协议栈
- 需要DBus系统服务正常运行
- 程序运行时需要适当的权限(通常需要root或加入bluetooth组)
- 某些操作可能需要先停止扫描才能执行
bluez-async库为Rust开发者提供了高效、类型安全的方式来与Linux蓝牙设备交互,特别适合需要高性能蓝牙通信的应用场景。