Notifications in Personal Event Networks


Summary

Providing event APIs for common services and then supplying rulesets that handle those services make personal event networks more powerful and easier to use. this post describes a notification system for Kynetx personal event networks.

10 floppies

If you're old enough to remember WordPerfect on DOS, it always came with a stack of disks for the printer drivers. That's because DOS had no printer drivers. Every application had to handle the printer itself. Every program treated the printer differently and the results were uneven at best. WordPerfect and other programs succeeded where others failed partly on the strength of their printer drivers. When Windows came along, it included printer drivers. This was a big change; once the OS knew about your printer and how to work with it, any application could print without ever worrying about the printer or how it works. I suspect WordPerfect had a dozen or more people working on printer drivers back in the day. With Windows that burden went away. (Well, not really since WordPerfect couldn't let go of DOS, but that's a different story...the burden could have gone away).

In the same way, providing event APIs for common services and then supplying rulesets that handle those services make personal event networks more powerful and easier to use. Personal event networks unleash tremendous power for apps to cooperate to provide better and more flexible services for their owners and a great deal of leverage for programmers who don't have to program all those services over and over.

A few weeks ago, I blogged about the new Sky API and what it means for KRL programmers. With Sky, KRL developers can raise events that any app a user has activated will see. In this post, I'll discuss a generalized event API for notiications. This is going to be a long post, so hang on. I'll break it up into sections that deal with specific parts of the post. You can probably stop reading after any section and have a good idea of why this matters to a certain level of specificity.

Notification Events

Urgent News

The Notification Event API defines an event domain, notification and two event types, status and log. Today, I'm going to focus on status events.

A status event has several attributes:

  • application (optional) - name of the application/ruleset raising the notification event. If not application is given, the current ruleset ID is used.
  • subject (required) - subject (title) of the notification. Typically a subject is one line.
  • description (optional) - additional information beyond what is in the subject.
  • priority (optional) - Every notification has a priority. If not priority is given, the priority is 0. The priorities are:
    • -2 (Very low)
    • -1 (Moderate)
    • 0 (Normal)
    • +1 (High)
    • +2 (Emergency)
  • id (optional) - a unique identifier that the event raiser chooses.

Our purpose in defining the Notification Event API is to put a stake in the ground around how notifications messages will be handled in a personal event network. With such a standard, developers can write apps that manage the notifications for a user's personal event network. Other developers can raise notification events knowing that if the user wants to see notifications, they will have activated an application that handles them. In effect, the Notification Event API is the printer interface for a personal event network.

This is the key point: with this development, KRL developers don't ever have to build notifications into their apps or worry about meeting the user's demands with regard to how they want to be notified. That's someone else's job. I anticipate that we'll give everyone with a KBX a basic notification application that they can use and configure. If they don't like that one, they can replace it with another one so long as it handles events as specified in the Notification Event API

For example, the basic notification app will likely make heavy use of email and SMS, but you could imagine someone building and selling an app that uses a service like Urban Airship to send notifications to a custom mobile application that manages them, allows for responses, and so on.

Events in the Personal Event Network

This wouldn't work if every app needing to make a notification had to be configured so it knew the identifier of the app that the user wanted to handle notifications. That's why Sky is so important.

I have a Simple Notification app and a Notification Testing app activated in my Kynetx account. The test app paints a form on a page and when the form is submitted turns the fields in the form into a notifiation:status event. Because the Simple Notification app is listening for notification:status events, it responds. Nothing links them except that I have them both activated in my account. If I delete the Simple Notification app and replace it with another that understands the Notification Event API, that new app will automatically start processing notifications for me. I can have more than one app listening for notification events. moreover, I can activate a dozen or a hundred apps that raise notification:status events and they will all be handled by whatever apps I've activated to listen for those particular events.

By defining the semantics of some common APIs like the one for notifications, we can start to build out flexible services on top of personal event networks. Users are in complete control of which apps they activate to handle those services. I suspect that most people will use the standard ones that we supply, but I also hope other developers see value in creating custom rulesets to handle common events.

This isn't unlike drivers for an operating system or standard services in application server. I'd be hard pressed to overemphasize the importance of this fact. Personal event networks are real and work now.

If you've been following along for the last year, you might be scratching your head and thinking "wait a minute, I thought that the apps I activated in my Kynetx account were 'browser apps' and just affected my browsing experience!" Nope! Those apps are functioning on the personal event network you created when you signed up for a Kynetx account. It just happens that all of the ones you've activated to date, work in the browser. They don't have to.

Processing Status Notifications

The simple notification ruleset has three rules to handle status notifications: one for notifications with priority 2, one for notifications with priority 0 or 1, and one for notifications with priority less than 0.

The meta section declares three libraries we're going to use: prowl, sendgrid, and Google spreadsheets:

use module a16x83 alias prowl with 
  apikey = keys:prowl_test("apikey") and 
  providerkey = keys:prowl_test("providerkey") and
  application = "Kynetx Notification Manager"
          
use module a16x129 version "dev" alias sendgrid with
  api_user = keys:sendgrid("api_user") and 
  api_key = keys:sendgrid("api_key") and
  application = "Kynetx Notification Manager"

use module a163x73 version "dev" alias spreadsheet with
  docskey = keys:docskey();

The ruleset processes event attributes, including setting defaults, in the global block so that they're available for the various rules:

global {
  app = event:attr("application");
  subj = event:attr("subject") || 
     "Status Notification for #{app}";
  priority = event:attr("priority") || 0;
  description = event:attr("description") || 
     "A status notification with priority 
      #{priority} was received from #{app}." ;
}

Low priority notifications (less than 0) are handled by the logonly rule. The logonly rule uses a Google spreadsheet module to merely save the notification in a "logging" spreadsheet to they can be viewed later:

rule low {
  select when notification status priority "^-[12]$"
  spreadsheet:submitrow() with 
      values = [app, priority, subj, description]
}

The result of this rule firing is a logging line in a google spreadsheet that records the attributes of the notification:

Google notification
(click to enlarge)

Medium priority notifications (0 or 1) are handled by the routine rule. The routine rule uses a SendGrid module to send an email to the owner of the personal event network. Right now, I'm storing the email address in an entity variable and setting it in a configuration step, but eventually that kind of data ought to be routinely available to the personal event network without multiple configurations.

rule routine {
  select when notification status priority "^[01]$"
  sendgrid:send(name, 
                ent:email_address, 
                "#{app}: #{subj}", 
                description);
}

The result of this rule fire is an email that looks like this:

Email notification

High priority notifications (2) are handled by the urgent rule. The urgent rule uses Prowl and a Prowl module to push notifications to the owner's phone. SMS is more generally available and would be a better choice for widely used ruleset, but I was anxious to try out Prowl. (Kind of a poor man's Urban Airship.)

rule urgent {
  select when notification status priority "^2$"
  prowl:notify(subj, description) with priority = priority;
}

The result of this rule firing is a push notification to my phone:

Prowl notification

The ruleset could be improved in a number of ways, including providing more configuration options for choosing what level of notifications get sent where and breaking out all five levels of notifications.

Using the Simple Notification App

As I said, any ruleset that the owner of the personal event network has activated can raise a notification:status event and the simple notification app will handle it according to the rules we just reviewed. To test it, I wrote a ruleset that places a form on a page and then raises notification:status events with the event attributes taken from the form. Here's an example of the form:

Priority 2 form

Here's the rule that handles the form submission:

rule respond_submit is active {
  select when web submit "#test_form"
  noop();
  always {
    raise notification event status with
      priority = event:attr("priority") and
      application = 
        event:attr("application") || "Kynetx Test" and
      subject = event:attr("subject") || "No Subject" and
      description = event:attr("desc") and
      _api = "sky"
  }
} 

The important part is the rule postlude (the always clause) where a notification:status event is raised with the appropriate attributes (taken from the form). Note that the raise statement does not specify the previous ruleset or any other for handling the event. That is determined automatically by the system based on what apps the owner of the personal event network has activate.

The only tricky part is the special attribute _api that tells the rules engine to use Sky API processing semantics when the event is raised. The current runtime still uses the Blue API and the rules engine tries to maintain consistency--if you start with Blue, it's Blue all the way through...unless you force another API as I have here.

Conclusions

If you're still with me, congratulations. This post has demonstrated the power of common services in a personal event network and shown how they can be implemented and leveraged. To summarize:

  • Sky means that any ruleset a personal event network owner activates will see relevant events from other rulesets that have been activated in the same network.
  • The Notification Event API defines a generalized service API for personal event networks. More will follow. If you have suggestions of other common services that ought to be standardized with an API, we're listening.
  • There will be certain services, like notifications, that every almost personal event network has a ruleset to handle. They can be customized to match the purpose of the personal event network.