Sixteenth PR of the alarms-over-gateway epic (docs/plans/alarms-over-gateway.md). Closes the documentation sweep the plan calls for. - docs/AlarmTracking.md — promoted top-level v2-final architecture doc (was a worktree-only draft pre-epic). Covers the three alarm sources (Galaxy MxAccess driver-native / Galaxy sub-attribute fallback / scripted alarms), how they converge on AlarmConditionService, the Acknowledge routing decision in DriverNodeManager (driver-native preferred over IWritable sub-attribute fallback), the sidecar historian write-back path for non-Galaxy producers, and cross-references to the plan + v1 archive. - docs/v1/AlarmTracking.md — banner pointing readers at the v2 doc; preserved as historical record. - docs/drivers/Galaxy.md — capability list updated to include IAlarmSource (now eight capabilities, restored by B.2). Replaced the "IAlarmSource retired in 7.2" sentence with the restoration note + cross-link to docs/AlarmTracking.md. - docs/plans/alarms-over-gateway.md — completion banner at the top of the plan, marking 14 of 16 PRs shipped 2026-04-30 and noting that A.2 + A.4 + D.1 are the hardware-gated follow-up. Memory entries updated separately: - project_alarms_over_gateway_epic.md (new) — epic summary + per-PR digest. - project_galaxy_via_mxgateway.md — added "Alarms restored" bullet pointing at the new architecture. - project_server_history_alarm_subsystems.md — bullet 2 updated to describe the new ack-routing decision (B.3) + bullet 3 added describing the historian write-back path that B.4 + C.1 + C.2 light up. - MEMORY.md index — new pointer entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.7 KiB
Galaxy Driver
The Galaxy driver bridges OtOpcUa to AVEVA System Platform (Wonderware) Galaxies. It is a Tier-A in-process driver that runs in the OtOpcUa server's .NET 10 AnyCPU process and speaks gRPC to a separately installed mxaccessgw server (sibling repo at c:\Users\dohertj2\Desktop\mxaccessgw\). The gateway owns the MXAccess COM apartment, the STA + Win32 message pump, the Galaxy Repository SQL reader, and the Historian SDK — all the bits that need x86 / .NET Framework 4.8 / COM interop. The driver itself is platform-agnostic and contains no COM, no STA thread, and no x86 bitness constraint.
For the driver spec (capability surface, config shape, addressing), see docs/v2/driver-specs.md §1. For the gateway setup recipe, see docs/v2/Galaxy.ParityRig.md. For tracing, metrics, and soak profile, see docs/v2/Galaxy.Performance.md.
Note
: the related drivers
Galaxy-Repository.mdandGalaxy-Test-Fixture.mddescribe the previous v1 / out-of-process topology and are being moved todocs/v1/by a parallel cleanup track. UseGalaxy.ParityRig.mdand themxaccessgwrepo for current testing.
Architecture
+---------------------------------------+
| OtOpcUa.Server (.NET 10 AnyCPU) |
| GalaxyDriver (in-process) |
| ITagDiscovery / IReadable / |
| IWritable / ISubscribable / |
| IRediscoverable / |
| IHostConnectivityProbe / |
| IAlarmSource |
+-------------------+-------------------+
|
gRPC (default http://localhost:5120)
|
v
+---------------------------------------+
| mxaccessgw (sibling repo) |
| +-------------------------------+ |
| | MxGateway.Worker (x86 net48) | |
| | STA + WM_APP pump | |
| | ArchestrA.MxAccess COM | |
| | Galaxy Repository SQL | |
| | Wonderware Historian SDK | |
| +-------------------------------+ |
+---------------------------------------+
History reads moved server-side in PR 7.2 (IHistoryRouter). Galaxy no longer implements IHistoryProvider of its own.
IAlarmSource was retired with PR 7.2 and restored in PR B.2 of the
alarms-over-gateway epic (docs/plans/alarms-over-gateway.md).
Alarm transitions arrive on the same gateway StreamEvents channel as
data-change events under the new MX_EVENT_FAMILY_ON_ALARM_TRANSITION
family; acknowledgements route through the gateway's
AcknowledgeAlarm RPC. The previous value-driven sub-attribute path
remains as a fallback for Galaxy templates without $Alarm*
extensions — the server-side AlarmConditionService dedups when both
paths fire on the same condition. See docs/AlarmTracking.md
for the v2-final architecture.
Project Layout
The driver ships as a single project: src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/ (.NET 10, AnyCPU). Sub-folders:
| Folder | Role |
|---|---|
Browse/ |
Static-side discovery: GalaxyDiscoverer walks the gateway's hierarchy + attribute-set RPCs, DataTypeMap and SecurityMap translate Galaxy types and security classifications into OPC UA equivalents, AlarmRefBuilder extracts alarm-bearing attribute references for the server-layer alarm engine. IGalaxyHierarchySource + GatewayGalaxyHierarchySource + TracedGalaxyHierarchySource decorate the gateway browse RPC; IGalaxyDeployWatchSource + GatewayGalaxyDeployWatchSource + DeployWatcher drive IRediscoverable. |
Runtime/ |
Live data path: EventPump runs the gateway's StreamEvents RPC and fans out to subscribers via a bounded channel; GalaxyMxSession is the read-side handle; GatewayGalaxySubscriber + GatewayGalaxyDataWriter (each with a Traced* decorator) implement ISubscribable / IWritable; SubscriptionRegistry tracks subscription state for replay; ReconnectSupervisor owns the backoff loop and triggers ReplaySubscriptions on session loss; StatusCodeMap translates gateway StatusCodes to OPC UA; MxValueDecoder / MxValueEncoder handle scalar + array marshalling; GalaxyTelemetry + GalaxySubscriptionHandle round out the surface. |
Health/ |
HostStatusAggregator rolls per-platform probe state into the driver's IHostConnectivityProbe view; PerPlatformProbeWatcher listens on the gateway's per-host status stream; HostConnectivityForwarder pushes transitions out to the server's connectivity bus. |
Config/ |
GalaxyDriverOptions and the four nested option records (GalaxyGatewayOptions, GalaxyMxAccessOptions, GalaxyRepositoryOptions, GalaxyReconnectOptions). |
Project root files:
GalaxyDriver.cs—IDriver+ capability-interface implementation; composes the Browse / Runtime / Health collaborators.GalaxyDriverFactoryExtensions.cs— DI registration helper used by the server's driver bootstrap.
Capability Surface
GalaxyDriver : IDriver, ITagDiscovery, IReadable, IWritable, ISubscribable, IRediscoverable, IHostConnectivityProbe, IDisposable.
| Capability | Implementation entry point |
|---|---|
ITagDiscovery |
Browse/GalaxyDiscoverer.cs |
IRediscoverable |
Browse/DeployWatcher.cs |
IReadable |
Runtime/GalaxyMxSession.cs |
IWritable |
Runtime/GatewayGalaxyDataWriter.cs |
ISubscribable |
Runtime/GatewayGalaxySubscriber.cs (driven by EventPump) |
IHostConnectivityProbe |
Health/HostStatusAggregator.cs |
Configuration
DriverConfig JSON binds to Config/GalaxyDriverOptions.cs. The four sections are:
Gateway— endpoint, API key secret ref, TLS knobs, connect/call/stream timeouts.StreamTimeoutSeconds = 0keeps the long-livedStreamEventsRPC open for the driver's lifetime.MxAccess—ClientName(must be unique per OtOpcUa instance — redundancy pairs enforce uniqueness at install time),PublishingIntervalMs(forwarded asbuffered_update_interval_mson subscribe),WriteUserIdfor ArchestrA secured-write,EventPumpChannelCapacity(default 50_000 — one second of headroom at 50k tags / 1Hz; tune via thegalaxy.events.droppedmetric).Repository—DiscoverPageSize,WatchDeployEvents.Reconnect—InitialBackoffMs,MaxBackoffMs,ReplayOnSessionLost(calls the gateway'sReplaySubscriptionsRPC after reconnect rather than re-issuing subscribe-bulk for every tag).
Full per-field descriptions live in Config/GalaxyDriverOptions.cs. The full JSON skeleton is reproduced in docs/v2/driver-specs.md §1.
Reconnect + Replay
ReconnectSupervisor owns an exponential-backoff loop bounded by Reconnect.InitialBackoffMs / MaxBackoffMs. On session loss it tears down the gRPC channel, redials, and — when ReplayOnSessionLost = true — calls the gateway's ReplaySubscriptions RPC with the cached subscription set from SubscriptionRegistry instead of re-subscribing tag-by-tag. The gateway's worker then re-issues AdviseSupervisory server-side under the apartment lock.
Testing
- Unit tests:
tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/— fakes the gateway gRPC surface; covers Browse, Runtime, Health, and Config in isolation. - Parity rig + dev-rig walkthrough: see docs/v2/Galaxy.ParityRig.md. The rig stands up a real
mxaccessgwagainst a live Galaxy and exercises the full read / write / subscribe / rediscover path. - Performance + soak: see docs/v2/Galaxy.Performance.md.
Operational Notes
- MXAccess
ClientNamecollisions: two OtOpcUa instances sharing aClientNamecause the older Wonderware session to lose subscription state. Redundancy pairs (decision #149) enforce uniqueness via install scripts. - Channel saturation:
galaxy.events.dropped > 0indicatesEventPumpis back-pressured. RaiseEventPumpChannelCapacityor investigate downstream slowness in the server-side fan-out. - Connectivity surface: per-platform probe state is exposed through
IHostConnectivityProbeand aggregated by the server's connectivity bus — there is no driver-private dashboard surface anymore. The Admin UI's Host Status panel is the consumer.