Files
lmxopcua/docs
Joseph Doherty acfb4fbaca
v2-ci / unit-tests (push) Has been cancelled
fix(redundancy): a failed OPC UA endpoint drops ServiceLevel to 0 and steps the Primary down (lmxopcua#762)
IOpcUaEndpointState (review-remediation lane C3) recorded whether the SDK started, but only the
health check read it: a fused node whose endpoint failed (port 4840 taken, ...) still advertised
250/240 and stayed driver Primary, so the Primary-gated data plane ran on a node no client could
reach while the reachable peer refused writes as Secondary.

- Move IOpcUaEndpointState/OpcUaEndpointState/OpcUaEndpointStatus from Host to Commons.OpcUa so
  the Runtime can consume it.
- ServiceLevelCalculator: new NodeHealthInputs.EndpointListening (default true). false -> 0,
  ahead of every other input including the +10 Primary bonus.
- OpcUaPublishActor: takes the endpoint state, feeds EndpointListening (Failed only; NotStarted /
  Stopped are boot/shutdown windows) on the DB-backed and DB-less paths, and the legacy role-only
  seam returns 0 for a failed endpoint too.
- New OpcUaEndpointStepDownActor (one per driver node): a Primary (ClusterActiveNode.SelfIsActive,
  the election's own primitive) with a Failed endpoint gracefully Leaves its mesh - the manual
  failover mechanism - so the peer becomes the oldest Up driver member, hosts the singletons and is
  Primary. The election itself is not bent. Guarded on a peer having recently reported its own
  endpoint listening (EndpointReport on the new opcua-endpoint-state DPS topic), so a pair with
  both endpoints failed does not bounce the role and restart nodes forever, and a lone node never
  shuts itself down.
- Runtime now references ZB.MOM.WW.Health.Akka (ClusterActiveNode).
- Docs: Redundancy.md tier table + new "Endpoint start failure: Primary step-down" section;
  cluster-topology rule; HealthEndpoints / OpcUaEndpointHealthCheck comments (F-C1 landed).

Tests: ServiceLevelCalculatorTests (+5), OpcUaPublishActorEndpointStateTests (7: DB-less,
DB-backed, legacy seam, NotStarted/Stopped do not demote, a later failure demotes on the next
tick), OpcUaEndpointStepDownActorTests (3, real two-node mesh: holds while the peer is not
listening then leaves and the peer becomes Primary; failed Secondary and healthy Primary never
leave). Each was mutation-checked: removing the calculator/legacy guard, the Leave, the
peer-listening guard or the Primary guard fails the corresponding tests.
2026-11-09 12:16:37 -05:00
..
…

OtOpcUa documentation

Two tiers of documentation live here:

  • Current reference at the top level (docs/*.md) — describes what's shipped today. Start here for operator + integrator reference.
  • Implementation history + design notes at docs/v2/*.md — the authoritative plan + decision log the current reference is built from. Start here when you need the why behind an architectural choice, or when a top-level doc says "see plan.md § X".

The project was originally called LmxOpcUa (a single-driver Galaxy/MXAccess OPC UA server) and has since become OtOpcUa, a multi-driver OPC UA server platform. Any lingering LmxOpcUa-string in a path you see in docs is a deliberate residual (executable name lmxopcua-cli, client PKI folder {LocalAppData}/LmxOpcUaClient/) — fixing those requires migration shims + is tracked as follow-ups.

Platform overview

v2 (2026-05-26): the separate OtOpcUa.Server + OtOpcUa.Admin services fused into a single role-gated OtOpcUa.Host binary, joined by an Akka.NET cluster. See v2 design for the architectural decision.

  • Core owns shared abstractions (driver capability contracts, scripting, virtual tags, alarm historian).
  • Drivers plug in via capability interfaces in ZB.MOM.WW.OtOpcUa.Core.Abstractions: IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IAlarmSource, IPerCallHostResolver. Each driver opts into whichever it supports.
  • Host (src/Server/ZB.MOM.WW.OtOpcUa.Host) is the single fused binary (.NET 10, AnyCPU). OTOPCUA_ROLES env decides what to mount: admin (Blazor + control-plane singletons), driver (OPC UA endpoint + per-node actors), or both. See ServiceHosting.md.
  • Cluster + ControlPlane + Runtime + AdminUI + Security sit between Core and Host. The cluster glues per-node actors into one logical fleet; the control-plane singletons (deploy coordinator, audit writer, redundancy state) live on the admin role-leader. See Redundancy.md.
  • The Galaxy driver still reaches MXAccess via gRPC to a separately-installed mxaccessgw sidecar (sibling repo).

Where to find what

Architecture + data-path reference

Doc Covers
OpcUaServer.md Top-level server architecture — Core, driver dispatch, Config DB, generations
AddressSpace.md GenericDriverNodeManager + ITagDiscovery + IAddressSpaceBuilder
ReadWriteOperations.md OPC UA Read/Write → CapabilityInvoker → IReadable/IWritable
DriverLifecycle.md Server-side driver lifecycle + infrastructure contracts (IDriverFactory, IDriverProbe, IDriverHealthPublisher, IDriverConfigEditor, IHistorianDataSource) + the Commons library
Subscriptions.md Monitored items → ISubscribable + per-driver subscription refcount (v1 archive)
AlarmTracking.md IAlarmSource + AlarmSurfaceInvoker + OPC UA alarm conditions — native Galaxy alarms end-to-end (live)
AlarmTracking.md Original alarm-tracking write-up (v1 archive)
AlarmHistorian.md Core.AlarmHistorian store-and-forward sink — LocalDbStoreAndForwardSink, the replicated alarm_sf_events buffer + Primary-only drain, IAlarmHistorianWriter, dead-letter/retry/eviction
DataTypeMapping.md Per-driver DriverAttributeInfo → OPC UA variable types (v1 archive — live mapping is in src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Browse/DataTypeMap.cs)
IncrementalSync.md Address-space rebuild on redeploy + sp_ComputeGenerationDiff
HistoricalDataAccess.md Historical v1 design: history as a per-driver capability (retired; history is now server-side, see Historian.md)
VirtualTags.md Core.Scripting + Core.VirtualTags — Roslyn script sandbox, engine, dispatch alongside driver tags
ScriptEditor.md Monaco script editor — Roslyn-backed IntelliSense (completions, diagnostics, hover, tag-path) for C# virtual-tag scripts; AdminUI/ScriptAnalysis/ backend
ScriptedAlarms.md Core.ScriptedAlarms — script-predicate IAlarmSource + Part 9 state machine

One Core subsystem is shipped without a dedicated top-level doc; see the section in the linked doc:

Project See
Analyzers (Roslyn OTOPCUA0001) security.md § OTOPCUA0001 Analyzer

Drivers

Doc Covers
drivers/README.md Index of the eight shipped drivers + capability matrix
drivers/Galaxy.md Galaxy driver — in-process gRPC client to the mxaccessgw sidecar
v1/drivers/Galaxy-Repository.md Galaxy-specific discovery via the ZB SQL database (v1 archive — the gateway owns this path now)

For Modbus / S7 / AB CIP / AB Legacy / TwinCAT / FOCAS / OPC UA Client specifics, see v2/driver-specs.md.

Operational

Doc Covers
Configuration.md Live appsettings + environment-variable reference (current state)
Configuration.md appsettings bootstrap + Config DB + Admin UI draft/publish (v1 archive — OTOPCUA_GALAXY_* env vars now live in mxaccessgw config)
Uns.md The global /uns master tree — manage Area/Line/Equipment/Tag/VirtualTag fleet-wide; replaces the per-cluster UNS/Equipment/Tags tabs
security.md Transport security profiles, LDAP auth, ACL trie, role grants, OTOPCUA0001 analyzer
Redundancy.md RedundancyStateActor (cluster-scoped singleton), ServiceLevelCalculator, IRedundancyRoleView, per-cluster meshes, Prometheus metrics
Reservations.md Fleet-wide ZTag / SAPID external-ID reservations — publish-time claim, release flow
ServiceHosting.md Single fused OtOpcUa.Host binary install/uninstall with OTOPCUA_ROLES gating; the historian backend is the external HistorianGateway
StatusDashboard.md Pointer — superseded by v2/admin-ui.md

Client tooling

Doc Covers
Client.CLI.md otopcua-cli — OPC UA command-line client
Client.UI.md Avalonia desktop client
DriverClis.md Driver test-client CLIs — index + shared commands
Driver.Modbus.Cli.md otopcua-modbus-cli — Modbus-TCP
Driver.AbCip.Cli.md otopcua-abcip-cli — ControlLogix / CompactLogix / Micro800 / GuardLogix
Driver.AbLegacy.Cli.md otopcua-ablegacy-cli — SLC / MicroLogix / PLC-5 (PCCC)
Driver.S7.Cli.md otopcua-s7-cli — Siemens S7-300 / S7-400 / S7-1200 / S7-1500
Driver.TwinCAT.Cli.md otopcua-twincat-cli — Beckhoff TwinCAT 2/3 ADS
Driver.FOCAS.Cli.md otopcua-focas-cli — Fanuc FOCAS/2 CNC

Requirements

Doc Covers
reqs/HighLevelReqs.md HLRs — numbered system-level requirements
reqs/OpcUaServerReqs.md OPC UA server-layer reqs
v1/reqs/ServiceHostReqs.md Per-process hosting reqs (v1 archive — only OtOpcUa server hosting remains in scope post-PR-7.2)
reqs/ClientRequirements.md Client CLI + UI reqs
v1/reqs/GalaxyRepositoryReqs.md Galaxy-scoped repository reqs (v1 archive — owned by mxaccessgw today)
v1/reqs/MxAccessClientReqs.md Galaxy-scoped MXAccess reqs (v1 archive — owned by mxaccessgw today)
reqs/StatusDashboardReqs.md Pointer — superseded by Admin UI

Implementation history (docs/v2/)

Design decisions + phase plans + execution notes. Load-bearing cross-references from the top-level docs:

v1 archive

The v1 in-process MXAccess architecture (Galaxy.Host + Galaxy.Proxy + Galaxy.Shared, .NET 4.8 x86 COM, the OtOpcUaGalaxyHost Windows service) was retired in PR 7.2 (2026-04-30, commit ae7106d). Docs that described that shape are kept under v1/ as historical record — see v1/README.md for the index.