fix(opcua): use config node_id as OPC-UA string NodeId#154
Merged
Conversation
The OPC-UA server auto-assigned numeric NodeIds (ns=2;i=N) and ignored the node_id supplied by the Editor, which was only used as an internal mapping/permissions key. Auto-numeric IDs are also unstable across compilations since they follow insertion order. Create every node with an explicit ua.NodeId(node_id, ns) so clients see stable, meaningful string identifiers (ns=2;s=PLC.Main.MotorSpeed). The browse name is now passed as an explicit ua.QualifiedName in the same namespace, since asyncua would otherwise default a bare-string browse name to namespace 0 when an explicit NodeId is given. Applies to simple variables, struct objects, struct fields (leaf and nested-object), and arrays. Runtime-side collision guard (belt-and-suspenders; the Editor already enforces uniqueness): duplicate node_id values emit a warning and get a numeric suffix (_1, _2, ...) to keep NodeIds unique within the namespace. An empty node_id falls back to a server-assigned numeric NodeId so a malformed config cannot crash address-space build. No config schema change (format_version unchanged) and no Editor change: the node_id field was already serialized and parsed; it is now honored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The OPC-UA server was auto-assigning numeric NodeIds (
ns=2;i=N) and ignoring thenode_idsupplied by the Editor. Thatnode_idtraveled all the way to the runtime (serialized toconf/opcua.json, parsed into the config model) but was only used as an internal mapping/permissions key — never as the exposed OPC-UA NodeId. On top of that, auto-numeric IDs are unstable across compilations because they follow insertion order, so clients can't reliably bind to them.This wires the Editor-provided
node_idthrough to the actual NodeId, so clients now see stable, meaningful string identifiers likens=2;s=PLC.Main.MotorSpeed.Reported on the forum: Node ID in OPC UA server.
What changed
Single file:
core/src/drivers/plugins/python/opcua/address_space.py.ua.NodeId(node_id, namespace_idx)— simple variables, struct objects, struct fields (leaf and nested-object, reusing the existingparent.fieldpath composition), and arrays.ua.QualifiedName(browse_name, namespace_idx). This is required: asyncua's arg parser defaults a bare-string browse name to namespace 0 whenever an explicit NodeId is provided, which would have silently changed browse-name behavior.node_idemits alog_warnand gets a numeric suffix (_1,_2, …) to keep NodeIds unique within the namespace.node_idfalls back to a server-assigned numeric NodeId, so a malformed config can't crash address-space build.What did NOT change
format_versionis untouched. Thenode_idfield already existed and was already sent by the Editor; it's simply honored now.PLC.<pou>.<path>), and its uniqueness validation are already in place.node_permissions,nodeid_to_variable) remain keyed by the confignode_id, so the permission-callback resolution path is unchanged.Compatibility note
Clients on existing deployments will see NodeIds change from
ns=2;i=Ntons=2;s=<node_id>on upgrade. This is acceptable and is a net improvement: the old numeric IDs already shifted between compilations (insertion order), so nothing could safely cache them. String IDs are stable and OPC-UA-idiomatic.Testing
py_compilepasses._parse_nodeid_qnameto confirm exact arg-type handling.BadNodeIdExists(proving the dedup guard is genuinely needed);_1dedup works; empty-config falls back to numeric.🤖 Generated with Claude Code