This lesson describes how to monitor data changes of a node.
For an introduction to the concept of subscriptions and monitored items see OPC UA Subscription Concept.
Step 1: Introducing UaSubscription and UaSubscriptionCallback
To create monitored items, we need a subscription first.
Add a new header file samplesubscription.h containing the following code to your project:
#ifndef SAMPLESUBSCRIPTION_H
#define SAMPLESUBSCRIPTION_H
#include "uabase.h"
#include "uaclientsdk.h"
class SampleSubscription :
{
UA_DISABLE_COPY(SampleSubscription);
public:
SampleSubscription();
virtual ~SampleSubscription();
virtual void subscriptionStatusChanged(
OpcUa_UInt32 clientSubscriptionHandle,
virtual void dataChange(
OpcUa_UInt32 clientSubscriptionHandle,
const UaDataNotifications& dataNotifications,
const UaDiagnosticInfos& diagnosticInfos);
virtual void newEvents(
OpcUa_UInt32 clientSubscriptionHandle,
private:
};
#endif // SAMPLESUBSCRIPTION_H
UaSubscriptionCallback defines the callback interface for the UaSubscription class.
This callback interface needs to be implemented by the user of the UaSubscription class to receive data change, event and subscription status change callbacks from the Client SDK.
Add a new source file samplesubscription.cpp containing the following code to your project:
#include "samplesubscription.h"
#include "uasubscription.h"
#include "uasession.h"
SampleSubscription::SampleSubscription()
: m_pSession(NULL),
m_pSubscription(NULL)
{
}
SampleSubscription::~SampleSubscription()
{
}
The constructor and destructor remain empty so far.
Implement subscriptionStatusChanged:
void SampleSubscription::subscriptionStatusChanged(
OpcUa_UInt32 clientSubscriptionHandle,
{
OpcUa_ReferenceParameter(clientSubscriptionHandle);
printf(
"Subscription not longer valid - failed with status %s\n", status.
toString().
toUtf8());
}
Implement dataChange:
void SampleSubscription::dataChange(
OpcUa_UInt32 clientSubscriptionHandle,
const UaDataNotifications& dataNotifications,
const UaDiagnosticInfos& diagnosticInfos)
{
OpcUa_ReferenceParameter(clientSubscriptionHandle);
OpcUa_ReferenceParameter(diagnosticInfos);
OpcUa_UInt32 i = 0;
printf("-- DataChange Notification ---------------------------------\n");
for ( i=0; i<dataNotifications.length(); i++ )
{
if ( OpcUa_IsGood(dataNotifications[i].Value.StatusCode) )
{
UaVariant tempValue = dataNotifications[i].Value.Value;
printf(
" Variable %d value = %s\n", dataNotifications[i].ClientHandle, tempValue.
toString().
toUtf8());
}
else
{
UaStatus itemError(dataNotifications[i].Value.StatusCode);
printf(" Variable %d failed with status %s\n", dataNotifications[i].ClientHandle, itemError.toString().toUtf8());
}
}
printf("------------------------------------------------------------\n");
}
Implement newEvents:
void SampleSubscription::newEvents(
OpcUa_UInt32 clientSubscriptionHandle,
{
OpcUa_ReferenceParameter(clientSubscriptionHandle);
OpcUa_ReferenceParameter(eventFieldList);
}
Step 2: Creating and Deleting a Subscription
In a next step we are implementing the methods to create and delete a subscription.
Add the following code to samplesubscription.h
Implement createSubscription:
{
if ( m_pSubscription )
{
printf("\nError: Subscription already created\n");
return OpcUa_BadInvalidState;
}
m_pSession = pSession;
ServiceSettings serviceSettings;
SubscriptionSettings subscriptionSettings;
subscriptionSettings.publishingInterval = 100;
printf("\nCreating subscription ...\n");
result = pSession->createSubscription(
serviceSettings,
this,
1,
subscriptionSettings,
OpcUa_True,
&m_pSubscription);
{
printf("CreateSubscription succeeded\n");
}
else
{
m_pSubscription = NULL;
printf(
"CreateSubscription failed with status %s\n", result.
toString().
toUtf8());
}
return result;
}
See SubscriptionSettings for possible settings.
Implement deleteSubscription:
UaStatus SampleSubscription::deleteSubscription()
{
if ( m_pSubscription == NULL )
{
printf("\nError: No Subscription created\n");
return OpcUa_BadInvalidState;
}
ServiceSettings serviceSettings;
printf("\nDeleting subscription ...\n");
result = m_pSession->deleteSubscription(
serviceSettings,
&m_pSubscription);
{
printf("DeleteSubscription succeeded\n");
}
else
{
printf(
"DeleteSubscription failed with status %s\n", result.
toString().
toUtf8());
}
m_pSubscription = NULL;
return result;
}
Add the following code to the destructor of SampleSubscription:
SampleSubscription::~SampleSubscription()
{
if ( m_pSubscription )
{
deleteSubscription();
}
}
Add the marked lines to sampleclient.h
#ifndef SAMPLECLIENT_H
#define SAMPLECLIENT_H
#include "uabase.h"
#include "uaclientsdk.h"
class SampleSubscription;
{
UA_DISABLE_COPY(SampleClient);
public:
SampleClient();
virtual ~SampleClient();
private:
SampleSubscription* m_pSampleSubscription;
};
#endif // SAMPLECLIENT_H
Add the following code to sampleclient.cpp
#include "sampleclient.h"
#include "uasession.h"
#include "samplesubscription.h"
SampleClient::SampleClient()
{
m_pSampleSubscription = new SampleSubscription();
}
SampleClient::~SampleClient()
{
if (m_pSampleSubscription)
{
delete m_pSampleSubscription;
m_pSampleSubscription = NULL;
}
if (m_pSession)
{
...
Implement subscribe:
{
result = m_pSampleSubscription->createSubscription(m_pSession);
return result;
}
Implement unsubscribe:
{
return m_pSampleSubscription->deleteSubscription();
}
Complete main to create and delete a subscription.
...
{
status = pMyClient->read();
printf("\nPress Enter to create subscription\n");
printf("Press Enter again to stop subscription\n");
getchar();
status = pMyClient->subscribe();
{
getchar();
status = pMyClient->unsubscribe();
}
printf("\nPress Enter to disconnect\n");
getchar();
status = pMyClient->disconnect();
}
...
Step 3: Adding MonitoredItems to a Subscription
Now that we have a subcription, we can add monitored items to this subscription. In this example, the value ServerStatus → CurrentTime is monitored.
Add the following code to samplesubscription.h
...
UaStatus createSubscription(
UaSession* pSession);
...
Implement createMonitoredItems:
UaStatus SampleSubscription::createMonitoredItems()
{
if ( m_pSubscription == NULL )
{
printf("\nError: No Subscription created\n");
return OpcUa_BadInvalidState;
}
OpcUa_UInt32 i;
ServiceSettings serviceSettings;
itemsToCreate[0].ItemToMonitor.AttributeId = OpcUa_Attributes_Value;
itemsToCreate[0].ItemToMonitor.NodeId.Identifier.Numeric = OpcUaId_Server_ServerStatus_CurrentTime;
itemsToCreate[0].RequestedParameters.ClientHandle = 1;
itemsToCreate[0].RequestedParameters.SamplingInterval = 100;
itemsToCreate[0].RequestedParameters.QueueSize = 1;
itemsToCreate[0].RequestedParameters.DiscardOldest = OpcUa_True;
printf("\nAdding monitored items to subscription ...\n");
result = m_pSubscription->createMonitoredItems(
serviceSettings,
itemsToCreate,
createResults);
{
for (i = 0; i < createResults.length(); i++)
{
if (OpcUa_IsGood(createResults[i].StatusCode))
{
printf("CreateMonitoredItems succeeded for item: %s\n",
}
else
{
printf("CreateMonitoredItems failed for item: %s - Status %s\n",
}
}
}
else
{
printf(
"CreateMonitoredItems failed with status %s\n", result.
toString().
toUtf8());
}
return result;
}
First, the item to monitor and the corresponding settings are stored in itemsToCreate.
Then the method calls UaSubscription::createMonitoredItems.
Finally, we create the monitored item in the subscribe method:
{
result = m_pSampleSubscription->createSubscription(m_pSession);
{
result = m_pSampleSubscription->createMonitoredItems();
}
return result;
}