Skip to content

feat(opcua): zero-config native A&C alarms -> faults#511

Merged
mfaferek93 merged 5 commits into
mainfrom
feat/opcua-auto-alarms
Jul 11, 2026
Merged

feat(opcua): zero-config native A&C alarms -> faults#511
mfaferek93 merged 5 commits into
mainfrom
feat/opcua-auto-alarms

Conversation

@mfaferek93

@mfaferek93 mfaferek93 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Closes #514

Summary

Zero-config native OPC-UA Alarms & Conditions: subscribe to the server's alarm events and surface them as faults with no per-alarm event_alarms mapping. Completes "find a PLC (#509) -> tree (#510) -> native faults, zero config". Default off.

What's included

  • Config auto_alarms: bare true or a map (source_node_id default i=2253, entity_id default <component_id>_alarms, auto_clear, severity_bands, include/exclude substring filters). Unknown keys warn.
  • Fault derivation (derive_auto_fault_code, pure): PLC_ALARM_<slug(ConditionName)> -> slug(SourceName) -> hash(SourceNode+EventType+Message). Message is folded into the hash tier because Siemens multiplexes every Program_Alarm of one FB through a single SourceNode with empty names, distinguished only by message.
  • System-message filter: events with a null ConditionId are dropped (Part 9 - only real Conditions carry one), so a "CPU not in RUN" system message on the Server EventNotifier raises no false fault.
  • Precedence: explicit event_alarms mappings resolve first; auto_alarms adds one synthetic mapping-less source for the rest (no duplicate subscriptions).

Tests

27 gtest cases (test_node_map, new test_opcua_poller): derivation tiers, message disambiguation, filters, severity bands, YAML parse, precedence, system-message filtering. Full suite green; clang-format-18 clean.

Hardware-tested

Real Siemens (opc.tcp://192.168.1.10:4840, zero event_alarms): zero-config subscription live, real "CPU not in RUN" system message correctly filtered (no false fault). Full raise->derive->clear proven against a real OPC-UA session (repo test_alarm_server): Overpressure/SensorLost -> PLC_ALARM_OVERPRESSURE (CRITICAL) / PLC_ALARM_SENSORLOST (INFO) with correct message/entity, cleared on clear. Fixed along the way: auto_clear must force both Ack+Confirm gates (auto alarms have no acknowledge op); default entity_id = <component_id>_alarms (bare component_id collided with the Component entity in the SOVD merge).

Copilot AI review requested due to automatic review settings July 9, 2026 16:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds zero-config native OPC-UA Alarms & Conditions → SOVD faults support to the ros2_medkit_opcua plugin via a new auto_alarms node-map configuration. This extends the plugin’s alarm ingestion beyond hand-written event_alarms mappings by auto-deriving faults from observed condition events, while preserving explicit-mapping precedence and avoiding duplicate subscriptions.

Changes:

  • Implemented auto_alarms parsing in NodeMap (bool + map forms, defaults, validation, unknown-key warnings) plus helpers for auto fault-code derivation, filtering, and severity mapping.
  • Updated OpcuaPoller to subscribe/replay effective alarm sources (explicit + optional synthetic auto source), filter non-condition “system message” events, and support auto_clear semantics.
  • Added/extended unit tests and wired a new gtest target to cover the pure-function selection/filters and YAML behavior; updated plugin README documentation.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_poller.cpp Adds effective alarm-source selection, non-condition event filtering, and auto-derived fault handling in the event + replay paths.
src/ros2_medkit_plugins/ros2_medkit_opcua/include/ros2_medkit_opcua/opcua_poller.hpp Exposes/notes new pure helpers and per-observation clear-gating override.
src/ros2_medkit_plugins/ros2_medkit_opcua/src/node_map.cpp Parses auto_alarms, warns on unknown keys, and registers the fallback fault-bearing entity.
src/ros2_medkit_plugins/ros2_medkit_opcua/include/ros2_medkit_opcua/node_map.hpp Introduces AutoAlarmsConfig/AutoAlarmsSeverityBands and declares auto-derivation helpers.
src/ros2_medkit_plugins/ros2_medkit_opcua/test/test_node_map.cpp Adds unit tests for fault-code derivation, filters, severity bands, and YAML parsing/defaults.
src/ros2_medkit_plugins/ros2_medkit_opcua/test/test_opcua_poller.cpp New tests for effective_alarm_sources() precedence and is_condition_event() system-message filtering.
src/ros2_medkit_plugins/ros2_medkit_opcua/CMakeLists.txt Registers the new test_opcua_poller gtest target and assigns a test domain.
src/ros2_medkit_plugins/ros2_medkit_opcua/README.md Documents auto_alarms configuration and behavior.

Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/include/ros2_medkit_opcua/node_map.hpp Outdated
Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_poller.cpp Outdated
Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/README.md Outdated
@mfaferek93 mfaferek93 marked this pull request as draft July 9, 2026 18:16
@mfaferek93 mfaferek93 self-assigned this Jul 9, 2026
@mfaferek93 mfaferek93 marked this pull request as ready for review July 10, 2026 17:06
@mfaferek93 mfaferek93 requested a review from bburda July 10, 2026 17:22
Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_poller.cpp Outdated
Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/src/node_map.cpp Outdated
Comment thread src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_poller.cpp
bburda
bburda previously approved these changes Jul 11, 2026
Add auto_alarms to the node map: subscribe to a server EventNotifier
(default Server object) and auto-derive a fault per condition with no
per-alarm event_alarms mapping. fault_code from ConditionName/SourceName,
falling back to a hash of SourceNode+EventType+Message so Siemens alarms
sharing one SourceNode don't collapse. Filters non-condition system
messages (null ConditionId). Explicit event_alarms still take precedence.

Composes with #509 (discovery) and #510 (auto_browse).
…mments

- AutoAlarmsConfig::entity_id doc (node_map.hpp) and the poller comment
  describing its fallback (opcua_poller.cpp) both said the default was the
  node map's bare component_id / PLC root component; NodeMap::load()
  actually defaults it to "<component_id>_alarms" to avoid an entity ID
  collision with the Component entity. Comments now match the code.
- apply_condition_state()'s require_confirm_for_clear doc (opcua_poller.hpp)
  described the auto-derived-alarm caller as passing '!auto_clear
  complemented'; the actual on_event()/read_fallback_replay() logic forces
  false (plus acked_state=true) when auto_clear is true, and otherwise
  passes the poller-wide config_.require_confirm_for_clear unchanged - not
  a value derived from auto_clear at all.
- README: auto_clear: false does not gate clearing through an
  event_alarms-mapping-provided acknowledge_fault operation (auto-derived
  alarms never get one); clearing is gated by the OPC-UA server's own
  Acked/Confirmed condition state, set by an HMI/SCADA system or another
  OPC-UA client.
- clang-format-18 pass on touched files.
Enables zero-config native A&C with no node_map file: endpoint (from
discovery) + auto_alarms: true is enough. The JSON/ROS param overlays the
node-map YAML auto_alarms config block (param wins, mirroring auto_browse);
explicit event_alarms mappings still win over auto-derivation at the poller.
finalize_auto_alarms_overlay re-derives the default entity + parsed source
NodeId and rebuilds entity_defs so the alarms App is discoverable with no map.
…edup

Derive and store the auto fault_code/entity once at first observation of a
ConditionId and deliver the stored values, so a condition's raise and clear
always carry one code across the live, replay and reconcile paths.
Fold the SourceNode into fault_code tiers 1/2 so same-named conditions on
different sources stay distinct, and compare NodeIds canonically so equivalent
spellings dedup and auto events already handled by an explicit event_alarms
source do not double-fire.
@mfaferek93 mfaferek93 merged commit 5b45fb8 into main Jul 11, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ros2_medkit_opcua: zero-config native A&C alarms -> faults

3 participants