ANSI C Based OPC UA Client/Server/PubSub SDK  1.9.1.442
Lesson 6: Create EventMonitoredItem

Files used in this lesson:

Step 1: Create Subscription with a Event Monitored Item

Sample client creates a subscription with EventMonitoredItem. The Event filter is set to receive only events of type "HeaterSwitchedEventType"(included in tutorial lesson05 server) and the event fields to include in the notification message are specified.

SampleSubscription *SampleSubscription_Create(UaClient_Session *a_pSession)
{
SampleSubscription *pSampleSubscription = OpcUa_Null;
UaClient_Subscription_Callback subscriptionCallback;
UaClient_Subscription *pSubscription = OpcUa_Null;
/* Allocate memory for the SampleSubscription */
pSampleSubscription = OpcUa_Alloc(sizeof(*pSampleSubscription));
if (pSampleSubscription == OpcUa_Null)
{
return OpcUa_Null;
}
/* Set callbacks */
OpcUa_MemSet(&subscriptionCallback, 0, sizeof(subscriptionCallback));
subscriptionCallback.pfStatusChanged_CB = SampleSubscription_StatusChanged_CB;
subscriptionCallback.pfDataChange_CB = SampleSubscription_DataChange_CB;
subscriptionCallback.pfNewEvents_CB = SampleSubscription_NewEvent_CB;
/* Create the underlying UaClient_Subscription */
uStatus = UaClient_Subscription_Create(a_pSession, &subscriptionCallback, &pSubscription);
if (OpcUa_IsBad(uStatus))
{
OpcUa_Free(pSampleSubscription);
return OpcUa_Null;
}
/* Initialize the SampleSubscription structure */
pSampleSubscription->pSubscription = pSubscription;
pSampleSubscription->uDataCount = 0;
pSampleSubscription->uMonitoredItemId = 0;
pSampleSubscription->State = State_SampleSubscription_Idle;
/* Set the most important Subscription properties */
pSubscription->pUserData = pSampleSubscription;
pSubscription->PublishingInterval = 1000.0;
return pSampleSubscription;
}
OpcUa_StatusCode SampleSubscription_CreateSubscription(SampleSubscription *a_pSampleSubscription)
{
a_pSampleSubscription->State = State_SampleSubscription_SubscriptionCreate;
return UaClient_Subscription_BeginCreateSubscription(a_pSampleSubscription->pSubscription,
OpcUa_Null,
SampleSubscription_Created_CB,
OpcUa_Null);
}
OpcUa_StatusCode SampleSubscription_CreateMonitoredItem(SampleSubscription *a_pSampleSubscription)
{
OpcUa_Int32 i;
OpcUa_Int32 numItemsToCreate = 1;
OpcUa_EventFilter *pEventFilter = OpcUa_Null;
OpcUa_LiteralOperand *pRawOperand = OpcUa_Null;
OpcUa_Int32 noOfSelectClauses = 3;
OpcUa_InitializeStatus(OpcUa_Module_Client, "SampleSubscription_CreateMonitoredItem");
a_pSampleSubscription->State = State_SampleSubscription_MonitoredItemCreate;
/* Fill in details of event monitored item */
OpcUa_MonitoredItemCreateRequest_Initialize(&itemsToCreate);
itemsToCreate.ItemToMonitor.AttributeId = OpcUa_Attributes_EventNotifier;
itemsToCreate.RequestedParameters.QueueSize = 0;
itemsToCreate.RequestedParameters.DiscardOldest = OpcUa_True;
itemsToCreate.ItemToMonitor.NodeId.Identifier.Numeric = OpcUaId_Server;
/* Set the Event Filter */
uStatus = OpcUa_EncodeableObject_CreateExtension(&OpcUa_EventFilter_EncodeableType,
&itemsToCreate.RequestedParameters.Filter,
(OpcUa_Void**)&pEventFilter);
OpcUa_GotoErrorIfBad(uStatus);
/* Fill in the eventfields to send with each event */
pEventFilter->NoOfSelectClauses = noOfSelectClauses;
pEventFilter->SelectClauses = (OpcUa_SimpleAttributeOperand*)OpcUa_Alloc(noOfSelectClauses * sizeof(OpcUa_SimpleAttributeOperand));
OpcUa_GotoErrorIfAllocFailed(pEventFilter->SelectClauses);
for (i = 0; i < noOfSelectClauses; i++)
{
OpcUa_SimpleAttributeOperand_Initialize(&pEventFilter->SelectClauses[i]);
}
pEventFilter->SelectClauses[0].NoOfBrowsePath = 1;
pEventFilter->SelectClauses[0].BrowsePath = (OpcUa_QualifiedName*)OpcUa_Alloc(sizeof(OpcUa_QualifiedName));
OpcUa_GotoErrorIfAllocFailed(pEventFilter->SelectClauses[0].BrowsePath);
OpcUa_QualifiedName_Initialize(pEventFilter->SelectClauses[0].BrowsePath);
uStatus = OpcUa_String_AttachCopy(&(pEventFilter->SelectClauses[0].BrowsePath->Name), "Message");
OpcUa_GotoErrorIfBad(uStatus);
pEventFilter->SelectClauses[0].BrowsePath->NamespaceIndex = 0;
pEventFilter->SelectClauses[0].AttributeId = OpcUa_Attributes_Value;
pEventFilter->SelectClauses[0].TypeDefinitionId.Identifier.Numeric = OpcUaId_BaseEventType;
pEventFilter->SelectClauses[1].NoOfBrowsePath = 1;
pEventFilter->SelectClauses[1].BrowsePath = (OpcUa_QualifiedName*)OpcUa_Alloc(sizeof(OpcUa_QualifiedName));
OpcUa_GotoErrorIfAllocFailed(pEventFilter->SelectClauses[1].BrowsePath);
OpcUa_QualifiedName_Initialize(pEventFilter->SelectClauses[1].BrowsePath);
uStatus = OpcUa_String_AttachCopy(&(pEventFilter->SelectClauses[1].BrowsePath->Name), "SourceName");
OpcUa_GotoErrorIfBad(uStatus);
pEventFilter->SelectClauses[1].BrowsePath->NamespaceIndex = 0;
pEventFilter->SelectClauses[1].AttributeId = OpcUa_Attributes_Value;
pEventFilter->SelectClauses[1].TypeDefinitionId.Identifier.Numeric = OpcUaId_BaseEventType;
pEventFilter->SelectClauses[2].NoOfBrowsePath = 1;
pEventFilter->SelectClauses[2].BrowsePath = (OpcUa_QualifiedName*)OpcUa_Alloc(sizeof(OpcUa_QualifiedName));
OpcUa_GotoErrorIfAllocFailed(pEventFilter->SelectClauses[2].BrowsePath);
OpcUa_QualifiedName_Initialize(pEventFilter->SelectClauses[2].BrowsePath);
uStatus = OpcUa_String_AttachCopy(&(pEventFilter->SelectClauses[2].BrowsePath->Name), "Severity");
OpcUa_GotoErrorIfBad(uStatus);
pEventFilter->SelectClauses[2].BrowsePath->NamespaceIndex = 0;
pEventFilter->SelectClauses[2].AttributeId = OpcUa_Attributes_Value;
pEventFilter->SelectClauses[2].TypeDefinitionId.Identifier.Numeric = OpcUaId_BaseEventType;
/* Fill in the Filter Operator and Filter Operand */
pEventFilter->WhereClause.NoOfElements = 1;
OpcUa_GotoErrorIfAllocFailed(pEventFilter->WhereClause.Elements);
pEventFilter->WhereClause.Elements->NoOfFilterOperands = 1;
OpcUa_GotoErrorIfAllocFailed(pEventFilter->WhereClause.Elements->FilterOperands);
uStatus = OpcUa_EncodeableObject_CreateExtension(&OpcUa_LiteralOperand_EncodeableType,
(OpcUa_Void**)&pRawOperand);
OpcUa_GotoErrorIfBad(uStatus);
/* Fill in details of "HeaterSwitchedEventType" included in lesson05 server */
pRawOperand->Value.Datatype = OpcUaType_NodeId;
pRawOperand->Value.Value.NodeId = (OpcUa_NodeId*)OpcUa_Alloc(sizeof(OpcUa_NodeId));
OpcUa_GotoErrorIfAllocFailed(pRawOperand->Value.Value.NodeId);
OpcUa_NodeId_Initialize(pRawOperand->Value.Value.NodeId);
pRawOperand->Value.Value.NodeId->NamespaceIndex = 4;
pRawOperand->Value.Value.NodeId->IdentifierType = OpcUa_IdentifierType_Numeric;
pRawOperand->Value.Value.NodeId->Identifier.Numeric = 2;
uStatus = UaClient_Subscription_BeginCreateMonitoredItems(a_pSampleSubscription->pSubscription,
OpcUa_Null,
numItemsToCreate,
&itemsToCreate,
SampleSubscription_MonitoredItems_Created_CB,
OpcUa_Null);
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_MonitoredItemCreateRequest_Clear(&itemsToCreate);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_MonitoredItemCreateRequest_Clear(&itemsToCreate);
OpcUa_FinishErrorHandling;
}

Step 2: Receive Event Notifications via UaClient_Subscription_Callback.pfNewEvents_CB

Sample client receives event notifications in NewEvents callback.

static OpcUa_Void SampleSubscription_NewEvent_CB(UaClient_Subscription *a_pSubscription,
OpcUa_Int32 a_noOfEvents,
OpcUa_EventFieldList *a_pEvents)
{
SampleSubscription *pSampleSubscription = a_pSubscription->pUserData;
OpcUa_Variant message = a_pEvents->EventFields[0];
OpcUa_Variant sourceName = a_pEvents->EventFields[1];
OpcUa_Variant severity = a_pEvents->EventFields[2];
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "\n--> SampleSubscription_NewEvent_CB\n\n");
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " noOfEvents: %i\n", a_noOfEvents);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Message = %s\n", OpcUa_String_GetRawString(&message.Value.LocalizedText->Text));
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "SourceName = %s\n", OpcUa_String_GetRawString(&sourceName.Value.String));
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Severity = %u\n", severity.Value.UInt16);
if (pSampleSubscription->State == State_SampleSubscription_WaitForNewEvent)
pSampleSubscription->State = State_SampleSubscription_NewEventReceived;
else
pSampleSubscription->State = State_SampleSubscription_Error;
}

Step 3: Call Methods to Trigger Events on Server

To test the event monitored item set up in the previous steps, Sample client calls method SetSwitchState of MyCustomMachine object that triggers an event matching filter criteria.

OpcUa_StatusCode Sample_MethodCall(UaClient_Session *a_pSession)
{
OpcUa_CallMethodRequest callMethodRequest;
OpcUa_InitializeStatus(OpcUa_Module_Client, "Sample_MethodCall");
OpcUa_CallMethodRequest_Initialize(&callMethodRequest);
/* Fill in details of SetSwitchState Method of MyCustomMachine Object included in lesson05 server*/
UaBase_CreateNumericNodeIdEx(&callMethodRequest.ObjectId, 15, 4);
UaBase_CreateNumericNodeIdEx(&callMethodRequest.MethodId, 19, 4);
callMethodRequest.InputArguments = (OpcUa_Variant*)OpcUa_Alloc(sizeof(OpcUa_Variant));
OpcUa_GotoErrorIfAllocFailed(callMethodRequest.InputArguments);
callMethodRequest.NoOfInputArguments = 1;
OpcUa_Variant_Initialize(&callMethodRequest.InputArguments[0]);
callMethodRequest.InputArguments[0].ArrayType = OpcUa_VariantArrayType_Scalar;
callMethodRequest.InputArguments[0].Datatype = OpcUaType_Boolean;
callMethodRequest.InputArguments[0].Value.Boolean = OpcUa_True;
uStatus = UaClient_Session_BeginCall(a_pSession,
OpcUa_Null,
&callMethodRequest,
Sample_MethodCall_CB,
OpcUa_Null);
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_CallMethodRequest_Clear(&callMethodRequest);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_CallMethodRequest_Clear(&callMethodRequest);
OpcUa_FinishErrorHandling;
}

Step 4: Integration in Main loop

/* Main loop */
while (!(bComplete && pSession->ConnectionStatus == UaClient_ConnectionStatus_Disconnected))
{
/* process sample state machine */
switch (clientContext.State)
{
case State_Idle:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Connecting to %s ...\n", SERVER_ENDPOINT_URL);
uStatus = UaClient_Session_BeginConnect(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Connect;
break;
case State_Connected:
/* create the sample subscription context */
pSampleSubscription = SampleSubscription_Create(pSession);
OpcUa_GotoErrorIfArgumentNull(pSampleSubscription);
/* create the server-side subscription */
uStatus = SampleSubscription_CreateSubscription(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Subscription;
break;
case State_Subscription:
switch (pSampleSubscription->State)
{
case State_SampleSubscription_SubscriptionCreateDone:
/* create monitored item */
uStatus = SampleSubscription_CreateMonitoredItem(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_MonitoredItemCreateDone:
/* call method */
uStatus = Sample_MethodCall(pSession);
OpcUa_GotoErrorIfBad(uStatus);
pSampleSubscription->State = State_SampleSubscription_WaitForNewEvent;
clientContext.State = State_MethodCall;
break;
case State_SampleSubscription_NewEventReceived:
/* delete the monitored item */
uStatus = SampleSubscription_DeleteMonitoredItem(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_MonitoredItemDeleteDone:
/* delete the subscription */
uStatus = SampleSubscription_DeleteSubscription(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_SubscriptionDeleteDone:
/* delete the sample subscription structure */
SampleSubscription_Delete(&pSampleSubscription);
pSampleSubscription = OpcUa_Null;
/* disconnect from the server */
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_False);
OpcUa_GotoErrorIfBad(uStatus);
/* exit the subscription state */
clientContext.State = State_Disconnect;
break;
case State_SampleSubscription_Error:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "An error occured. Terminating now.\n");
bComplete = OpcUa_True;
break;
default:
break;
}
break;
case State_MethodCallDone:
clientContext.State = State_Subscription;
break;
case State_Disconnected:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample successfully completed. Terminating now.\n");
bComplete = OpcUa_True;
break;
case State_Error:
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_True);
if (OpcUa_IsBad(uStatus) && uStatus != OpcUa_BadInvalidState) { OpcUa_GotoError; }
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "An error occured. Terminating now.\n");
bComplete = OpcUa_True;
break;
default:
break;
}
/* Process Ua Client events */
uStatus = UaBase_DoCom();
if (OpcUa_IsBad(uStatus))
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UaBase_DoCom failed (0x%08x)\n", uStatus);
bComplete = OpcUa_True;
}
}