Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rs-matter/src/utils/zbus_proxies.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2025 Project CHIP Authors
* Copyright (c) 2025-2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,5 +20,6 @@
pub mod avahi;
pub mod bluez;
pub mod nm;
pub mod openthread;
pub mod resolve;
pub mod wpa_supp;
23 changes: 23 additions & 0 deletions rs-matter/src/utils/zbus_proxies/openthread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/

//! zbus proxies for OpenThread Border Router (`otbr-agent`).
//!
//! OTBR exposes a per-Thread-interface D-Bus service named
//! `io.openthread.BorderRouter.<ifname>` (typically `io.openthread.BorderRouter.wpan0`)
//! under the well-known object path `/io/openthread/BorderRouter/<ifname>`.
//!
//! The full interface is defined in `openthread/src/posix/platform/dbus/` and
//! documented at <https://github.com/openthread/ot-br-posix>. We only proxy
//! the surface needed by the controller today; more methods can be added
//! incrementally without disturbing this module's existing users.

pub mod border_router;
67 changes: 67 additions & 0 deletions rs-matter/src/utils/zbus_proxies/openthread/border_router.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/

//! # D-Bus interface proxy for: `io.openthread.BorderRouter`
//!
//! Hand-written from the OpenThread sources at
//! <https://github.com/openthread/ot-br-posix/blob/main/src/dbus/server/introspect.xml>
//! and verified against a live `otbr-agent` via:
//!
//! ```text
//! busctl introspect io.openthread.BorderRouter.wpan0 \
//! /io/openthread/BorderRouter/wpan0
//! ```
//!
//! Only the properties/methods needed today are proxied. The interface
//! exposes many more (`Scan`, `EnergyScan`, `Attach`, `Detach`,
//! `JoinerStart`, `FactoryReset`, etc.) — they can be added incrementally.

use zbus::proxy;

#[proxy(
interface = "io.openthread.BorderRouter",
default_service = "io.openthread.BorderRouter.wpan0",
default_path = "/io/openthread/BorderRouter/wpan0"
)]
Comment on lines +29 to +33
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The #[proxy] macro uses the interface name as the default D-Bus service name if default_service is not specified. In this case, it would default to io.openthread.BorderRouter.

However, the OpenThread D-Bus service is named io.openthread.BorderRouter.<ifname>, which for the hardcoded wpan0 interface would be io.openthread.BorderRouter.wpan0. Without specifying the correct default_service, attempts to use this proxy with default settings will fail to connect.

Please add the default_service to the #[proxy] attribute.

#[proxy(
    interface = "io.openthread.BorderRouter",
    default_service = "io.openthread.BorderRouter.wpan0",
    default_path = "/io/openthread/BorderRouter/wpan0"
)]

pub trait BorderRouter {
/// Active Thread Operational Dataset, TLV-encoded.
///
/// This is the same byte sequence `ot-ctl dataset active -x` emits
/// (just unhexed). Roughly 100–110 bytes for a typical dataset.
///
/// Returned when there's an active dataset; empty if the device is
/// disabled/detached.
#[zbus(property)]
fn active_dataset_tlvs(&self) -> zbus::Result<Vec<u8>>;

/// Set the active dataset (TLV-encoded). Triggers re-attach.
#[zbus(property)]
fn set_active_dataset_tlvs(&self, value: Vec<u8>) -> zbus::Result<()>;

/// Pending Thread Operational Dataset, TLV-encoded.
///
/// Used for coordinated dataset rotations. Empty if no pending change.
#[zbus(property)]
fn pending_dataset_tlvs(&self) -> zbus::Result<Vec<u8>>;

/// Device role on the Thread network. One of:
/// `"disabled" | "detached" | "child" | "router" | "leader"`.
#[zbus(property)]
fn device_role(&self) -> zbus::Result<String>;
Comment on lines +57 to +58
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The device_role property returns a string, but the set of possible values is finite. To improve type safety and make the API more robust, consider defining an enum for the device role. zbus can automatically handle the conversion from a D-Bus string.

You could define an enum like this, for example, above the BorderRouter trait:

use serde::{Deserialize, Serialize};
use zbus::zvariant;

#[derive(Debug, Clone, PartialEq, Eq, zvariant::Type, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[zvariant(signature = "s")]
pub enum DeviceRole {
    Disabled,
    Detached,
    Child,
    Router,
    Leader,
}

Then, you can change the property in the trait to use this enum:

#[zbus(property)]
fn device_role(&self) -> zbus::Result<DeviceRole>;

This change will prevent bugs related to typos in role strings and make the code that uses this proxy cleaner.


/// 64-bit IEEE EUI-64 of the Thread radio, as a hex string.
#[zbus(property)]
fn eui64(&self) -> zbus::Result<String>;

/// Currently-active Thread channel (11-26 for 2.4 GHz).
#[zbus(property)]
fn channel(&self) -> zbus::Result<u16>;
}
Loading