Skip navigation
All People > MaxStrueverWipro > Max Struever's PI Blog

My hackathon submission will (if I have time) have two parts.

GitHub - madmaxlax/OSIsoftVisualizationHackathon: submission for PI hackathon

I ran into a nasty caching issue (bug?) where the DataShape was incorrectly getting a value from an earlier file version. That got me held up for a while


Part 1 Timestamp Color Scale

Screen cast on youtube

As a PI admin, data 'freshness' or, how recently a tag or group of tags has gotten data, is of the utmost importance to me. I have made a lot of PB displays (and other apps!) to try and get an idea of how my interfaces are doing and if there's recent data.

Multi-state is only helpful for the actual value of the PI tag, and not anything related to the timestamp.

So I wanted to create a symbol that shows this info.

It is mostly just an extension of the regular Value symbol, but with a color scale on the timestamp.

Untitled.pngas the value doesn't change and becomes more 'stale' the color changes from green to yellow to red.


In the symbol configuration, you can set up how long ago is considered "old"

for example, if you want everything over an hour to show up as red, you set the "red time" to 60 minutes ago.

anything older than 60 mins will be red. any values between now and 60 minutes will be on a green-yellow-red color scale.


Part 2 Bullet Graph

(submitted a little late apologies; was working solo and weekend got away from me due to unexpectedly good weather here in Amsterdam)

Based off the specification laid out here

Idea by Jason Wallace

Screen cast on youtube (sorry I couldn't get audio to work, but it's hopefully self-explanatory!)

This symbol is similar to a bar graph, but extends it with some options for a few other comparative metrics, as laid out in the design spec linked above

The bullet graph lets you add a bad, warning, and good range, as well as a comparative value (for example; a previous run's results or maybe a golden batch value)

With my AF server and PI notifications, we have a lot of notifications running, and a lot that are automatically created from templates.

AF automatically names them "Notification37" or something, which I find to not be particularly helpful.

I wrote a small app that goes through the notifications, and renames them based on their target, parent, and template name (you can of course change how exactly the renaming works for you


it is a little C# console app

I put it up on my github as well GitHub - madmaxlax/OSIsoftAFNotificationsRename: A small app that goes through your automatically-created notifications …


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PISDK;
using OSIsoft.AF;
using OSIsoft.AF.Asset;
using System.Configuration;
using System.Diagnostics;
using System.IO;

namespace NotificationsRename
    class Program
        static void Main(string[] args)
  //connect to AF
            string pisysname = ConfigurationSettings.AppSettings["PISystemName"];
            string Afdbname = ConfigurationSettings.AppSettings["afdb"];
            Console.WriteLine("Connecting to AF DB " + Afdbname + " on " + pisysname);
            PISystem PISys = new PISystems()[pisysname];
            AFDatabase AFDb = PISys.Databases[Afdbname];
            Console.WriteLine("Connected to AF DB " + Afdbname + " on " + pisysname);
  //refresh and check in, just in case

            Console.WriteLine("Ready to begin? Press any key");

            foreach(OSIsoft.AF.Notification.AFNotification curr in AFDb.Notifications)
  //only change name of notifications coming from templates (which have a name)
                if (! (curr.Template == null) )
  //this is the format I chose for the naming: [Template name] [parent name]-[element name]
  string newname = curr.Template.Name + " " + ((OSIsoft.AF.Asset.AFElement)(curr.Target)).Parent.Name + "-" + curr.Target.ToString();
                    Console.WriteLine("Renaming this notification: " + curr.Name + " to: "+ newname);
                    //rename the notification
                        curr.Name = newname;
                    catch (Exception e)
                        Console.WriteLine("*Unable to rename: " + e.Message);
                Console.WriteLine("Name: " + curr.Name);

            Console.WriteLine("Checking in changes...");
            Console.WriteLine("Press enter to quit");


By request of a user, I needed to change all the values to show 3 decimal places in a given display.

The display had a ton of values, and I had to do it on several displays. I wanted to find an easier way to do this. After some messing around in VBA, I got this simple function to work:


Option Exclicit Public Sub decimals() 'set up some vars to be used     Dim symb As Symbol     Dim name As String     Dim typ As Integer     Dim tagname As String     Dim val As Value 'go through all symbols in a display     For Each symb In ThisDisplay.Symbols         name =         typ = symb.Type           'type 7 symbols are Values         If typ = 7 Then                  'get the name of the PI point (if you only want to change certain tags)                'format is \\servername\PointName             tagname = symb.GetTagName(1)                 'this will only change tags with the word 'temp' in the name, you can take this if statement out if you want to change all  values             If InStr(1, tagname, "temp") Then                'need to have a var of type Value to set the number format                 Set val = symb                'sets the formal to 3 decimals always                 val.NumberFormat = "0.000"             End If                      End If                            Next      End Sub




Added to github repo

GitHub - madmaxlax/helpful-OSIsoftProcessBookVBA: a collection of helpful VBA functions for ProcessBook