10/29/2021
Dear OPCUA,
I have a request for creating a custom structure in the server address space.
Something like:
Struct
{
string x1;
string x2;
int32 y1;
datetime z1;
}
Do you have an example of code?
Another request is for exchanging files. I see that there is a FileState Variable to be used. But i Think I need to create the Method for opening reading, closing and writing.
Do you have an example?
Many thanks,
Cristian
05/30/2017
FileType:
https://reference.opcfoundatio.....5/docs/4.2
Start reading at the DataTypeDefinition Attribute:
10/29/2021
Ok thanks,
It helped a lot.
For the file, I add the file with the following code:
private NodeState AddFile(ISystemContext a_Context, string a_NodeId, string a_BrowseName, NodeState a_tagNode, bool a_Writable)
{
//Create a variable
FileState fs = new FileState(a_tagNode);
fs.ClearChangeMasks(a_Context, true);
fs.NodeId = new NodeId(a_NodeId, NamespaceIndex);
fs.BrowseName = new QualifiedName(a_BrowseName, NamespaceIndex);
fs.DisplayName = fs.BrowseName.Name;
fs.Description = a_BrowseName;
fs.WriteMask = AttributeWriteMask.None;
fs.UserWriteMask = AttributeWriteMask.None;
fs.ReferenceTypeId = ReferenceTypeIds.HasProperty;
PropertyState<bool> Wr = new PropertyState<bool>(fs);
Wr.Value = a_Writable;
fs.Writable = Wr;
fs.UserWritable = Wr;
PropertyState<ulong> Size = new PropertyState<ulong>(fs);
Size.Value = 100;
fs.Size = Size;
fs.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; // new NodeId("String");
fs.ReferenceTypeId = ReferenceTypes.Organizes;
//Add the methods
fs.Open = new OpenMethodState(fs);
fs.Open.OnCall += OnOpenFileEvent;
fs.Read = new ReadMethodState(fs);
fs.Read.OnCall += OnReadFileCall;
fs.Close = new CloseMethodState(fs);
fs.Close.OnCall += OnCloseFileCall;
fs.Write = new WriteMethodState(fs);
fs.Write.OnCall += OnWriteFileEventCall;
fs.GetPosition = new GetPositionMethodState(fs);
fs.GetPosition.OnCall += OnGetPositionEventCall;
fs.SetPosition = new SetPositionMethodState(fs);
fs.SetPosition.OnCall += OnSetPositionEventCall;
a_tagNode.AddReference(ReferenceTypeIds.Organizes, false, fs.NodeId);
fs.AddReference(ReferenceTypeIds.Organizes, true, a_tagNode.NodeId);
a_tagNode.AddChild(fs);
AddPredefinedNode(a_Context, fs);
return fs;
}
But once I call AddPredefinedNode(a_Context, fs) (near the end of the method) an exception is risen.
SystemArgumentNullException: Value cannot be null.
Parameter name: key
at Opc.Ua.NodeIdDictionary'1.set_Item(NodeId key, T value)
at Opc.Ua.Server.CustomNodeManager2.AddPredefinedNode(ISystemContext context, NodeState node)
at Opc.Ua.Server.CustomNodeManager2.AddPredefinedNode(ISystemContext context, NodeState node)
at....
Did I forgot to set any property of FileState? Why NodeId in set_Item is null? The NodeId of the file should be correctly set
10/29/2021
Randy Armstrong said
I would have go through at look at the code examples to be sure but the process should be something like:1) Create an ObjectState
2) Add optional children;
3) Call Create to instantiate the hierarchy.
I don't see a call to Create.
Which is the function that lack written in the third point?
Something similar I used with variables, method, folder, object and seems to work well... But probably I miss something!
10/29/2021
Thanks,
One question. In the example provided, where are the struct created? In which source file?
I can see that in the file
Quickstarts.DataTypes.Instances.PredefinedNodes.xml
there are a lot of structure, but once compiled whith the compiler provided I think that it is the file .uanodes which is created whit this built-in structures.
But what I want, is to create the structures using the code at start-up during the execution (I must release a library which can't be recompiled every time the structure is changed).
I think that there is a DataTypeState and a BaseDataVariableTypeState that should be used to create structure if i'm not wrong.... But i'm trying to understand how to add the childs (the string, int, ....) to fill the structure into DataTypeState.
Cristian
05/30/2017
The DataTypeState represents a DataType Node - not a Structure.
The DataTypeDefinition Atttribute of the DataType Node describes the Structure as a sequences of Name-Value pairs.
You do not need to have a C# class in the server to represent the Structure. You could keep everything in a Dictionary but you would have to manually serialize/deserialize the values as part of an Read/Write operation.
IN the example, the actual structions are generated from a ModelDesign file. The generated file is here:Quickstarts.DataTypes.Instances.DataTypes.cs
https://github.com/OPCFoundati...../Instances
The uanodes file only defines DataType Node.
10/29/2021
One question.
I have defined the structure in the datatype that I have called SingleEvent.
It can be seen using a commercial client free (uaexpert) in Root-->Types->DataTypes->BaseDataType-->Structure->Single Event
Do I have to create even a variable type or it isn't necessary?
Thanks,
Cristian
10/29/2021
Hello,
one question more.
I have created the XML file with the model of the data to be used.
<opc:DataType SymbolicName="SingleEvent" BaseType="ua:Structure">
<opc:Description>Generic event in the array</opc:Description>
<opc:Fields>
<opc:Field Name="Component" DataType="ua:String"/>
<opc:Field Name="Identifier" DataType="ua:String"/>
<opc:Field Name="TimeStamp" DataType="ua:DateTime"/>
<opc:Field Name="System" DataType="ua:UInt32"/>
</opc:Fields>
</opc:DataType>
<opc:ObjectType SymbolicName="OPCUAServerType" BaseType="ua:BaseObjectType" SupportsEvents="true">
<opc:Description>A production machine.</opc:Description>
<opc:Children>
<opc:Object SymbolicName="Machine" TypeDefinition="MachineType" SupportsEvents="true">
<opc:BrowseName>Machine</opc:BrowseName>
</opc:Object>
<opc:Variable SymbolicName="Event" DataType="SingleEvent" AccessLevel="ReadWrite"></opc:Variable>
</opc:Children>
</opc:ObjectType>
<opc:Object SymbolicName="OPCUAServerVar" TypeDefinition="OPCUAServerType" SupportsEvents="true">
<opc:BrowseName>Line</opc:BrowseName>
<opc:References>
<opc:Reference IsInverse="true">
<opc:ReferenceType>ua:Organizes</opc:ReferenceType>
<opc:TargetId>ua:ObjectsFolder</opc:TargetId>
</opc:Reference>
</opc:References>
</opc:Object>
After compiling (using the model compiler program) I create the various files to be inserted in my program.
(OPCUAServer.Classes.cs, OPCUAServer.Constants.cs OPCUAServer.DataType.cs, ....)
After launching the program, I can see (using the commercial client) the DataType SingleEvent structure (Types->DataTypes->BaseDataType->Structure->SingleEvent) whose DatatypeDefinition has Fields considered as a structure field array with the field name and type correctly set.
The variable Event (Root->Objects->Line->Event) exist, has a dataType SingleEvent but the Value.Value is Null, while Value.StatusCode is Good so the client can't write anything.
Why?
The other property of the Variable Event are:
Event.DataType=SingleEvent
Event.ValueRank = -1;
Event.ArrayDimension = Null;
Event.AccessLevel = CurrentRead, CurrentWrite;
Historizing = false;
.
.
.
Thanks,
Cristian
05/30/2017
The ModelCompiler generates static code. If you want live data then you need to write code to populate it.
You can specify a default value in the ModelDesign.
<opc:Property SymbolicName="EngineeringUnits" DataType="EUInformation" ModellingRule="Mandatory"> <opc:DefaultValue> <uax:ExtensionObject> <uax:TypeId> <uax:Identifier>i=888</uax:Identifier> </uax:TypeId> <uax:Body> <uax:EUInformation> <uax:NamespaceUri>http://www.opcfoundation.org/UA/units/un/cefact</uax:NamespaceUri> <uax:UnitId>4337968</uax:UnitId> <uax:DisplayName> <uax:Locale>en</uax:Locale> <uax:Text>bit/s</uax:Text> </uax:DisplayName> <uax:Description> <uax:Locale>en</uax:Locale> <uax:Text>bit per second</uax:Text> </uax:Description> </uax:EUInformation> </uax:Body> </uax:ExtensionObject> </opc:DefaultValue> </opc:Property>
10/29/2021
Hello Randy,
I have created the structures using Model compiler and even some variables.
One problem I have, is that if the client activate a subscription monitoring a variable created with Model compiler, it seems that if I change the value of the variable (it isn't important if it's a structure or not), the notification of the change doesn't arrive to the client (from the server the subscription seems active).
<opc:ObjectType SymbolicName="MachineType" BaseType="ua:FolderType">
<opc:Children>
<opc:Variable SymbolicName="MachineId" DataType="ua:String" ValueRank="Scalar" TypeDefinition="ua:AnalogItemType" AccessLevel="ReadWrite">
<opc:BrowseName>MachineId</opc:BrowseName>
<opc:DisplayName>MachineId</opc:DisplayName>
</opc:Variable>
</opc:Children>
</opc:ObjectType>
The variable i'm monitoring is the one with SymbolicName:"MachineId"
Thanks,
Cristian
05/30/2017
The NET Server codebase maintains a copy of nodes loaded from the uanodes file.
If you change the value of the a variable you have to update that copy in memory.
When a client subscribes it species a sampling interval which should mean the server code polls the variable value at that rate.
There are also ChangeMasks that tell the server code when the value has changed.
See DoSimulation:
10/29/2021
Many thanks,
one last question.
The structure is seen from the client, the subscription I think is working (but with UaExpert the content is visible in the access view only opening a pop up and it seems that the content of the structured variables is updated only closing and opening again the popup) but I think is right since initially, when the subscription didn't work, even opening and closing the popup the values weren't updated.
Only one problem remains. If I read the value of a structured node that hasn't been changed by the client i can see the value. The Server can change the value any time and it work well, but if the client change the value of the structured variable it appears as if the content begins with "Byte[33]". It seems like if the serialization of data hasn't worked, but maybe it's something I did wrong in the code...
Cristian
10/29/2021
Hello,
another question.
I was able to create array of standard object. I neeld only to set
variable.ValueRank = ValueRanks.OneDimension, and
variable.value =TypeInfo.CreateArray(type of variable, array number);
After I have created the structure type (singleEvent) in the .uanodes file.
Then I was able to create many variables in real time of the type singleEvent by using:
BaseDataVariableState<OPCUAServer.SingleEvent> EventN = new BaseDataVariableState<OPCUAServer.SingleEvent> (...);
Now a customer ask me to create an array of structure <OPCUAServer.SingleEvent>, so that there is a single NodeID fo the whole structure.
I would like to create such array in real time (while executing the code) if possible, so that changing the array size is easier.
Can you explain how to do it?
1 Guest(s)