Files
lmxopcua/gr/build_layout_plan.md
Joseph Doherty a7576ffb38 Implement LmxOpcUa server — all 6 phases complete
Full OPC UA server on .NET Framework 4.8 (x86) exposing AVEVA System
Platform Galaxy tags via MXAccess. Mirrors Galaxy object hierarchy as
OPC UA address space, translating contained-name browse paths to
tag-name runtime references.

Components implemented:
- Configuration: AppConfiguration with 4 sections, validator
- Domain: ConnectionState, Quality, Vtq, MxDataTypeMapper, error codes
- MxAccess: StaComThread, MxAccessClient (partial classes), MxProxyAdapter
  using strongly-typed ArchestrA.MxAccess COM interop
- Galaxy Repository: SQL queries (hierarchy, attributes, change detection),
  ChangeDetectionService with auto-rebuild on deploy
- OPC UA Server: LmxNodeManager (CustomNodeManager2), LmxOpcUaServer,
  OpcUaServerHost with programmatic config, SecurityPolicy None
- Status Dashboard: HTTP server with HTML/JSON/health endpoints
- Integration: Full 14-step startup, graceful shutdown, component wiring

175 tests (174 unit + 1 integration), all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 05:55:27 -04:00

3.1 KiB

OPC UA Server Layout — Build Plan

Overview

Extract the Galaxy object hierarchy and tag definitions from the ZB (Galaxy Repository) database to construct an OPC UA server address space. The root node is hardcoded as ZB.

Step 1: Build the Browse Tree

Run queries/hierarchy.sql to get all deployed automation objects and their parent-child relationships.

For each row returned:

  • parent_gobject_id = 0 → child of the root ZB node
  • is_area = 1 → create as an OPC UA folder node (organizational)
  • is_area = 0 → create as an OPC UA object node (container for tags)
  • Use browse_name as the OPC UA BrowseName/DisplayName
  • Store gobject_id and tag_name for attribute lookup and tag reference translation

Build the tree by matching each row's parent_gobject_id to another row's gobject_id. The result is:

ZB (root, hardcoded)
└── DEV (folder, is_area=1)
    ├── DevAppEngine (object)
    ├── DevPlatform (object)
    └── TestArea (folder, is_area=1)
        ├── DevTestObject (object)
        └── TestMachine_001 (object)
            ├── DelmiaReceiver (object, browse_name from contained_name)
            └── MESReceiver (object, browse_name from contained_name)

Step 2: Attach Attributes as Tag Nodes

Run queries/attributes.sql to get all user-defined attributes for deployed objects.

For each attribute row:

  • Match to the browse tree via gobject_id
  • Create an OPC UA variable node under the matching object node
  • Use attribute_name as the BrowseName/DisplayName
  • Use full_tag_reference as the runtime tag path for read/write operations
  • Map mx_data_type to OPC UA built-in types:
mx_data_type Description OPC UA Type
1 Boolean Boolean
2 Integer Int32
3 Float Float
4 Double Double
5 String String
6 Time DateTime
7 ElapsedTime Double (seconds) or Duration
  • If is_array = 1, create the variable as an array with rank 1 and dimension from array_dimension

Step 3: Monitor for Changes

Poll queries/change_detection.sql on a regular interval (e.g., every 30 seconds).

SELECT time_of_last_deploy FROM galaxy;

Compare the returned time_of_last_deploy to the last known value:

  • No change → do nothing
  • Changed → a deployment occurred; re-run Steps 1 and 2 to rebuild the address space

This handles objects being deployed, undeployed, added, or removed.

Connection Details

See connectioninfo.md for database connection parameters and sqlcmd usage.

sqlcmd -S localhost -d ZB -E -Q "YOUR QUERY HERE"

Query Files

File Purpose
queries/hierarchy.sql Deployed object hierarchy with browse names and parent relationships
queries/attributes.sql User-defined attributes with data types and array dimensions
queries/attributes_extended.sql All attributes (system + user-defined) with data types and array dimensions
queries/change_detection.sql Poll galaxy.time_of_last_deploy for deployment changes