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>
114 lines
6.3 KiB
Markdown
114 lines
6.3 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Goal
|
|
|
|
Build an OPC UA server on .NET Framework 4.8 (32-bit) that exposes AVEVA System Platform (Wonderware) Galaxy tags via the MXAccess toolkit. The server mirrors the Galaxy object hierarchy as an OPC UA address space, translating between contained-name browse paths and tag-name runtime references.
|
|
|
|
## Architecture Overview
|
|
|
|
### Data Flow
|
|
|
|
1. **Galaxy Repository DB (ZB)** — SQL Server database holding the deployed object hierarchy and attribute definitions. Queried at startup and on change detection to build/rebuild the OPC UA address space.
|
|
2. **MXAccess COM API** — Runtime data access layer. Subscribes to Galaxy tag attributes for live read/write. Requires a dedicated STA thread with a Win32 message pump for COM callbacks.
|
|
3. **OPC UA Server** — Exposes the hierarchy as browse nodes and attributes as variable nodes. Clients browse via contained names but reads/writes are translated to `tag_name.AttributeName` format for MXAccess.
|
|
|
|
### Key Concept: Contained Name vs Tag Name
|
|
|
|
Galaxy objects have two names:
|
|
- **contained_name** — human-readable name scoped to parent (used for OPC UA browse tree)
|
|
- **tag_name** — globally unique system name (used for MXAccess read/write)
|
|
|
|
Example: browsing `TestMachine_001/DelmiaReceiver/DownloadPath` translates to MXAccess reference `DelmiaReceiver_001.DownloadPath`.
|
|
|
|
See `gr/layout.md` for the full mapping and target OPC UA structure.
|
|
|
|
### Data Type Mapping
|
|
|
|
Galaxy `mx_data_type` values map to OPC UA types (Boolean, Int32, Float, Double, String, DateTime, etc.). Array attributes use ValueRank=1 with ArrayDimensions from the Galaxy attribute definition. Full mapping in `gr/data_type_mapping.md`.
|
|
|
|
### Change Detection
|
|
|
|
Poll `galaxy.time_of_last_deploy` in the ZB database to detect redeployments, then rebuild the address space. See `gr/build_layout_plan.md` for the step-by-step plan.
|
|
|
|
## Reference Implementation
|
|
|
|
An existing MXAccess client implementation is at:
|
|
`C:\Users\dohertj2\Desktop\scadalink-design\lmxproxy\src\ZB.MOM.WW.LmxProxy.Host`
|
|
|
|
Key patterns from that codebase:
|
|
- **StaComThread** — Dedicated STA thread with Win32 message pump (`GetMessage`/`DispatchMessage` loop). All MXAccess COM objects must be created and called on this thread. Uses `PostThreadMessage(WM_APP)` to marshal work items.
|
|
- **LMXProxyServer COM object** — `Register(clientName)` returns a connection handle. `AddItem(handle, address)` + `AdviseSupervisory(handle, itemHandle)` for subscriptions. `OnDataChange`/`OnWriteComplete` events for callbacks.
|
|
- **Reconnect** — Stored subscriptions are replayed after reconnect. A probe tag subscription monitors connection health.
|
|
- **COM cleanup** — `Marshal.ReleaseComObject()` on disconnect. Event handlers must be unwired before unregister.
|
|
|
|
## MXAccess Documentation
|
|
|
|
`mxaccess_documentation.md` in the project root contains the full ArchestrA MXAccess Toolkit User's Guide. Key API: `ArchestrA.MxAccess` namespace, `LMXProxyServer` class. The toolkit DLLs are in `Program Files (x86)\ArchestrA\Framework\bin`.
|
|
|
|
## Galaxy Repository Database
|
|
|
|
Connection: `sqlcmd -S localhost -d ZB -E` (Windows Auth). See `gr/connectioninfo.md`.
|
|
|
|
The `gr/` folder contains:
|
|
- `queries/` — SQL for hierarchy extraction, attribute lookup, and change detection
|
|
- `ddl/tables/` and `ddl/views/` — Schema definitions
|
|
- `schema.md` — Full table/view reference
|
|
- `build_layout_plan.md` — Step-by-step plan for building the OPC UA address space from DB queries
|
|
- `gr/CLAUDE.md` — Detailed guidance for working within the `gr/` subfolder
|
|
|
|
Key tables: `gobject` (hierarchy/deployment), `template_definition` (object categories), `dynamic_attribute` (user-defined attributes), `primitive_instance` (primitive-to-attribute links), `galaxy` (change detection).
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
dotnet restore ZB.MOM.WW.LmxOpcUa.slnx
|
|
dotnet build ZB.MOM.WW.LmxOpcUa.slnx
|
|
dotnet test ZB.MOM.WW.LmxOpcUa.slnx # all tests
|
|
dotnet test tests/ZB.MOM.WW.LmxOpcUa.Tests # unit tests only
|
|
dotnet test tests/ZB.MOM.WW.LmxOpcUa.IntegrationTests # integration tests only
|
|
dotnet test --filter "FullyQualifiedName~MyTestClass.MyMethod" # single test
|
|
```
|
|
|
|
## Build & Runtime Constraints
|
|
|
|
- Language: C#, .NET Framework 4.8, **x86 (32-bit)** platform target — required for MXAccess COM interop
|
|
- MXAccess requires a deployed ArchestrA Platform on the machine running the server
|
|
- COM apartment: MXAccess objects must live on an STA thread with a message pump
|
|
|
|
## Library Preferences
|
|
|
|
- **Logging**: Serilog with rolling daily file sink
|
|
- **Unit tests**: xUnit + Shouldly for assertions
|
|
- **Service hosting**: TopShelf (Windows service install/uninstall/run as console)
|
|
- **OPC UA**: OPC Foundation UA .NET Standard stack (https://github.com/opcfoundation/ua-.netstandard) — NuGet: `OPCFoundation.NetStandard.Opc.Ua.Server`
|
|
|
|
## OPC UA .NET Standard Documentation
|
|
|
|
Use the DeepWiki MCP (`mcp__deepwiki`) to query documentation for the OPC UA .NET Standard stack: `https://deepwiki.com/OPCFoundation/UA-.NETStandard`. Tools: `read_wiki_structure`, `read_wiki_contents`, and `ask_question` with repo `OPCFoundation/UA-.NETStandard`.
|
|
|
|
## Testing
|
|
|
|
Use the dotnet OPC UA CLI tool at `tools/opcuacli-dotnet/` for manual testing against the running OPC UA server. Supports connect, read, write, subscribe, and browse commands. See `tools/opcuacli-dotnet/README.md` for usage details.
|
|
|
|
```bash
|
|
cd tools/opcuacli-dotnet
|
|
dotnet run -- connect -u opc.tcp://localhost:4840
|
|
dotnet run -- browse -u opc.tcp://localhost:4840 -r -d 3
|
|
dotnet run -- read -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode"
|
|
dotnet run -- subscribe -u opc.tcp://localhost:4840 -n "ns=2;s=SomeNode" -i 500
|
|
```
|
|
|
|
### OPC PLC Sample Server
|
|
|
|
A test OPC UA server is available at `tools/opcsampleserver/` (Azure IoT OPC PLC). It generates simulated data nodes (slow, fast, anomaly, GUID) on `opc.tcp://localhost:50000`. Must run from the `publish` directory or use the provided batch scripts. Requires `--unsecuretransport` flag for the CLI tool to connect. See `tools/opcsampleserver/README.md` for full details.
|
|
|
|
```bash
|
|
# Start the test server
|
|
cd tools/opcsampleserver/publish && dotnet opcplc.dll --pn=50000 --autoaccept --unsecuretransport --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint
|
|
|
|
# Or use the batch script
|
|
tools/opcsampleserver/start-server.bat
|
|
```
|