PI and Python? PIthon!

Blog Post created by rborges Employee on Aug 1, 2016

Hello everybody! Today I'm going to talk about my favorite programming language: Python. More specifically, how to integrate Python and our beloved AF SDK in order to extract data from PI. PI and Python? Let's call it PIthon.


Some of you may be wondering why would one do that. (If you are not, jump to the next paragraph). Well, Python has a very active community and is a well established programming language. It's multi-platform and has an uncountable number of libraries and tools. It's also heavily used for big data analytics when used together with libraries like SciPy and NumPy.


First, let me explain why I'm not using IronPython. If you don't know what it is, let me get its description: "IronPython is an implementation of the Python programming language targeting the .NET Framework and Mono.". See the problem? It's an implementation (C# if you are wondering) and not pure Python, so it frequently has problems integrating with third-party libraries. Also, it targets Mono (i.e Linux) and currently AF SDK does not support it. Last but not least, the latest stable release was almost two years ago, so things may be very outdated.


So let's start. For this tutorial you will need:

- A Windows box

- Python 2.7

- AF SDK (Included in the AF Client installer)

- Pythonnet


Proceed with the installation of everything and once it's done, go ahead and create a module called PIthon. Now comes the most important part: libraries import.


import sys
sys.path.append('C:\\Program Files (x86)\\PIPC\\AF\\PublicAssemblies\\4.0\\')
import clr


And that's all. No kidding. It's so simple I don't dare to explain it. The important thing is that from here you can use a syntax that resembles a lot C# development. Start by importing classes:


from OSIsoft.AF.PI import *
from OSIsoft.AF.Search import *
from OSIsoft.AF.Asset import *
from OSIsoft.AF.Data import *
from OSIsoft.AF.Time import *


Now let's create two important functions.


def connect_to_Server(serverName):
    piServers = PIServers()
    global piServer
    piServer = piServers[serverName]

def get_tag_snapshot(tagname):
    tag = PIPoint.FindPIPoint(piServer, tagname)
    lastData = tag.Snapshot()
    return lastData.Value, lastData.Timestamp


Did you notice how close to C# development this is? Most of the time is pretty much the same, but let me give you a very important tip : PythonNet does not handle well optional parameters from .NET assemblies, so you always need to be explicit. That's why I had to pass False on piServer.Connect. The explicit parameter allows me to dodge the optional parameter problem.


Well, from here you have your module, so let's use it! Go ahead and create a new script and use PIthon:


from PIthon import PIthon

value, timestamp = PIConnector.get_tag_snapshot('sinusoid')
print('Timestamp: {0} Value: {1}'.format(timestamp, value))


And if you run this...

Timestamp: 8/1/2016 5:03:59 PM Value: 73.48035

Voilà! See how simple it was? From here you have the base to create your own AF SDK module for Python! And if you have any questions, feel free to ask them!


Have fun coding with PIthon!