Files
lmxopcua/docs/drivers/Historian.Wonderware.md

6.0 KiB

Wonderware Historian Backend

The Wonderware Historian backend is not a tag driver — it has no address space, no IDriver lifecycle, and exposes no PLC. It is a server-side historian sink: an optional sidecar that gives OtOpcUa read access to AVEVA System Platform (Wonderware) Historian history and a write-back path for alarm events. It runs only when Historian:Wonderware:Enabled=true.

For the sidecar's place in a deployment, see ServiceHosting.md. For the alarm-history store-and-forward flow that drains into it, see AlarmHistorian.md.

Architecture

        +-------------------------------------------+
        |  OtOpcUa Host (.NET 10 AnyCPU)            |
        |    Server.History.IHistoryRouter  --read--+--+
        |    Core.AlarmHistorian.SqliteStore       |  |
        |      AndForwardSink            --write----+--+
        |    WonderwareHistorianClient (.NET 10)    |  |
        +-------------------------------------------+  |
                                                       | named pipe
                                  MessagePack frames   | (shared secret + allowed-SID)
                                                       v
        +-------------------------------------------+
        |  OtOpcUaWonderwareHistorian (sidecar)    |
        |    net48 / x64                            |
        |    PipeServer + HistorianFrameHandler     |
        |    HistorianDataSource    (reads)         |
        |    SdkAlarmHistorianWriteBackend (writes) |
        |    aahClientManaged / HistorianAccess     |
        +-------------------------------------------+

The split exists because the AVEVA Historian SDK (aahClientManaged + native aahClient.dll) is .NET Framework 4.8 / x64 — so it lives out-of-process in the sidecar, and everything in the OtOpcUa host stays .NET 10 AnyCPU. The host never references the SDK; it speaks the pipe contract only.

Project split

Project Target Role
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware/ net48 / x64 The sidecar (OutputType=Exe). Hosts the named-pipe server, the historian reader, and the alarm-write backend bound to the AVEVA SDK
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client/ net10.0 WonderwareHistorianClient — the in-host pipe client consumed by the history router and the alarm sink
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client.Contracts/ net10.0 WonderwareHistorianClientOptions (pipe name, shared secret, timeouts)

The csproj targets net48 / x64 (PlatformTarget=x64) — the AVEVA Historian 2020 SDK ships an x64 aahClientManaged build; the earlier x86 default was an inherited v1 artifact, not a constraint of the Historian SDK.

What it does

The sidecar exposes two surfaces, both over the same named pipe:

Read path — IHistorianDataSource

HistorianDataSource (in the sidecar) reads history through the aahClientManaged SDK; WonderwareHistorianClient (in the host) implements IHistorianDataSource and maps returned samples back to OPC UA DataValues for Server.History.IHistoryRouter. The read surface is:

Call Maps to
ReadRawAsync Raw historical samples for a tag over a time range
ReadProcessedAsync / ReadAggregateAsync Aggregated samples at an interval
ReadAtTimeAsync Samples at specific timestamps
ReadEventsAsync Historical events for a source
GetHealthSnapshot Connection health for the host-side health surface

Write path — alarm-historian write-back

WonderwareHistorianClient also implements IAlarmHistorianWriter. Alarm events are drained into the sidecar from Core.AlarmHistorian.SqliteStoreAndForwardSink and persisted by SdkAlarmHistorianWriteBackend via HistorianAccess.AddStreamedValue(HistorianEvent, out HistorianAccessError). The production writer is wrapped by AahClientManagedAlarmEventWriter, which handles batch orchestration and per-event HistorianAccessError outcome classification (connection-class errors are retryable; malformed-argument errors are not).

The alarm write path can be disabled independently of reads by setting OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED=false — the sidecar then rejects WriteAlarmEvents frames while still serving history reads.

Hosting and IPC

  • Process: OtOpcUaWonderwareHistorian, installed/managed by scripts/install/ (Install-Services.ps1 -InstallWonderwareHistorian).
  • Spawn config: the supervisor passes the pipe name, the allowed server principal SID, and a per-process shared secret via environment (OTOPCUA_HISTORIAN_PIPE, OTOPCUA_ALLOWED_SID, OTOPCUA_HISTORIAN_SECRET); Historian connection settings come from OTOPCUA_HISTORIAN_SERVER / _PORT / _INTEGRATED / _USER / _PASS etc. (see src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware/Program.cs).
  • Pipe-only mode: with OTOPCUA_HISTORIAN_ENABLED!=true the sidecar boots without loading the SDK at all — used for smoke and IPC tests.
  • Wire: MessagePack-framed request/reply; the named-pipe ACL restricts the pipe to the allowed SID and the client proves the shared secret in a Hello frame. The client owns a single channel with one in-flight call at a time and retries a transport failure once before propagating — broader backoff is the caller's responsibility.

Testing

  • Sidecar unit teststests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Tests/ cover the reader, the alarm-write backend outcome classification, and the pipe-frame handler with a faked SDK seam.
  • Client unit teststests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client.Tests/ cover the pipe client + framing against an in-process duplex pipe pair.

Further reading

  • ServiceHosting.md — where the sidecar fits in a deployment and how it's installed
  • AlarmHistorian.md — the alarm store-and-forward flow that feeds the write-back path