Skip navigation
All Places > PI Developers Club > Blog > 2014 > June
2014

Anyone who was at vCampus Live this past year may remember a session on what was then known as “PI Geo Services.” We showed a proof-of-concept delivering PI data into Esri’s ArcGIS geospatial platform, just a few months after having begun product development in earnest. Since then, the product name has changed and our team has grown slightly – and we are proud to announce the beta availability of PI Integrator for Esri ArcGIS!

 

 

 

6758.osiandesri.png

 

 

 

 

 

The idea behind the product is – not surprisingly – to stick PI data on a map. For many of us (including both developers on the project), we’re probably muttering “yeah, I wrote something like that one afternoon, with the Google Maps API and some beer.” Unsurprisingly, one of the first things our team learned (as PI guys) was that true geospatial folks (e.g. Esri) take maps really seriously. To them, in the beginning before we got to know each other, we were just “a database” – and to us, they were “a map.” That’s all fixed now, of course. In the same way that OSIsoft has built a company around time-series data, Esri has built a company around maps and geo-analytics. That rabbit hole goes deep, and it’s pretty cool to imagine analytical situations where time and space collide. Herein lies much of the power of our new product – the folks who know PI and PI data can very easily deliver that data into the skilled hands of Esri ArcGIS gurus.

 

This product is really supposed to be a product, and not something requiring extensive custom work/rework every time you need new widgets on a map. “Point, click, done” is the goal. So the human interface with PI Integrator for Esri ArcGIS is a friendly Configuration Portal.

 

7737.streamlist_2D00_sm.png

 

 

 

 

 

Within the Configuration Portal, you configure map services which are containers for map layers. In our implementation, map layers are like an AF Element search for one specific AF Element Template. You could configure a map layer to point to { your production PI AF Server, the NuGreen database, elements of the Boiler template, within Houston } – and then the data for all of those boilers is ready to stream out and onto a map. That publishing process is handled by a graphical wizard. Once the PI data is live on an ArcGIS map, the circle can be completed by linking back into a PI Coresight display.

 

6064.dashboard_2D00_sm.png

 

 

 

 

 

Architecturally, we've built the product to share a codebase for on-premises deployment (onto an IIS Server) and an Azure cloud deployment. This open beta announcement is for the on-premises deployment, which we’re focusing on for now.

 

Architecturally, zoomed in a bit: the product consists of two main components – a Data Relay service (read: PI AF client) and a Configuration Portal (read: web application). The Data Relay service gathers PI data, executes AF data references, and such. The Configuration Portal, as the name suggests, is the front-end to the product. It is also the muscle behind packaging and pushing data from the Data Relay node over to the ArcGIS system.

 

Right now, all data passes through Esri’s GeoEvent Processor engine and then into an ArcGIS Feature Layer which feeds maps. In upcoming releases, we’ll be doing some things to expose historical data and event frames. Right now, we’re very happy to start with real-time data!

 

5850.data_2D00_flow.png

 

 

 

 

 

If you’re itching to jump in and get started, there’s a full-fledged user manual available on the Tech Support website and within the download bundle – and, just as importantly, release notes! Since this is a beta, the section of the release notes titled “Known Issues” is mandatory reading :) ... Other than reading the release notes and user guide, my best advice is to find a buddy who knows ArcGIS. They’ll know how to work magic with the PI data you put in their hands. And they will be an indispensable interpreter as you get the hang of the ArcGIS lexicon.

 

Our talk from the San Francisco Users Conference this year has some further detail on the product and its provenance, scope and direction: http://www.osisoft.com/Templates/item-abstract.aspx?id=10993 Note that much time has passed since our vCL!13 talk, but for the sake of posterity, it’s at http://www.osisoft.com/Templates/item-abstract.aspx?id=10819

 

In the next post, we’ll outline the process of getting started with the product, and perhaps show an example of the product in action.

 

A big thanks to the rest of our team, and a heartfelt cheers to all who take our product for a spin!

 

Michael van der Veeken
Brandon Perry

PI Web API is coming soon and I hope this blog post will help you develop your custom web application taking advantage of the features provided on the latest release of jQuery and HTML5.

 

As you probably know already, PI Web API is a RESTful web service on top of the PI System whose beta version could be downloaded from the vCampus Download Center. In order to clarify some concepts of jQuery and RESTful service, I invite you to read one of my previous blog posts: Calling RESTful services using jQuery.

 

In this blog post you will learn how to develop a HTML5 pages using jQuery showing PI System data without the need of a server-side scripting like PHP or ASP.NET. Please download the source code package by visiting this GitHub repository.

Objectives

 

The sample application is an example about how to use the PI Web API module within your custom HTML5 web pages.  You can download the source code package here.

 

Once the form-data is filled, this application, should:

  • Validate if the PI Data Archive name is correct and if PI Web API is able to connect to it.
  • Validate if the given PI Point name exists on the PI Data Archive
  • Get the snapshot, recorded and interpolated values if the related parameters are properly defined.
  • Show the requested data on an HTML5 page, updating the DOM (Document Object Model) objects with jQuery.

In order to make this work more scalable, a PI Web API module was developed.

 

PI Web API module

 

 

The module is simply a js file extension with 6 public methods available:

  •         SetBaseServiceUrl(string baseUrl) --> This method defined the BaseServiceUrl so that all the other methods could connect to PI Web API. This method should always the the first one to be executed otherwise the other methods will receive an exception.
  •         ValidPIServerName(piServerName) -->Checks if the PI Data Archive name is valid.
  •         ValidPIPointName(piServerName, piPointName) -->Checks if the PI Point name exists within the chosen PI Data Archive.
  •         GetSnapshotValue(piServerName, piPointName) --> Gets the snapshot value  of the selected PI Point.
  •         GetRecordedValues(piServerName, piPointName, startTime, endTime) -->Gets the recorded values  within the chosen start time, end time and PI Point name.
  •         GetInterpolatedValues(piServerName, piPointName, startTime, endTime, interval) -->Gets the interpolated values  within the chosen start time, end time, interval and PI Point name.

Although the methods are able to connect only to the PI Data Archive, you can easily extend them adding new features to connect to the AF Server or to insert new values to in a PI Point using the POST transaction.

 

The complete code of this module is on the file piwebapi_class.js within the source code package under js folder or below:

 

 

 

 

 

var piwebapi = (function () {
    var base_service_url = "NotDefined";

    function GetJsonContent(url, SuccessCallBack, ErrorCallBack) {
        $.ajax({
            type: 'GET',
            url: url,
            cache: false,
            async: true,
            success: SuccessCallBack,
            error: ErrorCallBack

        });
    }

    function CheckPIServerName(piServerName, UpdateDOM) {
        BaseUrlCheck();
        var url = base_service_url + "dataservers?name=" + piServerName;
        GetJsonContent(url, (function (piServerJsonData) {
            UpdateDOM(true);
        }), (function () {
            UpdateDOM(false);
        }));
    }


    function CheckPIPointName(piServerName, piPointName, UpdateDOM) {

        BaseUrlCheck();
        url = base_service_url + "points?path=\\\\" + piServerName + "\\" + piPointName;
        GetJsonContent(url, (function (piPointJsonData) {
            piPointLinksJsonData = piPointJsonData;
            UpdateDOM(true);
        }), (function () {
            UpdateDOM(false)
        }));
    }



    function GetData(piServerName, piPointName, ServiceUrl, QueryString, UpdateDOM) {
        BaseUrlCheck();
        url = base_service_url + "points?path=\\\\" + piServerName + "\\" + piPointName;
        GetJsonContent(url, (function (piPointJsonData) {
            var url_data = piPointJsonData["Links"][ServiceUrl] + QueryString;
            GetJsonContent(url_data, (function (JsonData) {
                UpdateDOM(JsonData);
            }), (function () {
                UpdateDOM("Error: Parameters are incorrect.");
            }));
        }), (function () {
            UpdateDOM("Error: Could not find PI Point on the selected PI Data Archive.");
        }));
    }

    function BaseUrlCheck() {
        if (base_service_url == "NotDefined") {
            alert("Service base url was not defined");
        }
    }

    return {
        ValidPIServerName: function (piServerName, UpdateDOM) {
            CheckPIServerName(piServerName, UpdateDOM)
        },

        ValidPIPointName: function (piServerName, piPointName, UpdateDOM) {
            CheckPIPointName(piServerName, piPointName, UpdateDOM);
        },

        GetSnapshotValue: function (piServerName, piPointName, UpdateDOM) {
            GetData(piServerName, piPointName, "Value", "", UpdateDOM);
        },
        GetRecordedValues: function (piServerName, piPointName, startTime, endTime, UpdateDOM) {
            GetData(piServerName, piPointName, "RecordedData", "?starttime=" + startTime + "&endtime=" + endTime, UpdateDOM);
        },
        GetInterpolatedValues: function (piServerName, piPointName, startTime, endTime, interval, UpdateDOM) {
            GetData(piServerName, piPointName, "InterpolatedData", "?starttime=" + startTime + "&endtime=" + endTime + "&interval=" + interval, UpdateDOM);
        },
        SetBaseServiceUrl: function (baseUrl) {
            base_service_url = baseUrl;
            if (base_service_url.slice(-1) != "/") {
                base_service_url = base_service_url + "/";
            }
        }
    }
}());
  

 

Sample Application

 

 

There are two main HTML5 pages in this application. The first one is pi_data_request.html which is the page responsible for requesting PI data. The user is going to select the PI data archive name, PI Point name, start time, end time, interval and some other options related to data retrieval. Figure 1 shows  the screenshot of the PI data request page on the browser.

 

 

 

5164.sc1.jpg

 

Figure 1 - Screenshot of  PI data request page.

 

 

 

All the text inputs of this page are part of a form. When the button “Get PI Data!” is pressed, the URL is redirected to the page pi_data_result.html appending the form-data into the query string as the method GET is used. One example of URL that shows the result page with the form-data is: http://localhost:36262/pi_data_result.html?piServerName=marc-pi2014&piPointName=SINUSOID&startTime=*-1d&endTime=*&interval=1h&getsnap=yes&getrec=yes&getint=yes.

 

The query string of the URL is read when pi_data_result.html loads, converting it into input variables. This means that the data shown is from the PI Point name stored on the query string. If the method POST is used instead of GET, this information would be stored inside the headers. Therefore, one of the advantages of using GET is that, the end-user would be able to bookmark the pages which he finds interesting. Figure 2 shows the screenshot of the requested data page.

 

 

 

6355.sc2.jpg

 

Figure 2 - Screenshot of  PI data result page.

 

This page takes advantage of the PI Web API module. When the data is received, some jQuery functions and calls are responsible for updating the DOM elements by adding values and timestamps to the appropriate tables, for instance.

 

The code snippet below shows how the application not only checks if the PI Data Archive and PI Point names are valid but also updates the result on the Connection Information table:

 

    piwebapi.ValidPIServerName(piServerName, (function (PIServerExist) { $("#PIServerExistValue").text(PIServerExist); }));
    piwebapi.ValidPIPointName(piServerName, piPointName, (function (PIPointExist) { $("#PIPointExistValue").text(PIPointExist); }));
  

If you are not familiar with jQuery, the last line of code updates the element whose id is "PIPointExistValue" with the content stored on the variable PIPointExist.

 

The other tables are updated also using jQuery methods. Please refer to the source code package.

 

You will realize that the HTML5 markup and the JavaScript/jQuery scripts are in separate files as this is a good practice.  All the JavaScript /jQuery files are within a folder called “js”. Hence, PI Web API module is also located on this folder.

 

If you are interested in developing web apps using AngularJS instead, please refer to this blog post.

Conclusions

 

PI Web API is the PI System access product to integrate the PI System with non .NET  coding languages, which JavaScript is onde of them. I hope that reading this blog post would be a great reference for you to start  developing against jQuery in HTML5 pages.

 

Two of my future blog posts will be about general PHP and how to integrate PI Web API with PHP. Stay tunned!!

Filter Blog

By date: By tag: