Files
lmxopcua/historiangaps.md
Joseph Doherty 41f0e9ec4c Migrate historian from SQL to aahClientManaged SDK and resolve all OPC UA Part 11 gaps
Replace direct SQL queries against Historian Runtime database with the Wonderware
Historian managed SDK (ArchestrA.HistorianAccess). Add HistoryServerCapabilities node,
AggregateFunctions folder, continuation points, ReadAtTime interpolation, ReturnBounds,
ReadModified rejection, HistoricalDataConfiguration per node, historical event access,
and client-side StandardDeviation aggregate support. Remove screenshot tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:38:00 -04:00

10 KiB

Historian Implementation Gap Analysis

Comparison of the current LmxOpcUa server historian implementation against the OPC UA Part 11 Historical Access specification requirements.

Current Implementation Summary

Feature Status
HistoryRead — ReadRawModifiedDetails Implemented (raw only, no modified)
HistoryRead — ReadProcessedDetails Implemented (7 aggregates)
Historizing attribute on nodes Implemented
AccessLevel.HistoryRead on nodes Implemented
Quality mapping (OPC DA → OPC UA) Implemented
Historian SDK (aahClientManaged) Implemented (replaced direct SQL)
Configurable enable/disable Implemented
SDK packet timeout Implemented
Max values per read Implemented
HistoryServerCapabilities node Implemented
AggregateFunctions folder Implemented (7 functions)
Continuation points for history reads Implemented

Gaps

1. HistoryServerCapabilities Node (Required) — RESOLVED

Spec requirement: All OPC UA servers supporting Historical Access SHALL include a HistoryServerCapabilities object under ServerCapabilities. This is mandatory, not optional.

Current state: Implemented. The server populates all HistoryServerCapabilities variables at startup via LmxOpcUaServer.ConfigureHistoryCapabilities(). All boolean capabilities are set, and MaxReturnDataValues reflects the configured limit.

Required variables:

Variable Expected Value Priority
AccessHistoryDataCapability true High
AccessHistoryEventsCapability false High
MaxReturnDataValues configurable (e.g., 10000) High
MaxReturnEventValues 0 Medium
InsertDataCapability false Medium
ReplaceDataCapability false Medium
UpdateDataCapability false Medium
DeleteRawCapability false Medium
DeleteAtTimeCapability false Medium
InsertAnnotationCapability false Low
InsertEventCapability false Low
ReplaceEventCapability false Low
UpdateEventCapability false Low
DeleteEventCapability false Low
ServerTimestampSupported true Medium

Files to modify: LmxOpcUaServer.cs or LmxNodeManager.cs — create and populate the HistoryServerCapabilities node in the server's address space during startup.

2. AggregateFunctions Folder (Required) — RESOLVED

Spec requirement: The HistoryServerCapabilities object SHALL contain an AggregateFunctions folder listing all supported aggregate functions as child nodes. Clients browse this folder to discover available aggregates.

Current state: Implemented. The AggregateFunctions folder under HistoryServerCapabilities is populated with references to all 7 supported aggregate function ObjectIds at startup.

Required: Create AggregateFunctions folder under HistoryServerCapabilities with references to the 7 supported aggregate ObjectIds:

  • AggregateFunction_Average
  • AggregateFunction_Minimum
  • AggregateFunction_Maximum
  • AggregateFunction_Count
  • AggregateFunction_Start
  • AggregateFunction_End
  • AggregateFunction_StandardDeviationPopulation

Priority: Medium

3. Continuation Points for History Reads (Required) — RESOLVED

Spec requirement: When a HistoryRead result exceeds MaxReturnDataValues or the client's NumValuesPerNode, the server SHALL return a ContinuationPoint in the result. The client then issues follow-up HistoryRead calls with the continuation point to retrieve remaining data. The server must maintain state for active continuation points and release them when complete or on timeout.

Current state: Implemented. HistoryContinuationPointManager stores remaining data keyed by GUID. Both HistoryReadRawModified and HistoryReadProcessed return a ContinuationPoint when results exceed NumValuesPerNode. Follow-up requests with the continuation point resume from stored state. Points expire after 5 minutes. Invalid or expired points return BadContinuationPointInvalid.

Priority: High (resolved)

4. ReadModified Support — RESOLVED

Spec requirement: ReadRawModifiedDetails has an IsReadModified flag. When true, the server should return the original value before modification along with the modification info (who modified, when, what the original value was). This is part of audit trail / data integrity use cases.

Current state: Implemented. HistoryReadRawModified checks details.IsReadModified and returns BadHistoryOperationUnsupported when true, since the Wonderware Historian does not expose modification history.

5. ReadAtTimeDetails — RESOLVED

Spec requirement: ReadAtTimeDetails allows a client to request interpolated values at specific timestamps (not raw samples). The server interpolates between the two nearest raw values for each requested timestamp.

Current state: Implemented. LmxNodeManager overrides HistoryReadAtTime. HistorianDataSource.ReadAtTimeAsync uses the Historian SDK with HistorianRetrievalMode.Interpolated to query interpolated values at each requested timestamp.

6. HistoryUpdate Service (Insert/Replace/Delete) — RESOLVED (N/A)

Spec requirement: The HistoryUpdate service allows clients to insert new values, replace existing values, update (insert or replace), and delete historical data. Each capability is separately advertised via the HistoryServerCapabilities node.

Current state: Not applicable. The Historian is read-only. All write capability booleans (InsertDataCapability, ReplaceDataCapability, UpdateDataCapability, DeleteRawCapability, DeleteAtTimeCapability) are explicitly set to false in ConfigureHistoryCapabilities(). No HistoryUpdate override exists, which is correct.

7. HistoryReadEventDetails (Historical Events) — RESOLVED

Spec requirement: Servers supporting historical event access implement HistoryReadEventDetails to retrieve past event notifications (e.g., alarm history).

Current state: Implemented. LmxNodeManager overrides HistoryReadEvents. HistorianDataSource.ReadEventsAsync uses the Historian SDK with a separate HistorianConnectionType.Event connection and EventQuery to retrieve historical alarm/event records. Events are mapped to OPC UA HistoryEventFieldList entries with standard fields (EventId, EventType, SourceNode, SourceName, Time, ReceiveTime, Message, Severity). AccessHistoryEventsCapability is set to true when alarm tracking is enabled.

8. HistoricalDataConfiguration Node — RESOLVED

Spec requirement: Each historized node SHOULD have a HistoricalDataConfiguration child object with properties describing how its history is stored: Stepped (interpolation type), MinTimeInterval, MaxTimeInterval, ExceptionDeviation, etc.

Current state: Implemented. Historized variables receive a HistoricalDataConfigurationState child node with Stepped = false and Definition = "Wonderware Historian". Recording parameters (intervals, deadbands) are not available from the Galaxy DB, so default values are used.

9. AggregateConfiguration — RESOLVED (N/A)

Spec requirement: The AggregateConfiguration object (child of HistoricalDataConfiguration or HistoryServerCapabilities) defines default aggregate behavior: TreatUncertainAsBad, PercentDataBad, PercentDataGood, UseSlopedExtrapolation.

Current state: Not applicable. The server delegates aggregation entirely to the Wonderware Historian's pre-computed summary tables, so these parameters are not actionable. Aggregate discovery is fully supported via the AggregateFunctions folder.

10. ReturnBounds Parameter — RESOLVED

Spec requirement: When ReturnBounds=true in ReadRawModifiedDetails, the server should return bounding values at the start and end of the requested time range, even if no raw samples exist at those exact times.

Current state: Implemented. When ReturnBounds is true, AddBoundingValues inserts boundary DataValue entries at StartTime and EndTime with StatusCodes.BadBoundNotFound if no sample exists at those exact times.

11. Client-Side: StandardDeviation Aggregate — RESOLVED

Current state: Implemented. AggregateType.StandardDeviation added to enum, AggregateTypeMapper, CLI parser (aliases: stddev, stdev), and UI dropdown. Full end-to-end support from client to server for the AggregateFunction_StandardDeviationPopulation aggregate.

Priority Gap Effort
High HistoryServerCapabilities node RESOLVED
High Continuation points for history reads RESOLVED
Medium AggregateFunctions folder RESOLVED
Medium ReadAtTimeDetails (interpolation) RESOLVED
Medium Advertise all capabilities as true/false RESOLVED
Low Return BadHistoryOperationUnsupported for ReadModified RESOLVED
Low HistoricalDataConfiguration per node RESOLVED
Low Client StdDev aggregate support RESOLVED
Low HistoryUpdate (write/delete) RESOLVED (N/A)
Low Historical event access RESOLVED
Low AggregateConfiguration RESOLVED (N/A)
Low ReturnBounds RESOLVED

References