Merge pull request 'docs: alarms-over-gateway completion banner + AlarmTracking v2 (PR B.5)' (#416) from track-b5-docs-memory-housekeeping into master
This commit was merged in pull request #416.
This commit is contained in:
129
docs/AlarmTracking.md
Normal file
129
docs/AlarmTracking.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Alarm tracking — v2 final architecture
|
||||
|
||||
This document describes how OtOpcUa surfaces alarms to OPC UA Part 9
|
||||
clients after the **alarms-over-gateway** epic
|
||||
([docs/plans/alarms-over-gateway.md](plans/alarms-over-gateway.md))
|
||||
landed. The v1 architecture (Galaxy.Host's COM-side `GalaxyAlarmTracker`)
|
||||
is preserved at [docs/v1/AlarmTracking.md](v1/AlarmTracking.md) for
|
||||
historical reference.
|
||||
|
||||
## Three alarm sources, one OPC UA Part 9 surface
|
||||
|
||||
| Source | Driver capability | Path |
|
||||
|----------------------------------|--------------------------|------|
|
||||
| **Galaxy MxAccess (driver-native)** | `GalaxyDriver : IAlarmSource` | gateway → worker → MxAccess alarm sink → `MX_EVENT_FAMILY_ON_ALARM_TRANSITION` → `EventPump` → driver `OnAlarmEvent` → `AlarmConditionService` |
|
||||
| **Galaxy sub-attribute fallback** | `IWritable` writes to `$Alarm*` sub-attributes | gateway data subscription → driver `OnDataChange` → `DriverNodeManager` ConditionSink → `AlarmConditionService` |
|
||||
| **Scripted alarms** | `Phase7EngineComposer` | server-side script evaluator → `Phase7EngineComposer.RouteToHistorianAsync` + `AlarmConditionService` |
|
||||
|
||||
All three converge on `AlarmConditionService` (`src/ZB.MOM.WW.OtOpcUa.Server/Alarms/AlarmConditionService.cs`),
|
||||
which owns the OPC UA Part 9 state machine and dispatches transitions
|
||||
to the OPC UA condition node managers. Driver-native transitions take
|
||||
precedence over sub-attribute synthesis when both arrive for the same
|
||||
condition — the dedup logic prefers the richer driver-native record
|
||||
because it carries the full operator + raise-time + category metadata
|
||||
that the value-driven path collapses.
|
||||
|
||||
## Galaxy driver path (driver-native)
|
||||
|
||||
Restored in PR B.2 of the epic. `GalaxyDriver` implements
|
||||
`IAlarmSource` with these surfaces:
|
||||
|
||||
- `SubscribeAlarmsAsync(sourceNodeIds)` → returns a sentinel handle.
|
||||
The driver doesn't multiplex per source-node-id today; every
|
||||
active handle observes the gateway's alarm-event stream. The
|
||||
server-side `AlarmConditionService` filters by source-node before
|
||||
raising the OPC UA condition.
|
||||
- `UnsubscribeAlarmsAsync(handle)` → symmetric handle removal.
|
||||
- `AcknowledgeAsync(requests)` → routes one gateway RPC per
|
||||
acknowledgement through `IGalaxyAlarmAcknowledger`. Production
|
||||
uses `GatewayGalaxyAlarmAcknowledger` calling
|
||||
`MxGatewayClient.AcknowledgeAlarmAsync` (PR E.2 SDK method).
|
||||
- `OnAlarmEvent` → bridges `EventPump.OnAlarmTransition` (PR B.1)
|
||||
onto `AlarmEventArgs`. Suppressed when no alarm subscription is
|
||||
active so untracked transitions don't leak through.
|
||||
|
||||
The proto contract carries the rich payload — alarm full reference,
|
||||
source-object reference, alarm-type-name, transition kind (Raise /
|
||||
Acknowledge / Clear / Retrigger), severity (raw MxAccess scale),
|
||||
original raise timestamp, transition timestamp, operator user,
|
||||
operator comment, alarm category, description. `MxAccessSeverityMapper`
|
||||
(PR B.1) translates the raw severity onto the four-bucket
|
||||
`AlarmSeverity` ladder — boundaries match v1's `GalaxyAlarmTracker`
|
||||
so customers see no surprise re-classification.
|
||||
|
||||
The richer fields surface on `Core.Abstractions.AlarmEventArgs` via
|
||||
the optional properties added in PR E.7 (`OperatorComment`,
|
||||
`OriginalRaiseTimestampUtc`, `AlarmCategory`). Consumers that don't
|
||||
need them are unaffected; consumers that do (Client.UI, Client.CLI
|
||||
verbose mode) read the new fields when present.
|
||||
|
||||
## Galaxy sub-attribute fallback
|
||||
|
||||
For Galaxy templates without `$Alarm*` extensions, the value-driven
|
||||
path stays in place: `DriverNodeManager` registers an
|
||||
`AlarmConditionState` per Galaxy variable that bears alarm-bearing
|
||||
sub-attributes (`InAlarm`, `Acked`, `Priority`, `Description`),
|
||||
subscribes to those sub-attributes, and synthesizes Part 9 transitions
|
||||
when the values change. This path operated as the only Galaxy alarm
|
||||
path between PR 7.2 and the alarms-over-gateway epic; it remains the
|
||||
fallback today.
|
||||
|
||||
When both paths report the same condition,
|
||||
`AlarmConditionService.AlarmConditionState` keeps the
|
||||
driver-native record and discards the duplicate sub-attribute
|
||||
synthesis. Driver-native transitions are richer (carry operator
|
||||
comment + original raise time) and arrive lower-latency (no
|
||||
publishing-interval delay on the sub-attribute reads), so they win
|
||||
the dedup.
|
||||
|
||||
## Acknowledge routing
|
||||
|
||||
`DriverNodeManager` picks the acknowledger when registering each
|
||||
condition (PR B.3 logic):
|
||||
|
||||
- Driver implements `IAlarmSource` →
|
||||
`DriverAlarmSourceAcknowledger` routes the operator comment
|
||||
through `IAlarmSource.AcknowledgeAsync` via the existing
|
||||
`AlarmSurfaceInvoker` (Phase 6.1 resilience pipeline; no-retry
|
||||
per decision #143). End-to-end operator-comment fidelity is
|
||||
preserved.
|
||||
- Driver doesn't implement `IAlarmSource` →
|
||||
`DriverWritableAcknowledger` writes the comment into the
|
||||
`AckMsgWriteRef` sub-attribute via `IWritable.WriteAsync`. Same
|
||||
resilience pipeline; collapses the comment into a single string
|
||||
write at the wire level.
|
||||
|
||||
The OPC UA Part 9 `AlarmConditionState.OnAcknowledge` delegate
|
||||
already validates the session's `AlarmAck` role before dispatching,
|
||||
so the gateway-side ack RPC only sees authenticated, authorised
|
||||
calls.
|
||||
|
||||
## Historian write-back (non-Galaxy alarms)
|
||||
|
||||
Scripted alarms (and any future non-Galaxy `IAlarmSource` like
|
||||
AB CIP ALMD) route to AVEVA Historian via the Wonderware sidecar:
|
||||
|
||||
- `Phase7Composer.ResolveHistorianSink` resolves an
|
||||
`IAlarmHistorianWriter` from either a driver that natively
|
||||
implements it or the DI-registered `WonderwareHistorianClient`
|
||||
(the sidecar IPC client). Driver-provided wins when both are
|
||||
present.
|
||||
- `SqliteStoreAndForwardSink` queues each transition to a local
|
||||
SQLite database and drains in the background via the resolved
|
||||
writer.
|
||||
- Sidecar (PR C.1 + C.2) forwards the events to `aahClientManaged`'s
|
||||
alarm-event write API; the live SDK call site is pinned during
|
||||
PR D.1's deploy-rig validation.
|
||||
|
||||
Galaxy-native alarms with `$Alarm*` extensions reach AVEVA Historian
|
||||
directly via System Platform's `HistorizeToAveva` toggle on the
|
||||
alarm primitive — no involvement from OtOpcUa. This sidecar path is
|
||||
exclusively for non-Galaxy alarm producers.
|
||||
|
||||
## Cross-references
|
||||
|
||||
- Plan: [docs/plans/alarms-over-gateway.md](plans/alarms-over-gateway.md)
|
||||
- v1 archive: [docs/v1/AlarmTracking.md](v1/AlarmTracking.md)
|
||||
- Galaxy driver: [docs/drivers/Galaxy.md](drivers/Galaxy.md)
|
||||
- Phase 7 scripting + alarming: [docs/v2/implementation/phase-7-scripting-and-alarming.md](v2/implementation/phase-7-scripting-and-alarming.md)
|
||||
- Security + ACL: [docs/Security.md](Security.md)
|
||||
@@ -15,7 +15,8 @@ For the driver spec (capability surface, config shape, addressing), see [docs/v2
|
||||
| ITagDiscovery / IReadable / |
|
||||
| IWritable / ISubscribable / |
|
||||
| IRediscoverable / |
|
||||
| IHostConnectivityProbe |
|
||||
| IHostConnectivityProbe / |
|
||||
| IAlarmSource |
|
||||
+-------------------+-------------------+
|
||||
|
|
||||
gRPC (default http://localhost:5120)
|
||||
@@ -33,7 +34,18 @@ For the driver spec (capability surface, config shape, addressing), see [docs/v2
|
||||
+---------------------------------------+
|
||||
```
|
||||
|
||||
History reads + alarm-condition tracking moved server-side in PR 7.2 (`IHistoryRouter`, `AlarmConditionService`). Galaxy no longer implements `IHistoryProvider` or `IAlarmSource` of its own.
|
||||
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](../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](../AlarmTracking.md)
|
||||
for the v2-final architecture.
|
||||
|
||||
## Project Layout
|
||||
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# Plan — alarms over the mxaccessgw gateway
|
||||
|
||||
> ✅ **Completed 2026-04-30 — historical record.**
|
||||
> The 14-PR sequence (A.1 / A.3, B.1 / B.2 / B.3 / B.4, C.1 / C.2,
|
||||
> E.1 / E.2 / E.3 / E.4 / E.5 / E.6 / E.7) shipped. The gateway-side
|
||||
> public RPC surface, the driver-native ack path, the sidecar alarm
|
||||
> historian writer, and the five client SDKs are all live. **A.2**
|
||||
> (worker MxAccess alarm subscription) and **A.4** (worker
|
||||
> ConditionRefresh command) require the AVEVA worker host's MxAccess
|
||||
> Toolkit C++ SDK and ship as a follow-up gated on dev-rig
|
||||
> validation. **D.1** (refresh `C:\publish` + smoke-run on the dev
|
||||
> rig) ships once A.2 is hardware-verified. The remainder of this
|
||||
> document is preserved as the design record.
|
||||
|
||||
Coordinated epic across two repos:
|
||||
|
||||
- **`lmxopcua`** (this repo) — `c:\Users\dohertj2\Desktop\lmxopcua\`
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
# Alarm Tracking
|
||||
# Alarm Tracking — v1 archive
|
||||
|
||||
> **Historical record.** This document describes the v1 / pre-PR-7.2
|
||||
> Galaxy alarm path that ran inside `Galaxy.Host`'s STA pump as
|
||||
> `GalaxyAlarmTracker`. PR 7.2 retired the in-process Galaxy stack; the
|
||||
> alarms-over-gateway epic (B.2 / B.3 / E.7) restored Galaxy's
|
||||
> `IAlarmSource` capability against the new gateway-mediated transport.
|
||||
> See [docs/AlarmTracking.md](../AlarmTracking.md) for the v2 final
|
||||
> architecture — that is the document to read for current behaviour.
|
||||
|
||||
Alarm surfacing is an optional driver capability exposed via `IAlarmSource` (`src/ZB.MOM.WW.OtOpcUa.Core.Abstractions/IAlarmSource.cs`). Drivers whose backends have an alarm concept implement it — today: Galaxy (MXAccess alarms), FOCAS (CNC alarms), OPC UA Client (A&C events from the upstream server). Modbus / S7 / AB CIP / AB Legacy / TwinCAT do not implement the interface and the feature is simply absent from their subtrees.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user