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 COM
- Discovery, Browsing, Browse Dialogs and Controls
- Browsing issue with KepServer
Browsing issue with KepServer
- m.baumgartner
- Topic Author
- Visitor
Please Log in or Create an account to join the conversation.
this works for me:
// This example shows how to read the DataType attributes of 3 different nodes at
// once. Using the same method, it is also possible to read multiple attributes
// of the same node.
class procedure ReadMultipleValues.DataType;
var
Client: TEasyUAClient;
ReadArguments1, ReadArguments2, ReadArguments3: _UAReadArguments;
Arguments, Results: OleVariant;
I: Cardinal;
Result: _ValueResult;
begin
// Instantiate the client object
Client := TEasyUAClient.Create(nil);
ReadArguments1 := CoUAReadArguments.Create;
ReadArguments1.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
ReadArguments1.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10845';
ReadArguments1.AttributeId := UAAttributeId_DataType;
ReadArguments2 := CoUAReadArguments.Create;
ReadArguments2.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
ReadArguments2.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10853';
ReadArguments2.AttributeId := UAAttributeId_DataType;
ReadArguments3 := CoUAReadArguments.Create;
ReadArguments3.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
ReadArguments3.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10855';
ReadArguments3.AttributeId := UAAttributeId_DataType;
Arguments := VarArrayCreate([0, 2], varVariant);
Arguments[0] := ReadArguments1;
Arguments[1] := ReadArguments2;
Arguments[2] := ReadArguments3;
// Obtain values. By default, the Value attributes of the nodes will be read.
TVarData(Results).VType := varArray or varVariant;
TVarData(Results).VArray := PVarArray(Client.ReadMultipleValues(
PSafeArray(TVarData(Arguments).VArray)));
// Display results
for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do
begin
Result := IInterface(Results[I]) as _ValueResult;
WriteLn;
WriteLn('Value: ', Result.Value);
WriteLn('Value.ExpandedText: ', Result.Value.ExpandedText);
WriteLn('Value.NamespaceUriString: ', Result.Value.NamespaceUriString);
WriteLn('Value.NamespaceIndex: ', Result.Value.NamespaceIndex);
WriteLn('Value.NumericIdentifier: ', Result.Value.NumericIdentifier);
end;
// Example output:
//
//
//Value: SByte
//Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=2
//Value.NamespaceUriString: http://opcfoundation.org/UA/
//Value.NamespaceIndex: 0
//Value.NumericIdentifier: 2
//
//Value: Float
//Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=10
//Value.NamespaceUriString: http://opcfoundation.org/UA/
//Value.NamespaceIndex: 0
//Value.NumericIdentifier: 10
//
//Value: String
//Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=12
//Value.NamespaceUriString: http://opcfoundation.org/UA/
//Value.NamespaceIndex: 0
//Value.NumericIdentifier: 12
end;
Please Log in or Create an account to join the conversation.
- m.baumgartner
- Topic Author
- Visitor
We've tried anything that seems remotely equivalent to the VB code you provided. If you can take some time to craft a quick functional delphi example it would be great.
Thank you.
Please Log in or Create an account to join the conversation.
Ad 1) You have already solved this - you need to use ReadMultiple or ReadMultipleValues. In .NET, we typically have several (sometimes many) method overloads, with different combinations of parameters, and using defaults for those that are not present. Unfortunately, on a COM interface you cannot have overloads - several methods with same name but different arguments. The only way to do this would be to give each method a different name - such as Read1, Read2 etc., but we intentionally decided not to do that. For each set of overloads, there always is one methods that actually does the work, and has full functionality coverage. All other methods then just prepare arguments for it and call this main method. Therefore, on COM interfaces, we just expose the main method - making it lengthier to write the code to supply all the arguments, but sill capable of doing everything needed. And, in .NET, there are also extension methods which have similar effect. So, Read and ReadValue are really just small wrappers around ReadMultiple. In fact, all UA reading can be achieved with that single ReadMultiple methods that we available to COM. And, in your own example you provided couple of posts earlier, I can see that you have resolved this by calling ReadMultiple (or ReadMultipleValues), so I assume this is no longer a problem.
ad 2) Here we are talking specifically about what to do something in Delphi. It is perfectly supported by QuickOPC COM interface, which I demonstrate by the VBScript example below (you can run it with cscript and see for yourself).
Rem This example shows how to read the DataType attributes of 3 different nodes at once. Using the same method, it is also possible
Rem to read multiple attributes of the same node.
Option Explicit
Const UAAttributeId_DataType = 14
' Instantiate the client object
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")
Dim ReadArguments1: Set ReadArguments1 = CreateObject("OpcLabs.EasyOpc.UA.OperationModel.UAReadArguments")
ReadArguments1.EndpointDescriptor.UrlString = "http://opcua.demo-this.com:51211/UA/SampleServer"
ReadArguments1.NodeDescriptor.NodeId.ExpandedText = "nsu=http://test.org/UA/Data/;i=10845"
ReadArguments1.AttributeId = UAAttributeId_DataType
Dim ReadArguments2: Set ReadArguments2 = CreateObject("OpcLabs.EasyOpc.UA.OperationModel.UAReadArguments")
ReadArguments2.EndpointDescriptor.UrlString = "http://opcua.demo-this.com:51211/UA/SampleServer"
ReadArguments2.NodeDescriptor.NodeId.ExpandedText = "nsu=http://test.org/UA/Data/;i=10853"
ReadArguments2.AttributeId = UAAttributeId_DataType
Dim ReadArguments3: Set ReadArguments3 = CreateObject("OpcLabs.EasyOpc.UA.OperationModel.UAReadArguments")
ReadArguments3.EndpointDescriptor.UrlString = "http://opcua.demo-this.com:51211/UA/SampleServer"
ReadArguments3.NodeDescriptor.NodeId.ExpandedText = "nsu=http://test.org/UA/Data/;i=10855"
ReadArguments3.AttributeId = UAAttributeId_DataType
Dim arguments(2)
Set arguments(0) = ReadArguments1
Set arguments(1) = ReadArguments2
Set arguments(2) = ReadArguments3
' Obtain values. By default, the Value attributes of the nodes will be read.
Dim results: results = Client.ReadMultipleValues(arguments)
' Display results
Dim i: For i = LBound(results) To UBound(results)
Dim ValueResult: Set ValueResult = results(i)
WScript.Echo
WScript.Echo "Value: " & ValueResult.Value
WScript.Echo "Value.ExpandedText: " & ValueResult.Value.ExpandedText
WScript.Echo "Value.NamespaceUriString: " & ValueResult.Value.NamespaceUriString
WScript.Echo "Value.NamespaceIndex: " & ValueResult.Value.NamespaceIndex
WScript.Echo "Value.NumericIdentifier: " & ValueResult.Value.NumericIdentifier
Next
' Example output:
'
'Value: SByte
'Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=2
'Value.NamespaceUriString: http://opcfoundation.org/UA/
'Value.NamespaceIndex: 0
'Value.NumericIdentifier: 2
'
'Value: Float
'Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=10
'Value.NamespaceUriString: http://opcfoundation.org/UA/
'Value.NamespaceIndex: 0
'Value.NumericIdentifier: 10
'
'Value: String
'Value.ExpandedText: nsu=http://opcfoundation.org/UA/;i=12
'Value.NamespaceUriString: http://opcfoundation.org/UA/
'Value.NamespaceIndex: 0
'Value.NumericIdentifier: 12
We are no Delphi experts here, but the same should be achievable in Delphi, as it goes through the same COM interfaces and is relatively powerful. Let me know if this helped enough. If not, I will try to rewrite this to Delphi; but I kind of hoped that you knew the tool better than us.
Best regards
Please Log in or Create an account to join the conversation.
- m.baumgartner
- Topic Author
- Visitor
1) the simple Read() function does not exist in our COM/Delphi version of QuickOPC with the full list of parameters. We cannot specify the attributeID as described here : opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...Descriptor,UAAttributeId).html
2) The ReadMultiple however is available with this possibility (through UAReadArguments array). But when we try to cas the value of the result (.attributedata or .attributedata.value) as a UANodeID, we get an error. It seems that we can only cast it to string and obtain the mnemonic description of the data type.
Thank you
Please Log in or Create an account to join the conversation.
The value that you from the DataType attribute is a NodeID (our UANodeId type). And you then convert it to string. We have an implementation of this conversion that, when the NodeId is one of the standard, "well-known" node Ids, we return just its short mnemonic name. (When it is not a standard NodeId, we return something like "nsu=...;ns=...";...").
The information that you could not find is therefore in there - you just needs to access the result as UANodeId (_UANodeId), instead of converting it to string, and look at the various properties it has - such as NamespaceUriString, Identifier etc.
Best regards
Please Log in or Create an account to join the conversation.
- m.baumgartner
- Topic Author
- Visitor
Just to clarify, we need to know the DataType in order to provide the correct operator list. Ex : AND, OR, XOR, NOT for Booleans.
Thanks to your explanations and the following code, we managed to get the data type as a String such as "Boolean" or "Double" :
BrowseDialog := TUABrowseDialog.Create(nil);
BrowseDialog.Mode.SelectElementType := UAElementType_Node;
//BrowseDialog.Mode.SelectableNodeClasses := UANodeClass_Variable;
BrowseDialog.Mode.MultiSelect := true;
BrowseDialog.ShowDialog(nil);
for i:=0 to BrowseDialog.Outputs.SelectionElements.Count - 1 do begin
Element := BrowseDialog.Outputs.SelectionElements.Item[i];
Endpoint := BrowseDialog.InputsOutputs.SelectionDescriptors[i].EndpointDescriptor.UrlString;
Tag := BrowseDialog.InputsOutputs.SelectionDescriptors[i].NodeDescriptor.NodeId.expandedText;
ClientUA := TEasyUAClient.Create(nil);
ReadArgs := CoUAReadArguments.Create;
ReadArgs.EndpointDescriptor.UrlString := Endpoint;
ReadArgs.NodeDescriptor.NodeId.expandedText := Tag;
ReadArgs.AttributeId := UAAttributeId_DataType;
Arguments := VarArrayCreate([0, 0], varVariant);
Arguments[0] := ReadArgs;
TVarData(ResultType).VType := varArray or varVariant;
TVarData(ResultType).VArray := PVarArray(ClientUA.ReadMultiple(
PSafeArray(TVarData(Arguments).VArray)));
for j := VarArrayLowBound(ResultType, 1) to VarArrayHighBound(ResultType, 1) do
begin
ResultAttribute := IInterface(ResultType[j]) as _UAAttributeDataResult;
AttributeData := VarToStr(ResultAttribute.AttributeData.value) ;
break;
end;
ClientUA.Destroy;
However, we are not able to get the ID of that datatype as you said it was defined in the OPC UA specifications (found here : github.com/OPCFoundation/UA-Nodeset/blob/master/Schema/NodeIds.csv).
Shouldn't we be able to get 11 for Double for example? That would make it more elegant to create a mapping and would feel more standard than relying on string representation of data types.
Thanks
Please Log in or Create an account to join the conversation.
(Coding: Normally you read the Value attribute, this is the default but nodes have other attributes, too. You can specify them by setting AttributeId (from UAAttribtueId enumeration) in UAReadARguments that you pass to the Read call. )
What you get back by reading the DataType attribute, however, is a UA NodeId of the data type. That's precise, but somewhat cryptical. It is up to you to deal with this information. The standard datatypes have their standard NodeIds, and they are all listed in the OPC UA specification.
At places, we are using this information inside QuickOPC as well, and have internal methods to convert at least the basic DataTypeIds to .NET types, but these methods are not public, and the data types would not make direct sense Delphi either.
Please describe how you would want to use this information, so that possibly I can suggest something.
Please Log in or Create an account to join the conversation.
- m.baumgartner
- Topic Author
- Visitor
One more thing. KepServer gives us a property called RawDataType that we can read to know which data type the tag is. It seems like your demothis server does not provide such metadata. How can we know which datatype a tag is? Is there a "standard"?
Thanks
Please Log in or Create an account to join the conversation.
Fortunately, the answer here is clear, and positive.
The ApplicationElement is for the "extended" information about the server - the stuff that comes from the discovery. It may, or it may not be available.
But, you can *always* access the information needed to connect to the server.
Just use UABrowseDialog.InputOutputs.SelectionDescriptors[...].EndpointDescriptor instead.
Best regards
Please Log in or Create an account to join the conversation.
- Forum
- Discussions
- QuickOPC-UA in COM
- Discovery, Browsing, Browse Dialogs and Controls
- Browsing issue with KepServer