Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro kilted showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro rolling showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro ardent showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro bouncy showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro crystal showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro eloquent showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro dashing showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro galactic showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro foxy showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro iron showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro lunar showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro jade showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro indigo showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro hydro showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro kinetic showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro melodic showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange

No version for distro noetic showing humble. Known supported distros are highlighted in the buttons above.

Package Summary

Version 0.7.0
License Apache-2.0
Build type AMENT_CMAKE
Use RECOMMENDED

Repository Summary

Checkout URI https://github.com/selfpatch/ros2_medkit.git
VCS Type git
VCS Version main
Last Updated 2026-09-13
Dev Status DEVELOPED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Package Description

OPC-UA gateway plugin for ros2_medkit - bridges PLC systems into the SOVD entity tree

Additional Links

Maintainers

  • mfaferek93

Authors

  • mfaferek93

ros2_medkit_opcua

Gateway plugin that bridges OPC-UA capable PLCs (OpenPLC, Siemens S7, Beckhoff, Allen-Bradley, etc.) into the SOVD entity tree. Enables unified diagnostics for mixed ROS 2 + industrial PLC deployments through a single REST API, with PLC alarms routed to ros2_medkit_fault_manager and numeric PLC values optionally bridged to ROS 2 std_msgs/Float32 topics.

Follows the same plugin pattern as ros2_medkit_graph_provider: implements GatewayPlugin + IntrospectionProvider against the get_routes() plugin API, loaded at runtime by ros2_medkit_gateway via dlopen.

What it does

  • Connects to any OPC-UA capable PLC server over opc.tcp
  • Emits SOVD entities (area, component, apps) from a YAML-driven node map, or discovers them automatically by browsing the live address space (auto_browse, see below) - zero node-map config required
  • Exposes PLC values as the x-plc-data vendor collection
  • Ships read-only by default: the shipped binary contains no compiled path that writes a value or acknowledges a condition, and exports nothing from the OPC UA stack (see Read-only and write-capable builds)
  • In a write-capable build, allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state, poll metrics and the build’s write surface via x-plc-status
  • Maps threshold-based PLC alarms to SOVD faults on the owning entity
  • Optionally publishes numeric PLC values to ROS 2 std_msgs/Float32 topics

Architecture

                    OPC-UA (TCP :4840)
PLC Runtime  <─────────────────────────>  OPC-UA Plugin (.so)
  IEC 61131-3 program                      │
  Cyclic execution (100ms)                 │  Polls all configured nodes
  Variables exposed as OPC-UA nodes        │  Maps to SOVD entity tree
                                           │  Alarm thresholds -> fault reporting
                                           │
                                           ▼
                                    ros2_medkit Gateway
                                      REST API :8080
                                           │
                                    ┌──────┴──────┐
                                    │             │
                              SOVD REST      Fleet Gateway
                              (direct)       (aggregation)
                                    │             │
                                Dashboard    Multi-device view

The plugin connects to any PLC with an OPC-UA server over TCP. No ROS 2 dependency between the plugin and the PLC - communication is pure OPC-UA. The plugin is loaded by the gateway at runtime via dlopen() and registers vendor REST endpoints for PLC data access and control.

SOVD Entity Model

The plugin creates a hierarchical entity tree from a YAML node map configuration:

Area: plc_systems
  └── Component: openplc_runtime
        ├── App: tank_process
        │     Data: tank_level (mm), tank_temperature (C), tank_pressure (bar)
        │     Faults: PLC_HIGH_TEMP, PLC_LOW_LEVEL, PLC_OVERPRESSURE
        ├── App: fill_pump
        │     Data: pump_speed (%)
        │     Operations: set_pump_speed
        └── App: drain_valve
              Data: valve_position (%)
              Operations: set_valve_position

Asset identity (x-medkit.identity)

The plugin auto-populates the PLC component’s asset-identity nameplate from the live server and serves it as x-medkit.identity on the component (see docs/api/rest.rst for the JSON shape). Two sources are read, best-effort:

  • Server/ServerStatus/BuildInfo (present on every compliant server): ManufacturerName, ProductName, SoftwareVersion, BuildNumber (carried as the extra.buildNumber key).
  • The OPC UA DI companion nameplate (http://opcfoundation.org/UA/DI/, only when the server exposes that namespace): Manufacturer, Model, SerialNumber, HardwareRevision, SoftwareRevision from the first device under Objects/DeviceSet that carries identification properties. DI values are device-specific and win over the server-level BuildInfo per field.

The read happens once per session - on the first introspect after a connect - and is refreshed after every reconnect: the cached nameplate is tied to the OPC UA session, so a PLC reboot, firmware update, or device swap is picked up on the next discovery refresh instead of latching the first read forever.

Trust-gated precedence. How the live nameplate ranks against a hand-authored manifest identity: block depends on whether the session authenticates the server:

  • Secured channel (security_mode: Sign/SignAndEncrypt) and reject_untrusted: true: the component is tagged with the protocol source opcua, which outranks manifest in the identity merge - an authenticated live read overrides stale manifest fields.
  • Anything else (SecurityPolicy=None, or reject_untrusted: false / accept-any cert): the nameplate is spoofable by a rogue endpoint, so the component keeps the generic plugin source, which ranks below manifest - the read fills fields the operator left empty but never overrides them.

Per-field _provenance records opcua in both cases, so consumers always see where a value was read even when it merged with low authority.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

0.7.0 (2026-08-27)

  • Config-less discovery. A read-only network scan finds the OPC UA server instead of requiring its endpoint up front (#509), auto_browse walks the address space recursively and builds the SOVD tree from it (#510), and identity, writability and fault triggers are read from the device itself rather than declared in a node map (#544)
  • Native OPC UA Alarms and Conditions become medkit faults with no configuration (#511). Alarms are routed to distinct faults by message substring (#506), severity is accepted as an alias in event_alarms (#501), and events that are not conditions are dropped from the alarm path instead of being reported as alarms (#552)
  • Asset identity is populated from the device nameplate, including order_code (#492, #499)
  • PLC_COMMS_LOST is raised when the connection to the PLC drops, so a lost link is a reported fault rather than an absence of data (#507)
  • Security and reconnect hardening: a secure connection profile, replay of alarm state after a reconnect, and correct handling of several simultaneous alarms (#485)
  • Fixed a data race between the REST thread and the poll thread on the pending-report buffer that crashed the gateway with a SIGSEGV (#519, #521)
  • Fault detection moved onto the shared ros2_medkit_fault_detection evaluator, and the node map enforces global fault-code uniqueness so two rules cannot claim the same code (#486)
  • This package is still excluded from the rosdistro binary release pending vendoring of open62541pp (#366)
  • Contributors: \@bburda, \@mfaferek93

0.6.0 (2026-06-22)

  • No functional changes; version bump for the coordinated 0.6.0 release.
  • Contributors: \@bburda

0.5.0 (2026-06-08)

  • Native OPC-UA Part 9 AlarmConditionType event subscription. The plugin now subscribes to vendor-defined alarms (Siemens S7-1500 Program_Alarm / ProDiag, Beckhoff TF6100, CodeSys 3.5+, Rockwell via FactoryTalk Linx) and bridges each event into the SOVD fault lifecycle. Configured via a new top-level event_alarms: block in the node map YAML; mutually exclusive per entry with the existing threshold-based alarm form. (issue #386)
  • New SOVD operations on entities that host alarm sources: acknowledge_fault invokes the inherited Acknowledge method on the live ConditionId (i=9111, EventId tracked per Part 9 §5.7.3); confirm_fault invokes Confirm (i=9113). Both accept an optional comment rendered as LocalizedText on the server.
  • OpcuaClient gains add_event_monitored_item / remove_event_monitored_item / call_method and a generation counter that filters callbacks fired from defunct subscriptions after a reconnect. Heap-owned EventCallbackContext resolves the open62541pp / raw-C lifetime hazard.
  • Header-only AlarmStateMachine mapping EnabledState x ShelvingState x ActiveState x AckedState x ConfirmedState x BranchId to SOVD CONFIRMED / HEALED / CLEARED / Suppressed. Full transition table documented in design/index.rst.
  • ConditionRefresh (Server method i=3875) is invoked on subscribe and on every reconnect, with RefreshStartEvent / RefreshEndEvent bracketing tracked for diagnostics.
  • New test_alarm_server fixture (open62541-based, full namespace 0 + alarms enabled) emits AlarmConditionType events on stdin commands; integration test run_alarm_tests.sh runs in CI alongside the existing OpenPLC threshold suite. The fixture builds by default via the workspace colcon build (gated on MEDKIT_OPCUA_BUILD_ALARM_SERVER which defaults to ON; ExternalProject_Add rebuilds open62541 with UA_NAMESPACE_ZERO=FULL and alarms ON, with a serial sub-build to dodge the upstream -j race on namespace0_generated.c).
  • New CTest wrapper test_alarm_server_smoke boots the fixture on an ephemeral port and runs the asyncua smoke test against it; skips with CTest exit 77 (treated as pass) when asyncua is not importable, so iterating on plugin code without the Python dependency does not fail the suite.
  • Contributors: \@mfaferek93, \@bburda

0.4.0 (2026-04-11)

  • Initial release
  • OpcuaPlugin implementation of GatewayPlugin and IntrospectionProvider that bridges OPC-UA capable PLCs into the

File truncated at 100 lines see the full file

Launch files

No launch files found

Messages

No message files found.

Services

No service files found

Plugins

No plugins found.

Recent questions tagged ros2_medkit_opcua at Robotics Stack Exchange