Skip to content

feat: add batch read support via UA_Client_Service_read#17

Open
juljimm wants to merge 2 commits intovaliot:masterfrom
juljimm:master
Open

feat: add batch read support via UA_Client_Service_read#17
juljimm wants to merge 2 commits intovaliot:masterfrom
juljimm:master

Conversation

@juljimm
Copy link

@juljimm juljimm commented Feb 11, 2026

Implement read_node_values to read multiple OPC-UA nodes in a single request, reducing N round-trips to 1. Tested against real PLC: 17.6x speedup (916ms -> 52ms for 36 nodes).

Description

Adds a new read_node_values/2 function that reads the 'value' attribute of multiple OPC-UA nodes in a single service call using UA_Client_Service_read, instead of issuing one request per node.

Motivation: When reading many nodes (e.g. 36 PLC tags), sequential reads cause significant latency due to per-request round-trip overhead. Batching all reads into one OPC-UA Read Service call eliminates this overhead.

Changes:

  • src/common.c: New handle_read_node_values() C NIF that builds a UA_ReadRequest with multiple UA_ReadValueId entries and calls UA_Client_Service_read. Results are encoded per-node as {:ok, value} or {:error, status}.
  • src/common.h: Declaration for handle_read_node_values.
  • src/opc_ua_client.c: Registered "read_node_values" in the client request handler table.
  • lib/opc_ua/common.ex: New read_node_values/2 public API, handle_call clause, and C response handler with parse_batch_value/1.
  • test/client_tests/batch_read_test.exs: 5 test cases covering multiple values, nil/unset values, nonexistent nodes, single node, and mixed data types.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

  • 5 unit tests in test/client_tests/batch_read_test.exs (batch read multiple values, nil values, nonexistent node per-node error, single node, mixed data types)
  • Manual testing against a real Siemens S7-1500 PLC reading 36 nodes: 17.6x speedup (916ms sequential → 52ms batched)

Test Configuration:

  • Toolchain: Elixir/OTP with open62541 v1.4.x C library
  • SDK: opex62541

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Note

Medium Risk
Introduces new C port handler and custom response encoding/decoding, so bugs could cause incorrect values or crashes under malformed inputs or large batches; scope is additive and gated to client reads.

Overview
Adds a new read_node_values/2 client API to batch-read the Value attribute for multiple nodes in one OPC-UA request, returning per-node success/error tuples and handling nil/array/structured variant decoding in Elixir.

Implements the C-side handle_read_node_values handler using UA_Client_Service_read, registers it in the client request handler table, exposes the new handler in headers, and adds an ExUnit suite covering multi-node reads, unset values, mixed types, and per-node errors.

Written by Cursor Bugbot for commit ab85bf6. This will update automatically on new commits. Configure here.

Implement read_node_values to read multiple OPC-UA nodes in a single
request, reducing N round-trips to 1. Tested against real PLC: 17.6x
speedup (916ms -> 52ms for 36 nodes).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

- Handle complex types (NodeId, QualifiedName, ExpandedNodeId) in
  parse_batch_value by reusing parse_c_value
- Fix GOOD status without value returning {:error, "Good"} by using
  encode_variant_struct for all GOOD statuses
- Reduce max batch node count from 200 to 100 and add buffer overflow
  check before erlcmd_send

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant