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.
UA Authentication
Please create a new topic thread next time, for any new issue. You can always put inside a link to some other post, if there is a relationship. In this case, you have added to a forum thread that is not actually related, making the forums look more confusing to the user.
I know where your problem comes from.
First, you can remove the parts of your code that set the UserInfo, UserName and/or Password on the $EndpointDescriptor directly. The correct part is the one with $EndpointDescriptor->UserIdentity.
Then, the actual problem lies in the usage of the CallMethod method, and the $EndpointDescriptor->ToString() as its first argument. What happens there is that $EndpointDescriptor->ToString() does not represent all contents of the endpoint descriptor - so by converting it to string, the user identity gets lost.
But if course you HAVE to use a string for the endpoint descriptor with the CallMethod call in COM (PHP). This is because COM does not have method overloads. In .NET we have an overload that has the actual UAEndpointDescriptor object as the first argument - as well as many other overloads. In COM we have chosen the most simplest case as the overload to expose.
We still allow the operation to made in COM as well - but you need to switch from the simplest method (which is CallMethod) to the other method that is the "most complicated" one: In this case, CallMultipleMethods.
So, even though you are calling just one method, in COM (PHP) you need to rewrite your code to use CallMultipleMethods, with one method. The CallMultipleMethods accept an array of arguments, each describing one method call. The array element then contains the full UAEndpointDescriptor object, so you can fill it in correctly, including its UserIdentity.
Unfortunately we do not have the PHP example with CallMultipleMethods currently available, but you should be available to construct it using that example in other programming languages, here: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...Call%20multiple%20methods.html .
I hope this helps.
Best regards
Please Log in or Create an account to join the conversation.
- m.spinsanti@swoa.it
- Offline
- Senior Member
- Posts: 6
- Thank you received: 1
We have never needed to activate the connection with user/password but now we find ourselves in the situation of needing it to be able to use the CALL function of a method that is inhibited for anonymous connection (in the below example you’ll find all the authenticated access modes we tested, even individually).
Let's start by saying that, on this same machine, we are already collecting data from an anonymous connection.
Below we attach the used code and runtime screenshots showing reported errors.
Can you give us some suggestions to unravel the problem?
PHP SOURCE CODE
<?php
$bDebug = true;
if ($bDebug)
error_reporting(E_ALL);
$EndpointDescriptor = new COM("OpcLabs.EasyOpc.UA.UAEndpointDescriptor");
$EndpointDescriptor->UrlString = "opc.tcp://192.168.10.20:51210/UA/E77Server";
//com_print_typeinfo($EndpointDescriptor->UserIdentity->AnonymousTokenInfo);
$EndpointDescriptor->UserInfo = "KM:km";
$EndpointDescriptor->UserName = "KM";
$EndpointDescriptor->Password = "km";
$EndpointDescriptor->UserIdentity->AnonymousTokenInfo->IsEnabled = false;
$EndpointDescriptor->UserIdentity->UserNameTokenInfo->UserName = "KM";
$EndpointDescriptor->UserIdentity->UserNameTokenInfo->Password = "km";
$Client = new COM("OpcLabs.EasyOpc.UA.EasyUAClient");
// This example shows how to call a single method, and pass arguments to and from it.
$inputs[0] = "a";
$inputs[1] = "b";
$inputs[2] = "c";
$inputs[3] = "d";
$inputs[4] = "e";
$inputs[5] = "f";
$inputs[6] = 2;
$inputs[7] = "";
$inputs[8] = "";
$inputs[9] = "";
$inputs[10] = true;
$inputs[11] = 3;
$inputs[12] = 0;
$inputs[13] = 0.0;
$typeCodes[0] = 18; // TypeCode.String
$typeCodes[1] = 18; // TypeCode.String
$typeCodes[2] = 18; // TypeCode.String
$typeCodes[3] = 18; // TypeCode.String
$typeCodes[4] = 18; // TypeCode.String
$typeCodes[5] = 18; // TypeCode.String
$typeCodes[6] = 10; // TypeCode.UInt32
$typeCodes[7] = 18; // TypeCode.String
$typeCodes[8] = 18; // TypeCode.String
$typeCodes[9] = 18; // TypeCode.String
$typeCodes[10] = 3; // TypeCode.Boolean
$typeCodes[11] = 12; // TypeCode.UInt64
$typeCodes[12] = 12; // TypeCode.UInt64
$typeCodes[13] = 14; // TypeCode.UInt64
// Perform the operation
try
{
$outputs = $Client->CallMethod(
$EndpointDescriptor->ToString(),
"nsu=http://www.euromap.org/euromap77/ ;ns=4;s=70250", // Node descriptor
"nsu=http://www.euromap.org/euromap77/ ;ns=4;s=70250", // Method Node Id
$inputs,
$typeCodes);
}
catch (com_exception $e)
{
printf("*** Failure: %s\n", $e->getMessage());
exit();
}
// Display results
for ($i = 0; $i < count($outputs); $i++)
{
printf("outputs[d]s\n", $i, $outputs[$i]);
}
unset($Client);
exit();
?>
Please Log in or Create an account to join the conversation.
Of course.
Code to send User and Password, acceptint de certificate:
EasyUAClientConfiguration := TEasyUAClientConfiguration.Create(nil);
UserIdentity := TUserIdentity.Create(nil);
try
UserIdentity.UserNameTokenInfo.UserName := ParamStr2;
Useridentity.UserNameTokenInfo.Password := ParamStr3;
EasyUAClientConfiguration.AdaptableParameters.SessionParameters.UserIdentity := Useridentity.DefaultInterface;
EasyUAClientConfiguration.RemoteMachineName := ParamStr1;
EasyUAClientConfiguration.AdaptableParameters.SessionParameters.EndpointSelectionPolicy.AllowedMessageSecurityModes := UAMessageSecurityModes_All;
EasyUAClientConfiguration.SharedParameters.EngineParameters.CertificateAcceptancePolicy.AcceptAnyCertificate := True;
EasyUAClientConfiguration.Connect;
finally
UserIdentity.Free;
EasyUAClientConfiguration.Free;
end;
For each value I need to read:
ReadArgument := CoUAReadArguments.Create;
ReadArgument.EndpointDescriptor.UrlString := strOPCServer;
ReadArgument.NodeDescriptor.NodeId.ExpandedText := NodeId + OPCItem;
ReadArgument.AttributeId := UAAttributeId_DataType;
The code to Read the items:
TVarData(Results).VType := varArray or varVariant;
TVarData(Results).VArray := PVarArray(ClienteOPCUA.ReadMultipleValues(PSafeArray(TVarData(Arguments).VArray)));
for intVariable := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do
begin
Result := IInterface(Results[intVariable]) as _ValueResult;
if VarIsEmpty(Result.Value) then
SaveError('Value.Value: ' + strIdVariableEscribir + ' - ' + ID_NO_EXISTE)
else
begin
SaveValue(strIdVariableEscribir , Result.Value);
end;
end;
Thanks for you help!
Escarre
Please Log in or Create an account to join the conversation.
The proper and secure way to get rid of the certificate validation dialog is to copy the server's certificate to the "trusted peers" certificate store. More information: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...%20Instance%20Certificate.html .
Most likely this means you should inspect the certificates you have under "C:\ProgramData\OPC Foundation\CertificateStores\RejectedCertificates\certs", locate the one you want to trust, and copy it over to "C:\ProgramData\OPC Foundation\CertificateStores\UA Applications\certs". Alternatively, there should also be a (server-specific) way to obtain the server's certificate on the server side directly (without it having to be first transferred to the client and initially rejected).
This will have to be repeated on every machine where the client app will run (and, if it is connecting to different server instances, the server certificates will then of course be different).
There are also insecure ways - not recommended.
Best regards
Please Log in or Create an account to join the conversation.
Attachments:
Please Log in or Create an account to join the conversation.
Attachments:
Please Log in or Create an account to join the conversation.
I made another test, using OnDataChangeNotification.
When I receive the event, the eventArgs.Arguments.NodeDescriptor.DisplayString value NodeId="ns=3;s=_System.General.Temperature"
But eventArgs.AttributeData is nil.
Thanks again,
Escarre
Please Log in or Create an account to join the conversation.
When I want to display results an exception raises: EIntFCastError Interface not supported
But if I use this code (Result is a _ValueResult variable):
Result := IInterface(Results[intVariable]) as _ValueResult
there are no error, but the Result.value is unassigned.
This code in another OPC server works properly, so I don't know why is not working.
Thanks,
Escarre
Please Log in or Create an account to join the conversation.
Reading a list of OPC UA items:
// This example shows how to read the attributes of 4 OPC-UA nodes at once, and
// display the results.
class procedure ReadMultiple.Main;
var
Arguments: OleVariant;
Client: OpcLabs_EasyOpcUA_TLB._EasyUAClient;
I: Cardinal;
ReadArguments1, ReadArguments2, ReadArguments3, ReadArguments4: _UAReadArguments;
Result: _UAAttributeDataResult;
Results: OleVariant;
begin
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=10853';
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=10845';
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=10304';
ReadArguments4 := CoUAReadArguments.Create;
ReadArguments4.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
ReadArguments4.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10389';
Arguments := VarArrayCreate([0, 3], varVariant);
Arguments[0] := ReadArguments1;
Arguments[1] := ReadArguments2;
Arguments[2] := ReadArguments3;
Arguments[3] := ReadArguments4;
// Instantiate the client object
Client := CoEasyUAClient.Create;
// Perform the operation
TVarData(Results).VType := varArray or varVariant;
TVarData(Results).VArray := PVarArray(Client.ReadMultiple(Arguments));
// Display results
for I := VarArrayLowBound(Results, 1) to VarArrayHighBound(Results, 1) do
begin
Result := IInterface(Results[I]) as _UAAttributeDataResult;
if Result.Succeeded then
WriteLn('results(', I, ').AttributeData: ', Result.AttributeData.ToString)
else
WriteLn('results(', I, ') *** Failure: ', Result.ErrorMessageBrief);
end;
end;
Setting username and password: At the beginning of opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...ck%20certificate%20status.html
(always switch to the "Object Pascal" example tab)
So you just need to combine parts of these two examples together.
Best regards
Please Log in or Create an account to join the conversation.
I need to set the user and password and read a list of OPC items.
What is the best way to get these data list?
Are there any example in Delphi?
Thanks,
Escarre
Please Log in or Create an account to join the conversation.