Skip to content

Commit 80889b0

Browse files
koepalexCopilot
andauthored
PumpDeviceIntegrationServer - Register DeviceHealth node, use HasAddIn for SoftwareUpdate (#4008)
This pull request makes important improvements to how the `SoftwareUpdate` object is modeled and registered in the OPC UA Device Integration (DI) server, ensuring better compliance with the OPC 10000-100 specification and improved compatibility with companion-spec checkers. The main changes involve updating the reference type for `SoftwareUpdate` to use `HasAddIn`, explicitly registering the `DeviceHealth` node, and enhancing related tests. **Device Model Compliance and Registration:** * The `SoftwareUpdate` object is now attached to its host device using the `HasAddIn` reference type instead of `HasComponent`, aligning with the OPC 10000-100 specification and reducing validation noise from companion-spec checkers. * The `DeviceHealth` child node is now explicitly registered with the node manager after device registration to ensure its attributes resolve correctly and it can be mapped by companion-spec checkers. **Testing Improvements:** * Added a test assertion to verify that the `SoftwareUpdate` child is attached via the `HasAddIn` reference, ensuring the implementation matches the OPC UA specification.Explicitly register DeviceHealth child node after creation to ensure attributes resolve and DI checker compatibility. Reference SoftwareUpdate facet via HasAddIn per OPC 10000-100 spec, not HasComponent, to avoid validation issues. Update tests to assert correct reference type. # Description _Describe the changes here to communicate to the maintainers why they should accept this pull request. By default - this will become the Commit message after merging and thus define history._ ## Related Issues _Reference all GitHub issues this PR addresses. If there is no issue yet, open one and link it here._ _If this is a relatively large or complex change, a design must have been discussed in the related tracking issue and signed off (which becomes the Architectural Decision Record (ADR))._ - Fixes #github-issue-number, ... ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] 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. - [ ] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [ ] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] 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. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 7d0e587 commit 80889b0

3 files changed

Lines changed: 24 additions & 1 deletion

File tree

Applications/PumpDeviceIntegrationServer/Program.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@
9494
// the simulated supervision flags shared across both pumps).
9595
pump.Device.AddDeviceHealth(ctx.Manager.SystemContext);
9696
pump.WithDeviceHealth(DeviceHealthEnumeration.NORMAL);
97+
98+
// The DeviceHealth child was added to the in-memory DeviceState
99+
// subtree after the device itself was registered, so it must be
100+
// registered with the manager explicitly. Without this the node
101+
// is browsable but its attributes never resolve, so the DI
102+
// companion-spec checker cannot map it to the declared DeviceHealth node.
103+
await ctx.Manager
104+
.AddPredefinedNodeAsync(pump.Device.DeviceHealth!, ctx.CancellationToken)
105+
.ConfigureAwait(false);
106+
97107
((PumpNodeManager)ctx.Manager)
98108
.RegisterSupervisedDeviceHealth(pump.Device.DeviceHealth);
99109

Libraries/Opc.Ua.Di.Server/Builders/SoftwareUpdateFacetWiring.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ public static SoftwareUpdateState BuildAndAttach(
102102
su.BrowseName = new QualifiedName(SoftwareUpdateBrowseName, diNs);
103103
su.DisplayName = new LocalizedText(SoftwareUpdateBrowseName);
104104
su.NodeId = context.NodeIdFactory.New(context, su);
105-
su.ReferenceTypeId = Types.ReferenceTypeIds.HasComponent;
105+
// OPC 10000-100 models the SoftwareUpdate object as an AddIn on
106+
// its host, referenced via HasAddIn (a subtype of HasComponent)
107+
// rather than a plain HasComponent. Using HasAddIn keeps the
108+
// facet spec-correct and lets companion-spec checkers treat it
109+
// as an added-in component instead of validating it against the
110+
// host type's OptionalPlaceholder children (GEN-07 noise).
111+
su.ReferenceTypeId = Types.ReferenceTypeIds.HasAddIn;
106112
su.ModellingRuleId = NodeId.Null;
107113

108114
// Loading subtype (the address-space slot is non-abstract;

Tests/Opc.Ua.Di.Tests/DeviceBuilderSoftwareUpdateTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ public async Task WithSoftwareUpdateAttachesSoftwareUpdateSubtree()
8585
"SoftwareUpdate child must be attached to the device.");
8686
Assert.That(su, Is.TypeOf<SoftwareUpdateState>(),
8787
"SoftwareUpdate child must be a SoftwareUpdateState instance.");
88+
89+
// OPC 10000-100 models the SoftwareUpdate object as an AddIn,
90+
// so it must be referenced from its host via HasAddIn rather
91+
// than a plain HasComponent.
92+
Assert.That(((BaseInstanceState)su!).ReferenceTypeId,
93+
Is.EqualTo(Opc.Ua.Types.ReferenceTypeIds.HasAddIn),
94+
"SoftwareUpdate must be attached via the HasAddIn reference.");
8895
}
8996

9097
[Test]

0 commit comments

Comments
 (0)