OPC Studio User's Guide and Reference
OPC UA Data Change Filter
View with Navigation Tools
Client and Subscriber Development > Development Models > Imperative Programming Model > Imperative Programming Model for OPC Data (Classic and UA) > Subscribing to Information (OPC Data) > Subscribing to OPC UA Data Changes > OPC UA Data Change Filter
In This Topic

General

OPC UA Data Change Filter is used when you are only interested in certain kinds of changes in the monitored item, or need to reduce the amount of incoming notifications by specifying a deadband. The Data Change Filter defines the conditions under which a data change notification should be reported and, optionally, a range or band for value changes where no data change notification is generated.

The data change filter, in its entirety, is represented by the UADataChangeFilter Class, and is located in the DataChangeFilter Property of the UAMonitoringParameters Class. There are also useful overloads of various IEasyUAClient Interface extension methods, and implicit conversions, that allow you to shorten the code, if you do not want to create an instance of the data change filter class explicitly.

Data change trigger

One of typical use cases for the data change filter is when the client application is only interested in receiving new data when the status code or the value has changed, but not when new data has been collected with the same value (and the new data only differ in the timestamp or timestamps). In such case, a data change filter with the trigger set to UADataChangeTrigger.StatusValue is used.

Following examples show this, for a single node and for multiple nodes.

.NET

// This example shows how to subscribe to changes of a monitored item with data change filter.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeDataChange
    {
        public static void Filter()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events.
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_Filter;

            Console.WriteLine("Subscribing...");
            // Report a notification if either the StatusCode or the value change. 
            // The UADataChangeTrigger has an implicit conversion to UADataChangeFilter and can thus be used in its place.
            client.SubscribeDataChange(endpointDescriptor, "nsu=http://test.org/UA/Data/ ;i=10853", 1000, 
                dataChangeFilter:UADataChangeTrigger.StatusValue);

            Console.WriteLine("Processing data change events for 20 seconds...");
            System.Threading.Thread.Sleep(20 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }

        static void client_DataChangeNotification_Filter(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value.
            if (e.Succeeded)
                Console.WriteLine($"Value: {e.AttributeData.Value}");
            else
                Console.WriteLine($"*** Failure: {e.ErrorMessageBrief}");
        }
    }
}

COM

// This example shows how to subscribe to changes of a monitored item
// with data change filter.
//
// Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

type
  TClientEventHandlers120 = class
    procedure Client_DataChangeNotification(
      ASender: TObject;
      sender: OleVariant;
      const eventArgs: _EasyUADataChangeNotificationEventArgs);
  end;

procedure TClientEventHandlers120.Client_DataChangeNotification(
  ASender: TObject;
  sender: OleVariant;
  const eventArgs: _EasyUADataChangeNotificationEventArgs);
begin
  // Display the data
  if eventArgs.Succeeded then
  begin
      WriteLn(eventArgs.AttributeData.ToString);
  end
  else
      WriteLn(' *** Failure: ', eventArgs.ErrorMessageBrief);
end;

class procedure SubscribeDataChange.Filter;
const
  UADataChangeFilter_StatusValue = 1;
var
  Arguments: OleVariant;
  Client: TEasyUAClient;
  ClientEventHandlers: TClientEventHandlers120;
  DataChangeFilter: _UADataChangeFilter;
  EndpointDescriptor: string;
  MonitoringItemArguments1: _EasyUAMonitoredItemArguments;
  MonitoringParameters:  _UAMonitoringParameters;
begin
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object and hook events
  Client := TEasyUAClient.Create(nil);
  ClientEventHandlers := TClientEventHandlers120.Create;
  Client.OnDataChangeNotification := ClientEventHandlers.Client_DataChangeNotification;

  // Prepare the arguments.
  // Report a notification if either the StatusCode or the value change.
  DataChangeFilter := CoUADataChangeFilter.Create;
  DataChangeFilter.Trigger := UADataChangeFilter_StatusValue;
  MonitoringParameters := CoUAMonitoringParameters.Create;
  MonitoringParameters.DataChangeFilter := DataChangeFilter;
  MonitoringParameters.SamplingInterval := 100;
  MonitoringItemArguments1 := CoEasyUAMonitoredItemArguments.Create;
  MonitoringItemArguments1.EndpointDescriptor.UrlString := EndpointDescriptor;
  MonitoringItemArguments1.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=10853';
  MonitoringItemArguments1.MonitoringParameters := MonitoringParameters;

  Arguments := VarArrayCreate([0, 0], varVariant);
  Arguments[0] := MonitoringItemArguments1;

  WriteLn('Subscribing...');
  Client.SubscribeMultipleMonitoredItems(arguments);

  WriteLn('Processing monitored item changed events for 20 seconds...');
  PumpSleep(20*1000);

  WriteLn('Unsubscribing...');
  Client.UnsubscribeAllMonitoredItems;

  WriteLn('Waiting for 5 seconds...');
  PumpSleep(5*1000);

  WriteLn('Finished.');
  VarClear(Arguments);
  FreeAndNil(Client);
  FreeAndNil(ClientEventHandlers);
end;

 

 

.NET

// This example shows how to subscribe to changes of multiple monitored items and use a data change filter.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeMultipleMonitoredItems
    {
        public static void Filter()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events.
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_Filter;

            Console.WriteLine("Subscribing...");
            // Report a notification if either the StatusCode or the value change. 
            // The UADataChangeTrigger has an implicit conversion to UADataChangeFilter and can thus be used in its place.
            client.SubscribeMultipleMonitoredItems(new[]
                {
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor, 
                        "nsu=http://test.org/UA/Data/ ;i=10845", 
                        new UAMonitoringParameters(1000, UADataChangeTrigger.StatusValue)),
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor, 
                        "nsu=http://test.org/UA/Data/ ;i=10853", 
                        new UAMonitoringParameters(1000, UADataChangeTrigger.StatusValue)),
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor, 
                        "nsu=http://test.org/UA/Data/ ;i=10855", 
                        new UAMonitoringParameters(1000, UADataChangeTrigger.StatusValue))
                });

            Console.WriteLine("Processing monitored item changed events for 10 seconds...");
            System.Threading.Thread.Sleep(10 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }

        static void client_DataChangeNotification_Filter(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value.
            if (e.Succeeded)
                Console.WriteLine($"{e.Arguments.NodeDescriptor}: {e.AttributeData.Value}");
            else
                Console.WriteLine($"{e.Arguments.NodeDescriptor} *** Failure: {e.ErrorMessageBrief}");
        }
    }
}

COM

// This example shows how to subscribe to changes of multiple monitored items
// and use a data change filter.
//
// Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

type
  TClientEventHandlers122 = class
    procedure OnDataChangeNotification(
      ASender: TObject;
      sender: OleVariant;
      const eventArgs: _EasyUADataChangeNotificationEventArgs);
  end;

procedure TClientEventHandlers122.OnDataChangeNotification(
  ASender: TObject;
  sender: OleVariant;
  const eventArgs: _EasyUADataChangeNotificationEventArgs);
begin
  // Display the data
  if eventArgs.Succeeded then
      WriteLn(eventArgs.Arguments.NodeDescriptor.ToString, ': ',
      eventArgs.AttributeData.ToString)
  else
      WriteLn(eventArgs.Arguments.NodeDescriptor.ToString, ' *** Failure: ',
      eventArgs.ErrorMessageBrief);
end;

class procedure SubscribeMultipleMonitoredItems.Filter;
const
  UADataChangeFilter_StatusValue = 1;
var
  Arguments: OleVariant;
  Client: TEasyUAClient;
  ClientEventHandlers: TClientEventHandlers122;
  DataChangeFilter: _UADataChangeFilter;
  HandleArray: OleVariant;
  MonitoredItemArguments1, MonitoredItemArguments2, MonitoredItemArguments3:
    _EasyUAMonitoredItemArguments;
  MonitoringParameters: _UAMonitoringParameters;
begin
  // Instantiate the client object and hook events
  Client := TEasyUAClient.Create(nil);
  ClientEventHandlers := TClientEventHandlers122.Create;
  Client.OnDataChangeNotification := ClientEventHandlers.OnDataChangeNotification;

  // Prepare the arguments.
  // Report a notification if either the StatusCode or the value change.
  DataChangeFilter := CoUADataChangeFilter.Create;
  DataChangeFilter.Trigger := UADataChangeFilter_StatusValue;

  MonitoringParameters := CoUAMonitoringParameters.Create;
  MonitoringParameters.DataChangeFilter := DataChangeFilter;
  MonitoringParameters.SamplingInterval := 1000;
  MonitoredItemArguments1 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments1.EndpointDescriptor.UrlString := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  MonitoredItemArguments1.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=10845';
  MonitoredItemArguments1.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments2 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments2.EndpointDescriptor.UrlString := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  MonitoredItemArguments2.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=10853';
  MonitoredItemArguments2.MonitoringParameters := MonitoringParameters;
  MonitoredItemArguments3 := CoEasyUAMonitoredItemArguments.Create;
  MonitoredItemArguments3.EndpointDescriptor.UrlString := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  MonitoredItemArguments3.NodeDescriptor.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=10855';
  MonitoredItemArguments3.MonitoringParameters := MonitoringParameters;
  Arguments := VarArrayCreate([0, 2], varVariant);
  Arguments[0] := MonitoredItemArguments1;
  Arguments[1] := MonitoredItemArguments2;
  Arguments[2] := MonitoredItemArguments3;

  WriteLn('Subscribing...');
  TVarData(HandleArray).VType := varArray or varVariant;
  TVarData(HandleArray).VArray := PVarArray(
    Client.SubscribeMultipleMonitoredItems(Arguments));

  WriteLn('Processing monitored item changed events for 10 seconds...');
  PumpSleep(10*1000);

  WriteLn('Unsubscribing...');
  Client.UnsubscribeAllMonitoredItems;

  WriteLn('Waiting for 5 seconds...');
  Sleep(5*1000);

  WriteLn('Finished.');
  VarClear(HandleArray);
  VarClear(Arguments);
  FreeAndNil(Client);
  FreeAndNil(ClientEventHandlers);
end;

 

Absolute deadband

When absolute deadband is specified in the data change filter, the data change notification is only generated (by the server) when the absolute value of the difference between the last cached value and the current value exceeds the specified absolute deadband value.

Following example shows how it can be done when subscribing to a single monitored item.

// This example shows how to subscribe to changes of a monitored item with absolute deadband.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeDataChange
    {
        public static void AbsoluteDeadband()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_AbsoluteDeadband;

            const double absoluteDeadband = 50;
            Console.WriteLine($"Subscribing with absolute deadband {absoluteDeadband}...");
            // The UADataChangeFilter has an implicit conversion from Double, which creates a filter with the specified
            // absolute deadband.
            client.SubscribeDataChange(endpointDescriptor, 
                "nsu=http://test.org/UA/Data/ ;i=11194",    // /Data.Dynamic.AnalogScalar.Int32Value
                samplingInterval:1000, 
                dataChangeFilter: absoluteDeadband);

            Console.WriteLine("Processing data change events for 20 seconds...");
            System.Threading.Thread.Sleep(20 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);
        }

        static void client_DataChangeNotification_AbsoluteDeadband(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value
            if (e.Succeeded)
                Console.WriteLine("Value: {0}", e.AttributeData.Value);
            else
                Console.WriteLine("*** Failure: {0}", e.ErrorMessageBrief);
        }
    }
}

 

Similarly, the following example specifies absolute deadbands when subscribing to multiple monitored items for data changes.

// This example shows how to subscribe to changes of multiple monitored items with absolute deadband.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeMultipleMonitoredItems
    {
        public static void AbsoluteDeadband()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_AbsoluteDeadband;

            Console.WriteLine("Subscribing with different absolute deadbands...");
            // The UADataChangeFilter has an implicit conversion from Double, which creates a filter with the specified
            // absolute deadband.
            client.SubscribeMultipleMonitoredItems(new[]
                {
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor,
                        "nsu=http://test.org/UA/Data/ ;i=11194",    // /Data.Dynamic.AnalogScalar.Int32Value
                        new UAMonitoringParameters(samplingInterval:100, dataChangeFilter:50)),
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor,
                        "nsu=http://test.org/UA/Data/ ;i=11218",    // /Data.Dynamic.AnalogScalar.FloatValue
                        new UAMonitoringParameters(samplingInterval:100, dataChangeFilter:20))
                });

            Console.WriteLine("Processing monitored item changed events for 10 seconds...");
            System.Threading.Thread.Sleep(10 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);
        }

        static void client_DataChangeNotification_AbsoluteDeadband(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value
            if (e.Succeeded)
                Console.WriteLine("{0}: {1}", e.Arguments.NodeDescriptor, e.AttributeData.Value);
            else
                Console.WriteLine("{0} *** Failure: {1}", e.Arguments.NodeDescriptor, e.ErrorMessageBrief);
        }
    }
}

 

Percent deadband

When percent deadband is used, the actual value of the deadband is computed as a relative portion from the range of values typical for the node. This only works with AnalogItems with an EURange property.

Following example shows how precent deadband can be specified when subscribing to a single monitored item.

// This example shows how to subscribe to changes of a monitored item with percent deadband.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeDataChange
    {
        public static void PercentDeadband()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_PercentDeadband;

            const double percentDeadband = 5.0;
            Console.WriteLine($"Subscribing with {percentDeadband}% deadband...");
            client.SubscribeDataChange(endpointDescriptor, 
                "nsu=http://test.org/UA/Data/ ;i=11194",    // /Data.Dynamic.AnalogScalar.Int32Value
                samplingInterval:1000, 
                new UADataChangeFilter(UADeadbandType.Percent, percentDeadband));

            Console.WriteLine("Processing data change events for 20 seconds...");
            System.Threading.Thread.Sleep(20 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);
        }

        static void client_DataChangeNotification_PercentDeadband(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value
            if (e.Succeeded)
                Console.WriteLine("Value: {0}", e.AttributeData.Value);
            else
                Console.WriteLine("*** Failure: {0}", e.ErrorMessageBrief);
        }
    }
}

 

Similarly, the following example specifies absolute deadbands when subscribing to multiple monitored items for data changes.

// This example shows how to subscribe to changes of multiple monitored items with percent deadband.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._EasyUAClient
{
    partial class SubscribeMultipleMonitoredItems
    {
        public static void PercentDeadband()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object and hook events
            var client = new EasyUAClient();
            client.DataChangeNotification += client_DataChangeNotification_PercentDeadband;

            Console.WriteLine("Subscribing with different percent deadbands...");
            client.SubscribeMultipleMonitoredItems(new[]
                {
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor,
                        "nsu=http://test.org/UA/Data/ ;i=11194",    // /Data.Dynamic.AnalogScalar.Int32Value
                        new UAMonitoringParameters(
                            samplingInterval:100,
                            new UADataChangeFilter(UADeadbandType.Percent, 5.0))),
                    new EasyUAMonitoredItemArguments(null, endpointDescriptor,
                        "nsu=http://test.org/UA/Data/ ;i=11218",    // /Data.Dynamic.AnalogScalar.FloatValue
                        new UAMonitoringParameters(
                            samplingInterval:100,
                            new UADataChangeFilter(UADeadbandType.Percent, 10.0)))
                });

            Console.WriteLine("Processing monitored item changed events for 10 seconds...");
            System.Threading.Thread.Sleep(10 * 1000);

            Console.WriteLine("Unsubscribing...");
            client.UnsubscribeAllMonitoredItems();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);
        }

        static void client_DataChangeNotification_PercentDeadband(object sender, EasyUADataChangeNotificationEventArgs e)
        {
            // Display value
            if (e.Succeeded)
                Console.WriteLine("{0}: {1}", e.Arguments.NodeDescriptor, e.AttributeData.Value);
            else
                Console.WriteLine("{0} *** Failure: {1}", e.Arguments.NodeDescriptor, e.ErrorMessageBrief);
        }
    }
}

 

 

See Also

Examples - Reactive Programming

Examples - OPC Unified Architecture