-
Notifications
You must be signed in to change notification settings - Fork 433
Client
The entry point for access to a remote server is via an instance of OpcUaClient
. An instance can be created by providing an OpcUaClientConfig
to the static OpcUaClient#create()
function.
Creating an OpcUaClientConfig
requires, at a minimum, a valid EndpointDescription
for the server this client will connect to. An EndpointDescription
can be obtained by calling the GetEndpoints service and selecting an endpoint that matches the criteria of the client application.
Each EndpointDescription
contains details about an endpoint such as the endpoint URL, SecurityPolicy
, MessageSecurityMode
, and UserTokenPolicy
s supported by that endpoint.
Putting this together, the process looks like:
- Given an endpoint URL, call the GetEndpoints service to get a list of endpoints.
- Select an endpoint that meets your application criteria.
- Create and configure an
OpcUaClientConfig
using the selected endpoint. - Create an
OpcUaClient
instance and callconnect()
.
OpcUaClient#create
has an overload that combines the above steps into a single call. The following example creates an OpcUaClient
after selecting the first endpoint that uses SecurityPolicy.None
.
OpcUaClient client = OpcUaClient.create(
"opc.tcp://milo.digitalpetri.com:62541/milo",
endpoints ->
endpoints.stream()
.filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
.findFirst(),
configBuilder ->
configBuilder.build()
);
Now the OpcUaClient
just needs to be connected:
client.connect().get();
From this call forward the OpcUaClient
instance will automatically attempt to reconnect any time the connection is lost, including if the initial connect()
call failed. This behavior persists until disconnect()
is called.
Endpoints can be discovered by calling the GetEndpoints service on a remote server.
The client SDK provides a DiscoveryClient
with convenient static helper methods to make this easier.
A list of EndpointDescriptions
can be obtained from DiscoveryClient#getEndpoints
:
List<EndpointDescription> endpoints =
DiscoveryClient.getEndpoints(endpointUrl).get();
The above example showed an extremely minimal configuriation for a client, but properly configured client applications need a little more configuration to identify them.
- Application Name
- Application URI
- Product URI
In order to connect to an endpoint that uses security additional configuration is needed.
- Public+Private Key Pair
- Certificate or Certificate Chain
- Certificate Validator
Authentication is configured by setting an IdentityProvider
when building an OpcUaClientConfig
. You must configure an IdentityProvider
that the selected endpoint indicates it supports in its UserTokenPolicy
array.
No additional configuration is necessary to connect anonymously as AnonymousProvider
is the default IdentityProvider
when one is not explicitly configured.
The selected endpoint must contain a UserTokenPolicy
with a UserTokenType
of UserTokenType.Anonymous
.
To connect with a username and password set an instance of UsernameProvider
when building the OpcUaClientConfig
.
The selected endpoint must contain a UserTokenPolicy
with a UserTokenType
of UserTokenType.UserName
.
To connect using an X509Certificate
as the identity set an instance of X509IdentityProvider
The selected endpoint must contain a UserTokenPolicy
with a UserTokenType
of UserTokenType.Certificate
.
Browsing can be done in three ways:
-
AddressSpace#browse
, a higher level API that provides blocking or non-blocking options and a reasonable set of default parameters.Using the default
BrowseOptions
:AddressSpace addressSpace = client.getAddressSpace(); UaNode serverNode = addressSpace.getNode(Identifiers.Server); List<? extends UaNode> nodes = addressSpace.browseNodes(serverNode);
Using a custom
BrowseOptions
:AddressSpace addressSpace = client.getAddressSpace(); UaNode serverNode = addressSpace.getNode(Identifiers.Server); BrowseOptions browseOptions = addressSpace.getBrowseOptions().copy( b -> b.setReferenceType(BuiltinReferenceType.HasProperty) ); // just UaNodes referenced by HasProperty references List<? extends UaNode> nodes = addressSpace.browseNodes(serverNode, browseOptions);
-
UaNode#browse
andUaNode#browseNodes
, a higher level API that makes gettingReference
s or otherUaNode
instances referenced by aUaNode
instance easy.BrowseOptions browseOptions = BrowseOptions.builder() .setReferenceType(Identifiers.HasProperty) .build(); // Browse for HasProperty references List<ReferenceDescription> references = node.browse(browseOptions); // Browse for HasProperty references and get the UaNodes they target List<? extends UaNode> nodes = node.browseNodes(browseOptions);
-
OpcUaClient#browse
, a lower level API that takes parameters corresponding directly to those defined for the Browse service in the OPC UA spec.// Browse for forward hierarchal references from the Objects folder // that lead to other Object and Variable nodes. BrowseDescription browse = new BrowseDescription( Identifiers.ObjectsFolder, BrowseDirection.Forward, Identifiers.References, true, uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()), uint(BrowseResultMask.All.getValue()) ); BrowseResult browseResult = client.browse(browse).get();
Unlike the previous browse methods, this one does not check whether a continuation point was returned and follow up with calls to the BrowseNext service until all
Reference
s have been retrieved. Subsequent calls to BrowseNext are the responsibility of the caller.
Attributes can be read using either the high or low level APIs:
-
Using
UaNode
, which provides a variety of high level calls to read each attribute directly or provide anAttributeId
to read.UaVariableNode testNode = (UaVariableNode) addressSpace.getNode( new NodeId(2, "TestInt32") ); // Read the Value attribute DataValue value = testNode.readValue(); // Read the BrowseName attribute QualifiedName browseName = testNode.readBrowseName(); // Read the Description attribute, with timestamps and quality intact DataValue descriptionValue = testNode.readAttribute(AttributeId.Description);
-
Using
OpcUaClient#read
, a lower level API that takes parameters corresponding directly to those defined for the Read service in the OPC UA spec.List<ReadValueId> readValueIds = new ArrayList<>(); readValueIds.add( new ReadValueId( new NodeId(2, "TestInt32"), AttributeId.Value.uid(), null, // indexRange QualifiedName.NULL_VALUE ) ); ReadResponse readResponse = client.read( 0.0, // maxAge TimestampsToReturn.Both, readValueIds ).get();
Attributes can be written using either the high or low level APIs:
-
Using
UaNode
, which provides a variety of high level calls to write each attribute directly or provide anAttributeId
andDataValue
to write.UaVariableNode testNode = (UaVariableNode) addressSpace.getNode( new NodeId(2, "TestInt32") ); // Write the Value attribute; throws UaException if the write fails testNode.writeValue(new Variant(42)); // Most servers don't allow quality or timestamps to be written, // hence the use of DataValue.valueOnly(), but this method could // be used to write to a server that did support it if necessary StatusCode statusCode = testNode.writeAttribute( AttributeId.Value, DataValue.valueOnly(new Variant(42)) );
-
Using
OpcUaClient#write
, a lower level API that takes parameters corresponding directly to those defined for the Write service in the OPC UA spec.List<WriteValue> writeValues = new ArrayList<>(); writeValues.add( new WriteValue( new NodeId(2, "TestInt32"), AttributeId.Value.uid(), null, // indexRange DataValue.valueOnly(new Variant(42)) ) ); WriteResponse writeResponse = client.write(writeValues).get();