- Posts: 34
- Thank you received: 1
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.
Subscription to events
thank you very much for you support.
I found the problem.
There was an error in the way I specify the monitored item; this line in the code:
MonitoredItemArguments->NodeDescriptor->NodeId->ExpandedText = L"nsu=http://serverName;ns=2;s=StampingStrokeParametersEventType";
Thank you again!!
Best regards,
Federica
Please Log in or Create an account to join the conversation.
I have reviewed your code and do not see anything obviously wrong with it.
Here are some options we can do - possibly all of them.
1. Can you try your code (with modified node ID) against our demo server?
2. Will you be able to write and test a short C# program instead, against your real server - just to find whether the problem is maybe in your code (the C# is much shorter and not so error prone, and I can point you to the right example).
3. I can instruct you to take Wireshark logs of the successful (OPCExpert) and unsuccessful communication, and we will try to analyze where is the difference.
Best regards
Please Log in or Create an account to join the conversation.
UASimpleAttributeOperandPtr UABaseEventObject_Operands_NodeId (__uuidof(UASimpleAttributeOperand));
UABaseEventObject_Operands_NodeId->TypeId->NodeId->StandardName = L"BaseEventType";
UABaseEventObject_Operands_NodeId->AttributeId = UAAttributeId_NodeId;
_UAAttributeFieldPtr ToUAAttributeField(__uuidof(UAAttributeField));
ToUAAttributeField->Operand = UABaseEventObject_Operands_NodeId;
_UANodeIdPtr ObjectTypeIds_BaseEventType(__uuidof(UANodeId));
ObjectTypeIds_BaseEventType->StandardName = L"BaseEventType";
_UASimpleAttributeOperandPtr UAFilterElements_SimpleAttribute(__uuidof(UASimpleAttributeOperand));
UAFilterElements_SimpleAttribute->TypeId->NodeId = ObjectTypeIds_BaseEventType;
_UABrowsePathParserPtr UABrowsePathParserPtr(__uuidof(UABrowsePathParser));
_bstr_t fieldName("/SourceNode");
UAFilterElements_SimpleAttribute->QualifiedNames = UABrowsePathParserPtr->ParseRelative(fieldName)->ToUAQualifiedNameCollection();
_UAAttributeFieldPtr ToUAAttributeField1(__uuidof(UAAttributeField));
ToUAAttributeField1->Operand = UAFilterElements_SimpleAttribute;
_UAAttributeFieldCollectionPtr SelectClauses(__uuidof(UAAttributeFieldCollection));
_variant_t arg1 = _variant_t((IDispatch*)ToUAAttributeField);
_variant_t arg2 = _variant_t((IDispatch*)ToUAAttributeField1);
SelectClauses->Add(arg1);
SelectClauses->Add(arg2);
_UAEventFilterPtr EventFilter (__uuidof(UAEventFilter));
EventFilter->SelectClauses = SelectClauses;
_UAMonitoringParametersPtr MonitoringParameters (__uuidof(UAMonitoringParameters));
MonitoringParameters->SamplingInterval = 1000;
MonitoringParameters->EventFilter = EventFilter;
MonitoringParameters->QueueSize = 1000;
_EasyUAMonitoredItemArgumentsPtr MonitoredItemArguments(__uuidof(EasyUAMonitoredItemArguments));
MonitoredItemArguments->EndpointDescriptor->UrlString = L"opc.tcp://serverAddress:4840";
MonitoredItemArguments->NodeDescriptor->NodeId->ExpandedText = L"nsu=http://serverName;ns=2;s=StampingStrokeParametersEventType";
MonitoredItemArguments->MonitoringParameters = MonitoringParameters;
MonitoredItemArguments->AttributeId = UAAttributeId_EventNotifier;
CComSafeArray<VARIANT> arguments(1);
arguments.SetAt(0, _variant_t((IDispatch*)MonitoredItemArguments));
LPSAFEARRAY pArguments = arguments.Detach();
ClientPtr->SubscribeMultipleMonitoredItems(&pArguments);
arguments.Attach(pArguments);
Inside the event handler
STDMETHOD(EventNotification)(VARIANT varSender, _EasyUAEventNotificationEventArgs* pEventArgs)
{
long errorCode = pEventArgs->ErrorCode;
CString errorMsg = pEventArgs->ErrorMessage;
[...]
}
OPC-UA service result - An error specific to OPC-UA service occurred.
---- SERVICE RESULT ----
Status Code: {BadNotSupported} = 0x803D0000 (2151481344)
What could be the problem?
Do you know how can I check that all parms I specify are correct (for example, using UaExpert or another tool)?
Thank you
Please Log in or Create an account to join the conversation.
If you need different/more fields, you need to specify them using so-called Select Clauses - and use the "universal", all-capable method SubscribeMultipleMonitoredItems. You need to put together a UAAttributeFieldCollection with the attributes you are interested in, the create UAEventFilter where this collection will be in the SelectClauses property, create UAMonitoringParameters where you assign the EventFilter, and finally create UAMonitoredItemArguments where you assign the MonitoringParameters. We have some extension methods that make it easier in .NET, but in COM you need to go through the whole process.
There is currently no example for this in C++, but conceptually, you can use the following example we have made for Free Pascal (which is also COM-based):
// This example shows how to select fields for event notifications.
type
TClientEventHandlers4 = class
procedure OnEventNotification(
Sender: TObject;
sender0: OleVariant;
eventArgs: _EasyUAEventNotificationEventArgs);
end;
procedure TClientEventHandlers4.OnEventNotification(
Sender: TObject;
sender0: OleVariant;
eventArgs: _EasyUAEventNotificationEventArgs);
function ToUAAttributeField(Operand: UASimpleAttributeOperand): UAAttributeField;
var
AttributeField: UAAttributeField;
begin
AttributeField := CoUAAttributeField.Create;
AttributeField.Operand := Operand;
ToUAAttributeField := AttributeField;
end;
function UAFilterElements_SimpleAttribute(TypeId: UANodeId; SimpleRelativeBrowsePathString: string): UASimpleAttributeOperand;
var
Operand: UASimpleAttributeOperand;
BrowsePathParser: UABrowsePathParser;
begin
BrowsePathParser := CoUABrowsePathParser.Create;
Operand := CoUASimpleAttributeOperand.Create;
Operand.TypeId.NodeId := TypeId;
Operand.QualifiedNames := BrowsePathParser.ParseRelative(SimpleRelativeBrowsePathString).ToUAQualifiedNameCollection;
UAFilterElements_SimpleAttribute := Operand;
end;
function ObjectTypeIds_BaseEventType: UANodeId;
var
NodeId: UANodeId;
begin
NodeId := CoUANodeId.Create;
NodeId.StandardName := 'BaseEventType';
ObjectTypeIds_BaseEventType := NodeId;
end;
var
Count: Cardinal;
Element: OleVariant;
EntryEnumerator: IEnumVariant;
Entry: DictionaryEntry2;
AttributeField: UAAttributeField;
AValueResult: ValueResult;
begin
WriteLn;
// Display the event
if eventArgs.EventData = nil then
begin
WriteLn(eventArgs.ToString);
Exit;
end;
WriteLn('All fields:');
EntryEnumerator := eventArgs.EventData.FieldResults.GetEnumerator;
while EntryEnumerator.Next(1, Element, Count) = S_OK do
begin
Entry := IUnknown(Element) as DictionaryEntry2;
AttributeField := IUnknown(Entry.key) as UAAttributeField;
AValueResult := IUnknown(Entry.Value) as ValueResult;
WriteLn(' ', AttributeField.ToString, ' -> ', AValueResult.ToString);
end;
// Extracting a specific field using an event type ID and a simple relative path
WriteLn('Source name: ',
eventArgs.EventData.FieldResults[ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/SourceName'))].ToString);
WriteLn('Message: ',
eventArgs.EventData.FieldResults[ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/Message'))].ToString);
end;
class procedure SelectClauses.Main;
function ToUAAttributeField(Operand: UASimpleAttributeOperand): UAAttributeField;
var
AttributeField: UAAttributeField;
begin
AttributeField := CoUAAttributeField.Create;
AttributeField.Operand := Operand;
ToUAAttributeField := AttributeField;
end;
function ObjectTypeIds_BaseEventType: UANodeId;
var
NodeId: UANodeId;
begin
NodeId := CoUANodeId.Create;
NodeId.StandardName := 'BaseEventType';
ObjectTypeIds_BaseEventType := NodeId;
end;
function UABaseEventObject_Operands_NodeId: UASimpleAttributeOperand;
var
Operand: UASimpleAttributeOperand;
begin
Operand := CoUASimpleAttributeOperand.Create;
Operand.TypeId.NodeId.StandardName := 'BaseEventType';
Operand.AttributeId := UAAttributeId_NodeId;
UABaseEventObject_Operands_NodeId := Operand;
end;
function UAFilterElements_SimpleAttribute(TypeId: UANodeId; SimpleRelativeBrowsePathString: string): UASimpleAttributeOperand;
var
Operand: UASimpleAttributeOperand;
BrowsePathParser: UABrowsePathParser;
begin
BrowsePathParser := CoUABrowsePathParser.Create;
Operand := CoUASimpleAttributeOperand.Create;
Operand.TypeId.NodeId := TypeId;
Operand.QualifiedNames := BrowsePathParser.ParseRelative(SimpleRelativeBrowsePathString).ToUAQualifiedNameCollection;
UAFilterElements_SimpleAttribute := Operand;
end;
var
Arguments: OleVariant;
EvsClient: TEvsEasyUAClient;
Client: EasyUAClient;
ClientEventHandlers: TClientEventHandlers4;
Handle: Cardinal;
HandleArray: OleVariant;
MonitoredItemArguments: EasyUAMonitoredItemArguments;
MonitoringParameters: UAMonitoringParameters;
EventFilter: UAEventFilter;
SelectClauses: UAAttributeFieldCollection;
begin
// Instantiate the client object and hook events
EvsClient := TEvsEasyUAClient.Create(nil);
Client := EvsClient.ComServer;
ClientEventHandlers := TClientEventHandlers4.Create;
EvsClient.OnEventNotification := @ClientEventHandlers.OnEventNotification;
WriteLn('Subscribing...');
SelectClauses := CoUAAttributeFieldCollection.Create;
// Select specific fields using an event type ID and a simple relative path
SelectClauses.Add(ToUAAttributeField(UABaseEventObject_Operands_NodeId));
SelectClauses.Add(ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/SourceNode')));
SelectClauses.Add(ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/SourceName')));
SelectClauses.Add(ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/Time')));
SelectClauses.Add(ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/Message')));
SelectClauses.Add(ToUAAttributeField(UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/Severity')));
EventFilter := CoUAEventFilter.Create;
EventFilter.SelectClauses := SelectClauses;
MonitoringParameters := CoUAMonitoringParameters.Create;
MonitoringParameters.SamplingInterval := 1000;
MonitoringParameters.EventFilter := EventFilter;
MonitoringParameters.QueueSize := 1000;
MonitoredItemArguments := CoEasyUAMonitoredItemArguments.Create;
MonitoredItemArguments.EndpointDescriptor.UrlString := 'opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer';
MonitoredItemArguments.NodeDescriptor.NodeId.StandardName := 'Server';
MonitoredItemArguments.MonitoringParameters := MonitoringParameters;
//MonitoredItemArguments.SubscriptionParameters.PublishingInterval := 0;
MonitoredItemArguments.AttributeId := UAAttributeId_EventNotifier;
Arguments := VarArrayCreate([0, 0], varVariant);
Arguments[0] := MonitoredItemArguments;
TVarData(HandleArray).VType := varArray or varVariant;
TVarData(HandleArray).VArray := PVarArray(
Client.SubscribeMultipleMonitoredItems(PSafeArray(TVarData(Arguments).VArray)));
WriteLn('Processing event notifications for 30 seconds...');
PumpSleep(30*1000);
WriteLn('Unsubscribing...');
Client.UnsubscribeAllMonitoredItems;
WriteLn('Waiting for 5 seconds...');
PumpSleep(5*1000);
WriteLn('Done...');
end;
Please Log in or Create an account to join the conversation.
But the field I receive are only the "base" fields.
I can access to some fields (heighlighted in green in the attached picture, as "/Message", "/Severity", "/EventId" or"/SourceNode") but not to the fields specific of my event (heighlighted in red in the attached picture).
It seem that the fields specific of the "StampingStrokeParametersEvent" are skipped and not available inside the _EasyUAEventNotificationEventArgs object. Is it possibile?
Attachments:
Please Log in or Create an account to join the conversation.
opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...ieldResultDictionary~Item.html
Have you tried casting the GetItem result to _ValueResultPtr, and what were the results?
Best regards
Please Log in or Create an account to join the conversation.
I receive no error but I can't cast the result of "GetItem" to any valid object because it should be a "KeyValuePair" object, I think (_UAAttributeField in the Key and _ValueResult in the Value, as you said), but "KeyValuePair" is not a COM object (as you can see from the definition: docs.microsoft.com/it-it/dotnet/api/system.collections.gener...uepair-2?view=netframework-4.8).
Please Log in or Create an account to join the conversation.
What error do you get from GetItem?
It should also be possible to enumerate the contents of the dictionary. The entries coming form the enumeration should have _UAAttributeField in the Key and _ValueResult in the Value.
Best regards
Please Log in or Create an account to join the conversation.
I'm sorry for my late answer.
I update you about my problem.
I developed a test application written in C++ (MFC C++, not managed C++) where I subscribe for events generated from the server.
I have a method which is called every time an event is generated from the server.
With the event, I receive some fields.
Now I have problem accessing this fields.
I have an "_UAFieldResultDictionaryPtr" object which contains all the fields but I can't extract data from this structure.
I also tried searching for an "_UAAttributeFieldPtr" object inside this structure using "GetItem" method but with no success...
Help please...!
Thank you,
Federica
Please Log in or Create an account to join the conversation.
please describe what the problem is. I do not quite understand what you mean by "I'm trying to use "SubscribeEvents" method but I can't use it in my C++ COM application.".
Certainly SubscribeEvents can be used from C++. Is the issue that you do not know what QuickOPC calls to make, or is the issue that you do not know how to translate it to C++? Or is it thaty you do not quite understand the Eventing in OPC UA in general?
Because, we do have examples for SubscribeEvents - but it's true that currently, there are none in C++. This is because the code is by far the longest and ugliest to write, from all the languages... Have you had a look at following examples (in other languages)?
- opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...20to%20a%20single%20event.html
- opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...20to%20a%20single%20event.html
- opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...20to%20a%20single%20event.html
Some of these particular examples are also provided in Free Pascal, Object Pascal, VBScript or VB6, which are all COM based, meaning that in C++ you need the same sequence of calls, just written differently.
Best regards
Please Log in or Create an account to join the conversation.