我已经从OPCFoundation示例-https://github.com/OPCFoundation/UA-.NETStandard
中构建了一个OPC UA服务器还使用-编译了我自己的模型 https://github.com/Pro/UA-ModelCompiler/tree/eebf9988940a789a4f36cbef8c5bd6340f1b2f42
在示例中,他们将生成的文件放在文件夹中,然后为NodeManger,State等自定义类。
我已经成功加载了生成的.uanodes文件,其中包含一些示例节点。但是我无法通过服务器端的代码创建这些节点。测试时,我正在使用功能-LoadPredefinedNodes(ISystemContext context)。
我的结构应该是在“标签”对象下的节点,在该节点中,我想动态添加节点并在服务器运行时设置其属性。
我在测试时使用的是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>
第三个是我尝试从服务器端的代码定义的属性。我添加了Value属性,但是我不知道如何写它的值。
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;
}
从此代码中,名为MyTestTag的节点被添加到“标签”节点中。从模型添加属性“名称”和“描述”。并通过代码添加“ Value”属性。但是,我无法为这些属性中的任何一个设置值。
在客户端中单击属性MyTestTag.Value时,将显示错误“可为空的对象必须具有值”。
请告诉我我在做错什么。
答案 0 :(得分:0)
OPC-UA的示例具有用于更新变量的代码位,因此我不确定它有什么问题。假设我设置好的值,代码可能像这样:
variable.Value = value;
variable.Timestamp = DateTime.UtcNow;
variable.StatusCode = StatusCodes.Good;
variable.ClearChangeMasks(SystemContext, false);
答案 1 :(得分:0)
在我的情况下,问题是nodeId。我改变了
ps.NodeId = new NodeId();
// to
ps.NodeId = new NodeId(Guid.NewGuid(), NamespaceIndex);
然后它确实出现在节点树中。