Files
UA-.NETStandard/samples/Machinery/README.md
Klaus Landsdorf 01d6b5d26c Machinery: the OPC 40001 companion SDK with Jobs, Result Transfer, Process Values and Energy (#4578)
> Tracking issue #4576. #4577 is merged, so this branch is rebased onto
> `master` and contains only the Machinery commits.

## Summary

Second of four stacked PRs. Adds the OPC UA for Machinery series as
model
packages plus a server and a client SDK, following the companion pattern
of
DI and Robotics, and the two models it depends on that the repository
does
not carry yet.

| Package | Content |
|---|---|
| `Opc.Ua.IA` | OPC 10000-200 IA 1.01.4, **moved out of
`Opc.Ua.Robotics`** (see below) |
| `Opc.Ua.ECM` | OPC 34100 Energy Consumption Management 1.0.1 |
| `Opc.Ua.PADIM` | OPC 30081 PA-DIM 1.02.0 with the IRDI dictionary |
| `Opc.Ua.Machinery` | OPC 40001-1 Basic Building Blocks 1.04.1 |
| `Opc.Ua.Machinery.ProcessValues` | OPC 40001-2 Process Values 1.00.0 |
| `Opc.Ua.Machinery.Jobs` | OPC 40001-3 Job Management 1.0.1 |
| `Opc.Ua.Machinery.Energy` | OPC 40001-4 Energy 1.00 |
| `Opc.Ua.Machinery.Result` | OPC 40001-101 Result Transfer 1.01.0 |
| `Opc.Ua.Machinery.Server` | `AddMachinery()` /
`ConfigureMachinery(...)`, fluent machine builder, server-driven state
machines, process values, job management over the shared ISA-95 V2
binder, energy, result management incl. `GenerateFileForRead` |
| `Opc.Ua.Machinery.Client` | machine discovery, identification, state
observation, process values, job and result access |

OPC 40001-101 `ResultTransferType` redeclares `GenerateFileForRead` with
its
own arguments; the generator fix for such overrides, merged with #4577,
is
what makes it appear on the `ResultTransfer` instances.

All NodeSets are byte-identical to `UA-Nodeset/latest`. Each model
carries a
pinned `Model/*.NodeIds.csv` the generator validates, next to the
unmodified
upstream table; `tools/nodesets/derive-identifier-table.py` derives the
former from the latter.

## Changes to existing code

- **IA moves out of Robotics.** Machinery needs IA as well (OPC 40001-1
types
`Stacklight` with `BasicStacklightType`), and two assemblies generating
the
same model under the same prefix collide at any consumer referencing
both.
The NodeSet moves verbatim, so no generated type changes; the prefix
stays
`Opc.Ua.IA`. Source-compatible, but IA types now live in `Opc.Ua.IA.dll`
rather than `Opc.Ua.Robotics.dll` — binary-breaking for consumers of the
  Robotics package.
- **`samples/OpenUsd/GeneratorServer`** drops its hand-reduced Machinery
  NodeSet copy and the script that produced it (a workaround for the
generator defect fixed by #4577) and references `Opc.Ua.Machinery`
instead.
- `README.md` and `docs/README.md` list the new models; the README also
  corrects the Industrial Automation entry (Part 200, not OPC 40001-1).

## Review follow-ups

Separate commits after the docs/samples commit, so the reviewed state
stays
comparable. Each fix comes with a test that fails without it.

- Copilot review: a transition is committed only while the state machine
is
still in its source state; optional Jobs/Result namespaces the server
does
not load are reported as absent, as documented; resources of registered
machines (result transfer, job-management change pumps) are released
with
  the node manager (`DisposeMachineryResourcesAsync` for a custom DI
  manager); `NodeId`/`LocalizedText` use their null sentinels instead of
  `Nullable<T>`.
- Own review with the rubric in `.github/copilot-instructions.md`: a
failed
browse call propagates from the client instead of reading as "no
children";
  the predefined result metadata compares `CreationTime` against the
  `DateTimeUtc` sentinels (the `DateTime` conversion shifted
  `DateTime.MaxValue` by the host's UTC offset); process values below
`Monitoring` are found; a second metering point named `Main` is
rejected;
  the zero-point event is reported when the handler throws; smaller
  state-sharing and documentation corrections.

## Testing

- `tests/Opc.Ua.Machinery.Tests`: 162 tests on net8 and net10 and with
the
netstandard2.1 libraries; the integration tests connect a real client
session over `opc.tcp` to a hosted
  server.
- With IA extracted: Robotics 636, OpenUsd 921, DI 433 and
SourceGeneration
  263 tests pass.
- `UA.slnx` builds for net472, net48, netstandard2.0/2.1 and net8/9/10
with
  SDK 10.0.401 and no warnings.
- Changed-line coverage of this layer (`check-coverage.ps1`): 91.68 %
(6059 of 6609 changed lines, against `master`).
- Fork CI, full PR matrix incl. macOS, on the current master: green, all
184
jobs ([run
36582685653](https://github.com/biancode/UA-.NETStandard/actions/runs/36582685653)).
CodeQL: green ([run
36582689589](https://github.com/biancode/UA-.NETStandard/actions/runs/36582689589)).
- Beyond the in-repo tests the implementation has been validated end to
end
  against a separate, non-public OPC UA client and server.

## Reviewing

Commits are ordered so each builds: IA extraction → identifier-table
tool →
ECM/PA-DIM → Machinery models → server → client → tests → docs/samples →
GeneratorServer sample → review follow-ups. The model commits are large
only because of the
NodeSets and identifier tables; the hand-written code starts at the
server
commit.

---------

Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
2026-09-29 19:59:34 +02:00

3.0 KiB

OPC 40001 Machinery samples

Two console applications that show the whole OPC 40001 series end to end.

Sample What it does
MachineryServer Serves one simulated hydraulic press with every part of the series
MachineryClient Walks the Machines folder, prints what it finds, downloads a result and streams state

Run them in two terminals:

dotnet run --project samples/Machinery/MachineryServer -- --port 62546
dotnet run --project samples/Machinery/MachineryClient -- --insecure

The client prints something like:

Machine 12:HydraPress-1 (ns=12;i=1)
  Acme Machine Tools HydraPress 500 — serial HP500-2024-0001
  location: Hall 3 / Line 2
  state: Executing / mode: Processing
  component 12:HydraulicUnit
  building block 13:Identification
  building block 3:MachineryEquipment
  building block 8:JobManagement
  building block 3:Monitoring
  building block 3:MachineryItemState
  building block 3:Notifications
  building block 13:OperationCounters
  building block 3:MachineryOperationMode
  building block 3:Components
  device health: NORMAL
  operation counters: power-on 12480.0 h, operating 9215.5 h
  equipment UpperDie (urn:acme-machine-tools.example:equipment:die)
    life: 118400 of 250000 left
  process value HydraulicOilTemperature: 44.0 °C (setpoint 45.0, 45.7 % of range)
    limits: 5.0 / 15.0 / 65.0 / 80.0
  energy CompressedAir: Main = HydraPress-1/CompressedAir
    NeEnergyImportHp = 0
    NeEnergyExportHp = 0
    Volume = 184320
    VolumeFlowRate = 18.4
    Pressure = 620000
    Temperature = 294.65
  energy Electricity: Main = HydraPress-1/Electricity
    AcActivePowerTotal = 41250
Latest result: stroke-000019
  downloaded 42 bytes:
  resultId,stroke-000019
  peakForceKN,4703.6
Observing MachineryItemState for 4s (OPC 40001-1 state changes always come from the server) …
  22:33:52  -> Executing (via FromNotExecutingToExecuting)
  22:33:52  -> NotExecuting (via FromExecutingToNotExecuting)

The namespace indices above are whatever the server happened to assign; only the browse names are stable. 2:Identification and 2:OperationCounters show up as 13: because OPC 40001-1 gives both the Device Integration namespace — see Default instance browse names are load-bearing.

The building blocks come from the OPC 40001-1 MachineryBuildingBlocks organizer, which is the one place a client can discover what a machine supports instead of probing for each block in turn. The oil temperature walks a slow ramp across the datasheet limits, so the exclusive limit alarm on the process value activates and clears while the sample runs; subscribe to HydraulicOilTemperature to watch it.

What the sample does not need a second terminal for is the same walk as an automated test: MachineryEndToEndTests runs this server and this client over opc.tcp inside the test suite.

See the Machinery developer guide.