On Galaxy deploy changes, only the affected gobject subtrees are torn down and rebuilt instead of destroying the entire address space. Unchanged nodes, subscriptions, and alarm tracking continue uninterrupted. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
11 KiB
OPC UA Server — Component Requirements
Parent: HLR-001, HLR-002, HLR-004
OPC-001: Server Endpoint
The OPC UA server shall listen on a configurable TCP port (default 4840) using the OPC Foundation .NET Standard stack.
Acceptance Criteria
- Server starts and accepts TCP connections on the configured port.
- Port is read from
appsettings.jsonunderOpcUa:Port; defaults to 4840 if absent. - Endpoint URL format:
opc.tcp://<hostname>:<port>/LmxOpcUa. - If the port is in use at startup, log an Error and fail to start (do not silently pick another port).
- Security policy: None (no certificate validation). This is an internal plant-floor service.
Details
- Configurable items: port (default 4840), endpoint path (default
/LmxOpcUa), server application name (defaultLmxOpcUa). - Server shall use the
OPCFoundation.NetStandard.Opc.Ua.ServerNuGet package. - On startup, log the endpoint URL at Information level.
OPC-002: Address Space Structure
The server shall create folder nodes for areas and object nodes for automation objects, organized in the same parent-child hierarchy as the Galaxy.
Acceptance Criteria
- The root folder node has BrowseName
ZB(hardcoded Galaxy name). - Objects where
is_area = 1are created as FolderType nodes (organizational). - Objects where
is_area = 0are created as BaseObjectType nodes. - Parent-child relationships use Organizes references (for areas) and HasComponent references (for contained objects).
- A client browsing Root → Objects → ZB → DEV → TestArea → TestMachine_001 → DelmiaReceiver sees the same structure as
gr/layout.md.
Details
- NodeIds use a string-based identifier scheme:
ns=1;s=<tag_name>for object nodes,ns=1;s=<tag_name>.<attribute_name>for variable nodes. - Infrastructure objects (AppEngines, Platforms) are included in the tree but may have no variable children.
- When
contained_nameis null or empty, fall back totag_nameas the BrowseName.
OPC-003: Variable Nodes for Attributes
Each user-defined attribute on a deployed object shall be represented as an OPC UA variable node under its parent object node.
Acceptance Criteria
- Each row from
attributes.sqlcreates one variable node under the matching object node (matched bygobject_id). - Variable node BrowseName and DisplayName are set to
attribute_name. - Variable node stores
full_tag_referenceas its runtime MXAccess address. - Variable node AccessLevel is set based on the attribute's
security_classificationper the mapping ingr/data_type_mapping.md. - FreeAccess (0), Operate (1), Tune (4), Configure (5) → AccessLevel = CurrentRead | CurrentWrite (3).
- SecuredWrite (2), VerifiedWrite (3), ViewOnly (6) → AccessLevel = CurrentRead (1).
- Objects with no user-defined attributes still appear as object nodes with zero children.
Details
- Security classification determines the OPC UA AccessLevel and UserAccessLevel attributes on each variable node. The OPC UA stack enforces read-only access for nodes with CurrentRead-only access level.
- Attributes whose names start with
_are already filtered by the SQL query.
OPC-004: Browse Name Translation
Browse names shall use contained names (human-readable, scoped to parent). The server shall internally translate browse paths to tag_name references for MXAccess operations.
Acceptance Criteria
- A variable node browsed as
ZB/DEV/TestArea/TestMachine_001/DelmiaReceiver/DownloadPathcorrectly translates to MXAccess referenceDelmiaReceiver_001.DownloadPath. - Translation uses the
tag_namestored on the parent object node, not the browse path. - No runtime path parsing — the mapping is baked into each node at build time.
Details
- Each variable node stores its
full_tag_reference(e.g.,DelmiaReceiver_001.DownloadPath) at address-space build time. Read/write operations use this stored reference directly.
OPC-005: Data Type Mapping
Variable nodes shall use OPC UA data types mapped from Galaxy mx_data_type values per the mapping in gr/data_type_mapping.md.
Acceptance Criteria
- Every
mx_data_typevalue in the mapping table produces the correct OPC UA DataType NodeId on the variable node. - Unknown/unmapped
mx_data_typevalues default to String (i=12). - ElapsedTime (type 7) maps to Double representing seconds.
Details
- Full mapping table in
gr/data_type_mapping.md. - DateTime conversion: Galaxy may store local time; convert to UTC for OPC UA.
- LocalizedText (type 15): use empty locale string with the text value.
OPC-006: Array Support
Attributes marked as arrays shall have ValueRank=1 and ArrayDimensions set to the attribute's array_dimension value.
Acceptance Criteria
is_array = 1produces ValueRank = 1 (OneDimension) and ArrayDimensions =[array_dimension].is_array = 0produces ValueRank = -1 (Scalar) and no ArrayDimensions.- MXAccess reference for array attributes uses
tag_name.attribute[](whole array) format.
Details
- Individual array element access (
tag_name.attribute[n]) is not required for initial implementation. Whole-array read/write only. - If
array_dimensionis null or 0 whenis_array = 1, log a Warning and default to ArrayDimensions = [0] (variable-length).
OPC-007: Read Operations
The server shall fulfill OPC UA Read requests by reading the corresponding tag value from MXAccess using the tag_name.AttributeName reference.
Acceptance Criteria
- OPC UA Read request for a variable node results in a read via MXAccess using the node's stored
full_tag_reference. - Returned value is converted from the COM variant to the OPC UA data type specified on the node.
- OPC UA StatusCode reflects MXAccess quality: Good maps to Good, Bad/Uncertain map appropriately.
- If MXAccess is not connected, return StatusCode = Bad_NotConnected.
- Read timeout: configurable, default 5 seconds. On timeout, return Bad_Timeout.
Details
- Prefer cached subscription-delivered values over on-demand reads to reduce COM round-trips.
- If no subscription is active for the tag, perform an on-demand read (AddItem, AdviseSupervisory, wait for first OnDataChange, then UnAdvise/RemoveItem).
- Concurrency: semaphore-limited to configurable max (default 10) concurrent MXAccess operations.
OPC-008: Write Operations
The server shall fulfill OPC UA Write requests by writing to the corresponding tag via MXAccess.
Acceptance Criteria
- OPC UA Write request results in an MXAccess
Write()call with completion confirmed viaOnWriteComplete()callback. - Write timeout: configurable, default 5 seconds. On timeout, log Warning and return Bad_Timeout.
- MXSTATUS_PROXY with
success = 0causes the OPC UA write to return Bad_InternalError with the detail message. - MXAccess errors 1008 (no permission), 1012 (secured write), 1013 (verified write) return Bad_UserAccessDenied.
- Write to a non-existent tag returns Bad_NodeIdUnknown.
- The server shall attempt to convert the written value to the expected Galaxy data type before passing to Write().
Details
- Write uses security classification -1 (no security). Galaxy runtime handles security enforcement.
- Write sequence: uses existing subscription handle if available, otherwise AddItem + AdviseSupervisory + Write + await OnWriteComplete + cleanup.
- Concurrent write limit: same semaphore as reads (configurable, default 10).
OPC-009: Subscriptions
The server shall support OPC UA subscriptions by mapping them to MXAccess advisory subscriptions and forwarding data change notifications.
Acceptance Criteria
- OPC UA CreateMonitoredItems results in MXAccess
AdviseSupervisory()subscriptions for the requested tags. - Data changes from
OnDataChangecallback are forwarded as OPC UA notifications to all subscribed clients. - Shared subscriptions: if two OPC UA clients subscribe to the same tag, only one MXAccess subscription exists (ref-counted).
- Last subscriber unsubscribing triggers UnAdvise/RemoveItem on the MXAccess side.
- After MXAccess reconnect, all active MXAccess subscriptions are re-established automatically.
Details
- Publishing interval from the OPC UA subscription request is honored on the OPC UA side; MXAccess delivers changes as fast as it receives them.
- OPC UA quality mapping from MXAccess quality integers: 192+ = Good, 64-191 = Uncertain, 0-63 = Bad.
- OnDataChange with MXSTATUS_PROXY failure: deliver notification with Bad quality to subscribed clients.
OPC-010: Address Space Rebuild
When a Galaxy deployment change is detected, the server shall rebuild the address space without dropping existing OPC UA client connections where possible.
Acceptance Criteria
- When Galaxy Repository detects a deployment change, the OPC UA address space is updated.
- Only changed gobject subtrees are torn down and rebuilt; unchanged nodes, subscriptions, and alarm tracking remain intact.
- Existing OPC UA client sessions are preserved — clients stay connected.
- Subscriptions for tags on unchanged objects continue to work without interruption.
- Subscriptions for tags that no longer exist receive a Bad_NodeIdUnknown status notification.
- Sync is logged at Information level with the number of changed gobjects.
Details
- Uses incremental subtree sync: compares previous hierarchy+attributes with new, identifies changed gobject IDs, expands to include child subtrees, tears down only affected subtrees, and rebuilds them.
- First build (no cached state) performs a full build.
- If no changes are detected, the sync is a no-op (logged and skipped).
- Alarm tracking and MXAccess subscriptions for unchanged objects are not disrupted.
- Falls back to full rebuild behavior if the entire hierarchy changes.
OPC-011: Server Diagnostics Node
The server shall expose a ServerStatus node under the standard OPC UA Server object with ServerState, CurrentTime, and StartTime. This is required by the OPC UA specification for compliant servers.
Acceptance Criteria
- ServerState reports Running during normal operation.
- CurrentTime returns the server's current UTC time.
- StartTime returns the UTC time when the service started.
OPC-012: Namespace Configuration
The server shall register a namespace URI at namespace index 1. All application-specific NodeIds shall use this namespace.
Acceptance Criteria
- Namespace URI:
urn:ZB:LmxOpcUa(Galaxy name is configurable). - All object and variable NodeIds created from Galaxy data use namespace index 1.
- Standard OPC UA nodes remain in namespace 0.
OPC-013: Session Management
The server shall support multiple concurrent OPC UA client sessions.
Acceptance Criteria
- Maximum concurrent sessions: configurable, default 100.
- Session timeout: configurable, default 30 minutes of inactivity.
- Expired sessions are cleaned up and their subscriptions removed.
- Session count is reported to the status dashboard.