Aggregate function
An aggregate function is a server-side computation over raw historical values, identified by a NodeId in the server's AggregateFunctions folder: Average, TimeAverage, Minimum, Maximum, Count, Total, Delta, StandardDeviation, DurationGood, PercentGood and more. Part 13 defines them, and you request one through HistoryRead with ReadProcessedDetails.
How you ask for one
HistoryRead carries a details structure. ReadRawModifiedDetails returns stored values; ReadProcessedDetails returns aggregates and takes a start time, an end time, a ProcessingInterval and an array of aggregate NodeIds, one per node you are reading. The server divides the span into intervals of the processing interval and returns one computed value per interval, each with its own StatusCode carrying the aggregate's quality information.
Discover what the server supports
Browse Server.ServerCapabilities.AggregateFunctions to get the actual list of supported aggregate NodeIds, and check ServerProfileArray for the Historical Aggregate Server Facet (2022), published as /Server/AggregateHistorical2022. Also read HistoryServerCapabilities, which advertises which read details and which aggregate behaviour the server implements. Asking for an unsupported aggregate returns BadAggregateNotSupported; asking with inconsistent arguments returns BadAggregateInvalidInputs.
Why server-side aggregation is the right default
For shift-level analytics you rarely need every raw sample. Asking the server for TimeAverage, DurationGood, PercentGood, Count and Total over shift windows moves the computation to where the data already sits and cuts the volume on the wire by orders of magnitude. The alternative, streaming raw and aggregating downstream, costs bandwidth, storage and a reimplementation of interval and quality semantics that the specification has already defined precisely.
The quality rules are the hard part
Part 13's real content is not the arithmetic but what happens at interval edges and with bad or missing data: how a value that spans an interval boundary is weighted, when an interval is Uncertain because too little of it was Good, what the bounding values contribute, and how partial intervals at the end of the request are marked. The normative worked examples ship as Schema/AggregateExamples.csv with the nodesets, which is the fastest way to check your understanding against the specification's own numbers.
Example
A processed history read for a shift, conceptually
HistoryRead
HistoryReadDetails = ReadProcessedDetails {
StartTime = 2026-09-07T06:00:00Z
EndTime = 2026-09-07T14:00:00Z
ProcessingInterval= 3600000 (ms - one value per hour)
AggregateType = [ TimeAverage ] (one NodeId per node read)
AggregateConfiguration = { UseServerCapabilitiesDefaults = true }
}
NodesToRead = [ ns=4;s=Line1/Tank3/Temperature ]
TimestampsToReturn = Source
-> 8 DataValues, one per hour, each with its own StatusCode
Discover support first:
Root/Objects/Server/ServerCapabilities/AggregateFunctions/
Root/Objects/Server/ServerCapabilities/HistoryServerCapabilities/
ServerProfileArray contains .../Server/AggregateHistorical2022
Defined in: Part 13 - Aggregate Functions, with the services in Part 11 - Historical Access.
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.