Crate opcua_client
source · [−]Expand description
The OPC UA Client module contains the functionality necessary for a client to connect to an OPC UA server, authenticate itself, send messages, receive responses, get values, browse the address space and provide callbacks for things to be propagated to the client.
A client has to specify the endpoint description they wish to connect to, security policy and other
configurable options, e.g. paths to PKI keys. All of this is encapsulated in a Client
object.
One of these may be made programatically using a ClientBuilder
or from a preexisting ClientConfig
which can be loaded fully or partially from disk. Use the way that suits you.
Once the Client
is created it can connect to a server by creating a Session
. Multiple sessions
can be created from the same client. Functions on the Session
correspond to OPC UA services so
it can be used to:
- Discover endpoints
- Activate a session
- Create / modify / delete subscriptions
- Create / modify / delete monitored items
- Read and write values
- Browse the address space
- Add or remove nodes
Functionality is synchronous and housekeeping such as renewing the active session and sending publish requests is handled automatically.
Data change and event notifications are via asynchronous callbacks.
Example
Here is a complete example of a client that connects to the samples/simple-server
, subscribes
to some values and prints out changes to those values. This example corresponds to the one
described in the in docs/client.md tutorial.
use std::sync::{Arc, RwLock};
use opcua_client::prelude::*;
fn main() {
let mut client = ClientBuilder::new()
.application_name("My First Client")
.application_uri("urn:MyFirstClient")
.create_sample_keypair(true)
.trust_server_certs(false)
.session_retry_limit(3)
.client().unwrap();
// Create an endpoint. The EndpointDescription can be made from a tuple consisting of
// the endpoint url, security policy, message security mode and user token policy.
let endpoint: EndpointDescription = ("opc.tcp://localhost:4855/", "None", MessageSecurityMode::None, UserTokenPolicy::anonymous()).into();
// Create the session
let session = client.connect_to_endpoint(endpoint, IdentityToken::Anonymous).unwrap();
// Create a subscription and monitored items
if subscribe_to_values(session.clone()).is_ok() {
let _ = Session::run(session);
} else {
println!("Error creating subscription");
}
}
fn subscribe_to_values(session: Arc<RwLock<Session>>) -> Result<(), StatusCode> {
let mut session = session.write().unwrap();
// Create a subscription polling every 2s with a callback
let subscription_id = session.create_subscription(2000.0, 10, 30, 0, 0, true, DataChangeCallback::new(|changed_monitored_items| {
println!("Data change from server:");
changed_monitored_items.iter().for_each(|item| print_value(item));
}))?;
// Create some monitored items
let items_to_create: Vec<MonitoredItemCreateRequest> = ["v1", "v2", "v3", "v4"].iter()
.map(|v| NodeId::new(2, *v).into()).collect();
let _ = session.create_monitored_items(subscription_id, TimestampsToReturn::Both, &items_to_create)?;
Ok(())
}
fn print_value(item: &MonitoredItem) {
let node_id = &item.item_to_monitor().node_id;
let data_value = item.last_value();
if let Some(ref value) = data_value.value {
println!("Item \"{}\", Value = {:?}", node_id, value);
} else {
println!("Item \"{}\", Value not found, error: {}", node_id, data_value.status.as_ref().unwrap());
}
}