You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用zbus从DBus接收UPower设备属性变更信号

监听UPower设备属性变化(zbus新版本适配方案)

问题说明

终端通过以下命令可正常监听电池设备的属性变化:

$ dbus-monitor --system  "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/UPower/devices/battery_BAT0'"

但使用zbus新版本重构代码时,原基于zbus 1.8的方案失效,尝试MatchRule结合DBusProxy::receive_all_signals()的方式无法正常捕获信号。

新版本zbus正确实现

以下两种方案均可实现需求,推荐第二种更简洁的方式:

方案一:手动匹配规则+连接监听信号

直接通过DBus连接添加匹配规则,然后监听所有符合规则的信号:

use zbus::{Connection, MessageType, MatchRule};
use zbus::zvariant::Dict;

#[tokio::main]
async fn main() -> zbus::Result<()> {
    // 建立系统总线连接
    let connection = Connection::system().await?;
    let battery_path = "/org/freedesktop/UPower/devices/battery_BAT0";

    // 构建与dbus-monitor完全一致的匹配规则
    let match_rule = MatchRule::builder()
        .msg_type(MessageType::Signal)
        .path(battery_path)?
        .interface("org.freedesktop.DBus.Properties")?
        .member("PropertiesChanged")?
        .build();
    
    // 向DBus总线注册匹配规则
    connection.add_match_rule(match_rule).await?;

    // 监听信号流并处理
    let mut signal_stream = connection.receive_signals().await?;
    while let Some(signal) = signal_stream.next().await {
        let msg = signal.message();
        // 解析PropertiesChanged信号的参数
        let (interface, changed_props, invalidated): (String, Dict, Vec<String>) = msg.body()?;
        println!("接口: {}", interface);
        println!("变化的属性: {:?}", changed_props);
        println!("失效的属性: {:?}", invalidated);
    }

    Ok(())
}

方案二:使用PropertiesProxy自动监听

利用zbus提供的PropertiesProxy直接监听属性变化,无需手动构建匹配规则:

use zbus::fdo::PropertiesProxy;

#[tokio::main]
async fn main() -> zbus::Result<()> {
    let connection = Connection::system().await?;
    let battery_path = "/org/freedesktop/UPower/devices/battery_BAT0";

    // 构建Properties代理,指定目标对象路径和服务名
    let props_proxy = PropertiesProxy::builder(&connection)
        .path(battery_path)?
        .destination("org.freedesktop.UPower")?
        .build()
        .await?;
    
    // 获取PropertiesChanged信号的监听流
    let mut props_stream = props_proxy.receive_properties_changed().await?;
    while let Some(signal) = props_stream.next().await {
        let args = signal.args()?;
        println!("接口名: {}", args.interface_name);
        println!("变化属性: {:?}", args.changed_properties);
        println!("失效属性: {:?}", args.invalidated_properties);
    }

    Ok(())
}

原代码失效原因

  • 旧版本DBusProxy::next_signal()本质是直接从连接中拉取所有信号,而新版本proxy.receive_all_signals()仅监听org.freedesktop.DBus接口自身的信号(如NameOwnerChanged),并非目标UPower设备的属性变化信号。
  • 正确的做法是直接通过Connection监听全局信号,或使用对应对象的PropertiesProxy来绑定特定对象的属性变化信号。

依赖配置

确保Cargo.toml中使用最新版zbus及异步运行时:

[dependencies]
zbus = "4.0"
tokio = { version = "1.0", features = ["full"] }

内容的提问来源于stack exchange,提问作者Flowneee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:43:11