Read Historical OPC UA Server Data

This example shows you how to read historical data from an OPC UA server. Specifically, this example reads data from a Prosys OPC UA Simulation Server.

To run this example in your MATLAB session, you will need to install the Prosys OPC UA Simulation Server. Read the Getting Started section of the OPC Toolbox documentation for further information.

Create a Client and Connect to the Server

You create client objects using the results of a query to the Local Discovery Service using opcuaserverinfo, or directly using the host name and port number of the server you are connecting to. In this case, connect directly to the OPC UA server on port 53530.

uaClient = opcua('localhost',53530);
connect(uaClient);
uaClient.Status
ans =

    'Connected'

Define Nodes to Read Historical Data

The Prosys OPC UA Simulation Server provides simulated signals for nodes in the "Simulation" branch. By default the Simulation Server updates the values each second. Define these nodes using the opcuanode function.

simNodeIds = {'Random1';
                 'Triangle1';
                 'Sinusoid1'};
simNodes = opcuanode(5,simNodeIds,uaClient)
simNodes = 

1x3 OPC UA Node array:
    index    Name     NsInd  Identifier  NodeType  Children
    -----  ---------  -----  ----------  --------  --------
      1    Random1    5      Random1     Variable  0
      2    Triangle1  5      Triangle1   Variable  0
      3    Sinusoid1  5      Sinusoid1   Variable  0

Read Historical Data from Nodes

Use the readHistory function to read the history of a node. You must pass a time range in which to read historical data. For the Prosys server, read the most recent 30 seconds of data.

dataSample = readHistory(uaClient,simNodes,datetime('now')-seconds(30),datetime('now'))
dataSample = 

1-by-3 OPC UA Data object array:

           Timestamp                  Random1                    Triangle1                   Sinusoid1           
    -----------------------  --------------------------  --------------------------  --------------------------  
    2019-03-04 03:27:53.000        0.049124 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:27:54.000        0.603238 [Good (Raw)]       -1.600000 [Good (Raw)]       -1.902113 [Good (Raw)]  
    2019-03-04 03:27:55.000        0.490724 [Good (Raw)]       -1.333333 [Good (Raw)]       -1.732051 [Good (Raw)]  
    2019-03-04 03:27:56.000        0.765201 [Good (Raw)]       -1.066667 [Good (Raw)]       -1.486290 [Good (Raw)]  
    2019-03-04 03:27:57.000        0.675620 [Good (Raw)]       -0.800000 [Good (Raw)]       -1.175571 [Good (Raw)]  
    2019-03-04 03:27:58.000        0.955830 [Good (Raw)]       -0.533333 [Good (Raw)]       -0.813473 [Good (Raw)]  
    2019-03-04 03:27:59.000        0.866249 [Good (Raw)]       -0.266667 [Good (Raw)]       -0.415823 [Good (Raw)]  
    2019-03-04 03:28:00.000        0.140726 [Good (Raw)]       -0.000000 [Good (Raw)]       -0.000000 [Good (Raw)]  
    2019-03-04 03:28:01.000        0.028212 [Good (Raw)]        0.266667 [Good (Raw)]        0.415823 [Good (Raw)]  
    2019-03-04 03:28:02.000        0.840722 [Good (Raw)]        0.533333 [Good (Raw)]        0.813473 [Good (Raw)]  
    2019-03-04 03:28:03.000        0.751141 [Good (Raw)]        0.800000 [Good (Raw)]        1.175570 [Good (Raw)]  
    2019-03-04 03:28:04.000        0.025618 [Good (Raw)]        1.066667 [Good (Raw)]        1.486290 [Good (Raw)]  
    2019-03-04 03:28:05.000        0.936036 [Good (Raw)]        1.333333 [Good (Raw)]        1.732051 [Good (Raw)]  
    2019-03-04 03:28:06.000        0.285045 [Good (Raw)]        1.600000 [Good (Raw)]        1.902113 [Good (Raw)]  
    2019-03-04 03:28:07.000        0.195464 [Good (Raw)]        1.866667 [Good (Raw)]        1.989044 [Good (Raw)]  
    2019-03-04 03:28:08.000        0.469941 [Good (Raw)]        1.866667 [Good (Raw)]        1.989044 [Good (Raw)]  
    2019-03-04 03:28:09.000        0.380360 [Good (Raw)]        1.600000 [Good (Raw)]        1.902113 [Good (Raw)]  
    2019-03-04 03:28:10.000        0.192870 [Good (Raw)]        1.333333 [Good (Raw)]        1.732051 [Good (Raw)]  
    2019-03-04 03:28:11.000        0.080355 [Good (Raw)]        1.066667 [Good (Raw)]        1.486290 [Good (Raw)]  
    2019-03-04 03:28:12.000        0.354833 [Good (Raw)]        0.800000 [Good (Raw)]        1.175571 [Good (Raw)]  
    2019-03-04 03:28:13.000        0.265251 [Good (Raw)]        0.533333 [Good (Raw)]        0.813473 [Good (Raw)]  
    2019-03-04 03:28:14.000        0.545462 [Good (Raw)]        0.266667 [Good (Raw)]        0.415823 [Good (Raw)]  
    2019-03-04 03:28:15.000        0.455880 [Good (Raw)]        0.000000 [Good (Raw)]        0.000000 [Good (Raw)]  
    2019-03-04 03:28:16.000        0.730358 [Good (Raw)]       -0.266667 [Good (Raw)]       -0.415823 [Good (Raw)]  
    2019-03-04 03:28:17.000        0.617843 [Good (Raw)]       -0.533333 [Good (Raw)]       -0.813473 [Good (Raw)]  
    2019-03-04 03:28:18.000        0.430353 [Good (Raw)]       -0.800000 [Good (Raw)]       -1.175571 [Good (Raw)]  
    2019-03-04 03:28:19.000        0.340772 [Good (Raw)]       -1.066667 [Good (Raw)]       -1.486290 [Good (Raw)]  
    2019-03-04 03:28:20.000        0.615249 [Good (Raw)]       -1.333333 [Good (Raw)]       -1.732051 [Good (Raw)]  
    2019-03-04 03:28:21.000        0.525668 [Good (Raw)]       -1.600000 [Good (Raw)]       -1.902113 [Good (Raw)]  
    2019-03-04 03:28:22.000        0.782945 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  

Read Historical Data at Specific Times

You can ask the server to retrieve data at specific times. If the server does not have an archived value for that specific time, an interpolated (or extrapolated) value is returned. Use the readAtTime function to retrieve data each minute for the last 10 minutes.

timesToReturn = datetime('now')-minutes(10):minutes(1):datetime('now');
dataRegular = readAtTime(uaClient,simNodes,timesToReturn)
dataRegular = 

1-by-3 OPC UA Data object array:

           Timestamp                  Random1                    Triangle1                   Sinusoid1           
    -----------------------  --------------------------  --------------------------  --------------------------  
    2019-03-04 03:18:22.000        0.580475 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:19:22.000        0.337058 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:20:22.000        0.070707 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:21:22.000        0.359589 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:22:22.000        0.649761 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:23:22.000        0.439925 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:24:22.000        0.705874 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:25:22.000        0.829382 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:26:22.000        0.585964 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:27:22.000        0.682371 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  
    2019-03-04 03:28:22.000        0.782945 [Good (Raw)]       -1.866667 [Good (Raw)]       -1.989044 [Good (Raw)]  

Read Processed Data from the Server

OPC UA Servers provide aggregate functions for returning preprocessed data to clients. This is most useful when you need to query data over a large period of time.

Query the AggregateFunctions property of a connected client to find out what aggregate functions the server supports.

uaClient.AggregateFunctions
ans =

  14×1 cell array

    {'Interpolative'    }
    {'Average'          }
    {'Minimum'          }
    {'Maximum'          }
    {'MinimumActualTime'}
    {'MaximumActualTime'}
    {'Range'            }
    {'Count'            }
    {'Start'            }
    {'End'              }
    {'Delta'            }
    {'WorstQuality'     }
    {'StartBound'       }
    {'EndBound'         }

Read the Average value for each 30 second period over the last 10 minutes.

dataAverage = readProcessed(uaClient,simNodes,'Average',seconds(30),datetime('now')-minutes(10),datetime('now'))
dataAverage = 

1-by-3 OPC UA Data object array:

           Timestamp                      Random1                           Triangle1                          Sinusoid1              
    -----------------------  ---------------------------------  ---------------------------------  ---------------------------------  
    2019-03-04 03:18:22.000        0.503119 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:18:52.000        0.544957 [Good (Calculated)]        0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:19:22.000        0.516937 [Good (Calculated)]        0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:19:52.000        0.554026 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:20:22.000        0.497120 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:20:52.000        0.477275 [Good (Calculated)]        0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:21:22.000        0.548093 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:21:52.000        0.501601 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:22:22.000        0.565680 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:22:52.000        0.489515 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:23:22.000        0.531994 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:23:52.000        0.477180 [Good (Calculated)]       -0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:24:22.000        0.464717 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:24:52.000        0.477862 [Good (Calculated)]       -0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:25:22.000        0.479600 [Good (Calculated)]       -0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:25:52.000        0.494738 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:26:22.000        0.577950 [Good (Calculated)]        0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:26:52.000        0.451383 [Good (Calculated)]        0.000000 [Good (Calculated)]       -0.000000 [Good (Calculated)]  
    2019-03-04 03:27:22.000        0.505575 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  
    2019-03-04 03:27:52.000        0.458428 [Good (Calculated)]        0.000000 [Good (Calculated)]        0.000000 [Good (Calculated)]  

Read the Average value for each half second period over the last 5 seconds. Note how the quality of the data includes Good quality, and Bad quality where there is no data available to perform the calculation.

dataMixedQuality = readProcessed(uaClient,simNodes,'Average',seconds(0.5),datetime('now')-seconds(5),datetime('now'))
dataMixedQuality = 

1-by-3 OPC UA Data object array:

           Timestamp                      Random1                           Triangle1                          Sinusoid1              
    -----------------------  ---------------------------------  ---------------------------------  ---------------------------------  
    2019-03-04 03:28:17.000             NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]   
    2019-03-04 03:28:17.500        0.617843 [Good (Calculated)]       -0.533333 [Good (Calculated)]       -0.813473 [Good (Calculated)]  
    2019-03-04 03:28:18.000             NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]   
    2019-03-04 03:28:18.500        0.430353 [Good (Calculated)]       -0.800000 [Good (Calculated)]       -1.175571 [Good (Calculated)]  
    2019-03-04 03:28:19.000             NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]   
    2019-03-04 03:28:19.500        0.340772 [Good (Calculated)]       -1.066667 [Good (Calculated)]       -1.486290 [Good (Calculated)]  
    2019-03-04 03:28:20.000             NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]   
    2019-03-04 03:28:20.500        0.615249 [Good (Calculated)]       -1.333333 [Good (Calculated)]       -1.732051 [Good (Calculated)]  
    2019-03-04 03:28:21.000             NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]              NaN [Bad:NoData (Raw)]   
    2019-03-04 03:28:21.500        0.525668 [Good (Calculated)]       -1.600000 [Good (Calculated)]       -1.902113 [Good (Calculated)]  

Filter the quality of the data to return only the Good data.

dataGood = filterByQuality(dataMixedQuality,'good')
dataGood = 

1-by-3 OPC UA Data object array:

           Timestamp                      Random1                           Triangle1                          Sinusoid1              
    -----------------------  ---------------------------------  ---------------------------------  ---------------------------------  
    2019-03-04 03:28:17.500        0.617843 [Good (Calculated)]       -0.533333 [Good (Calculated)]       -0.813473 [Good (Calculated)]  
    2019-03-04 03:28:18.500        0.430353 [Good (Calculated)]       -0.800000 [Good (Calculated)]       -1.175571 [Good (Calculated)]  
    2019-03-04 03:28:19.500        0.340772 [Good (Calculated)]       -1.066667 [Good (Calculated)]       -1.486290 [Good (Calculated)]  
    2019-03-04 03:28:20.500        0.615249 [Good (Calculated)]       -1.333333 [Good (Calculated)]       -1.732051 [Good (Calculated)]  
    2019-03-04 03:28:21.500        0.525668 [Good (Calculated)]       -1.600000 [Good (Calculated)]       -1.902113 [Good (Calculated)]  

Disconnect from Server

When you have finished communicating with the server, disconnect the client from the server. This is also automatically performed when the client variable goes out of scope in MATLAB®.

disconnect(uaClient);