如何添加具有子属性的节点并为其设置值?

How to add a node with child properties and set values to them?

我已经根据 OPCFoundation 示例构建了一个 OPC UA 服务器 - https://github.com/OPCFoundation/UA-.NETStandard

还编译了我自己的模型 - https://github.com/Pro/UA-ModelCompiler/tree/eebf9988940a789a4f36cbef8c5bd6340f1b2f42

在示例中,他们在文件夹中生成了文件,然后为 NodeManger、State 等定制了 类。

我已成功加载生成的 .uanodes 文件,其中包含一些示例节点。但是我无法通过服务器端的代码创建这些节点。测试时,我在函数中进行 - LoadPredefinedNodes(ISystemContext context).

我的结构应该是名为 "Tags" 的对象下方的节点,在该节点中我想在服务器为 运行 时动态添加节点并设置它们的属性。

我在测试时使用 Integration Object 的 OPC UA 客户端。

结构看起来正确,例如: 对象 => 标签 => MyTestTag(属性:名称、说明、值)

根据模型文件定义正确添加了前两个属性

    <!-- ### Object Types ###-->

    <!-- BaseType -->
    <ObjectType SymbolicName="TAG:TagType" BaseType="ua:BaseObjectType" IsAbstract="true" SupportsEvents="true" AccessLevel="ReadWrite">
        <Description>Base type for all tags</Description>
        <Children>
            <Property SymbolicName="TAG:Name" DataType="ua:String" ValueRank="Scalar" ModellingRule="Mandatory" AccessLevel="ReadWrite">
                <Description>Name of the tag</Description>
            </Property>
            <Property SymbolicName="TAG:Description" DataType="ua:String" ValueRank="Scalar" ModellingRule="Optional" AccessLevel="ReadWrite">
                <Description>Description of the tag</Description>
            </Property>
        </Children>
    </ObjectType>

    <!-- ### Objects ###-->
    <Object SymbolicName="TAG:Tags" TypeDefinition="ua:BaseObjectType">
        <Description>Contains all instances of tags</Description>
        <References>
            <Reference IsInverse="true">
                <ReferenceType>ua:Organizes</ReferenceType>
                <TargetId>ua:ObjectsFolder</TargetId>
            </Reference>
        </References>
    </Object>

第三个是 属性 我尝试从服务器端的代码定义。我添加了值 属性,但我不知道如何写它的值。

        protected override NodeStateCollection LoadPredefinedNodes(ISystemContext context)
        {
            NodeStateCollection predefinedNodes = new NodeStateCollection();
            predefinedNodes.LoadFromBinaryResource(context, "Opc.Ua.ValmetData.Tag.Tag.PredefinedNodes.uanodes", this.GetType().GetTypeInfo().Assembly, true);

            // The defined ObjectType in the model
            NodeState tageTypeNode = predefinedNodes.Find(x => x.SymbolicName == "TagType");

            // List node to add the tag to
            NodeState tagsNode = predefinedNodes.Find(x => x.SymbolicName == "Tags");

            ushort namespaceIndex = Server.NamespaceUris.GetIndexOrAppend(Namespaces.Tag);


            TagState tagNode = new TagState(tagsNode);
            tagNode.SymbolicName = "MyTestTag";
            tagNode.ClearChangeMasks(context, true);            

            PropertyState ps = new PropertyState(tagNode);
            ps.ClearChangeMasks(context, true);
            ps.NodeId = new NodeId();
            ps.Description = "This is a description";
            ps.TypeDefinitionId = tageTypeNode.NodeId;
            ps.NumericId = 66;
            //  ps.NodeClass = NodeClass.Variable;
            ps.ReferenceTypeId = ReferenceTypeIds.HasProperty;
            ps.BrowseName = new QualifiedName("Value", NamespaceIndex);
            ps.DisplayName = ps.BrowseName.Name;
            ps.DataType = (uint)BuiltInType.Int32;
            // ps.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
            // ps.AccessLevel = AccessLevels.CurrentReadOrWrite;
            ps.Value = 66;

            tagNode.AddChild(ps);

            // assign
            tagNode.Create(
                SystemContext,
                new NodeId(tagNode.SymbolicName, namespaceIndex),
                new QualifiedName(tagNode.SymbolicName, namespaceIndex),
                null,
                true);

            tagsNode.AddChild(tagNode);

            return predefinedNodes;

}

从此代码中,在 Tags 节点中添加了一个名为 MyTestTag 的节点。从模型中添加属性 "Name" 和 "Description"。 "Value" 属性 是由代码添加的。但是,我无法为这些属性中的任何一个设置值。

在客户端中单击 属性 MyTestTag.Value 时,打印错误 "Nullable object must have a value"。

请告诉我哪里做错了。

来自 OPC-UA 的例子有更新变量的代码位,所以我不确定它有什么问题。假设我设置了好的值,代码可能如下所示:

variable.Value = value;
variable.Timestamp = DateTime.UtcNow;
variable.StatusCode = StatusCodes.Good;
variable.ClearChangeMasks(SystemContext, false);

在我的例子中,问题是 nodeId。我变了

ps.NodeId = new NodeId();
// to
ps.NodeId = new NodeId(Guid.NewGuid(), NamespaceIndex);

然后它确实出现在节点树中。