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-Classic in COM
- Reading, Writing, Subscriptions, Property Access
- Subscribing to a non-existent item
Subscribing to a non-existent item
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.
Please Log in or Create an account to join the conversation.
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.
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.
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.
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.
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.
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.
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.
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.
- Forum
- Discussions
- QuickOPC-Classic in COM
- Reading, Writing, Subscriptions, Property Access
- Subscribing to a non-existent item