Rust蓝牙通信库bluez-generated的使用,bluez-generated提供与Linux蓝牙协议栈BlueZ的高效交互接口

Rust蓝牙通信库bluez-generated的使用

bluez-generated是为Linux蓝牙协议栈BlueZ生成的异步D-Bus绑定库,提供了与BlueZ高效交互的接口。

基本介绍

bluez-generated库具有以下特点:

  • 通过D-Bus与BlueZ交互
  • 基于异步编程模型
  • 通过自省数据生成绑定接口
  • 目前仅包含作者测试过的设备接口

安装

在Cargo.toml中添加依赖:

bluez-generated = "0.4.0"

或者运行命令:

cargo add bluez-generated

完整示例代码

以下是一个使用bluez-generated进行蓝牙设备扫描的完整示例:

use bluez_generated::{
    org_bluez::{
        Adapter1Proxy, 
        Device1Proxy,
        ObjectManagerProxy
    },
    OrgBluezObjectManager,
    OrgFreedesktopDBusObjectManager,
};
use dbus::nonblock::SyncConnection;
use dbus_tokio::connection;
use futures::stream::StreamExt;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 建立D-Bus连接
    let (resource, conn) = connection::new_system_sync()?;
    
    // 在后台运行连接
    tokio::spawn(async {
        let err = resource.await;
        panic!("Lost connection to D-Bus: {}", err);
    });

    // 获取对象管理器代理
    let proxy = ObjectManagerProxy::new(&conn, "/");

    // 获取所有管理对象
    let objects = proxy.get_managed_objects().await?;

    // 查找蓝牙适配器
    let adapter_path = objects.keys()
        .find(|path| path.to_string().contains("hci0"))
        .ok_or("No Bluetooth adapter found")?;

    // 创建适配器代理
    let adapter = Adapter1Proxy::new(&conn, adapter_path.clone());

    // 设置适配器为可发现模式
    adapter.set_discoverable(true).await?;
    
    // 开始扫描设备
    adapter.start_discovery().await?;

    // 监听设备添加事件
    let mut device_added = proxy.receive_interfaces_added().await;
    
    tokio::spawn(async move {
        while let Some(signal) = device_added.next().await {
            if let Some(device_proxy) = Device1Proxy::from_path(&conn, signal.path.clone()) {
                if let Ok(properties) = device_proxy.get_all().await {
                    println!("Found device: {:?}", properties.address);
                }
            }
        }
    });

    // 持续扫描10秒
    tokio::time::sleep(Duration::from_secs(10)).await;
    
    // 停止扫描
    adapter.stop_discovery().await?;

    Ok(())
}

添加新接口

如果需要使用bluez-generated未包含的接口,可以按照以下步骤添加:

  1. 参考项目中的introspect.sh脚本生成新接口
  2. 提交Pull Request或直接在你的项目中包含生成的接口文件

许可证

bluez-generated采用双重许可:

  • Apache License 2.0
  • MIT license

未来发展方向

  • 目前仅支持异步绑定,未来可能添加阻塞式绑定
  • 计划为PropertiesChanged信号生成强类型绑定,便于订阅属性变更事件

贡献

欢迎贡献代码,所有提交默认采用上述双重许可。

完整示例代码(连接并读取蓝牙设备属性)

以下是另一个完整示例,展示如何连接已发现的蓝牙设备并读取其属性:

use bluez_generated::{
    org_bluez::{
        Adapter1Proxy,
        Device1Proxy,
        ObjectManagerProxy
    },
    OrgBluezObjectManager,
    OrgFreedesktopDBusObjectManager,
};
use dbus::nonblock::SyncConnection;
use dbus_tokio::connection;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 建立D-Bus系统连接
    let (resource, conn) = connection::new_system_sync()?;
    
    // 后台运行D-Bus连接
    tokio::spawn(async {
        let err = resource.await;
        panic!("Lost connection to D-Bus: {}", err);
    });

    // 创建对象管理器代理
    let manager = ObjectManagerProxy::new(&conn, "/");

    // 获取所有已配对的蓝牙设备
    let objects = manager.get_managed_objects().await?;
    
    // 打印所有已配对设备
    for (path, _) in objects.iter() {
        if let Some(device) = Device1Proxy::from_path(&conn, path.clone()) {
            if let Ok(props) = device.get_all().await {
                println!("Paired device: {} ({})", props.alias.unwrap_or_default(), props.address);
            }
        }
    }

    // 查找特定设备(示例: 查找名为"MyDevice"的设备)
    let device_path = objects.keys()
        .find(|path| {
            if let Some(device) = Device1Proxy::from_path(&conn, path.clone()) {
                if let Ok(props) = device.get_all().await {
                    return props.alias.as_ref().map_or(false, |a| a == "MyDevice");
                }
            }
            false
        })
        .ok_or("Device not found")?;

    // 创建设备代理
    let device = Device1Proxy::new(&conn, device_path.clone());

    // 连接设备
    device.connect().await?;
    println!("Device connected successfully");

    // 获取并打印设备属性
    let properties = device.get_all().await?;
    println!("Device properties: {:#?}", properties);

    // 保持连接5秒
    tokio::time::sleep(Duration::from_secs(5)).await;

    // 断开连接
    device.disconnect().await?;
    println!("Device disconnected");

    Ok(())
}

1 回复

Rust蓝牙通信库bluez-generated使用指南

介绍

bluez-generated是一个Rust库,提供了与Linux蓝牙协议栈BlueZ的高效交互接口。它通过DBus接口与BlueZ通信,允许开发者构建蓝牙应用程序而不需要直接处理底层协议细节。

主要特性

  • 自动生成的BlueZ DBus接口绑定
  • 支持大多数BlueZ功能
  • 类型安全的API
  • 异步/同步两种操作模式

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
bluez-generated = "0.4"
tokio = { version = "1.0", features = ["full"] } # 如果需要异步支持

基本示例

1. 扫描蓝牙设备

use bluez_generated::OrgBluezAdapter1;
use dbus::nonblock::SyncConnection;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 建立DBus连接
    let (resource, conn) = SyncConnection::new_system()?;
    
    // 在后台处理DBus消息
    tokio::spawn(async {
        resource.await;
    });
    
    // 获取蓝牙适配器代理
    let proxy = OrgBluezAdapter1::new(&conn, "/org/bluez/hci0");
    
    // 开始扫描
    proxy.start_discovery().await?;
    println!("Scanning for Bluetooth devices...");
    
    // 扫描10秒
    tokio::time::sleep(Duration::from_secs(10)).await;
    
    // 停止扫描
    proxy.stop_discovery().await?;
    
    Ok(())
}

2. 列出已配对设备

use bluez_generated::OrgBluezManager;
use dbus::nonblock::SyncConnection;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (resource, conn) = SyncConnection::new_system()?;
    tokio::spawn(async {
        resource.await;
    });
    
    let manager = OrgBluezManager::new(&conn, "/");
    let adapters = manager.get_managed_objects().await?;
    
    for (path, interfaces) in adapters {
        if interfaces.contains_key("org.bluez.Device1") {
            println!("Found device at path: {}", path);
        }
    }
    
    Ok(())
}

3. 连接蓝牙设备

use bluez_generated::{OrgBluezDevice1, OrgBluezAdapter1};
use dbus::nonblock::SyncConnection;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (resource, conn) = SyncConnection::new_system()?;
    tokio::spawn(async {
        resource.await;
    });
    
    // 假设设备地址为00:11:22:33:44:55
    let device_path = format!("/org/bluez/hci0/dev_00_11_22_33_44_55");
    let device = OrgBluezDevice1::new(&conn, &device_path);
    
    // 连接设备
    match device.connect().await {
        Ok(()) => println!("Connected successfully"),
        Err(e) => eprintln!("Connection failed: {}", e),
    }
    
    Ok(())
}

高级用法

处理蓝牙事件

use bluez_generated::OrgBluezAdapter1;
use dbus::nonblock::SyncConnection;
use dbus::message::MatchRule;
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (resource, conn) = SyncConnection::new_system()?;
    tokio::spawn(async {
        resource.await;
    });
    
    // 设置匹配规则监听设备添加事件
    let rule = MatchRule::new()
        .with_interface("org.freedesktop.DBus.ObjectManager")
        .with_member("InterfacesAdded");
    
    let mut stream = conn.add_match(rule).await?.msg_stream();
    
    // 开始扫描
    let proxy = OrgBluezAdapter1::new(&conn, "/org/bluez/hci0");
    proxy.start_discovery().await?;
    
    // 处理事件
    while let Some(msg) = stream.next().await {
        println!("New device detected: {:?}", msg);
    }
    
    Ok(())
}

完整示例代码

下面是一个完整的蓝牙设备扫描和连接示例:

use bluez_generated::{OrgBluezAdapter1, OrgBluezDevice1, OrgBluezManager};
use dbus::nonblock::SyncConnection;
use std::time::Duration;
use tokio::time;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 建立DBus系统连接
    let (resource, conn) = SyncConnection::new_system()?;
    
    // 后台处理DBus消息
    tokio::spawn(async {
        resource.await;
    });

    // 2. 获取蓝牙管理器
    let manager = OrgBluezManager::new(&conn, "/");
    
    // 3. 获取默认适配器(通常为hci0)
    let adapter = OrgBluezAdapter1::new(&conn, "/org/bluez/hci0");
    
    // 4. 开始扫描设备
    println!("Starting Bluetooth scan...");
    adapter.start_discovery().await?;
    
    // 扫描5秒
    time::sleep(Duration::from_secs(5)).await;
    
    // 5. 获取所有发现的设备
    let objects = manager.get_managed_objects().await?;
    
    println!("Discovered devices:");
    for (path, interfaces) in objects {
        if interfaces.contains_key("org.bluez.Device1") {
            println!("- Device path: {}", path);
            
            // 6. 尝试连接设备
            let device = OrgBluezDevice1::new(&conn, &path);
            match device.connect().await {
                Ok(()) => println!("  Connected successfully"),
                Err(e) => eprintln!("  Connection failed: {}", e),
            }
        }
    }
    
    // 7. 停止扫描
    adapter.stop_discovery().await?;
    
    Ok(())
}

注意事项

  1. 需要Linux系统和BlueZ蓝牙协议栈
  2. 需要DBus系统总线权限
  3. 某些操作可能需要root权限
  4. 异步操作需要使用tokio或async-std等运行时

bluez-generated为Rust开发者提供了强大的蓝牙操作能力,适合构建各种蓝牙管理工具、物联网应用等。

回到顶部