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>
This commit is contained in:
Joseph Doherty
2026-04-06 16:38:00 -04:00
parent 5c89a44255
commit 41f0e9ec4c
35 changed files with 1858 additions and 536 deletions

View File

@@ -199,6 +199,89 @@ writeconfig write → denied (WriteConfigure doesn't match Operate)
admin write → allowed (has all write roles)
```
## Historian SDK Migration
Updated: `2026-04-06`
Both instances updated to use the Wonderware Historian SDK (`aahClientManaged.dll`) instead of direct SQL queries for historical data access.
Code changes:
- `HistorianDataSource` rewritten from `SqlConnection`/`SqlDataReader` to `ArchestrA.HistorianAccess` SDK
- Persistent connection with lazy connect and auto-reconnect on failure
- `HistorianConfiguration.ConnectionString` replaced with `ServerName`, `IntegratedSecurity`, `UserName`, `Password`, `Port`
- `HistorianDataSource` now implements `IDisposable`, disposed on service shutdown
- `ConfigurationValidator` validates Historian SDK settings at startup
SDK DLLs deployed to both instances:
- `aahClientManaged.dll` (primary SDK, v2.0.0.0)
- `aahClient.dll`, `aahClientCommon.dll` (dependencies)
- `Historian.CBE.dll`, `Historian.DPAPI.dll`, `ArchestrA.CloudHistorian.Contract.dll`
Configuration changes (both instances):
- `Historian.ConnectionString` removed
- `Historian.ServerName`: `"localhost"`
- `Historian.IntegratedSecurity`: `true`
- `Historian.Port`: `32568`
- `Historian.Enabled`: `true` (unchanged)
Verification (instance1 startup log):
```
Historian.Enabled=true, ServerName=localhost, IntegratedSecurity=true, Port=32568
Historian.CommandTimeoutSeconds=30, MaxValuesPerRead=10000
=== Configuration Valid ===
LmxOpcUa service started successfully
```
## HistoryServerCapabilities and Continuation Points
Updated: `2026-04-06`
Both instances updated with OPC UA Part 11 spec compliance improvements.
Code changes:
- `HistoryServerCapabilities` node populated under `ServerCapabilities` with all boolean capability properties
- `AggregateFunctions` folder populated with references to 7 supported aggregate functions
- `HistoryContinuationPointManager` added — stores remaining data when results exceed `NumValuesPerNode`
- `HistoryReadRawModified` and `HistoryReadProcessed` now return `ContinuationPoint` in `HistoryReadResult` for partial reads
- Follow-up requests with `ContinuationPoint` resume from stored state; invalid/expired points return `BadContinuationPointInvalid`
No configuration changes required.
Verification (instance1 startup log):
```
HistoryServerCapabilities configured with 7 aggregate functions
LmxOpcUa service started successfully
```
## Remaining Historian Gaps Fix
Updated: `2026-04-06`
Both instances updated with remaining OPC UA Part 11 spec compliance fixes.
Code changes:
- **Gap 4**: `HistoryReadRawModified` returns `BadHistoryOperationUnsupported` when `IsReadModified=true`
- **Gap 5**: `HistoryReadAtTime` override added with `ReadAtTimeAsync` using SDK `HistorianRetrievalMode.Interpolated`
- **Gap 8**: `HistoricalDataConfigurationState` child nodes added to historized variables (`Stepped=false`, `Definition="Wonderware Historian"`)
- **Gap 10**: `ReturnBounds` parameter handled — boundary `DataValue` entries with `BadBoundNotFound` inserted at StartTime/EndTime
- **Gap 11**: `StandardDeviation` aggregate added to client enum, mapper, CLI (aliases: `stddev`/`stdev`), and UI dropdown
No configuration changes required.
## Historical Event Access
Updated: `2026-04-06`
Both instances updated with OPC UA historical event access (Gap 7).
Code changes:
- `HistorianDataSource.ReadEventsAsync` queries Historian event store via separate `HistorianConnectionType.Event` connection
- `LmxNodeManager.HistoryReadEvents` override maps `HistorianEvent` records to OPC UA `HistoryEventFieldList` entries
- `AccessHistoryEventsCapability` set to `true` when `AlarmTrackingEnabled` is true
- Event fields: EventId, EventType, SourceNode, SourceName, Time, ReceiveTime, Message, Severity
No configuration changes required. All historian gaps (1-11) are now resolved.
## Notes
The service deployment and restart succeeded. The live CLI checks confirm the endpoint is reachable and that the array node identifier has changed to the bracketless form. The array value on the live service still prints as blank even though the status is good, so if this environment should have populated `MoveInPartNumbers`, the runtime data path still needs follow-up investigation.