With the imminent release Notifications 2016 R2, people are hearing that notifications has been rewritten and wondering "How do I configure notifications in code?"

 

The fundamental change to Notifications has been that Event Frames are now central to how a notification is triggered. The Notifications service monitors AF for changes and notifies users

when Event Frames are about are created, updated, or closed. Fortunately we have a built-in component that can be used to generate event frames when interesting things are happening in our system: Asset-based Analytics.

With this we will configure a simple analysis that triggers off of a tag and generate an event frame that will drive a notification.

 

Previously, Notifications had its own SDK that was used to assist in configuring AFNotification objects as well as query for history and acknowledge. There is no longer a separate SDK

for Notifications. The functionality provided by the old SDK will be supported by new objects and methods in AFSDK. One SDK to rule them all...

 

The primary new object in AFSDK is AFNotificationRule. There are some other new objects like AFDeliveryFormat and AFNotificationRuleSubscriber, but I will leave those details for later blog posts.

 

I'm assuming you've got AF 2016 R2 with the Analysis and Notifications services installed and running.

 

Without further ado, here is the example:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OSIsoft.AF;
using OSIsoft.AF.Analysis;
using OSIsoft.AF.EventFrame;
using OSIsoft.AF.Notification;
namespace AFSDKExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string afServerName = ConfigurationManager.AppSettings["afServer"];
            string dataArchiveName = ConfigurationManager.AppSettings["dataArchive"];
            var systems = new PISystems();
            var system = systems[ConfigurationManager.AppSettings["afServer"]];
            var db = system.Databases["notificationtestdb"] ?? system.Databases.Add("notificationtestdb");
            // create an event frame template for the analysis
            var eft = db.ElementTemplates["ExampleEventFrameTemplate"];
            if (eft == null)
            {
                Console.WriteLine("Creating event frame template");
                eft = db.ElementTemplates.Add("ExampleEventFrameTemplate");
                eft.InstanceType = typeof(AFEventFrame);
            }
            // create an element with an attribute
            var element = db.Elements["NotificationsExample"];
            if (element == null)
            {
                Console.WriteLine("Creating element");
                element = db.Elements.Add("NotificationsExample");
                var sinusoid = element.Attributes.Add("sinusoid");
                sinusoid.DataReferencePlugIn = system.DataReferencePlugIns["PI Point"];
                sinusoid.DataReference.ConfigString = $@"\\{dataArchiveName}\sinusoid";
            }
            // Configure an analysis with a condition 'sinusoid' > 50, data event-triggered.
            Console.WriteLine("Creating analysis");
            var analysis = element.Analyses.Add("Analysis*");
            analysis.AnalysisRulePlugIn = system.AnalysisRulePlugIns["EventFrame"];
            analysis.AnalysisRule.ConfigString = $"EFTGUID={eft.ID};EFTNAME={eft.Name}";
            var pe = analysis.AnalysisRule.AnalysisRules.Add(system.AnalysisRulePlugIns["PerformanceEquation"]);
            pe.ConfigString = "@group(\"Start triggers\") @severity(\"Warning\")\nStartTrigger1:= 'sinusoid' > 50;";
            analysis.TimeRulePlugIn = system.TimeRulePlugIns["Natural"];
            analysis.SetStatus(AFStatus.Enabled);
            // Configure the trigger for the notification rule
            Console.WriteLine("Creating notification");
            var notificationRule = element.NotificationRules.Add("MyNotification*");
            notificationRule.Criteria = $"AnalysisName:\"{analysis.Name}\"";
            notificationRule.SetStatus(AFStatus.Enabled);
            var testEmail = system.NotificationContactTemplates["TestEmail"];
            if (testEmail == null)
            {
                Console.WriteLine("Creating TestEmail endpoint");
                testEmail = new AFNotificationContactTemplate(system, "TestEmail");
                testEmail.DeliveryChannelPlugIn = system.DeliveryChannelPlugIns["Email"];
                testEmail.DeliveryChannel.ConfigString = "ToEmail=mike@testemail.com";
                testEmail.CheckIn();
            }
            // Add a subscription to a notification.
            notificationRule.Subscribers.Add(testEmail);
            db.CheckIn();
            Console.WriteLine("Done");
        }
    }

 

There are a few lines to take note of here.

The first is line 46 where start trigger is configured. This shows a new syntactic element in analysis PEs, annotations which are prefixed with @. The group annotation is used to organize elements of the PE. Start triggers are put into the "Start triggers" group.

This is not totally necessary here, but is needed if you want to use multiple start triggers. We've also set the severity of the generated event frame to Warning with the severity annotation.

 

Next on line 52 sets the main property needed to trigger a notification, Criteria. This is required to be a valid event frame search. To match the an event frame from the analysis we have just created, we simply need to provide a filter on the analysis name, since the analysis service will attach the analysis object to event frame.

 

Finally we configure a subscriber using email and add it in line 64.

 

So that's all there is to it. Note that event frame criteria could be some arbitrary criteria that matches event frames generated by some other tool that you've written using AFSDK.

 

Also one last pro-tip, if you want to programmatically configure something a certain way. Generally the easiest path is to create it in the UI then export to XML and view the properties. You can't export individual notifications right now but they are included by default when exporting an AFElement.