This document defines the handling of historical time series data and historical Event data in the OPC Unified Architecture (in a Historian). Included is the specification of the representation of historical data and Events in the AddressSpace.
A Server supporting Historical Access provides Clients with transparent access to different historical data and/or historical Event sources (e.g., process Historians, event Historians, etc.).
The historical data or Events may be in a proprietary data collection, database or a short-term buffer within memory. A Server supporting Historical Access will provide historical data and Events for all or a subset of the available Variables, Objects, Properties or Views within the Server AddressSpace.
Figure 1 illustrates how the AddressSpace of a UA Server might consist of a broad range of different historical data and/or historical Event sources.
Figure 1 – Possible OPC UA Server supporting Historical Access
The Historian may be implemented as a standalone OPC UA Server that collects data from another OPC UA Server or another data source. The Historian may also just aggregate historical data from underlying Historians. The Client that references the OPC UA Server supporting Historical Access for historical data may be simple trending packages that desire values over a given time frame or they may be complex reports that require data in multiple formats.
There are general requirements for Historians, but Historians can vary in functionality. A consistent requirement for all Historians is that they store Historical data including a timestamp. All historical data should include status information for each value, but a Historian may compress this to only storing status information that indicates a problem (Bad status) and/or status change, instead of storing a status for every time series data item. The status of historical data can be complex. What is required is that the values returned as part of the timeseries raw data match the data that would have been observed if the Value was subscribed to at that point in time.
Historical Events are more complicated. In a stream of Events each Event can have a different list of fields. EventTypes are defined in a hierarchical manner, where each EventType inherits fields from its parent type and can add additional fields. Some of these additional fields may be mandatory and are required to understand or process the given EventType. A Historian that stores Events, shall be configurable to store all mandatory fields for any EventTypes that it historizes. If it receives for storage an EventType that it does not support all mandatory fields for, it may store it as one of its supertype EventTypes (one that it does support all mandatory fields for), but then it shall not claim that it supports historizing of that EventType (see 5.4.3). The Historian shall also provide information about the fields that are currently being historized (see 5.4.3).
When an Historian is collecting and storing data, the data collection may be interrupted. The interruption may have been for collecting the current values of data or for an event stream. The interruption may have been due to an interruption in the source of a value or an interruption of the forwarding of historical data from an underlying Historian. The interruption might also have been due to an action that stopped the collection of HistoricalData or historical Events. Some of these interruptions may recover with no loss of data, others may result in data gaps. The Historian shall report any gaps when a client is accessing the stored historical data with an error code of Bad_DataLost.
For example, if a subscription for data breaks, and the historian recovers the subscription after several minutes, it can check the SourceTimestamp of the initial values in the subscription. If the initial value SourceTimestamp matches the last stored value SourceTimestamp, then no data was lost and nothing needs to be stored indicating the given HistoricalDataNode‘s data collection was interrupted. But if the SourceTimestamp of the initial value is later than the SourceTimestamp of the last stored value, then the historian has no way of knowing if any data was lost and it shall record a bad status for the value with the timestamp of when the connection was broken.
For Event collection, in addition to what is described for a data collection the following also has to be addressed. If a Subscription for Event is interrupted for long enough that the Subscription buffer reports an overflow (instance of EventQueueOverflowEventType), then the Event storage shall report this error. This can be accomplished by storing the instance of EventQueueOverflowEventType event or by recording a Bad_DataLost. If the lost data is indicated by EventQueueOverflowEventType, this event shall always be returned for any filter, just as it is in an Event Subscription.
A Historian collects values (data or Events) and provides long term storage of these values. Occasionally data that is collected is incorrect. It may be incorrect for many reasons, such as a failed sensor, or failed communication or even an out of calibration sensor. Sometimes the correct values are obtained from another source and the historical value will need to be updated. In many Historians, the act of updating a historical value needs to be tracked. This specification provides two aspects for tracking:
- Recording the original value and information related to who made the change (see section 6.9 for HistoryUpdateDetails).
- Generating an audit event describing the history edit action (see section 5.8).
Some Historians obtain data from other sources (for example not an OPC UA Subscription). This data may be from lab data analysis package or other off-line activities. This data is typically provided in bulk and with SourceTimestamps that are in the past. For this type of data, even though it may be inserted using an HistoryUpdateDetails service call, the Historian does not have to create a modification record for the initial insertion.
Modification of Events is different than modification of data, in that in a single event stream there may be many Events with the same Timestamp. Events need to be identified by their EventId. The EventId is generated as part of normal Event processing in a Server and is used to correlate actions related to the Event. For example, when an Alarm (which is represented by an Event) is acknowledged, the acknowledgement is related to the specific EventId that represent that event is time. A Historian that historizes Events shall store the EventId that it receives; Modification of Events shall not allow modification to EventIds.
The nature of OPC UA Historical Access requires that a single timestamp reference be used to relate the multiple data points, and the Client may request which timestamp will be used as the reference. See OPC 10000-4 for details on the TimestampsToReturn enumeration. An OPC UA Server supporting Historical Access will treat the various timestamp settings as described below. A HistoryRead with invalid settings will be rejected with Bad_TimestampsToReturnInvalid (see OPC 10000-4).
For HistoricalDataNodes, the SourceTimestamp is used to determine which historical data values are to be returned.
The request is in terms of SourceTimestamp but the reply could be in SourceTimestamp, ServerTimestamp or both timestamps. If the reply has the Server timestamp the timestamps could fall outside of the range of the requested time.
SOURCE Return the SourceTimestamp.
SERVER Return the ServerTimestamp.
BOTH Return both the SourceTimestamp and ServerTimestamp.
NEITHER This is not a valid setting for any HistoryRead accessing HistoricalDataNodes.
Any reference to timestamps in this context throughout this standard will represent either ServerTimestamp or SourceTimestamp as dictated by the type requested in the HistoryRead Service. Some Servers may not support historizing both SourceTimestamp and ServerTimestamp, but it is expected that all Servers will support historizing SourceTimestamp (see OPC 10000-7 for details on Server Profiles).
If a request is made requesting both ServerTimestamp and SourceTimestamp and the Server is only collecting the SourceTimestamp, the Server shall return Bad_TimestampNotSupported. Some Historians may aggregate data from underlying Historians. These Servers might have a mix of data, some with ServerTimestamp some without. The Historian may not know if a HistoricalDataNode supports ServerTimestamps. As a result of this uncertainty, the Bad_TimestampNotSupported may be returned on the service level or at the operation level.
For HistoricalEventNodes this parameter does not apply. This parameter is ignored since the entries returned are dictated by the Event Filter. See OPC 10000-4 for details.
When accessing HistoricalDataNodes via the HistoryRead Service, requests can set a flag, returnBounds, indicating that BoundingValues are requested. For a complete description of the Extensible Parameter HistoryReadDetails that include StartTime, EndTime and NumValuesPerNode, see 6.5. The concept of Bounding Values and how they affect the time domain that is requested as part of the HistoryRead request is further explained in 4.4. 4.4 also provides examples of TimeDomains to further illustrate the expected behaviour.
When making a request for historical data using the HistoryRead Service, the required parameters include at least two of these three parameters: startTime, endTime and numValuesPerNode. What is returned when BoundingValues are requested varies according to which of these parameters are provided. For a Historian that has values stored at 5:00, 5:02, 5:03, 5:05 and 5:06, the data returned when using the Read Raw functionality is given by Table 1. In the table, FIRST stands for a tuple with a value of null, a timestamp of the specified StartTime, and a StatusCode of Bad_BoundNotFound. LAST stands for a tuple with a value of null, a timestamp of the specified EndTime, and a StatusCode of Bad_BoundNotFound.
In some cases, attempting to locate bounds, particularly FIRST or LAST points, may be resource intensive for Servers. Therefore, how far back or forward to look in history for Bounding Values is Server dependent, and the Server search limits may be reached before a bounding value can be found. There are also cases, such as reading Annotations or Attribute data where Bounding Values may not be appropriate. For such use cases it is permissible for the Server to return a StatusCode of Bad_BoundNotSupported.
Table 1 – Bounding Value examples
Start Time |
End Time |
numValuesPerNode |
Bounds |
Data Returned |
5:00 |
5:05 |
0 |
Yes |
5:00, 5:02, 5:03, 5:05 |
5:00 |
5:05 |
0 |
No |
5:00, 5:02, 5:03 |
5:01 |
5:04 |
0 |
Yes |
5:00, 5:02, 5:03, 5:05 |
5:01 |
5:04 |
0 |
No |
5:02, 5:03 |
5:05 |
5:00 |
0 |
Yes |
5:05, 5:03, 5:02, 5:00 |
5:05 |
5:00 |
0 |
No |
5:05, 5:03, 5:02 |
5:04 |
5:01 |
0 |
Yes |
5:05, 5:03, 5:02, 5:00 |
5:04 |
5:01 |
0 |
No |
5:03, 5:02 |
4:59 |
5:05 |
0 |
Yes |
FIRST, 5:00, 5:02, 5:03, 5:05 |
4:59 |
5:05 |
0 |
No |
5:00, 5:02, 5:03 |
5:01 |
5:07 |
0 |
Yes |
5:00, 5:02, 5:03, 5:05, 5:06, LAST |
5:01 |
5:07 |
0 |
No |
5:02, 5:03, 5:05, 5:06 |
5:00 |
5:05 |
3 |
Yes |
5:00, 5:02, 5:03 |
5:00 |
5:05 |
3 |
No |
5:00, 5:02, 5:03 |
5:01 |
5:04 |
3 |
Yes |
5:00, 5:02, 5:03 |
5:01 |
5:04 |
3 |
No |
5:02, 5:03 |
5:05 |
5:00 |
3 |
Yes |
5:05, 5:03, 5:02 |
5:05 |
5:00 |
3 |
No |
5:05, 5:03, 5:02 |
5:04 |
5:01 |
3 |
Yes |
5:05, 5:03, 5:02 |
5:04 |
5:01 |
3 |
No |
5:03, 5:02 |
4:59 |
5:05 |
3 |
Yes |
FIRST, 5:00, 5:02 |
4:59 |
5:05 |
3 |
No |
5:00, 5:02, 5:03 |
5:01 |
5:07 |
3 |
Yes |
5:00, 5:02, 5:03 |
5:01 |
5:07 |
3 |
No |
5:02, 5:03, 5:05 |
5:00 |
UNSPECIFIED |
3 |
Yes |
5:00, 5:02, 5:03 |
5:00 |
UNSPECIFIED |
3 |
No |
5:00, 5:02, 5:03 |
5:00 |
UNSPECIFIED |
6 |
Yes |
5:00, 5:02, 5:03, 5:05, 5:06, LASTa |
5:00 |
UNSPECIFIED |
6 |
No |
5:00, 5:02, 5:03, 5:05, 5:06 |
5:07 |
UNSPECIFIED |
6 |
Yes |
5:06, LAST |
5:07 |
UNSPECIFIED |
6 |
No |
NODATA |
UNSPECIFIED |
5:06 |
3 |
Yes |
5:06,5:05,5:03 |
UNSPECIFIED |
5:06 |
3 |
No |
5:06,5:05,5:03 |
UNSPECIFIED |
5:06 |
6 |
Yes |
5:06,5:05,5:03,5:02,5:00, FIRSTb |
UNSPECIFIED |
5:06 |
6 |
No |
5:06, 5:05, 5:03, 5:02, 5:00 |
UNSPECIFIED |
4:48 |
6 |
Yes |
5:00, FIRST |
UNSPECIFIED |
4:48 |
6 |
No |
NODATA |
4:48 |
4:48 |
0 |
Yes |
FIRST,5:00 |
4:48 |
4:48 |
0 |
No |
NODATA |
4:48 |
4:48 |
1 |
Yes |
FIRST |
4:48 |
4:48 |
1 |
No |
NODATA |
4:48 |
4:48 |
2 |
Yes |
FIRST,5:00 |
5:00 |
5:00 |
0 |
Yes |
5:00,5:02c |
5:00 |
5:00 |
0 |
No |
5:00 |
5:00 |
5:00 |
1 |
Yes |
5:00 |
5:00 |
5:00 |
1 |
No |
5:00 |
5:01 |
5:01 |
0 |
Yes |
5:00, 5:02 |
5:01 |
5:01 |
0 |
No |
NODATA |
5:01 |
5:01 |
1 |
Yes |
5:00 |
5:01 |
5:01 |
1 |
No |
NODATA |
aThe timestamp of LAST cannot be the specified End Time because there is no specified End Time. In this situation the timestamp for LAST will be equal to the previous timestamp returned plus one second. b The timestamp of FIRST cannot be the specified End Time because there is no specified Start Time. In this situation the timestamp for FIRST will be equal to the previous timestamp returned minus one second. c When the Start Time = End Time (there is data at that time), and Bounds is set to True, the start bounds will equal the Start Time and the next data point will be used for the end bounds. |
Clients use the browse Services of the View Service Set to navigate through the AddressSpace to discover the HistoricalNodes and their characteristics. These Services provide the most current information about the AddressSpace. It is possible and probable that the AddressSpace of a Server will change over time (i.e. TypeDefinitions may change; NodeIds may be modified, added or deleted).
Server developers and administrators need to be aware that modifying the AddressSpace may impact a Client’s ability to access historical information. If the history for a HistoricalDataNodes is still required, but the HistoricalDataNodes is no longer historized, then the Object should be maintained in the AddressSpace, with the appropriate AccessLevel Attribute and Historizing Attribute settings (see OPC 10000-3 for details on access levels).
If the HistoricalConfiguration of a HistoricalDataNode in the AddressSpace is changed and audit events are supported, an audit Event of AuditHistoryConfigurationChangeEventType shall be generated.
A Historian shall expose the Historizing attribute on any nodes that are currently collecting historical data. They shall also set the AccessLevel HistoryRead and optionally the HistoryWrite bits for HistoricalNodes (those with Historical data).
If a HistoricalConfiguration Object is added to or deleted from a Server or a Reference to a HistoricalConfiguration Object is added to or deleted from a Node, a GeneralModelChangeEvent shall be generated. If an Annotation Property is added to or deleted from a Node, a GeneralModelChangeEvent shall be generated.