Professional OPC
Development Tools

logos

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.

New Version old bug

More
20 Jan 2017 12:10 #4808 by support
Replied by support on topic New Version old bug
Note that OleVariant handling and conversions are slightly out of the scope of QUickOPC support forums, and we are no Delphi experts here. But I understand it is a common needs, so I have prepared the examples below.

With State as an integer:
// This example shows how to subscribe to changes of a single monitored item
// and display each change, identifying the different subscription by an
// integer.
 
type
  TIntegerClientEventHandlers = class
    procedure OnDataChangeNotification(
      ASender: TObject;
      sender: OleVariant;
      const eventArgs: _EasyUADataChangeNotificationEventArgs);
  end;
 
procedure TIntegerClientEventHandlers.OnDataChangeNotification(
  ASender: TObject;
  sender: OleVariant;
  const eventArgs: _EasyUADataChangeNotificationEventArgs);
var
  stateAsInteger: Integer;
begin
  // Obtain the integer state we have passed in.
  stateAsInteger := eventArgs.Arguments.State;
  // Display the data
  // Remark: Production code would check eventArgs.Exception before accessing
  // eventArgs.AttributeData.
	WriteLn(stateAsInteger, ': ', eventArgs.AttributeData.ToString);
end;
 
 
class procedure SubscribeMultipleMonitoredItems.StateAsInteger;
var
  Arguments: OleVariant;
  Client: TEasyUAClient;
  ClientEventHandlers: TIntegerClientEventHandlers;
  Handle: Cardinal;
  HandleArray: OleVariant;
  I: Cardinal;
  MonitoredItemArguments1, MonitoredItemArguments2, MonitoredItemArguments3:
    _EasyUAMonitoredItemArguments;
  MonitoringParameters: _UAMonitoringParameters;
begin
  // Instantiate the client object and hook events
  Client := TEasyUAClient.Create(nil);
  ClientEventHandlers := TIntegerClientEventHandlers.Create;
  Client.OnDataChangeNotification := ClientEventHandlers.OnDataChangeNotification;
 
  WriteLn('Subscribing...');
  MonitoringParameters := CoUAMonitoringParameters.Create;
  MonitoringParameters.SamplingInterval := 1000;
 
  MonitoredItemArguments1 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments1.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments1.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10845';
  MonitoredItemArguments1.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments1.SetState(1);  // An integer we have chosen to identify the subscription
 
  MonitoredItemArguments2 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments2.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments2.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10853';
  MonitoredItemArguments2.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments2.SetState(2);  // An integer we have chosen to identify the subscription
 
  MonitoredItemArguments3 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments3.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments3.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10855';
  MonitoredItemArguments3.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments3.SetState(3);  // An integer we have chosen to identify the subscription
 
  Arguments := VarArrayCreate([0, 2], varVariant);
  Arguments[0] := MonitoredItemArguments1;
  Arguments[1] := MonitoredItemArguments2;
  Arguments[2] := MonitoredItemArguments3;
 
  TVarData(HandleArray).VType := varArray or varVariant;
  TVarData(HandleArray).VArray := PVarArray(
    Client.SubscribeMultipleMonitoredItems(PSafeArray(TVarData(Arguments).VArray)));
 
  for I := VarArrayLowBound(HandleArray, 1) to VarArrayHighBound(HandleArray, 1) do
  begin
      Handle := Cardinal(HandleArray[I]);
      WriteLn('HandleArray[', I, ']: ', Handle);
  end;
 
  WriteLn('Processing monitored item changed events for 10 seconds...');
  PumpSleep(10*1000);
 
  WriteLn('Unsubscribing...');
  Client.UnsubscribeAllMonitoredItems;
 
  WriteLn('Waiting for 5 seconds...');
  Sleep(5*1000);
 
  WriteLn('Done...');
end;

With State as an arbitrary Delphi object:
// This example shows how to subscribe to changes of a single monitored item
// and display each change, identifying the different subscription by an
// object.
 
type
  TCustomObject = class
    Name: string;
    constructor Create(name: string);
  end;
 
constructor TCustomObject.Create(name: string);
begin
  Self.Name := name;
end;
 
 
 
type
  TObjectClientEventHandlers = class
    procedure OnDataChangeNotification(
      ASender: TObject;
      sender: OleVariant;
      const eventArgs: _EasyUADataChangeNotificationEventArgs);
  end;
 
procedure TObjectClientEventHandlers.OnDataChangeNotification(
  ASender: TObject;
  sender: OleVariant;
  const eventArgs: _EasyUADataChangeNotificationEventArgs);
var
  stateAsObject: TCustomObject;
begin
  // Obtain the custom object we have passed in.
  stateAsObject := TCustomObject(INT_PTR(eventArgs.Arguments.State));
  // Display the data
  // Remark: Production code would check eventArgs.Exception before accessing
  // eventArgs.AttributeData.
	WriteLn(stateAsObject.Name, ': ', eventArgs.AttributeData.ToString);
end;
 
 
 
class procedure SubscribeMultipleMonitoredItems.StateAsObject;
var
  Arguments: OleVariant;
  Client: TEasyUAClient;
  ClientEventHandlers: TObjectClientEventHandlers;
  Handle: Cardinal;
  HandleArray: OleVariant;
  I: Cardinal;
  MonitoredItemArguments1, MonitoredItemArguments2, MonitoredItemArguments3:
    _EasyUAMonitoredItemArguments;
  MonitoringParameters: _UAMonitoringParameters;
begin
  // Instantiate the client object and hook events
  Client := TEasyUAClient.Create(nil);
  ClientEventHandlers := TObjectClientEventHandlers.Create;
  Client.OnDataChangeNotification := ClientEventHandlers.OnDataChangeNotification;
 
  WriteLn('Subscribing...');
  MonitoringParameters := CoUAMonitoringParameters.Create;
  MonitoringParameters.SamplingInterval := 1000;
 
  MonitoredItemArguments1 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments1.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments1.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10845';
  MonitoredItemArguments1.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments1.SetState(INT_PTR(TCustomObject.Create('First')));  // A custom object that corresponds to the subscription
 
  MonitoredItemArguments2 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments2.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments2.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10853';
  MonitoredItemArguments2.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments2.SetState(INT_PTR(TCustomObject.Create('Second')));  // A custom object that corresponds to the subscription
 
  MonitoredItemArguments3 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments3.EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  MonitoredItemArguments3.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/;i=10855';
  MonitoredItemArguments3.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments3.SetState(INT_PTR(TCustomObject.Create('Third')));  // A custom object that corresponds to the subscription
 
  Arguments := VarArrayCreate([0, 2], varVariant);
  Arguments[0] := MonitoredItemArguments1;
  Arguments[1] := MonitoredItemArguments2;
  Arguments[2] := MonitoredItemArguments3;
 
  TVarData(HandleArray).VType := varArray or varVariant;
  TVarData(HandleArray).VArray := PVarArray(
    Client.SubscribeMultipleMonitoredItems(PSafeArray(TVarData(Arguments).VArray)));
 
  for I := VarArrayLowBound(HandleArray, 1) to VarArrayHighBound(HandleArray, 1) do
  begin
      Handle := Cardinal(HandleArray[I]);
      WriteLn('HandleArray[', I, ']: ', Handle);
  end;
 
  WriteLn('Processing monitored item changed events for 10 seconds...');
  PumpSleep(10*1000);
 
  WriteLn('Unsubscribing...');
  Client.UnsubscribeAllMonitoredItems;
 
  WriteLn('Waiting for 5 seconds...');
  Sleep(5*1000);
 
  WriteLn('Done...');
end;
 

In the above code snippet, INT_PTR comes from the Windows unit, so you need to add that to your 'uses' list.

In my opinion, non-trivial real-world projects will typically use the latter approach, i.e. with some object being passed as State. The use of other types (integers) usually leads to some kind of value tests and/or switch statements, which is both ugly and inefficient. On the other hand, passing in an object fits well into the OOP scheme of things, as you may already have such an object in your project anyway, and it can have properties and methods that do reasonable things with the data that has arrived, without need to write extra code to find a correspondence between "something" that is incoming in the notification, and the "other thing" you actually need. You'd just pass in "the thing" you need as State, and you will also get it in the notifications (leaving aside the typecasting to and from, which is technical detail only).

Best regards

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 20:06 #4804 by alr1976
Replied by alr1976 on topic New Version old bug
Ok i ll wait examples so after that i can ask you about variable type.
I need to convert
Olevariant to tobject,tobject to olevariant
Olevariant to int,int to olevariant
I need it because i want test state

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 18:32 #4803 by support
Replied by support on topic New Version old bug
Hello.

Ad 1) As with all errors that occur within a subscription, you should receive an OnDataChangeNotification where Exception is non-null and contains information about the problem.

Ad 2) I will answer later (probably tomorrow) and provide some examples.

Ad 3) Can you please describe your use case? Typically the variable type is fixed and the application knows to expect for a particular node, or you find the type upfront in the app (I can provide some guidance for this too).

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 17:28 #4802 by alr1976
Replied by alr1976 on topic New Version old bug
Ok i have last questions..

1)if i insert an wrong nodedescriptionstring in subscribemultimonitoritems there is a way that subscription is incorrect?
2)how can i insert in setstate a tobject or/and a number?
3)how can i understand variable type in ondatachange?

Thank you very much for tour help

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 16:10 #4801 by support
Replied by support on topic New Version old bug
Yes, I have answered the same already - you have probably missed that answer.

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 15:06 #4800 by alr1976
Replied by alr1976 on topic New Version old bug
ok but if i use SubscribeDataChange i can t use state....correct? if i need setstate i must use SubscribeMultipleMonitoredItems?

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 15:03 #4799 by support
Replied by support on topic New Version old bug
These things have changed in relation to adding OPC UA Alarms&Events support. It is described in the changelog: kb.opclabs.com/What%E2%80%99s_New_in_QuickOPC_5.40 . Specifically, look under "Component Core Refactorings" header.

Some relevant piece of it:

  • Changes in member names are as follows:
    • The IEasyUAClient.MonitoredItemChanged event has been renamed to DataChangeNotification.
    • Some overloads of the extension method IEasyUAClient.SubscribeMonitoredItem have been renamed to SubscribeDataChange.
    • Some overloads of the extension methods IEasyUAClient.ChangeMonitoredItemSubscription and IEasyUAClient.ChangeMultipleMonitoredItemSubscriptions have been renamed to ChangeDataChangeSubscription and ChangeMultipleDataChangesSubscriptions, respectively.
    • The EasyUAMonitoredItemArguments.Callback property has been renamed to DataChangeCallback.
  • In .NET, backward compatibility is provided for the most commonly used renamed types and members. This means that if your existing code uses them, you will get a compiler warning recommending you to use a different type or member, but the code will still compile. For the remaining types and members, you need to perform a manual renaming in your code, using the correspondences outlined above. We plan to remove the obsoleted types and members from the product with a version that will come approx. 1 year after the release of this version.
  • For COM development, where applicable, the corresponding types and members have been renamed in an identical manner. Backward compatible types and members are not provided for COM development.


The documentation and examples to the affected version are all updated. If you have a preexisting code, you need to change things according to the descriptions in the knowledge base article and the newest doc. In your case:

- Use OnDataChangeNotification instead of OnMonitoredItemChanged.
- Use SubscribeDataChange instead of SubscribeMonitoredItem if possible. Where not possible, use SubscribeMultipleMonitoredItems.

Regards
The following user(s) said Thank You: alr1976

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 14:53 #4798 by support
Replied by support on topic New Version old bug
Yes. SubscribeDataChange is just a shortcut for the simplest situations. In COM (incl. Delphi), we do not have the luxury of being able to provide many overloads of the same method.

You will therefore find yourself generally using SubscribeMultipleMonitoredItems instead.

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 13:42 - 19 Jan 2017 14:56 #4796 by alr1976
Replied by alr1976 on topic New Version old bug
Ok i understand..... in my library (2016.2) missing OnMonitoredItemChanged and SubscribeMonitoredItem so was difficult to understand it. I have uninstalled and reinstalled 3 times so how can i fix it?
var
  client :IEasyUAClient;
begin
  Client := TEasyUAClient.Create(nil);
I have :
Client.OnDataChangeNotification
Client.OnServerConditionChanged
Client.OnEventNotification
But i don t have:
Client.OnMonitoredItemChanged
so i have :
Client.SubscribeEvent
Client.SubscribeDataChange
Client. SubscribeMultipleMonitoredItems
but i don t have :
Client.SubscribeMonitoredItem
end;

I m using Delphi 2010
Last edit: 19 Jan 2017 14:56 by support. Reason: formatting

Please Log in or Create an account to join the conversation.

More
19 Jan 2017 10:32 #4794 by alr1976
Replied by alr1976 on topic New Version old bug
Ok so in com (Delphi) i don t have subscribemonitoritem but only subscribedatachange. So i must to use subscribemultiplemonitoritems to setup state object?

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.083 seconds