MATLAB Examples

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 the OPC Foundation Quickstart Historical Access Server.

PREREQUISITES:

Contents

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, find the server with a name containing 'Quickstart Historical'.

serverList = opcuaserverinfo('localhost');
historicalServer = findDescription(serverList,'Quickstart Historical');
uaClient = opcua(historicalServer);
connect(uaClient);
uaClient.Status
ans =

Connected

Define Nodes to Read Historical Data

The Quickstart Historical Access Server simulates some historical data for nodes in the namespace. Two sets of data are provided: Sample data, which is a small data set, and Dynamic data, which varies in size depending on when the server was started. Define these nodes using the opcuanode function.

sampleNodeIds = {'1:Quickstarts.HistoricalAccessServer.Data.Sample.Double.txt';
                 '1:Quickstarts.HistoricalAccessServer.Data.Sample.Float.txt';
                 '1:Quickstarts.HistoricalAccessServer.Data.Sample.Int32.txt'};
sampleNodes = opcuanode(2,sampleNodeIds,uaClient)

dynamicNodeIds = strrep(sampleNodeIds,'Sample','Dynamic');
dynamicNodes = opcuanode(2,dynamicNodeIds,uaClient)
sampleNodes = 

1x3 OPC UA Node array:
    index   Name   NsInd                          Identifier                           NodeType  Children
    -----  ------  -----  -----------------------------------------------------------  --------  --------
      1    Double  2      1:Quickstarts.HistoricalAccessServer.Data.Sample.Double.txt  Variable  2
      2    Float   2      1:Quickstarts.HistoricalAccessServer.Data.Sample.Float.txt   Variable  2
      3    Int32   2      1:Quickstarts.HistoricalAccessServer.Data.Sample.Int32.txt   Variable  2


dynamicNodes = 

1x3 OPC UA Node array:
    index   Name   NsInd                           Identifier                           NodeType  Children
    -----  ------  -----  ------------------------------------------------------------  --------  --------
      1    Double  2      1:Quickstarts.HistoricalAccessServer.Data.Dynamic.Double.txt  Variable  2
      2    Float   2      1:Quickstarts.HistoricalAccessServer.Data.Dynamic.Float.txt   Variable  2
      3    Int32   2      1:Quickstarts.HistoricalAccessServer.Data.Dynamic.Int32.txt   Variable  2

(Server-Specific) Discover When the Server Was Launched

The Quickstart Historical Access server creates a simulated archive of data from the beginning of the hour that the server was started to the start time of the server (for the Dynamic nodes). To provide reasonable time ranges over which to retrieve data, query the server for the start time.

All servers must publish a ServerStatus node which includes information on the start time of the server. You can read this value directly from the OPC server, using the getServerStatus function. Calculate the start and end times of the history stored by the server.

serverStatus = getServerStatus(uaClient)
serverStartTime = serverStatus.StartTime;
startHistory = dateshift(serverStartTime,'start','hour')
endHistory = serverStartTime
serverStatus = 

              StartTime: 13-Apr-2016 12:06:15
            CurrentTime: 13-Apr-2016 12:14:15
                  State: 'Running'
              BuildInfo: [1×1 struct]
    SecondsTillShutdown: 0
         ShutdownReason: ''


startHistory = 

   13-Apr-2016 12:00:00


endHistory = 

   13-Apr-2016 12:06:15

Read Historical Data from Nodes

Use the readHistorical function to read the history of a node. You must pass a time range in which to read historical data. For the Quickstart server sample data, read the first 2 minutes of data.

dataSample = readHistory(uaClient,sampleNodes,startHistory,startHistory+minutes(2))
dataSample = 

1-by-3 OPC UA Data object:

     Name        Value            Start Timestamp           End Timestamp            Quality      
    ------  ----------------  -----------------------  -----------------------  ------------------
    Double  9 double values   2016-04-13 12:00:10.000  2016-04-13 12:01:30.000  3 unique qualities
    Float   12 single values  2016-04-13 12:00:02.000  2016-04-13 12:01:30.000  3 unique qualities
    Int32   12 int32 values   2016-04-13 12:00:02.000  2016-04-13 12:01:30.000  3 unique qualities

Read Historical Data at Specific Times

You can ask the servfer 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 5 minutes for two hours.

timesToReturn = startHistory:minutes(5):endHistory;
dataRegular = readAtTime(uaClient,dynamicNodes,timesToReturn)
dataRegular = 

1-by-3 OPC UA Data object array:

           Timestamp                       Double                                Float                                Int32                  
    -----------------------  -----------------------------------  -----------------------------------  ------------------------------------  
    2016-04-13 12:00:00.000        0.000000 [Good (Interpolated)]        0.000000 [Good (Interpolated)]               10 [Good (Interpolated)]  
    2016-04-13 12:05:00.000       30.000000 [Good (Raw)]                30.000000 [Good (Raw)]                        30 [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 = 

    'Interpolative'
    'Average'
    'TimeAverage'
    'Total'
    'Minimum'
    'Maximum'
    'MinimumActualTime'
    'MaximumActualTime'
    'Range'
    'AnnotationCount'
    'Count'
    'NumberOfTransitions'
    'Start'
    'End'
    'Delta'
    'DurationGood'
    'DurationBad'
    'PercentGood'
    'PercentBad'
    'WorstQuality'
    'TimeAverage2'
    'Minimum2'
    'Maximum2'
    'Range2'
    'WorstQuality2'
    'Total2'
    'MinimumActualTime2'
    'MaximumActualTime2'
    'DurationInStateZero'
    'DurationInStateNonZero'
    'StandardDeviationSample'
    'StandardDeviationPopulation'
    'VarianceSample'
    'VariancePopulation'
    'StartBound'
    'EndBound'
    'DeltaBounds'

Read the Average value for each 10 second period over 2 minutes. Note how the quality of the data includes Good quality, Bad quality (where there is no data available to perform the calculation), and Uncertain quality (where insufficient data is available to classify it as Good).

dataAverage = readProcessed(uaClient,dynamicNodes,'Average',seconds(10),startHistory,startHistory+minutes(2))
dataAverage = 

1-by-3 OPC UA Data object array:

           Timestamp                                Double                                                Float                                                 Int32                          
    -----------------------  ----------------------------------------------------  ----------------------------------------------------  ----------------------------------------------------  
    2016-04-13 12:00:00.000             NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                      
    2016-04-13 12:00:10.000       10.000000 [Good (Calculated)]                          10.000000 [Good (Calculated)]                          10.000000 [Good (Calculated)]                     
    2016-04-13 12:00:20.000       20.000000 [Good (Calculated)]                          20.000000 [Good (Calculated)]                          20.000000 [Good (Calculated)]                     
    2016-04-13 12:00:30.000       30.000000 [Good (Calculated)]                          30.000000 [Good (Calculated)]                          30.000000 [Good (Calculated)]                     
    2016-04-13 12:00:40.000             NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                      
    2016-04-13 12:00:50.000       50.000000 [Good (Calculated)]                          50.000000 [Good (Calculated)]                          50.000000 [Good (Calculated)]                     
    2016-04-13 12:01:00.000       60.000000 [Good (Calculated)]                          60.000000 [Good (Calculated)]                          60.000000 [Good (Calculated)]                     
    2016-04-13 12:01:10.000             NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                                 NaN [Bad:NoData (Raw)]                      
    2016-04-13 12:01:20.000       80.000000 [Good (Calculated)]                          80.000000 [Good (Calculated)]                          80.000000 [Good (Calculated)]                     
    2016-04-13 12:01:30.000       53.750000 [Uncertain:DataSubnormal (Calculated)]       53.750000 [Uncertain:DataSubnormal (Calculated)]       53.750000 [Uncertain:DataSubnormal (Calculated)]  
    2016-04-13 12:01:40.000       43.750000 [Uncertain:DataSubnormal (Calculated)]       43.750000 [Uncertain:DataSubnormal (Calculated)]       43.750000 [Uncertain:DataSubnormal (Calculated)]  
    2016-04-13 12:01:50.000       45.000000 [Uncertain:DataSubnormal (Calculated)]       45.000000 [Uncertain:DataSubnormal (Calculated)]       45.000000 [Uncertain:DataSubnormal (Calculated)]  

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

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

1-by-3 OPC UA Data object array:

           Timestamp                      Double                              Float                              Int32                
    -----------------------  ---------------------------------  ---------------------------------  ---------------------------------  
    2016-04-13 12:00:10.000       10.000000 [Good (Calculated)]       10.000000 [Good (Calculated)]       10.000000 [Good (Calculated)]  
    2016-04-13 12:00:20.000       20.000000 [Good (Calculated)]       20.000000 [Good (Calculated)]       20.000000 [Good (Calculated)]  
    2016-04-13 12:00:30.000       30.000000 [Good (Calculated)]       30.000000 [Good (Calculated)]       30.000000 [Good (Calculated)]  
    2016-04-13 12:00:50.000       50.000000 [Good (Calculated)]       50.000000 [Good (Calculated)]       50.000000 [Good (Calculated)]  
    2016-04-13 12:01:00.000       60.000000 [Good (Calculated)]       60.000000 [Good (Calculated)]       60.000000 [Good (Calculated)]  
    2016-04-13 12:01:20.000       80.000000 [Good (Calculated)]       80.000000 [Good (Calculated)]       80.000000 [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);