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.

Subscribing to a non-existent item

More
07 Jul 2021 18:03 #9941 by support
Furthermore, If the item was truly non-existent, I would expect your code to only show the message "1 ...", but not 2 to 6.

Anyway, it looks like I need a full repro code to be able to go further.

Regards

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

More
07 Jul 2021 17:59 #9940 by support
The fourth item in my example is a non-existent item. It is clearly labeled as such, and its non-existence is reflected in the example output. It looks like that you have not examined my example code and the output.

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

More
07 Jul 2021 17:57 #9939 by lamar
Seems, you checked your code with existing items. The problem comes with non-existant items.

I tested it with the following fool-compliant code. All IF statements were passed even if a the non-existent item.
  • EventArgs <> nil
  • EventArgs.Succeeded
  • EventArgs.VTQ.HasValue and EventArgs.VTQ.Quality.IsGood

The code freezes between showmessage('5') and showmessage('6') with a non-exstent item.

Here is the code:
  Repeat
    EventArgs := D^.UserDataPtr.OPCDAClient.PullItemChanged(5) ;
    If EventArgs <> nil Then
    Begin
      showmessage('1 ' + EventArgs.Arguments.ItemDescriptor.ItemId );
      If EventArgs.Succeeded Then
      Begin
        showmessage('2 ' + EventArgs.Arguments.ItemDescriptor.ItemId);
        If EventArgs.VTQ.HasValue and EventArgs.VTQ.Quality.IsGood Then
        Begin
          showmessage('3 '+ EventArgs.Arguments.ItemDescriptor.ItemId);
          For i := 1 To D.UserDataPtr.Outputs Do
          Begin
            showmessage('4 + EventArgs.Arguments.ItemDescriptor.ItemId');
            If EventArgs.Arguments.ItemDescriptor.ItemId = D^.UserDataPtr.Variables[i] Then
            Begin
              showmessage('5 ' + EventArgs.Arguments.ItemDescriptor.ItemId);
              Outputs^[i] := EventArgs.VTQ.Value ;
              showmessage('6 + EventArgs.Arguments.ItemDescriptor.ItemId');
            End;
          End;
        End;
      End;
    End;
  Until EventArgs = nil ;
 

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

More
07 Jul 2021 15:47 #9934 by support
Hello,

I have made the following example, and it works for me:
// This example shows how to subscribe to changes of multiple items and obtain the item changed events by pulling them.
 
class procedure PullItemChanged.MultipleItems;
var
  Arguments: OleVariant;
  Client: OpcLabs_EasyOpcClassic_TLB._EasyDAClient;
  EndTick: Cardinal;
  EventArgs: _EasyDAItemChangedEventArgs;
  HandleArray: OleVariant;
  ItemSubscriptionArguments1: _EasyDAItemSubscriptionArguments;
  ItemSubscriptionArguments2: _EasyDAItemSubscriptionArguments;
  ItemSubscriptionArguments3: _EasyDAItemSubscriptionArguments;
  ItemSubscriptionArguments4: _EasyDAItemSubscriptionArguments;
begin
  ItemSubscriptionArguments1 := CoEasyDAItemSubscriptionArguments.Create;
  ItemSubscriptionArguments1.ServerDescriptor.ServerClass := 'OPCLabs.KitServer.2';
  ItemSubscriptionArguments1.ItemDescriptor.ItemID := 'Simulation.Random';
  ItemSubscriptionArguments1.GroupParameters.RequestedUpdateRate := 1000;
 
  ItemSubscriptionArguments2 := CoEasyDAItemSubscriptionArguments.Create;
  ItemSubscriptionArguments2.ServerDescriptor.ServerClass := 'OPCLabs.KitServer.2';
  ItemSubscriptionArguments2.ItemDescriptor.ItemID := 'Trends.Ramp (1 min)';
  ItemSubscriptionArguments2.GroupParameters.RequestedUpdateRate := 1000;
 
  ItemSubscriptionArguments3 := CoEasyDAItemSubscriptionArguments.Create;
  ItemSubscriptionArguments3.ServerDescriptor.ServerClass := 'OPCLabs.KitServer.2';
  ItemSubscriptionArguments3.ItemDescriptor.ItemID := 'Trends.Sine (1 min)';
  ItemSubscriptionArguments3.GroupParameters.RequestedUpdateRate := 1000;
 
  // Intentionally specifying an unknown item here, to demonstrate its behavior.
  ItemSubscriptionArguments4 := CoEasyDAItemSubscriptionArguments.Create;
  ItemSubscriptionArguments4.ServerDescriptor.ServerClass := 'OPCLabs.KitServer.2';
  ItemSubscriptionArguments4.ItemDescriptor.ItemID := 'SomeUnknownItem';
  ItemSubscriptionArguments4.GroupParameters.RequestedUpdateRate := 1000;
 
  Arguments := VarArrayCreate([0, 3], varVariant);
  Arguments[0] := ItemSubscriptionArguments1;
  Arguments[1] := ItemSubscriptionArguments2;
  Arguments[2] := ItemSubscriptionArguments3;
  Arguments[3] := ItemSubscriptionArguments4;
 
  // Instantiate the client object
  Client := CoEasyDAClient.Create;
  // In order to use event pull, you must set a non-zero queue capacity upfront.
  Client.PullItemChangedQueueCapacity := 1000;
 
  WriteLn('Subscribing item changes...');
  TVarData(HandleArray).VType := varArray or varVariant;
  TVarData(HandleArray).VArray := PVarArray(
    Client.SubscribeMultipleItems(Arguments));
 
  WriteLn('Processing item changes for 1 minute...');
  EndTick := Ticks + 60*1000;
  while Ticks < EndTick do
  begin
    EventArgs := Client.PullItemChanged(2*1000);
    if EventArgs <> nil then
      // Handle the notification event
      if eventArgs.Succeeded then
        WriteLn(eventArgs.Arguments.ItemDescriptor.ItemId, ': ', eventArgs.Vtq.ToString)
      else
        WriteLn(eventArgs.Arguments.ItemDescriptor.ItemId, ' *** Failure: ', eventArgs.ErrorMessageBrief);
  end;
 
  WriteLn('Unsubscribing item changes...');
  Client.UnsubscribeAllItems;
 
  WriteLn('Finished.');
end;

The sample output (below) is as I expect it:
Subscribing item changes...
Processing item changes for 1 minute...
SomeUnknownItem *** Failure: The item is no longer available in the server address space. [...]
Simulation.Random: 0.175908688619648 {System.Double} @2021-07-07T15:26:50.721; GoodNonspecific (192)
Trends.Ramp (1 min): 0.845354557037354 {System.Double} @2021-07-07T15:26:50.721; GoodNonspecific (192)
Trends.Sine (1 min): -0.825826343091083 {System.Double} @2021-07-07T15:26:50.721; GoodNonspecific (192)
Simulation.Random: 0.00125125888851588 {System.Double} @2021-07-07T15:42:51.521; GoodNonspecific (192)
Trends.Ramp (1 min): 0.858685851097107 {System.Double} @2021-07-07T15:42:51.521; GoodNonspecific (192)
Trends.Sine (1 min): -0.775750152879805 {System.Double} @2021-07-07T15:42:51.521; GoodNonspecific (192)
Simulation.Random: 0.56358531449324 {System.Double} @2021-07-07T15:42:52.503; GoodNonspecific (192)
Trends.Ramp (1 min): 0.875057846307755 {System.Double} @2021-07-07T15:42:52.503; GoodNonspecific (192)
Trends.Sine (1 min): -0.706849730113164 {System.Double} @2021-07-07T15:42:52.503; GoodNonspecific (192)
Simulation.Random: 0.193304239020966 {System.Double} @2021-07-07T15:42:53.516; GoodNonspecific (192)
Trends.Ramp (1 min): 0.891934543848038 {System.Double} @2021-07-07T15:42:53.516; GoodNonspecific (192)
Trends.Sine (1 min): -0.628011468825186 {System.Double} @2021-07-07T15:42:53.516; GoodNonspecific (192)
Simulation.Random: 0.58500930814539 {System.Double} @2021-07-07T15:42:55.528; GoodNonspecific (192)
Trends.Ramp (1 min): 0.925476461648941 {System.Double} @2021-07-07T15:42:55.528; GoodNonspecific (192)
Trends.Sine (1 min): -0.451321065935034 {System.Double} @2021-07-07T15:42:55.528; GoodNonspecific (192)
Simulation.Random: 0.47987304300058 {System.Double} @2021-07-07T15:42:56.523; GoodNonspecific (192)
Trends.Ramp (1 min): 0.942061632871628 {System.Double} @2021-07-07T15:42:56.523; GoodNonspecific (192)
Trends.Sine (1 min): -0.356050032411034 {System.Double} @2021-07-07T15:42:56.523; GoodNonspecific (192)
Simulation.Random: 0.350291451765496 {System.Double} @2021-07-07T15:42:57.534; GoodNonspecific (192)
Trends.Ramp (1 min): 0.958907425403595 {System.Double} @2021-07-07T15:42:57.534; GoodNonspecific (192)
Trends.Sine (1 min): -0.255333151872067 {System.Double} @2021-07-07T15:42:57.534; GoodNonspecific (192)
...

Can you please check if you get the same behavior with my code. Assuming that the answer is Yes, then try to find out what causes the the difference between your code, and mine.

If you fail to find it, I will then a need a full reproducible scenario, with the code, from your side, so that I can troubleshoot it here.

Best regards

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

More
07 Jul 2021 12:26 #9929 by lamar
I tried two ways, both of them do not work.

EventArgs := D^.UserDataPtr.OPCDAClient.PullItemChanged(5) ;
If (EventArgs <> nil) and (EventArgs.Exception = nil) Then
[TAB]If EventArgs.VTQ.Quality.IsGood Then ....

EventArgs := D^.UserDataPtr.OPCDAClient.PullItemChanged(5) ;
If (EventArgs <> nil) and EventArgs.Succeeded Then
[TAB]If EventArgs.VTQ.Quality.IsGood Then ....

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

More
07 Jul 2021 11:49 #9928 by support
One apparent error in this code is accessing EventArgs.VTQ.Quality or EventArgs.VTQ.Value without testing EventArgs.Exception (or EventArgs.Succeeded) first.

For events that carry errors, EventArgs.VTQ will be nil, and accessing EventArgs.VTQ.Quality or EventArgs.VTQ.Value will crash the event delivery thread.

You probably thought that an invalid item would be a VTQ with a "bad" quality, but that's not the case. Qualities relate to the communication between the OPC Server and the source/target data. But in case of an invalid item ID, there is no quality to speak about, and there is no VTQ at all.

Best regards

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

More
07 Jul 2021 11:41 #9927 by lamar
I subscribe to trhree items, two existing, one non-existent.
App does not go on after the first pullin. Here is the code, it is very simple.

Repeat
[TAB]EventArgs := D^.UserDataPtr.OPCDAClient.PullItemChanged(5) ;
[TAB]If (EventArgs <> nil) and EventArgs.VTQ.Quality.IsGood Then
[TAB][TAB]For i := 1 To D.UserDataPtr.Outputs Do
[TAB][TAB][TAB]If EventArgs.Arguments.ItemDescriptor.ItemId = D^.UserDataPtr.Variables"["i"]" Then Outputs^"["i"]" := EventArgs.VTQ.Value ;
Until EventArgs = nil ;

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

More
07 Jul 2021 10:15 #9922 by support
Need your code.

The only other way to check the item presence would be to try to read it, and check the specific error codes.

Also, are you saying that if the item exists, you *do* get an event through the event pull?

Regards

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

More
07 Jul 2021 10:10 #9920 by lamar
"When event pull is used, you should be able to pull this event."

it does not work for me. Application freezes.
Is there way to check if the items are existent before subscribing to them?

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

More
07 Jul 2021 09:52 #9915 by support
Hello.

The expected behavior is

1) yes, the subscription call should succeed (it always does, except for usage errors), and
2) the ItemChanged event is generated, containing an indication that that particular item subscription has failed - and contains an Exception which tell you the reason. When event pull is used, you should be able to pull this event.
3) The component will periodically (but slowly...) try to continue to subscribe to the item, because the server's configuration may change over time, and an item that has been invalid may become valid.

Regards

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

Moderators: support
Time to create page: 0.064 seconds