mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-23 10:23:13 +08:00
a6a5275006
# Description The `PumpDeviceIntegrationServer` sample simulates OPC 40223 pumps but had no product documentation, a thin nameplate, and a duty point that was not physically self-consistent. This PR gives the sample an **official-style product datasheet** for its simulated asset and aligns the server to it, so the document and the running address space cannot drift apart. ### New: `samples/PumpDeviceIntegrationServer/DATASHEET.md` A vendor-style datasheet for the fictitious *SimPump Corp PumpX-2000* (clearly marked as a simulated device): - Nameplate table mapped to OPC UA browse paths **and namespaces** (DI / Machinery / Pumps) - Best-efficiency duty point, characteristic curves and a performance table - Operating limits, motor / materials / dimensions data - Instrument list (tag → browse path → unit → `EURange`) and a Mermaid process schematic - Alarm trip points and the deterministic simulation profile ### Server aligned to the datasheet - `PumpDatasheet.cs` — the datasheet expressed as compile-time constants. - `MaterialiseNameplate` — materialises the 19 optional identification properties through the generator-emitted `AddXxx(context)` helpers, so each carries the browse name, namespace and DataType declared by the model (21 nameplate fields in total per pump). - `WithIdentification` now assigns the full datasheet nameplate to **every** simulated unit. Product-level fields are shared; unit-level fields (`SerialNumber`, `AssetId`, `ComponentName`, `Location`, `FabricationNumber`) are derived from the pump number, so `--pumps N` yields a consistent nameplate for each instance. - **Simulation rebuilt around the datasheet curves.** Volumetric flow is the only independent variable; differential pressure, mass flow, efficiency and shaft power are derived from `H(Q) = 32 − 0.0104·Q²`, `η(Q) = 72·(1 − 0.6·((Q−25)/25)²)` and `P = ρ·g·Q·H/η`, so `P = Δp·Q/η` holds at every tick. Previously every measurement was an independent sine and the sample published 5 kW of shaft power for 0.05 kg/s at 2 bar Δp. - `EURange` values now come from the datasheet; `OverTempAlarm` reports the `BearingTemperature` chain (the correct `SourceNode` for an alarm whose limits are in Kelvin) rather than a boolean; `Cavitation` and `MotorOverheat` are derived from suction level and bearing temperature with hysteresis instead of `tick % n`. ### Diagrams The sample README gains a simulated-device summary, a link to the datasheet, and three Mermaid diagrams: **address space**, **startup / hosting sequence**, and **simulation + alarm dataflow**. ### Drift protection `PumpDatasheetConformanceTests` pins the nameplate, engineering ranges, trip points, published-value envelope and hydraulic consistency against the datasheet, and the exact pump node-surface baseline in `PumpInstanceNodeIdRegressionTests` covers the new identification properties. No changes to `src/` — this is sample, test and documentation only. ### Rebased on #4117 master has been merged into this branch. #4117 reshaped the same sample (loop-based pump creation via `--pumps N`, `Pump_1` / `Pump_2` BrowseNames with `Pump #n` DisplayNames, historian wiring, `WireBoolean`, per-pump `Diagnostics` group). Both intents are preserved: - the datasheet nameplate is applied through upstream's per-pump `WithIdentification(builder, pump, pumpNumber)` hook, so it scales to `--pumps N`; - `Program.cs` is left exactly as upstream has it — identification is configured centrally, so the old per-pump block there is gone; - the datasheet curve values are published through upstream's status-code / source-timestamp plumbing, and upstream's `WireBoolean` (TrueState/FalseState text + history) is kept; - the node-surface baseline is the union of both identification lists; - `docs/SourceGeneratedNodeManagers.md` was consolidated upstream into `docs/NodeManagers.md`, so the snippet fixes were ported there. ## Related Issues _No tracking issue; this is a documentation and sample-quality improvement to the pump reference sample._ ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. ### Verification (post-merge) - `dotnet build samples/PumpDeviceIntegrationServer` (net10.0): 0 warnings, 0 errors - `dotnet build tests/Opc.Ua.Di.Tests` (net10.0): 0 warnings, 0 errors - `dotnet test tests/Opc.Ua.Di.Tests -f net10.0`: **331/331 passed** (includes upstream's new `PumpAddressSpaceComplianceTests` and `DiConformanceFacetTests`) - `dotnet test tests/Opc.Ua.Di.Tests -f net48 --filter Pump`: **44/44 passed** - Live client read against the merged sample: Δp 214 079 Pa, ṁ 8.654 kg/s, η 69.33 %, P 2 677.4 W — `Δp·(ṁ/ρ)/η` matches the published shaft power; `Pump_1` reads SN-001 / PMP-1001 / Feed Pump A / Bay 3 and `Pump_2` reads SN-002 / PMP-1002 / Feed Pump B / Bay 4, exactly as documented. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fe608993-f3c9-4779-a6b9-9a9eabfc24ba
69 lines
3.7 KiB
XML
69 lines
3.7 KiB
XML
<Project Sdk="Microsoft.NET.Sdk">
|
|
<PropertyGroup>
|
|
<TargetFrameworks>$(AppTargetFrameworks)</TargetFrameworks>
|
|
<OutputType>Exe</OutputType>
|
|
<IsPackable>false</IsPackable>
|
|
<AssemblyName>PumpDeviceIntegrationServer</AssemblyName>
|
|
<PackageId>PumpDeviceIntegrationServer</PackageId>
|
|
<Description>Self-contained .NET console OPC UA server demonstrating the OPC 40223 Pumps companion specification end-to-end, including full simulation and additive OPC 10000-100 topology-element builder integration.</Description>
|
|
<RootNamespace>Pumps</RootNamespace>
|
|
<Nullable>enable</Nullable>
|
|
<IsPackable>false</IsPackable>
|
|
<NoWarn>$(NoWarn);CA1822</NoWarn>
|
|
<PublishAot Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))">true</PublishAot>
|
|
</PropertyGroup>
|
|
<ItemGroup>
|
|
<ProjectReference Include="..\..\src\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
|
|
<ProjectReference Include="..\..\src\Opc.Ua.Server\Opc.Ua.Server.csproj" />
|
|
<ProjectReference Include="..\..\src\Opc.Ua.Di\Opc.Ua.Di.csproj" />
|
|
<ProjectReference Include="..\..\src\Opc.Ua.Di.Server\Opc.Ua.Di.Server.csproj" />
|
|
<ProjectReference Include="..\..\src\Opc.Ua.OpenUsd\Opc.Ua.OpenUsd.csproj" />
|
|
<ProjectReference Include="..\..\src\Opc.Ua.OpenUsd.Server\Opc.Ua.OpenUsd.Server.csproj" />
|
|
</ItemGroup>
|
|
<ItemGroup>
|
|
<ProjectReference Include="..\..\tools\Opc.Ua.SourceGeneration\Opc.Ua.SourceGeneration.csproj">
|
|
<OutputItemType>Analyzer</OutputItemType>
|
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
|
</ProjectReference>
|
|
</ItemGroup>
|
|
<ItemGroup>
|
|
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
|
</ItemGroup>
|
|
<!-- Artist-authored USD layers embedded so the server ships (and serves) its own
|
|
twin geometry: Plant.usda (RootLayer) + pump.usda (Reference). -->
|
|
<ItemGroup>
|
|
<EmbeddedResource Include="Assets\Plant.usda"><LogicalName>Plant.usda</LogicalName></EmbeddedResource>
|
|
<EmbeddedResource Include="Assets\pump.usda"><LogicalName>pump.usda</LogicalName></EmbeddedResource>
|
|
</ItemGroup>
|
|
<!-- Machinery + Pumps NodeSet2 XMLs are source-generated locally;
|
|
no library refs needed. The generator emits typed classes,
|
|
NodeId tables, and AddOpcUaMachinery / AddOpcUaPumps extension
|
|
methods in the Opc.Ua.Machinery and Opc.Ua.Pumps namespaces
|
|
(internal to this assembly). Cross-namespace type references
|
|
to DI types resolve via the [assembly: ModelDependencyAttribute]
|
|
carried in the Opc.Ua.Di assembly — no DI NodeSet2 XML
|
|
needed here.
|
|
|
|
The matching *.NodeSet2.csv files (alongside the XML) are
|
|
picked up by the source generator as the stable NodeId tables.
|
|
Without them the generator would assign synthetic NodeIds at
|
|
compile time, breaking byte-stable wire formats for clients
|
|
that cache NodeIds across builds. -->
|
|
<ItemGroup>
|
|
<AdditionalFiles Include="Model\Opc.Ua.Machinery.NodeSet2.xml">
|
|
<ModelSourceGeneratorPrefix>Opc.Ua.Machinery</ModelSourceGeneratorPrefix>
|
|
</AdditionalFiles>
|
|
<AdditionalFiles Include="Model\Opc.Ua.Machinery.NodeSet2.csv" />
|
|
<AdditionalFiles Include="Model\Opc.Ua.Pumps.NodeSet2.xml">
|
|
<ModelSourceGeneratorPrefix>Opc.Ua.Pumps</ModelSourceGeneratorPrefix>
|
|
</AdditionalFiles>
|
|
<AdditionalFiles Include="Model\Opc.Ua.Pumps.NodeSet2.csv" />
|
|
</ItemGroup>
|
|
<Import Project="..\..\tools\Opc.Ua.SourceGeneration\OPCFoundation.Opc.Ua.SourceGeneration.props" />
|
|
<PropertyGroup>
|
|
<ModelSourceGeneratorVersion>v105</ModelSourceGeneratorVersion>
|
|
<ModelSourceGeneratorUseAllowSubtypes>true</ModelSourceGeneratorUseAllowSubtypes>
|
|
</PropertyGroup>
|
|
</Project>
|