Package Summary

Version 0.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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.6.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-07-03
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
  • Exposes PLC values as the x-plc-data vendor collection
  • Allows writing setpoints via x-plc-operations with type-aware coercion and range validation
  • Reports the connection state and poll metrics 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.

Note: identity (model, serial number, firmware/software versions) is served unauthenticated on the default gateway configuration (auth.enabled defaults to false) like every other discovery resource - it is a device fingerprint, useful for reconnaissance. Enable gateway authentication (auth.enabled: true) or front the API with an authenticating proxy to gate access to it.

File truncated at 100 lines see the full file

CHANGELOG

Changelog for package ros2_medkit_opcua

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 SOVD entity tree
  • REST endpoints via the new get_routes() plugin API: x-plc-data, x-plc-operations, x-plc-status
  • Vendor capabilities registered per entity - only PLC-backed apps and the PLC runtime component advertise the x-plc-* endpoints
  • Full OPC 10000-6 section 5.3.1.10 node identifier support (i= numeric, s= string, g= GUID, b= opaque ByteString); example node maps for OpenPLC, Siemens S7-1500 TIA Portal, Beckhoff TwinCAT 3, Allen-Bradley via Kepware and KUKA KR C5
  • NodeMap driven by YAML configuration - same binary serves any OPC-UA compliant server by changing the node map file
  • Deterministic entity ordering in IntrospectionResult output (entries sorted by id)
  • Threshold-based PLC alarm detection routed to SOVD faults via ros2_medkit_msgs services ReportFault / ClearFault
  • Optional bridging of numeric PLC values to ROS 2 std_msgs/Float32 topics from set_context()
  • Type-aware writes with per-node range validation
  • Robust connection-loss detection: all three OPC-UA client paths (read_value, read_values, write_value) mark the connection as dropped on terminal status codes so OpcuaPoller reconnect kicks in without stalling
  • Polling mode (default) and OPC-UA subscription mode, backed by open62541pp v0.16.0
  • Integration test suite against an OpenPLC IEC 61131-3 tank demo container
  • Contributors: \@mfaferek93

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