Access Data from OPC UA Servers
OPC UA Programming Overview
This topic shows the basic steps to create an OPC Unified Architecture (UA) application by retrieving current and historical data from a Simulation Server running on your local machine.
Note
To run the sample code in the following steps you need the Prosys OPC UA Simulation Server running on your local machine. You can also optionally install the Local Discovery Service and register the Prosys server with the LDS. For installation details, see Install an OPC UA Simulation Server for OPC UA Examples. The code requires only minor changes to work with other servers.
Step 1: Locate Your OPC UA Server
In this step, you obtain information that the toolbox needs to uniquely identify the OPC UA server that you want to connect to. You use this information when creating an OPC UA client object, described in Step 2: Create an OPC UA Client Object.
The first piece of information is the host name of the server computer. The host
name (a descriptive name like "HistorianServer" or an IP address such as
192.168.16.32) qualifies that computer on the network, and is used by the OPC
protocols to determine the available OPC servers on that computer. In any OPC
application, you must know the name of the OPC server host, so that a connection
with that host can be established. Your network administrator can provide a list of
host names that provide OPC servers on your network. In this example, you will use
'localhost'
as the host name, because you will connect to the
OPC server on the same machine as the client.
OPC UA servers are uniquely identified by Universal Resource Locations. Similar to
web addresses, a URL for an OPC UA server starts with opc.tcp://
,
and then provides an address of the server as a hostname, port, and address in
standard ASCII text. For example, the URL for the Prosys OPC UA Simulation Server is
opc.tcp://localhost:53530/OPCUA/SimulationServer
.
OPC UA Server URLs are advertised through an OPC UA Local Discovery Service (LDS), available on every OPC UA server host machine. Your system administrator can provide a list of server URLs for a particular host, or you can query the host for all available OPC UA servers.
If you have installed the LDS and registered the OPC UA server with the LDS, you
can use the opcuaserverinfo
function to query
hosts from the command line. If you have not installed the LDS, skip to Step
2.
serverList = opcuaserverinfo('localhost')
serverList = 1x2 OPC UA ServerInfo array: index Description Hostname Port ----- ----------------------------- ------------ ----- 1 SimulationServer myhost.local 53530 2 Quickstart Data Access Server myhost.local 62547
Locate the server of interest by using the findDescription
function to search for a specific character vector
in the server description.
hsInfo = findDescription(serverList,'Simulation')
hsInfo = OPC UA ServerInfo 'SimulationServer': Connection Information Hostname: 'myhost.local' Port: 53530 Endpoints: [1×11 opc.ua.EndpointDescription] Security Information: BestMessageSecurity: SignAndEncrypt BestChannelSecurity: Aes256_Sha256_RsaPss UserTokenTypes: {'Anonymous' 'Username' 'Certificate'}
From this discovery process, you can identify the port (53530) on which the OPC UA server listens for connections. The discovery process also makes it easier to construct and connect to the required OPC UA server.
Step 2: Create an OPC UA Client and Connect to the Server
After locating your OPC UA server, you create an OPC UA Client to manage the
connection to the server, obtain key server characteristics, and read and write data
from the server. You can use the opcuaserverinfo
result to
construct an OPC UA client directly.
uaClient = opcua(hsInfo)
Or you could create a client using the hostname and port directly.
uaClient = opcua('localhost',53530)
uaClient = OPC UA Client: Server Information: Name: 'SimulationServer@localhost' Hostname: 'localhost' Port: 53530 EndpointUrl: 'opc.tcp://localhost:53530/OPCUA/SimulationServer' Connection Information: Timeout: 10 Status: 'Disconnected' ServerState: '<Not connected>' Security Information: MessageSecurityMode: SignAndEncrypt ChannelSecurityPolicy: Aes256_Sha256_RsaPss Endpoints: [1×11 opc.ua.EndpointDescription]
The client is initially disconnected from the server, as shown by the
Status
property. After you connect to the server,
additional properties are shown in the client display.
connect(uaClient)
uaClient OPC UA Client: Server Information: Name: 'SimulationServer@localhost' Hostname: 'localhost' Port: 53530 EndpointUrl: 'opc.tcp://localhost:53530/OPCUA/SimulationServer' Connection Information: Timeout: 10 Status: 'Connected' ServerState: 'Running' Security Information: MessageSecurityMode: SignAndEncrypt ChannelSecurityPolicy: Aes256_Sha256_RsaPss Endpoints: [1×11 opc.ua.EndpointDescription] Server Limits: MinSampleRate: 0 sec MaxReadNodes: 0 MaxWriteNodes: 0 MaxHistoryReadNodes: 0 MaxHistoryValuesPerNode: 0
The additional properties describe capabilities of the server, notably limits for various read and write operations. A limit value of 0 indicates that the server does not impose a direct limit on that capability.
Step 3: Browse OPC UA Server Namespace
OPC UA servers provide a single namespace for you to read and write both current data and historical data. The namespace is organized as a hierarchy of nodes. Each node has attributes which describe that node. A node is uniquely identified by two elements: A namespace index (numeric integer) and a node identifier (numeric integer, character vector, or Globally Unique Identifier or GUID). To uniquely describe a node, you have to provide both the namespaceindex and the identifier; you cannot provide only the identifier because that might be repeated for different namespace indexes.
Industrial Communication Toolbox™ exposes the hierarchy of nodes through the namespace property of the
OPC UA client. Each element of the namespace property is a node at the top-most
level of the server. Every node in the namespace has a Children
property which exposes the subnodes contained in that node. You can browse the
namespace graphically using the browseNamespace
function. The resulting dialog box allows you to
select nodes from the hierarchy and return them in the output from the
function.
serverNodes = browseNamespace(uaClient)
When you click OK the selected items are returned in the command window output.
serverNodes = 1x2 OPC UA Node array: index Name NsInd Identifier NodeType ----- ---------------------- ----- ---------- -------- 1 MinSupportedSampleRate 0 2272 Variable 2 MaxArrayLength 0 11702 Variable
Nodes can have data values associated with them or can simply be containers for
other nodes. The NodeType
property of a node identifies the
node as an object node (container) or variable node (data). For more information on
how to programmatically search the server namespace, see Browse OPC UA Server Namespace.
Step 4: Read Current Values from the OPC UA Server
OPC UA servers provide access to both current and historical values of their
Variable
nodes. With Industrial Communication Toolbox you use arrays of Nodes to read current values from the server.
Current data includes the value, a timestamp that the server received the data value
from the sensor, and a quality describing the accuracy and source of the data
value.
[val,ts,qual] = readValue(uaClient,serverNodes)
val = 2×1 cell array {[0 sec]} {[65535]} ts = 2×1 datetime array 23-Apr-2024 08:58:23 23-Apr-2024 08:58:23 qual = OPC UA Quality ID: 'Good' 'Good'
For more information on reading and writing current values, see Read and Write Current OPC UA Server Data.
Step 5: Read Historical Data from the OPC UA Server
Historical data is stored for selected nodes on the OPC UA server. The server
nodes retrieved in the previous step will not be archived by the server because the
values do not generally change. You can query the Historizing
property of a Node to determine if the server is currently archiving data for that
node.
Because the serverNode list is an array, you must collect the outputs using concatenation.
[serverNodes.Historizing]
ans = 1×2 logical array 0 0
None of the server nodes are currently being historized. In addition, the server
does not allow historical access to these nodes, as evidenced by the
AccessLevelHistory
property of the nodes.
{serverNodes.AccessLevelHistory}
ans = 1×2 cell array {'none'} {'none'}
To locate nodes with history, query the server for the Double and Int32 nodes in
the Simulation
parent node.
simNode = findNodeByName(uaClient.Namespace,'Simulation')
simNode = OPC UA Node: Node Information: Name: 'Simulation' Description: '' NamespaceIndex: 3 Identifier: '85/0:Simulation' NodeType: 'Object' Hierarchy Information: Parent: Server Children: 7
The Simulation
node is an Object
node, so it
has no Value
. However, it has 7 Children. Locate the
Sinusoid
and Random
child nodes. The
'-partial'
flag finds nodes beginning with the argument
provided.
sineNode = findNodeByName(simNode,'Sinusoid', '-partial'); randNode = findNodeByName(simNode,'Random', '-partial')
randNode = OPC UA Node: Node Information: Name: 'Random' Description: '' NamespaceIndex: 3 Identifier: 1003 NodeType: 'Variable' Hierarchy Information: Parent: 'Simulation' Children: 1 ServerDataType: 'Double' AccessLevelCurrent: 'read' AccessLevelHistory: 'read' Historizing: 1
As the Sinusoid
and Random
nodes are
currently being archived (Historizing
is true) you can read
history data from the nodes. You can also read history data from the nodes when
Historizing
is false, if the history was logged at startup,
and then turned off. To read all data stored on the server within a specified time
range, use the readHistory
function, passing the
nodes to read and the time range over which to read the data.
histData = readHistory(uaClient,[sineNode,randNode],datetime('now')-seconds(10),datetime('now'))
histData = 1-by-2 OPC UA Data object array: Timestamp Sinusoid Random ------------------- -------------------------- -------------------------- 04/23/2024 9:00 AM 1.732051 [Good (Raw)] -1.343764 [Good (Raw)] 04/23/2024 9:00 AM 1.486290 [Good (Raw)] -0.985439 [Good (Raw)] 04/23/2024 9:00 AM 1.175571 [Good (Raw)] 0.821036 [Good (Raw)] 04/23/2024 9:00 AM 0.813473 [Good (Raw)] 1.179361 [Good (Raw)] 04/23/2024 9:00 AM 0.415824 [Good (Raw)] 0.150251 [Good (Raw)] 04/23/2024 9:00 AM 0.000000 [Good (Raw)] 0.508576 [Good (Raw)] 04/23/2024 9:00 AM -0.415823 [Good (Raw)] -0.589333 [Good (Raw)] 04/23/2024 9:00 AM -0.813473 [Good (Raw)] -0.231007 [Good (Raw)] 04/23/2024 9:00 AM -1.175570 [Good (Raw)] -1.351849 [Good (Raw)] 04/23/2024 9:00 AM -1.486290 [Good (Raw)] -0.901792 [Good (Raw)] 04/23/2024 9:00 AM -1.732051 [Good (Raw)] -0.128899 [Good (Raw)]
Obtain a summary of the data retrieved.
summary(histData)
1-by-2 OPC UA Data object: Name Value Start Timestamp End Timestamp Quality -------- ---------------- ------------------- ------------------- ----------------------------- Sinusoid 11 double values 04/23/2024 9:00 AM 04/23/2024 9:00 AM 1 unique quality [Good (Raw)] Random 11 double values 04/23/2024 9:00 AM 04/23/2024 9:00 AM 1 unique quality [Good (Raw)]
Step 6: Plot the Data
You can plot the data directly from the resulting opc.ua.Data
object.
plot(histData)
legend show
You can also convert the data into MATLAB® native data types for further processing. For information on processing data, see Visualize and Preprocess OPC UA Data.
Step 7: Clean Up
When you have finished exchanging data with the OPC server, you should disconnect from the server.
disconnect(uaClient)
You can then clear the OPC UA variables from MATLAB memory. If you clear an OPC UA client from memory, the connection to the server is automatically closed.