- Posts: 7
- Thank you received: 0
Online Forums
Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.
Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.
Do not use the Contact page for technical issues.
- Forum
- Discussions
- QuickOPC-UA in .NET
- Reading, Writing, Subscriptions
- How to create and write a simple complex type
How to create and write a simple complex type
A colleague showed me that specifying the type was not necessary. It was probably the fact that I specified the wrong type that got me in trouble.
Please Log in or Create an account to join the conversation.
Some notes:
1. Constructing the DataType (I mean your "myStructuredDataType") and passing it into Write is optional. You can try creating the myStructuredData without myStructuredDataType, and things should work the same. The DataType, when given, allows an initial validation of the GenericData.
2. The fact that it is often needed to specify TypeCode or Type when writing numbers (because a precise built-in type needs to be send to OPC UA server but that mioght not be the same type as in the application) should not confuse you into thinking that such steps are necessary with complex data types. You can simply omit the Type/TypeCode argument to WriteValue.
3. In situations where you need to specify the Type or TypeCode (e.g. you need to specify the types of arguments for CallMethod because you need that UInt16 there), I recommend you use TypeCode.Empty for complex data types.
Best regards
Please Log in or Create an account to join the conversation.
First, the string that describes the type of the variable had to be correct in both the constructor for myStructured Data and myGenericData (obviously ) . As you showed us, the correct type string was confirmed by examining the variable after we read it. We previously tried that correct type string many times, but without the second necessary change.
With the correct string we received an exception saying:
Exception thrown: 'OpcLabs.EasyOpc.UA.OperationModel.UAException' in OpcLabs.EasyOpcUA.dll
*** Failure: Object must implement IConvertible.
+ Attempting to change an object of type "OpcLabs.EasyOpc.UA.UAExtensionObject" to type "OpcLabs.BaseLib.DataTypeModel.StructuredDataType".
+ The client method called was 'WriteMultiple'.
from:
client.WriteValue(endpointDescriptor, nodeDescriptor, myGenericData, typeof(StructuredDataType));
client.WriteValue(endpointDescriptor, nodeDescriptor, myGenericData, typeof(UAGenericObject));
It was easy to incorrectly assume that the type problem was a single issue associated just with the node descriptor string because we had tried the correct string so many times unsuccessfully. It was the second problem with the argument in typeof() that finally fixed it.
Unfortunately, we are now struggling with passing exactly the same object to a method call immediately after the successful write using the following additional snippet after the WriteValue in succession. The method call fails though using the same data, and endpoint used one line before. We are troubleshooting. We've tried TypeCode.Object and TypeCode.Empty and also not using TypeCodes at all, but get various exceptions. If we do the same method call approach with a double, instead of the complex object it works fine.
object[] inputs =
{
myGenericData,
0
};
TypeCode[] typeCodes =
{
TypeCode.Object,
TypeCode.UInt16
};
object[] outputs;
outputs = client.CallMethod(
endpointDescriptor,
"ns=4;s=OpcCommunication.OpcEffectLinear[1]",
"ns=4;s=OpcCommunication.OpcEffectLinear[1]#MoveAbsolute",
inputs,
typeCodes);
Strangely, the inner exception seems to say there is no valid endpoint, which seems odd because it was used the moment before in WriteValue()
Exception thrown: 'OpcLabs.EasyOpc.UA.OperationModel.UAException' in OpcLabs.EasyOpcUA.dll
*** Failure: Invalid opc.tcp endpoint URL ("opc.tcp:/"): The Host must not be empty.
+ The client method called was 'CallMultipleMethods'.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Although this is not its final form, this code allowed us to construct a variable and successfully write it. In case this is any help to others.
var myStructuredDataType = new StructuredDataType(
"ST_OpcMoveAbsoluteData",
"nsu=urn:BeckhoffAutomation:Ua:PLC1 ;ns=4;s=<StructuredDataType>:ST_OpcMoveAbsoluteData")
{
new DataField("fTarget", UAOpcBinaryStandardDataTypes.Double),
new DataField("fVelocity", UAOpcBinaryStandardDataTypes.Double),
new DataField("fAccel", UAOpcBinaryStandardDataTypes.Double),
new DataField("fDecel", UAOpcBinaryStandardDataTypes.Double),
new DataField("fDelay", UAOpcBinaryStandardDataTypes.Double)
};
var myStructuredData = new StructuredData(myStructuredDataType);
// previously used myStucturedData.Add(). It worked. But below is more
// appropriate as the type definition above appears to create those fields.
myStructuredData.FieldData["fTarget"] = new PrimitiveData(111d);
myStructuredData.FieldData["fVelocity"] = new PrimitiveData(22d);
myStructuredData.FieldData["fAccel"] = new PrimitiveData(33d);
myStructuredData.FieldData["fDecel"] = new PrimitiveData(33d);
myStructuredData.FieldData["fDelay"] = new PrimitiveData(4d);
var myGenericData = new UAGenericObject(
myStructuredData,
new UAModelNodeDescriptor(
endpointDescriptor,
"nsu=urn:BeckhoffAutomation:Ua:PLC1 ;ns=4;s=<StructuredDataType>:ST_OpcMoveAbsoluteData"));
client.WriteValue(endpointDescriptor, nodeDescriptor, myGenericData, typeof(UAGenericObject));
The successful write was verified in the PLC.
Please Log in or Create an account to join the conversation.
Yes, we were able to read the variable and immediately write it back again unchanged without error.
The value of UAGenericObject.DataTypeId.NodeDescriptor.NodeId.ExpandedText after reading the variable was :
"nsu=urn:BeckhoffAutomation:Ua:PLC1 ;ns=4;s=<StructuredDataType>:ST_OpcMoveAbsoluteData"
If I use that value in the constructor for a new structured variable, we still get the type exception. We are continuing to troubleshoot.
Thanks,
Rick
Please Log in or Create an account to join the conversation.
I suspect (the same as you) that the problem can be in the improper DataTypeId in the UAGenericObject you pass to WriteValue.
Some questions:
1. Are you able to write back directly what you have read? Take the whole UAGenericObject you receive from ReadValue, and pass it to WriteValue?
2. What is the contents of UAGenericObject.DataTypeId.NodeDescriptor.NodeId.ExpandedText you get from ReadValue?
Kind regards
Please Log in or Create an account to join the conversation.
The PLC is Beckhoff with the Beckhoff OPC Server. The simple type is shown below.
{attribute 'OPC.UA.DA.StructuredType' := '1'}
TYPE ST_OpcMoveAbsoluteData :
STRUCT
fTarget : LREAL;
fVelocity : LREAL;
fAccel : LREAL;
fDecel : LREAL;
fDelay : LREAL;
END_STRUCT
END_TYPE
We've tried several ways to construct an acceptable complex type variable to write with no success. It seems that we are unable to make the library aware of the type of the complex object being written Our common error message has been some form of this:
Exception thrown: 'OpcLabs.EasyOpc.UA.OperationModel.UAException' in OpcLabs.EasyOpcUA.dll
*** Failure: No data type system found for node "NodeId="nsu=urn:BeckhoffAutomation:Ua:PLC1 ;ns=4;s=OpcCommunication.OpcTestData1"" on endpoint "opc.tcp://192.168.78.64:4840". The 0 encoding name(s) were: .
Browsing the nodes in the code, from Connectivity Explorer or UAExpert all seem to identify the type easily. We see 2 different nomenclatures for the type depending on the method for browsing it as:
Connectivity Explorer:
nsu=urn:BeckhoffAutomation:Ua:PLC1;ns=4;s=#Type|ST_OpcMoveAbsoluteData
Browsing the variable after being read in code:
Name = "ST_OpcMoveAbsoluteData""
FullName = "urn:BeckhoffAutomation:Ua:PLC1:ST_OpcMoveAbsoluteData"
Others:
nsu=urn:BeckhoffAutomation:Ua:PLC1;ns=4;s=<StructuredDataType>:ST_OpcMoveAbsoluteData"
UANodeDescriptor nodeDescriptor =
"nsu=urn:BeckhoffAutomation:Ua:PLC1;ns=4;s=OpcCommunication.OpcTestData1";
var myStructuredDataType = new StructuredDataType(
"ST_OpcMoveAbsoluteData",
"urn:BeckhoffAutomation:Ua:PLC1:ST_OpcMoveAbsoluteData")
{
new DataField("fTarget", UAOpcBinaryStandardDataTypes.Double),
new DataField("fVelocity", UAOpcBinaryStandardDataTypes.Double),
new DataField("fAccel", UAOpcBinaryStandardDataTypes.Double),
new DataField("fDecel", UAOpcBinaryStandardDataTypes.Double),
new DataField("fDelay", UAOpcBinaryStandardDataTypes.Double)
};
var myStructuredData = new StructuredData(myStructuredDataType);
myStructuredData.Add("fTarget", new PrimitiveData(100d));
myStructuredData.Add("fVelocity", new PrimitiveData(10d));
myStructuredData.Add("fAccel", new PrimitiveData(10d));
myStructuredData.Add("fDecel", new PrimitiveData(10d));
myStructuredData.Add("fDelay", new PrimitiveData(0d));
var myGenericData = new UAGenericObject(myStructuredData, new UAModelNodeDescriptor(endpointDescriptor, "urn:BeckhoffAutomation:Ua:PLC1:ST_OpcMoveAbsoluteData"));
client.WriteValue(endpointDescriptor, nodeDescriptor, myGenericData, typeof(StructuredDataType));
Can you see any fundamental error in understanding we may have in using the library?
Thank you. We tried to include a few details that might show our missteps.
Please Log in or Create an account to join the conversation.
- Forum
- Discussions
- QuickOPC-UA in .NET
- Reading, Writing, Subscriptions
- How to create and write a simple complex type