10:19, EET
January 21, 2022
Hi all,
I’m currently evaluating the ProSys Java SDK and so far all our tests have succeeded but now I’m stuck calling a method that has two parameters. One is a simple integer and the other is a complex type conisting of several integers, strings and doubles. I’ve previously tested calling a method with simple parameters which was not a problem and also reading and writing complete structs which was also not a problem. However I can’t seem to instantiate the DynamicStructure that is used as parameter. When browsing through the attributes of the node that is the completex type parameter and the attribute for value is null (which makes sense since it is a input parameter) and the attribute for DataTypeDefinition contains a StructureDefinition but how am I able to create a new empty dynamic structure that I can fill with data and post to the method?
Thanks for your reply!
Sander
11:45, EET
Moderators
February 11, 2020
Hello,
To instantiate a Structure (which is the supertype of DynamicStructure) you will need its StructureSpecification. If your Client has succefully initialized the TypeDictionary, you should be able to get the StructureSpecification by calling
StructureSpecification structureSpecification = client.getEncoderContext().getStructureSpecification(dataTypeId)
where client is your UaClient and dataTypeId is the UaNodeId version of the NodeId of the Structure DataType. After you have the StructureSpecification, you can build a new Structure by calling
Structure structure = structureSpecification.toStructureBuilder().build()
You can then use structure.set(String fieldName, Object value) to set the value of a Field with the specified name to the given Object.
Finally you can create a Variant from the Structure by calling
Variant variant = new Variant(structure)
and use that Variant as an input argument of the Method.
14:38, EET
January 21, 2022
Thanks! That solved the issue with creating structs.
I do have a problem with calling methods that have multiple input arguments, not necessarily structs. I did test a method with one input and output parameter which worked without problem. However adding a second parameter gives a BadInvalidArgument exception. This is also when the method has just twee int16 parameters and the exception is also thrown when calling the method from UA Expert leading me to believe that the problem is not actually in the client but the server.
Is there a limit within the OPC specification on how this is done? Of is this vendor specific with regards to the OPC Server. I’m testing with a Siemens Simatic S7 PLC.
15:06, EET
Moderators
February 11, 2020
Hello,
Since you’ve also tested this with UaExpert, I would assume there is problem in the Server.
However, Servers are allowed to return StatusCode Bad_InvalidArgument even if the given input argument has the correct DataType but its value is outside of acceptable range of values. This information should be available in the Value of the InputArguments Property Node of the Method Node, but it’s not mandatory to include this information in the Description Field of the Argument Structure.
12:09, EET
January 21, 2022
11:49, EET
June 27, 2018
How exactly do I get the “UaNodeId” object?
First I have the NodeId of the method and the method:
NodeId methodId = new NodeId(2, “xy921id”);
UaMethod method = client.getAddressSpace().getMethod(methodId);
Then I extract the InputArguements – in the example the first place is the CustomStructure:
Argument[] inArgs = method.getInputArguments();
NodeId inTypeNode = inArgs[0].getDataType();
Then I want to get the DynamicStructure via the Specification. I am failing to get the UaNodeId:
UaNodeId inUaNodeId = null; // ??
StructureSpecification inSpec = client.getEncoderContext().getStructureSpecification(inUaNodeId);
DynamicStructure inStructure = new DynamicStructure(inSpec);
13:10, EET
April 3, 2012
As a general rule, when there are no constructors, look for static factory methods, most IDEs show them when writing the class name (or typically you autocomplete it after few letters) and then a dot. Most of the “newer stuff” in the SDK uses static factory methods, whenever possible (I have forgotten it a few times).
Instances of UaNodeId are obtained via static factory methods. The methods for converting NodeIds and ExpandedNodeIds are:
UaNodeId.fromLocal(ExpandedNodeId)
UaNodeId.fromLocal(ExpandedNodeId, NamespaceTable)
UaNodeId.fromLocal(NodeId, NamespaceTable)
Get the NamespaceTable via client.getNamespaceTable(). The version without it is only for cases where the ExpandedNodeId has the uri and not the index.
UaNodeId.fromStandard(NodeId) works only for NodeIds of the base, standard, namespace (with index 0, as it’s uri is known and it is always index 0).
The “intended to be used” method … could maybe do some improvements, but is:
UaNodeId from(String namespaceUri, Object value)
It behaves like UaNodeId from(String namespaceUri, Object value) constructor does, i.e. value must be UnsignedInteger, String, UUID or ByteString. We probably should add some helpers in some future version like UaNodeId.numeric etc. to fix the type in the signature.
P.S.
For reasons, see e.g. https://www.baeldung.com/java-constructors-vs-static-factory-methods
So basically the static factory methods might return an existing instance (if it is equal to the given data) and/or a subtype of UaNodeId (we could save memory e.g. via https://refactoring.guru/design-patterns/flyweight, but I will skip details) . Like technically for the most parts that is not yet used, but we can do so in the future without breaking the API (could not do that with constructors, as they must always return a new instances and instance of that exact class).
P.S.2
And SDK-reasons (prev was “java-reasons”) is that NodeId should “never be used”, as the index is only constant for an NamespaceUri within a scope of a single Session (e.g. server can change it at will on e.g. a restart). ExpandedNodeId has the problem that it can be local or remote and have uri or index, so it is impossible to properly .equals it, without the context of NamespaceTable (since other could have index and other could have uri), so ExpandedNodeId should also not be used. OK, local ExpandedNodeIds should not have uri, but back in the days we ended up needing to use the uri-form in e.g. our Codegen (as NodeIds obiviously could not be used). Thus, to solve this issue we made UaNodeId (and UaExpandedNodeId and UaQualifiedName) as a better alternative that wont suffer from this problem (always local, always has uri). Thus most “new API” tries to use UaNodeId+UaQualifiedName as much as possible (this is more seen in PubSub configuration API)
13:22, EET
April 3, 2012
P.S.3
For the
UaNodeId from(String namespaceUri, Object value)
the NamespaceUri should be “known to you”, i.e. instead of writing “2” in the index like in NodeIds, you would write the known uri of that index. The index is basically just an transfer optimization technique in the binary stream (numbers take less space than uris), but it should _only_ be treated like that. Thus everything should begin with the uri in the “though process”. And pretty much every SDK has done the mistake of having APIs with indexes. It should just be an encoding level “step” (also many UIs do visualize NodeIds with the index), but it might take us a very long time to “fix this”, as half of the SDK APIs have used classes with the index.
The index to uri mappings can be seen the “Root/Objects/Server/NamespaceArray” node.
Most Users Ever Online: 1919
Currently Online:
19 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 735
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1523
Posts: 6449
Newest Members:
rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, Thomassnism, biancacraft16Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1