Skip to main content

BacnetClient

Struct BacnetClient 

Source
pub struct BacnetClient<D: DataLink> { /* private fields */ }
Expand description

High-level async BACnet client.

BacnetClient<D> wraps any DataLink transport and exposes ergonomic methods for common BACnet operations: reading and writing properties, device and object discovery, COV subscriptions, alarm/event services, file I/O, and device management.

The invoke-id counter and the per-request I/O lock are stored behind Mutexes, so the client is intentionally not Clone — wrap it in an Arc to share it across tasks.

§Construction

Implementations§

Source§

impl BacnetClient<BacnetIpTransport>

Source

pub async fn new() -> Result<Self, ClientError>

Create a UDP/IP BACnet client bound to an ephemeral port on all interfaces.

Returns ClientError::DataLink if the socket cannot be bound.

Source

pub async fn new_foreign( bbmd_addr: SocketAddr, ttl_seconds: u16, ) -> Result<Self, ClientError>

Create a UDP/IP BACnet client registered as a foreign device with the BBMD at bbmd_addr.

ttl_seconds is the time-to-live for the foreign-device registration. Returns ClientError::DataLink if the socket cannot be bound or the initial registration request fails.

Source

pub async fn register_foreign_device( &self, ttl_seconds: u16, ) -> Result<(), ClientError>

Re-register this client as a foreign device with the BBMD, using ttl_seconds as the new time-to-live.

Source

pub async fn read_broadcast_distribution_table( &self, ) -> Result<Vec<BroadcastDistributionEntry>, ClientError>

Read the Broadcast Distribution Table (BDT) from the BBMD.

Source

pub async fn write_broadcast_distribution_table( &self, entries: &[BroadcastDistributionEntry], ) -> Result<(), ClientError>

Write (replace) the Broadcast Distribution Table on the BBMD with the given entries.

Source

pub async fn read_foreign_device_table( &self, ) -> Result<Vec<ForeignDeviceTableEntry>, ClientError>

Read the Foreign Device Table (FDT) from the BBMD.

Source

pub async fn delete_foreign_device_table_entry( &self, address: SocketAddrV4, ) -> Result<(), ClientError>

Delete the foreign device entry for address from the BBMD’s Foreign Device Table.

Source

pub fn start_foreign_device_renewal( &self, ttl_seconds: u16, ) -> Result<ForeignDeviceRenewal, ClientError>

Spawn a background task that re-registers this client as a foreign device at roughly 75 % of ttl_seconds to keep the registration alive indefinitely.

Returns a ForeignDeviceRenewal handle; dropping it (or calling .stop()) cancels the task. Returns an error if ttl_seconds is 0.

Source§

impl BacnetClient<BacnetScTransport>

Source

pub async fn new_sc(endpoint: impl Into<String>) -> Result<Self, ClientError>

Create a BACnet/SC client by connecting to the WebSocket hub at endpoint (e.g. "wss://hub.example.com:47808/bacnet").

Source§

impl<D: DataLink> BacnetClient<D>

Create a client wrapping an already-constructed datalink.

Use this when you need a custom or pre-configured DataLink implementation.

Source

pub fn with_response_timeout(self, timeout: Duration) -> Self

Override the per-request response timeout (default: 3 s).

Source

pub fn with_segmented_request_window_size(self, window_size: u8) -> Self

Override the segmented-request window size (number of segments sent before waiting for an ACK). Clamped to a minimum of 1. Default: 16.

Source

pub fn with_segmented_request_retries(self, retries: u8) -> Self

Override the number of times a segment window is retried after a negative ACK or segment-ACK timeout before giving up. Default: 2.

Source

pub fn with_segment_ack_timeout(self, timeout: Duration) -> Self

Override the timeout used when waiting for a segment ACK from the remote device during a segmented confirmed request. Clamped to a minimum of 1 ms. Default: 500 ms.

Source

pub async fn who_is( &self, range: Option<(u32, u32)>, wait: Duration, ) -> Result<Vec<DiscoveredDevice>, ClientError>

Broadcast a Who-Is request and collect I-Am replies for the duration of wait.

range constrains the device-instance range as (low, high); None performs a global Who-Is. Duplicate devices (same object id) are deduplicated. Returns ClientError::DataLink on send/receive failure.

Source

pub async fn who_has_object_id( &self, range: Option<(u32, u32)>, object_id: ObjectId, wait: Duration, ) -> Result<Vec<DiscoveredObject>, ClientError>

Broadcast a Who-Has request for a specific object id and collect I-Have replies for wait.

range constrains the responding device-instance range; None means any device.

Source

pub async fn who_has_object_name( &self, range: Option<(u32, u32)>, object_name: &str, wait: Duration, ) -> Result<Vec<DiscoveredObject>, ClientError>

Broadcast a Who-Has request for an object by name and collect I-Have replies for wait.

range constrains the responding device-instance range; None means any device.

Source

pub async fn device_communication_control( &self, address: DataLinkAddress, time_duration_seconds: Option<u16>, enable_disable: DeviceCommunicationState, password: Option<&str>, ) -> Result<(), ClientError>

Send a DeviceCommunicationControl request to a device.

time_duration_seconds sets the duration for which the state applies; None means indefinite. enable_disable selects the new communication state. password is only required if the device is password-protected.

Source

pub async fn reinitialize_device( &self, address: DataLinkAddress, state: ReinitializeState, password: Option<&str>, ) -> Result<(), ClientError>

Send a ReinitializeDevice request to a device (e.g. cold-start, warm-start, or backup).

state selects the reinitialization type. password is sent only if Some.

Source

pub async fn time_synchronize( &self, address: DataLinkAddress, date: Date, time: Time, utc: bool, ) -> Result<(), ClientError>

Send a TimeSynchronization (or UTCTimeSynchronization) request to a device.

Set utc to true to send the UTC variant of the request. This is a fire-and-forget unconfirmed service; no response is awaited.

Source

pub async fn create_object_by_type( &self, address: DataLinkAddress, object_type: ObjectType, ) -> Result<ObjectId, ClientError>

Create a new object of the given type on the device, letting the device choose the instance number. Returns the ObjectId assigned by the device.

Source

pub async fn create_object( &self, address: DataLinkAddress, request: CreateObjectRequest, ) -> Result<ObjectId, ClientError>

Send a CreateObject request to the device and return the ObjectId of the newly created object. Use this variant when you need fine-grained control over the request (e.g. specifying initial property values).

Source

pub async fn delete_object( &self, address: DataLinkAddress, object_id: ObjectId, ) -> Result<(), ClientError>

Send a DeleteObject request to remove object_id from the device.

Source

pub async fn add_list_element( &self, address: DataLinkAddress, request: AddListElementRequest<'_>, ) -> Result<(), ClientError>

Send an AddListElement request to append elements to a list property on the device.

Source

pub async fn remove_list_element( &self, address: DataLinkAddress, request: RemoveListElementRequest<'_>, ) -> Result<(), ClientError>

Send a RemoveListElement request to delete elements from a list property on the device.

Source

pub async fn get_alarm_summary( &self, address: DataLinkAddress, ) -> Result<Vec<AlarmSummaryItem>, ClientError>

Send a GetAlarmSummary request and return the list of active alarms on the device.

Source

pub async fn get_enrollment_summary( &self, address: DataLinkAddress, ) -> Result<Vec<EnrollmentSummaryItem>, ClientError>

Send a GetEnrollmentSummary request and return the list of event enrollments on the device.

Source

pub async fn get_event_information( &self, address: DataLinkAddress, last_received_object_id: Option<ObjectId>, ) -> Result<EventInformationResult, ClientError>

Send a GetEventInformation request and return active event summaries from the device.

Pass last_received_object_id to page through results; the returned EventInformationResult::more_events indicates whether another call is needed.

Source

pub async fn acknowledge_alarm( &self, address: DataLinkAddress, request: AcknowledgeAlarmRequest<'_>, ) -> Result<(), ClientError>

Send an AcknowledgeAlarm request to the device.

Source

pub async fn atomic_read_file_stream( &self, address: DataLinkAddress, file_object_id: ObjectId, file_start_position: i32, requested_octet_count: u32, ) -> Result<AtomicReadFileResult, ClientError>

Read a contiguous byte range from a BACnet File object using stream access.

file_start_position is the byte offset (may be negative for end-relative access). requested_octet_count is the number of bytes to read.

Source

pub async fn atomic_read_file_record( &self, address: DataLinkAddress, file_object_id: ObjectId, file_start_record: i32, requested_record_count: u32, ) -> Result<AtomicReadFileResult, ClientError>

Read a range of records from a BACnet File object using record access.

file_start_record is the first record index (may be negative for end-relative access). requested_record_count is the number of records to read.

Source

pub async fn atomic_write_file_stream( &self, address: DataLinkAddress, file_object_id: ObjectId, file_start_position: i32, file_data: &[u8], ) -> Result<AtomicWriteFileResult, ClientError>

Write file_data to a BACnet File object starting at file_start_position using stream access. The returned result contains the actual start position used by the device.

Source

pub async fn atomic_write_file_record( &self, address: DataLinkAddress, file_object_id: ObjectId, file_start_record: i32, file_record_data: &[&[u8]], ) -> Result<AtomicWriteFileResult, ClientError>

Write records to a BACnet File object starting at file_start_record using record access.

Each element of file_record_data is one record’s raw bytes.

Source

pub async fn subscribe_cov( &self, address: DataLinkAddress, request: SubscribeCovRequest, ) -> Result<(), ClientError>

Send a SubscribeCOV request to start (or renew) a COV subscription on the device.

Use cancel_cov_subscription to unsubscribe.

Source

pub async fn cancel_cov_subscription( &self, address: DataLinkAddress, subscriber_process_id: u32, monitored_object_id: ObjectId, ) -> Result<(), ClientError>

Cancel an existing COV subscription identified by subscriber_process_id and monitored_object_id.

Source

pub async fn subscribe_cov_property( &self, address: DataLinkAddress, request: SubscribeCovPropertyRequest, ) -> Result<(), ClientError>

Send a SubscribeCOVProperty request to subscribe to changes of a specific property.

Use cancel_cov_property_subscription to unsubscribe.

Source

pub async fn cancel_cov_property_subscription( &self, address: DataLinkAddress, subscriber_process_id: u32, monitored_object_id: ObjectId, monitored_property_id: PropertyId, monitored_property_array_index: Option<u32>, ) -> Result<(), ClientError>

Cancel an existing COV property subscription.

The combination of subscriber_process_id, monitored_object_id, monitored_property_id, and monitored_property_array_index must match the subscription to cancel.

Source

pub async fn read_range_by_position( &self, address: DataLinkAddress, object_id: ObjectId, property_id: PropertyId, array_index: Option<u32>, reference_index: i32, count: i16, ) -> Result<ReadRangeResult, ClientError>

Read a range of entries from a list/log property by absolute position.

reference_index is the 1-based starting entry index. A positive count reads forward; negative reads backward from reference_index.

Source

pub async fn read_range_by_sequence_number( &self, address: DataLinkAddress, object_id: ObjectId, property_id: PropertyId, array_index: Option<u32>, reference_sequence: u32, count: i16, ) -> Result<ReadRangeResult, ClientError>

Read a range of entries from a list/log property anchored at a sequence number.

reference_sequence is the sequence number of the anchor entry. A positive count reads forward; negative reads backward.

Source

pub async fn read_range_by_time( &self, address: DataLinkAddress, object_id: ObjectId, property_id: PropertyId, array_index: Option<u32>, at: (Date, Time), count: i16, ) -> Result<ReadRangeResult, ClientError>

Read a range of entries from a list/log property anchored at a timestamp.

at is the reference date and time. A positive count reads forward from that timestamp; negative reads backward.

Source

pub async fn recv_cov_notification( &self, wait: Duration, ) -> Result<Option<CovNotification>, ClientError>

Wait up to wait for a single incoming COV notification (confirmed or unconfirmed).

Returns Ok(Some(_)) when a notification arrives, Ok(None) on timeout, and Err on transport failure. Confirmed notifications are automatically acknowledged. Segmented confirmed notifications return ClientError::UnsupportedResponse.

Source

pub async fn recv_event_notification( &self, wait: Duration, ) -> Result<Option<EventNotification>, ClientError>

Wait up to wait for a single incoming event notification (confirmed or unconfirmed).

Returns Ok(Some(_)) when a notification arrives, Ok(None) on timeout, and Err on transport failure. Confirmed notifications are automatically acknowledged. Segmented confirmed notifications return ClientError::UnsupportedResponse.

Source

pub async fn read_property( &self, address: DataLinkAddress, object_id: ObjectId, property_id: PropertyId, ) -> Result<ClientDataValue, ClientError>

Send a ReadProperty request and return the property value as a ClientDataValue.

Use read_property_multiple to fetch several properties in a single round-trip.

Source

pub async fn write_property( &self, address: DataLinkAddress, request: WritePropertyRequest<'_>, ) -> Result<(), ClientError>

Send a WriteProperty request to set a single property on the device.

Source

pub async fn read_property_multiple( &self, address: DataLinkAddress, object_id: ObjectId, property_ids: &[PropertyId], ) -> Result<Vec<(PropertyId, ClientDataValue)>, ClientError>

Send a ReadPropertyMultiple request to fetch several properties of one object in a single round-trip.

Returns pairs of (PropertyId, ClientDataValue) in the order returned by the device.

Source

pub async fn write_property_multiple( &self, address: DataLinkAddress, object_id: ObjectId, properties: &[PropertyWriteSpec<'_>], ) -> Result<(), ClientError>

Send a WritePropertyMultiple request to set several properties of one object in a single round-trip.

Source

pub async fn private_transfer( &self, address: DataLinkAddress, vendor_id: u32, service_number: u32, service_parameters: Option<&[u8]>, ) -> Result<PrivateTransferAck, ClientError>

Send a ConfirmedPrivateTransfer request and return the ack.

Source

pub async fn read_many( &self, address: DataLinkAddress, requests: &[(ObjectId, PropertyId)], ) -> Result<HashMap<(ObjectId, PropertyId), ClientDataValue>, ClientError>

Read multiple (object_id, property_id) pairs in a single ReadPropertyMultiple round-trip.

All pairs must target the same device at address. Returns a map from each requested (ObjectId, PropertyId) to its value. Properties not returned by the device are absent from the map (the device may skip unknown properties rather than erroring).

Source

pub async fn write_many( &self, address: DataLinkAddress, writes: &[(ObjectId, PropertyId, ClientDataValue, Option<u8>)], ) -> Result<(), ClientError>

Write multiple properties across one or more objects in a single WritePropertyMultiple round-trip.

writes is a slice of (object_id, property_id, value, priority) tuples. priority may be None for the relinquish-default case. All writes target the same device at address. Takes ClientDataValue (the owned form) for ergonomic use.

Trait Implementations§

Source§

impl<D: Debug + DataLink> Debug for BacnetClient<D>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<D> !Freeze for BacnetClient<D>

§

impl<D> !RefUnwindSafe for BacnetClient<D>

§

impl<D> Send for BacnetClient<D>

§

impl<D> Sync for BacnetClient<D>

§

impl<D> Unpin for BacnetClient<D>
where D: Unpin,

§

impl<D> UnsafeUnpin for BacnetClient<D>
where D: UnsafeUnpin,

§

impl<D> UnwindSafe for BacnetClient<D>
where D: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V