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
- UDP/IP:
BacnetClient::new()(local broadcast) orBacnetClient::new_foreign()(register as a foreign device with a BBMD). - BACnet/SC (WebSocket):
BacnetClient::new_sc(). - Custom transport:
BacnetClient::with_datalink().
Implementations§
Source§impl BacnetClient<BacnetIpTransport>
impl BacnetClient<BacnetIpTransport>
Sourcepub async fn new() -> Result<Self, ClientError>
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.
Sourcepub async fn new_foreign(
bbmd_addr: SocketAddr,
ttl_seconds: u16,
) -> Result<Self, ClientError>
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.
Sourcepub async fn register_foreign_device(
&self,
ttl_seconds: u16,
) -> Result<(), ClientError>
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.
Sourcepub async fn read_broadcast_distribution_table(
&self,
) -> Result<Vec<BroadcastDistributionEntry>, ClientError>
pub async fn read_broadcast_distribution_table( &self, ) -> Result<Vec<BroadcastDistributionEntry>, ClientError>
Read the Broadcast Distribution Table (BDT) from the BBMD.
Sourcepub async fn write_broadcast_distribution_table(
&self,
entries: &[BroadcastDistributionEntry],
) -> Result<(), ClientError>
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.
Sourcepub async fn read_foreign_device_table(
&self,
) -> Result<Vec<ForeignDeviceTableEntry>, ClientError>
pub async fn read_foreign_device_table( &self, ) -> Result<Vec<ForeignDeviceTableEntry>, ClientError>
Read the Foreign Device Table (FDT) from the BBMD.
Sourcepub async fn delete_foreign_device_table_entry(
&self,
address: SocketAddrV4,
) -> Result<(), ClientError>
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.
Sourcepub fn start_foreign_device_renewal(
&self,
ttl_seconds: u16,
) -> Result<ForeignDeviceRenewal, ClientError>
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<D: DataLink> BacnetClient<D>
impl<D: DataLink> BacnetClient<D>
Sourcepub fn with_datalink(datalink: D) -> Self
pub fn with_datalink(datalink: D) -> Self
Create a client wrapping an already-constructed datalink.
Use this when you need a custom or pre-configured DataLink implementation.
Sourcepub fn with_response_timeout(self, timeout: Duration) -> Self
pub fn with_response_timeout(self, timeout: Duration) -> Self
Override the per-request response timeout (default: 3 s).
Sourcepub fn with_segmented_request_window_size(self, window_size: u8) -> Self
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.
Sourcepub fn with_segmented_request_retries(self, retries: u8) -> Self
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.
Sourcepub fn with_segment_ack_timeout(self, timeout: Duration) -> Self
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.
Sourcepub async fn who_is(
&self,
range: Option<(u32, u32)>,
wait: Duration,
) -> Result<Vec<DiscoveredDevice>, ClientError>
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.
Sourcepub async fn who_has_object_id(
&self,
range: Option<(u32, u32)>,
object_id: ObjectId,
wait: Duration,
) -> Result<Vec<DiscoveredObject>, ClientError>
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.
Sourcepub async fn who_has_object_name(
&self,
range: Option<(u32, u32)>,
object_name: &str,
wait: Duration,
) -> Result<Vec<DiscoveredObject>, ClientError>
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.
Sourcepub async fn device_communication_control(
&self,
address: DataLinkAddress,
time_duration_seconds: Option<u16>,
enable_disable: DeviceCommunicationState,
password: Option<&str>,
) -> Result<(), ClientError>
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.
Sourcepub async fn reinitialize_device(
&self,
address: DataLinkAddress,
state: ReinitializeState,
password: Option<&str>,
) -> Result<(), ClientError>
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.
Sourcepub async fn time_synchronize(
&self,
address: DataLinkAddress,
date: Date,
time: Time,
utc: bool,
) -> Result<(), ClientError>
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.
Sourcepub async fn create_object_by_type(
&self,
address: DataLinkAddress,
object_type: ObjectType,
) -> Result<ObjectId, ClientError>
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.
Sourcepub async fn create_object(
&self,
address: DataLinkAddress,
request: CreateObjectRequest,
) -> Result<ObjectId, ClientError>
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).
Sourcepub async fn delete_object(
&self,
address: DataLinkAddress,
object_id: ObjectId,
) -> Result<(), ClientError>
pub async fn delete_object( &self, address: DataLinkAddress, object_id: ObjectId, ) -> Result<(), ClientError>
Send a DeleteObject request to remove object_id from the device.
Sourcepub async fn add_list_element(
&self,
address: DataLinkAddress,
request: AddListElementRequest<'_>,
) -> Result<(), ClientError>
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.
Sourcepub async fn remove_list_element(
&self,
address: DataLinkAddress,
request: RemoveListElementRequest<'_>,
) -> Result<(), ClientError>
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.
Sourcepub async fn get_alarm_summary(
&self,
address: DataLinkAddress,
) -> Result<Vec<AlarmSummaryItem>, ClientError>
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.
Sourcepub async fn get_enrollment_summary(
&self,
address: DataLinkAddress,
) -> Result<Vec<EnrollmentSummaryItem>, ClientError>
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.
Sourcepub async fn get_event_information(
&self,
address: DataLinkAddress,
last_received_object_id: Option<ObjectId>,
) -> Result<EventInformationResult, ClientError>
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.
Sourcepub async fn acknowledge_alarm(
&self,
address: DataLinkAddress,
request: AcknowledgeAlarmRequest<'_>,
) -> Result<(), ClientError>
pub async fn acknowledge_alarm( &self, address: DataLinkAddress, request: AcknowledgeAlarmRequest<'_>, ) -> Result<(), ClientError>
Send an AcknowledgeAlarm request to the device.
Sourcepub async fn atomic_read_file_stream(
&self,
address: DataLinkAddress,
file_object_id: ObjectId,
file_start_position: i32,
requested_octet_count: u32,
) -> Result<AtomicReadFileResult, ClientError>
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.
Sourcepub async fn atomic_read_file_record(
&self,
address: DataLinkAddress,
file_object_id: ObjectId,
file_start_record: i32,
requested_record_count: u32,
) -> Result<AtomicReadFileResult, ClientError>
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.
Sourcepub async fn atomic_write_file_stream(
&self,
address: DataLinkAddress,
file_object_id: ObjectId,
file_start_position: i32,
file_data: &[u8],
) -> Result<AtomicWriteFileResult, ClientError>
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.
Sourcepub async fn atomic_write_file_record(
&self,
address: DataLinkAddress,
file_object_id: ObjectId,
file_start_record: i32,
file_record_data: &[&[u8]],
) -> Result<AtomicWriteFileResult, ClientError>
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.
Sourcepub async fn subscribe_cov(
&self,
address: DataLinkAddress,
request: SubscribeCovRequest,
) -> Result<(), ClientError>
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.
Sourcepub async fn cancel_cov_subscription(
&self,
address: DataLinkAddress,
subscriber_process_id: u32,
monitored_object_id: ObjectId,
) -> Result<(), ClientError>
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.
Sourcepub async fn subscribe_cov_property(
&self,
address: DataLinkAddress,
request: SubscribeCovPropertyRequest,
) -> Result<(), ClientError>
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.
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub async fn recv_cov_notification(
&self,
wait: Duration,
) -> Result<Option<CovNotification>, ClientError>
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.
Sourcepub async fn recv_event_notification(
&self,
wait: Duration,
) -> Result<Option<EventNotification>, ClientError>
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.
Sourcepub async fn read_property(
&self,
address: DataLinkAddress,
object_id: ObjectId,
property_id: PropertyId,
) -> Result<ClientDataValue, ClientError>
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.
Sourcepub async fn write_property(
&self,
address: DataLinkAddress,
request: WritePropertyRequest<'_>,
) -> Result<(), ClientError>
pub async fn write_property( &self, address: DataLinkAddress, request: WritePropertyRequest<'_>, ) -> Result<(), ClientError>
Send a WriteProperty request to set a single property on the device.
Sourcepub async fn read_property_multiple(
&self,
address: DataLinkAddress,
object_id: ObjectId,
property_ids: &[PropertyId],
) -> Result<Vec<(PropertyId, ClientDataValue)>, ClientError>
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.
Sourcepub async fn write_property_multiple(
&self,
address: DataLinkAddress,
object_id: ObjectId,
properties: &[PropertyWriteSpec<'_>],
) -> Result<(), ClientError>
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.
Sourcepub async fn private_transfer(
&self,
address: DataLinkAddress,
vendor_id: u32,
service_number: u32,
service_parameters: Option<&[u8]>,
) -> Result<PrivateTransferAck, ClientError>
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.
Sourcepub async fn read_many(
&self,
address: DataLinkAddress,
requests: &[(ObjectId, PropertyId)],
) -> Result<HashMap<(ObjectId, PropertyId), ClientDataValue>, ClientError>
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).
Sourcepub async fn write_many(
&self,
address: DataLinkAddress,
writes: &[(ObjectId, PropertyId, ClientDataValue, Option<u8>)],
) -> Result<(), ClientError>
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.