Rust蓝牙低功耗(BLE)开发库btleplug的使用,支持跨平台蓝牙设备通信与管理

Rust蓝牙低功耗(BLE)开发库btleplug的使用,支持跨平台蓝牙设备通信与管理

btleplug是一个异步Rust BLE库,支持Windows 10、macOS、Linux、iOS和Android平台。

平台状态

  • Linux/Windows/macOS/iOS/Android
    • 设备枚举和特性/服务已实现并正常工作
    • 如果发现问题请提交bug

平台功能表

功能 Windows MacOS/iOS Linux Android
启动适配器 ✔️ ✔️ ✔️ ✔️
发现设备 ✔️ ✔️ ✔️ ✔️
发现服务 ✔️ ✔️ ✔️ ✔️
发现特性 ✔️ ✔️ ✔️ ✔️
GATT服务器连接 ✔️ ✔️ ✔️ ✔️
写入特性 ✔️ ✔️ ✔️ ✔️
读取特性 ✔️ ✔️ ✔️ ✔️
订阅特性 ✔️ ✔️ ✔️ ✔️

库特性

序列化/反序列化

启用serde的SerializeDeserialize支持:

[dependencies]
btleplug = { version = "0.11", features = ["serde"] }

完整示例代码

以下是一个更完整的BLE设备交互示例,包含设备连接、服务发现和特性读写操作:

use btleplug::api::{Central, CentralEvent, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;
use futures::stream::StreamExt;
use std::error::Error;
use tokio::time;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 1. 初始化BLE管理器
    let manager = Manager::new().await?;
    
    // 2. 获取第一个蓝牙适配器
    let adapter_list = manager.adapters().await?;
    let adapter = adapter_list.into_iter().next().ok_or("没有可用的蓝牙适配器")?;
    
    // 3. 开始扫描设备
    println!("开始扫描BLE设备...");
    adapter.start_scan(ScanFilter::default()).await?;
    
    // 4. 监听设备事件
    let mut events = adapter.events().await?;
    let mut target_peripheral = None;
    
    while let Some(event) = events.next().await {
        match event {
            CentralEvent::DeviceDiscovered(id) => {
                println!("发现设备: {:?}", id);
                // 这里可以添加设备过滤逻辑
                target_peripheral = Some(adapter.peripheral(&id).await?);
                break;
            }
            _ => {}
        }
    }
    
    // 5. 停止扫描
    adapter.stop_scan().await?;
    println!("扫描停止");
    
    // 6. 连接到目标设备
    if let Some(peripheral) = target_peripheral {
        println!("尝试连接设备...");
        peripheral.connect().await?;
        println!("设备已连接");
        
        // 7. 发现服务
        println!("发现服务...");
        peripheral.discover_services().await?;
        let services = peripheral.services();
        
        // 8. 遍历服务和特性
        for service in services {
            println!("服务: {:?}", service.uuid);
            for characteristic in service.characteristics {
                println!("  特性: {:?} - 属性: {:?}", 
                    characteristic.uuid, 
                    characteristic.properties);
                
                // 9. 示例: 读取特性值
                if characteristic.properties.read {
                    let value = peripheral.read(&characteristic).await?;
                    println!("    值: {:?}", value);
                }
                
                // 10. 示例: 订阅通知
                if characteristic.properties.notify {
                    peripheral.subscribe(&characteristic).await?;
                    println!("    已订阅通知");
                }
            }
        }
        
        // 11. 保持连接一段时间
        time::sleep(time::Duration::from_secs(10)).await;
        
        // 12. 断开连接
        peripheral.disconnect().await?;
        println!("设备已断开");
    }
    
    Ok(())
}

平台特定说明

macOS

在macOS Big Sur(11)或更高版本上需要:

  1. 将二进制文件打包到包含NSBluetoothAlwaysUsageDescription的应用程序包中
  2. 或者在系统偏好设置中为终端启用蓝牙权限

Android

Android上的设置步骤:

  1. 需要jni-utils-rs的Java部分
  2. 构建btleplug的Java部分
  3. 使用cargo-ndk构建Rust部分

iOS

iOS构建步骤:

  1. 编写使用btleplug并暴露C API的Rust静态库
  2. 使用cbindgen生成C头文件
  3. 使用cargo-lipo构建通用静态库
  4. 将头文件和库拖入Xcode项目
  5. 在Info.plist中添加NSBluetoothAlwaysUsageDescription

替代库

如果btleplug不符合需求,可以考虑:

  • Bluest - 跨平台BLE库(Windows/macOS/iOS/Linux)
  • Bluey - 跨平台BLE库(Windows/Android)
  • Bluer - Linux上的Bluez官方Rust接口

许可证

btleplug采用BSD 3-Clause许可证,部分代码来自Rumble/Blurmac,采用MIT/Apache双许可证和BSD 3-Clause许可证。


1 回复

Rust蓝牙低功耗(BLE)开发库btleplug使用指南

完整示例代码

下面是一个完整的btleplug使用示例,整合了设备扫描、连接、读写特征值和订阅通知等功能:

use btleplug::api::{Central, CentralEvent, Manager as _, Peripheral, ScanFilter, WriteType};
use btleplug::platform::{Adapter, Manager, Peripheral as BtlePeripheral};
use futures::stream::StreamExt;
use tokio::time::{sleep, Duration};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 1. 初始化适配器
    let manager = Manager::new().await?;
    let adapter = manager.adapters().await?.into_iter().nth(0).ok_or("没有可用的蓝牙适配器")?;
    println!("使用适配器: {}", adapter.adapter_info().await?);

    // 2. 扫描设备
    scan_devices(&adapter).await?;

    // 3. 连接设备
    let device = connect_to_device(&adapter).await?;
    
    // 4. 发现服务
    device.discover_services().await?;
    
    // 5. 读取特征值
    if let Some(char) = find_readable_characteristic(&device) {
        let value = device.read(&char).await?;
        println!("读取到特征值: {:?}", value);
    }
    
    // 6. 写入特征值
    if let Some(char) = find_writable_characteristic(&device) {
        let data = vec![0x01, 0x02];
        device.write(&char, &data, WriteType::WithoutResponse).await?;
        println!("写入特征值成功");
    }
    
    // 7. 订阅通知
    if let Some(char) = find_notifiable_characteristic(&device) {
        subscribe_notifications(&device, &char).await?;
        sleep(Duration::from_secs(5)).await;
    }
    
    // 8. 断开连接
    device.disconnect().await?;
    Ok(())
}

async fn scan_devices(adapter: &Adapter) -> Result<(), Box<dyn Error>> {
    println!("开始扫描BLE设备...");
    adapter.start_scan(ScanFilter::default()).await?;
    sleep(Duration::from_secs(5)).await;
    adapter.stop_scan().await?;
    
    let devices = adapter.peripherals().await?;
    for device in devices {
        let props = device.properties().await?;
        println!("发现设备: {:?}, RSSI: {:?}", props.local_name, props.rssi);
    }
    Ok(())
}

async fn connect_to_device(adapter: &Adapter) -> Result<BtlePeripheral, Box<dyn Error>> {
    let devices = adapter.peripherals().await?;
    let device = devices.first().ok_or("没有发现设备")?;
    
    if !device.is_connected().await? {
        device.connect().await?;
        println!("已连接到设备");
    }
    Ok(device.clone())
}

fn find_readable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
    device.services()
        .iter()
        .flat_map(|service| &service.characteristics)
        .find(|c| c.properties.read)
        .cloned()
}

fn find_writable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
    device.services()
        .iter()
        .flat_map(|service| &service.characteristics)
        .find(|c| c.properties.write)
        .cloned()
}

fn find_notifiable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
    device.services()
        .iter()
        .flat_map(|service| &service.characteristics)
        .find(|c| c.properties.notify)
        .cloned()
}

async fn subscribe_notifications(device: &BtlePeripheral, characteristic: &btleplug::api::Characteristic) -> Result<(), Box<dyn Error>> {
    device.subscribe(characteristic).await?;
    
    let mut notification_stream = device.notifications().await?;
    tokio::spawn(async move {
        while let Some(data) = notification_stream.next().await {
            println!("收到通知: {:?}", data.value);
        }
    });
    
    Ok(())
}

代码说明

  1. 初始化适配器:通过Manager获取系统蓝牙适配器
  2. 扫描设备:扫描5秒并打印发现的BLE设备信息
  3. 连接设备:连接到第一个发现的设备
  4. 发现服务:发现设备提供的所有服务
  5. 读取特征值:查找并读取第一个可读特征的值
  6. 写入特征值:查找并写入第一个可写特征
  7. 订阅通知:查找并订阅第一个支持通知的特征
  8. 断开连接:最后断开设备连接

使用说明

  1. 将上述代码保存为main.rs
  2. 确保Cargo.toml中包含正确的依赖:
[dependencies]
btleplug = "0.10"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"
  1. 根据平台安装必要依赖:

    • Linux: sudo apt-get install libbluetooth-dev bluez
    • 其他平台请参考前面的平台注意事项
  2. 运行程序:cargo run

这个完整示例演示了btleplug库的主要功能,包括设备发现、连接管理、数据读写和通知处理,可以作为开发BLE应用的起点。

回到顶部