Opcua server managing files and structure|OPC UA Standard|Forum|OPC Foundation

Avatar
Search
Forum Scope


Match



Forum Options



Minimum search word length is 3 characters - maximum search word length is 84 characters
Lost password?
sp_Feed sp_PrintTopic sp_TopicIcon
Opcua server managing files and structure
Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
1
05/11/2023 - 04:14
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
2
05/11/2023 - 04:37
sp_Permalink sp_Print

FileType:

https://reference.opcfoundatio.....5/docs/4.2

Start reading at the DataTypeDefinition Attribute:

https://reference.opcfoundatio.....5/docs/5.8

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
3
05/16/2023 - 09:25
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
4
05/17/2023 - 04:02
sp_Permalink sp_Print

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.

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
5
05/17/2023 - 07:12
sp_Permalink sp_Print

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!

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
7
05/18/2023 - 00:06
sp_Permalink sp_Print

Ok thanks,

Now no more exception.

Now it's time to start with the implementation of the struct.... 

Thanks,

Cristian

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
8
05/18/2023 - 00:30
sp_Permalink sp_Print

Thanks,

I really appreciate your help.

Do you have an example of a custom struct implemented on a opcua server? 

Thanks,

Cristian

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
10
05/18/2023 - 09:06
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
11
05/18/2023 - 11:15
sp_Permalink sp_Print

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.

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
12
05/26/2023 - 09:23
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
13
05/27/2023 - 01:17
sp_Permalink sp_Print

You only create a VariableType if you want to expose the fields of Structure as individual Variables in the AddressSpace.

Most DataTypes do not have a matching VariableType.

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
14
05/29/2023 - 03:54
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
15
05/30/2023 - 05:03
sp_Permalink sp_Print

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>
 
Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
16
06/06/2023 - 09:40
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
17
06/06/2023 - 15:17
sp_Permalink sp_Print sp_EditHistory

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:

https://github.com/OPCFoundati.....Manager.cs

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
18
06/20/2023 - 09:01
sp_Permalink sp_Print

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

Avatar
Randy Armstrong
Admin
Forum Posts: 1451
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
19
06/21/2023 - 17:01
sp_Permalink sp_Print

When you write the value you need to set the TypeId in the ExtensionObject to the DataTypeEncodingId.

Avatar
Cristian Denti
Member
Members
Forum Posts: 22
Member Since:
10/29/2021
sp_UserOfflineSmall Offline
20
10/19/2023 - 05:44
sp_Permalink sp_Print

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?

Forum Timezone: America/Phoenix
Most Users Ever Online: 510
Currently Online:
Guest(s) 20
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Forum Stats:
Groups: 2
Forums: 10
Topics: 1349
Posts: 4577