Skip to content

Commit

Permalink
Expanding the address space with nodes of type NodeId and ExpandedNod…
Browse files Browse the repository at this point in the history
…eId (#367)

* * Rename `OpaquePluginNode` to `OpaqueAndNodeIdPluginNode`
* Extend address space with nodes of type NodeId with IdType String, Numeric, Guid and Opaque
* Add tests to read new nodes and check data value

* * Add nodes of type ExpandedNodeId with IdType String, Numeric, Guid and Opaque
  • Loading branch information
koepalex authored Jun 19, 2024
1 parent 2103f74 commit 592443d
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 68 deletions.
174 changes: 174 additions & 0 deletions src/PluginNodes/OpaqueAndNodeIdPluginNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
namespace OpcPlc.PluginNodes;

using Microsoft.Extensions.Logging;
using Opc.Ua;
using OpcPlc.Helpers;
using OpcPlc.PluginNodes.Models;
using System;
using System.Collections.Generic;

/// <summary>
/// Node with an opaque identifier (free-format byte string that might or might not be human interpretable).
/// as well as nodes of type NodeId and ExpandedNodeId with IdType of String, Numeric, Opaque, and Guid.
/// </summary>
public class OpaqueAndNodeIdPluginNode(TimeService timeService, ILogger logger) : PluginNodeBase(timeService, logger), IPluginNodes
{
private PlcNodeManager _plcNodeManager;
private SimulatedVariableNode<uint> _node;

public void AddOptions(Mono.Options.OptionSet optionSet)
{
// on|opaquenode
// Add node with an opaque identifier.
// Enabled by default.
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
{
_plcNodeManager = plcNodeManager;

FolderState folder = _plcNodeManager.CreateFolder(
telemetryFolder,
path: "Special",
name: "Special",
NamespaceType.OpcPlcApplications);

AddNodes(folder);
}

public void StartSimulation()
{
_node.Start(value => value + 1, periodMs: 1000);
}

public void StopSimulation()
{
_node.Stop();
}

private void AddNodes(FolderState folder)
{
BaseDataVariableState variable = _plcNodeManager.CreateBaseVariable(
folder,
path: new byte[] { (byte)'a', (byte)'b', (byte)'c' },
name: "Opaque_abc",
new NodeId((uint)BuiltInType.UInt32),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Constantly increasing value",
NamespaceType.OpcPlcApplications,
defaultValue: (uint)0);

_node = _plcNodeManager.CreateVariableNode<uint>(variable);

BaseDataVariableState stringNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticNodeIdString",
"ScalarStaticNodeIdString",
new NodeId("ScalarStaticNodeIdString", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"String representation of the NodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new NodeId("this is a string node id", 3)
);

BaseDataVariableState numericNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticNodeIdNumeric",
"ScalarStaticNodeIdNumeric",
new NodeId("ScalarStaticNodeIdNumeric", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"UInt32 representation of the NodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new NodeId(42, 3)
);

BaseDataVariableState opaqueNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticNodeIdOpaque",
"ScalarStaticNodeIdOpaque",
new NodeId("ScalarStaticNodeIdOpaque", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Opaque representation of the NodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new NodeId(new byte[] { 0x01, 0x02, 0x03, 0x04 }, 3)
);

BaseDataVariableState guidNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticNodeIdGuid",
"ScalarStaticNodeIdGuid",
new NodeId("ScalarStaticNodeIdGuid", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Guid representation of the NodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new NodeId(Guid.NewGuid(), 3)
);

BaseDataVariableState stringExpandedNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticExpandedNodeIdString",
"ScalarStaticExpandedNodeIdString",
new NodeId("ScalarStaticExpandedNodeIdString", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"String representation of the ExpandedNodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new ExpandedNodeId("this is a string expanded node id", 3, OpcPlc.Namespaces.OpcPlcApplications, 0)
);

BaseDataVariableState numericExpandedNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticExpandedNodeIdNumeric",
"ScalarStaticExpandedNodeIdNumeric",
new NodeId("ScalarStaticExpandedNodeIdNumeric", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Numeric representation of the ExpandedNodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new ExpandedNodeId(444u, 3, OpcPlc.Namespaces.OpcPlcApplications, 0)
);

BaseDataVariableState guidExpandedNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticExpandedNodeIdGuid",
"ScalarStaticExpandedNodeIdGuid",
new NodeId("ScalarStaticExpandedNodeIdGuid", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Guid representation of the ExpandedNodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new ExpandedNodeId(Guid.NewGuid(), 3, OpcPlc.Namespaces.OpcPlcApplications, 0)
);

BaseDataVariableState opaqueExpandedNodeIdVariable = _plcNodeManager.CreateBaseVariable(
folder,
"ScalarStaticExpandedNodeIdOpaque",
"ScalarStaticExpandedNodeIdOpaque",
new NodeId("ScalarStaticExpandedNodeIdOpaque", 3),
ValueRanks.Scalar,
AccessLevels.CurrentReadOrWrite,
"Opaque representation of the ExpandedNodeId",
NamespaceType.OpcPlcApplications,
defaultValue: new ExpandedNodeId(new byte[] { 0xCA, 0xFE}, 3, OpcPlc.Namespaces.OpcPlcApplications, 0)
);

// Add to node list for creation of pn.json.
Nodes = new List<NodeWithIntervals>
{
PluginNodesHelper.GetNodeWithIntervals(variable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(stringNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(numericNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(opaqueNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(guidNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(stringExpandedNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(numericExpandedNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(guidExpandedNodeIdVariable.NodeId, _plcNodeManager),
PluginNodesHelper.GetNodeWithIntervals(opaqueExpandedNodeIdVariable.NodeId, _plcNodeManager),
};
}
}
68 changes: 0 additions & 68 deletions src/PluginNodes/OpaquePluginNode.cs

This file was deleted.

67 changes: 67 additions & 0 deletions tests/OpaqueAndNodeIdTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
namespace OpcPlc.Tests;

using FluentAssertions;
using NUnit.Framework;

/// <summary>
/// Tests NodeIds of various IdTypes and ExpandedNodeIds.
/// </summary>
[TestFixture]
public class OpaqueAndNodeIdTests : SubscriptionTestsBase
{

[Test]
public void TestNodeIdNodes()
{
var specialFolder = FindNode(ObjectsFolder, Namespaces.OpcPlcApplications, "OpcPlc", "Telemetry", "Special");
specialFolder.Should().NotBeNull();

var stringNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticNodeIdString");
stringNodeId.Should().NotBeNull();
var stringNodeIdValue = ReadValue<Opc.Ua.NodeId>(stringNodeId);
stringNodeIdValue.Should().NotBeNull();
stringNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.String);

var numericNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticNodeIdNumeric");
numericNodeId.Should().NotBeNull();
var numericNodeIdValue = ReadValue<Opc.Ua.NodeId>(numericNodeId);
numericNodeIdValue.Should().NotBeNull();
numericNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Numeric);

var guidNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticNodeIdGuid");
guidNodeId.Should().NotBeNull();
var guidNodeIdValue = ReadValue<Opc.Ua.NodeId>(guidNodeId);
guidNodeIdValue.Should().NotBeNull();
guidNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Guid);

var opaqueNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticNodeIdOpaque");
opaqueNodeId.Should().NotBeNull();
var opaqueNodeIdValue = ReadValue<Opc.Ua.NodeId>(opaqueNodeId);
opaqueNodeIdValue.Should().NotBeNull();
opaqueNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Opaque);

var stringExpandedNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticExpandedNodeIdString");
stringExpandedNodeId.Should().NotBeNull();
var stringExpandedNodeIdValue = ReadValue<Opc.Ua.ExpandedNodeId>(stringExpandedNodeId);
stringExpandedNodeIdValue.Should().NotBeNull();
stringExpandedNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.String);

var numericExpandedNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticExpandedNodeIdNumeric");
numericExpandedNodeId.Should().NotBeNull();
var numericExpandedNodeIdValue = ReadValue<Opc.Ua.ExpandedNodeId>(numericExpandedNodeId);
numericExpandedNodeIdValue.Should().NotBeNull();
numericExpandedNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Numeric);

var guidExpandedNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticExpandedNodeIdGuid");
guidExpandedNodeId.Should().NotBeNull();
var guidExpandedNodeIdValue = ReadValue<Opc.Ua.ExpandedNodeId>(guidExpandedNodeId);
guidExpandedNodeIdValue.Should().NotBeNull();
guidExpandedNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Guid);

var opaqueExpandedNodeId = FindNode(specialFolder, Namespaces.OpcPlcApplications, "ScalarStaticExpandedNodeIdOpaque");
opaqueExpandedNodeId.Should().NotBeNull();
var opaqueExpandedNodeIdValue = ReadValue<Opc.Ua.ExpandedNodeId>(opaqueExpandedNodeId);
opaqueExpandedNodeIdValue.Should().NotBeNull();
opaqueExpandedNodeIdValue.IdType.Should().Be(Opc.Ua.IdType.Opaque);
}
}

0 comments on commit 592443d

Please sign in to comment.