Skip to main content

Crate bacnet_client

Crate bacnet_client 

Source
Expand description

§bacnet-client

Run a standalone asynchronous BACnet client with client::BACnetClient in the Rusty BACnet workspace. It owns a transport and request lifecycle, with property/service APIs, discovery, transaction management and segmentation. Use client::ClientConfig for request settings or a transport-specific builder for connection setup.

This hosted crate requires std, Tokio and allocating state. It has no alloc-only or no-heap profile. For one device combining client and server roles under one transport owner, see the separate bacnet-endpoint crate and its narrower service contract.

§Send Who-Is using development source

Place an application directory beside a checkout named rusty-bacnet, then add this exact dependency block to the application’s Cargo.toml. These paths refer to development source; they do not imply the shown APIs are published. Adjust paths for a different layout. Tokio uses its current-thread runtime, macros and time support; the program needs no multi-thread runtime feature.

[dependencies]
bacnet-client = { path = "../rusty-bacnet/crates/bacnet-client", default-features = false }
bacnet-transport = { path = "../rusty-bacnet/crates/bacnet-transport" }
tokio = { version = "1", features = ["macros", "rt", "time"] }

Save this complete program as src/main.rs. It starts a real client over bounded in-process loopback channels and sends Who-Is without device-instance limits. The paired raw transport receives the emitted frame. Sending and receiving share a two-second timeout; the complete NPDU is checked against independent expected bytes for this global Who-Is request.

use bacnet_client::client::{BACnetClient, ClientConfig};
use bacnet_transport::loopback::LoopbackTransport;
use bacnet_transport::port::TransportPort;
use tokio::time::{timeout, Duration};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (client_port, mut peer) = LoopbackTransport::pair(vec![1], vec![2]);
    let mut frames = peer.start().await?;
    let mut client = BACnetClient::start(ClientConfig::default(), client_port).await?;
    let received = timeout(Duration::from_secs(2), async {
        client.who_is(None).await?;
        let frame = frames.recv().await.ok_or_else(|| {
            std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "loopback peer closed")
        })?;
        Ok::<_, Box<dyn std::error::Error>>(frame)
    })
    .await;

    let client_stopped = client.stop().await;
    let peer_stopped = peer.stop().await;
    let frame = received??;
    client_stopped?;
    peer_stopped?;
    assert_eq!(
        &frame.npdu[..],
        &[0x01, 0x20, 0xFF, 0xFF, 0x00, 0xFF, 0x10, 0x08]
    );
    assert_eq!(&frame.source_mac[..], &[1]);
    assert!(frame.link_layer_group);
    Ok(())
}

Both owners are explicitly stopped before the operation result is propagated. The operation timeout does not impose a shutdown deadline. This program observes an emitted Who-Is frame; it neither receives I-Am nor establishes that a device was discovered. For a complete client/server ReadProperty exchange, see the server guide.

Loopback sends to its paired peer regardless of the requested destination. This program establishes in-process transmission, receipt and cleanup, not destination filtering, UDP, TLS, serial, physical equipment, timing, firmware behavior or BACnet conformance. Enabling an optional feature while running it does not exercise that feature’s network transport.

§Features and builders

Feature selectionPublic entry points
Default or --no-default-featuresBACnetClient::start, BACnetClient::generic_builder and BACnetClient::bip_builder; hosted std/Tokio/allocation remain required.
ipv6Adds Bip6ClientBuilder and BACnetClient::bip6_builder for BACnet/IPv6.
sc-tlsAdds ScClientBuilder and BACnetClient::sc_builder for a constrained-TLS BACnet/SC hub connection.

For the displayed application, select --features bacnet-client/ipv6, --features bacnet-client/sc-tls, or --features bacnet-client/ipv6,bacnet-client/sc-tls when running Cargo. Each selection still runs the loopback program above. Real connections need the appropriate transport addresses and, for SC, validated TLS policy and a caller-provisioned nonzero device UUID. TLS peer authentication does not by itself authorize BACnet services or mutations on a server.

The docs.rs profile enables ipv6 and sc-tls, disables defaults and targets x86_64-unknown-linux-gnu. Optional builders and factories carry feature badges; the always-present client module and generic builder stay available under each profile. This README is the crate landing page and its program runs as a doctest. A local render does not establish a docs.rs deployment.

§Request and lifecycle ownership

client::BACnetClient::read_property returns encoded property data and checks that the acknowledgement matches the requested object, property and array index. Decode it for your property’s expected type; the Who-Is byte literal above is not a property-value decoder.

Keep the client owner until requests finish, then call client::BACnetClient::stop. Stop aborts and joins its dispatch and local network-number work, cancels transactions and stops the owned transport. A cancelled stop waiter retains joins for a later stop; dropping the client is not a substitute for awaiting cleanup. The API does not promise a universal fixed shutdown deadline.

When using a server, its database exposes raw object state; use its read_local method for executor-owned live properties. Release database guards before network requests or shutdown. Server service/mutation/source policies remain application decisions, including when a transport authenticates its peers.

Modules§

client
BACnetClient: high-level and low-level request APIs.
discovery
Device discovery table — collects IAm responses for WhoIs/WhoHas lookups.
log_reader
Paged reads of a log’s Log_Buffer over ReadRange (#1530).
segmentation
Segmentation re-exports from bacnet-encoding.
tags
Typed interpretation of the value bytes returned by a Tags read.
tsm
Transaction State Machine (TSM) per ASHRAE 135-2020 Clause 5.4.