Introduction

 

The upcoming PI Web API 2017 release will come with lots of great new features. One of the them is the Swagger specification which is a JSON string that allows you to generate client-side libraries in many different programming languages including Java, C#, AngularJS etc...

On this blog post, I will show you how to have access to the PI Web API Swagger JSON specification definition and generate a PI Web API library to be used with any web site developed using AngularJS. If you want only to download the library please visit this GitHub repository. A sample web application using this library is available here.

 

What is Swagger?

 

If you visit the Swagger web site, this is how they define their product: "The goal of Swagger™ is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via Swagger, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, Swagger removes the guesswork in calling the service.".

 

Please visit this page to find more information about getting started with Swagger.

 

How to access the PI Web API Swagger definition?

 

Just make a GET request against the following url: https://servername/piwebapi/help/specification?pretty=true. You will receive a JSON response back with the Swagger definition.

Remember that you must be using at least PI Web API 2017 in order to have access to the Swagger definition. This url won't work with PI Web API 2016 R2 and older versions of the product. Nevertheless, if you download the library from our GitHub repository, it will be compatible with all PI Web API versions. Just expect to receive some exceptions in case you are using a method that is not implemented on the server side as result of not using the latest PI Web API version.

 

How to generate client libraries using the PI Web API Swagger definition?

 

You can download the Swagger Code Generator directly from this GitHub repository. This application allows generation of API client libraries automatically with the OpenAPI specification. If you visit their repository, you will see that the following languages are supported:

 

  • API clients: ActionScript, Bash, C# (.net 2.0, 4.0 or later), C++ (cpprest, Qt5, Tizen), Clojure, Dart, Elixir, Go, Groovy, Haskell, Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign), Node.js (ES5, ES6, AngularJS with Google Closure Compiler annotations) Objective-C, Perl, PHP, Python, Ruby, Scala, Swift (2.x, 3.x), Typescript (Angular1.x, Angular2.x, Fetch, jQuery, Node)

 

Read the readme.md file in order to build from source with Java and Apachen Maven.

 

The next step is to run swagger-codegen using JAVA and the Command Prompt:

 

java -jar swagger-codegen/modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i https://servername/piwebapi/help/specification?pretty=true -l typescript-angular -o /PIWebAPIClient/swagger-project/PI-Web-API-Client-library-for-AngularJS

 

The TypeScript AngularJS library will be available under the PIWebAPIClient\swagger-project\PI-Web-API-Client-library-for-AngularJS folder.

 

Since I couldn't control very well how the library is going to be generated with the Swagger Generator, I have decided to create my own generator which is available here. I have described how to generate a client library with the Swagger code generator so you can learn how to generate libraries for many different languages and platforms.

 

 

Compiling the TypeScript libraries to generate JavaScript libraries with VS Code

 

Create a new folder under the PI-Web-API-Client-library-for-AngularJS named src and move the API folder to this new directly.

 

If you navigate through the PI-Web-API-Client-library-for-AngularJS\src\API\Client folder, you will see files with ts extension, which are TypeScript files. We need to convert them to JavaScript files since we want to generate a JavaScript AngularJS service.

 

Let's start installing TypeScript gloabally with the command:

 

npm install -g typescript@2.3.0 

 

 

Note 1: I wasn't able to compile the project using typescript 2.4.2. This is why you must be using typescript 2.3.0 to avoid errors on the angular.d.ts definitions.

Note 2: you must have NodeJS installed. Click here to download in case this product is not installed on your machine.

 

Open Visual Studio Code and click on File --> Open Folder. And select the PI-Web-API-Client-library-for-AngularJS folder. Click on View --> Integrated Terminal and type on the terminal:

 

tsc --init

 

This will create the tsconfig.json file on the root folder. This file should be used to set up options for the TypeScript compiler.

 

Next, press SHIFT + CTRL + P to show all the commands available and type "task" and click on "Tasks:Configure Task Runner". Press enter and select "TypeScript - tsconfig.json". This will create the file tasks.json under the .vscode folder. When you compile the project, Visual Studio Code will read the content of this tasks.json file and run the TypeScript compiler. If you open the tasks.json, you will realize that the "command" field is "tsc".

 

Let's compile this product by pressing SHIFT + CTRL +B and see what happens..... If you want to learn about Visual Studio Code key shortcuts, click here.

 

Nevertheless, there are more than 99 errors:

 

pastedImage_4.png

 

The main error is  "Cannot find namespace 'ng'.  This means that we need to add the AngularJS typescript library in order to compile our project."

 

Let's install Bower to download the AngularJS TypeScript library:

 

npm install -g bower 

 

And then type:

 

bower install angular-ts

 

This will create a folder bower_components and some subfolders:

 

pastedImage_2.png

 

The file we need to reference is bower_components\angular-ts\angular.d.ts which contains the ng TypeScript namespace.

 

The file that we need to change in order to add this reference is api.d.ts. All other files located on the API\Client folder reference this file.

 

Open the api.d.ts file on the editor and add the following line.

 

/// <reference path="../../../bower_components/angular-ts/angular.d.ts" />

 

Let's compile again by pressing SHIFT + CTRL +B. Now we receive a difference type of error:

 

pastedImage_3.png

 

The problem is with the following function which is present on all *Api.ts files:

 

        private extendObj<T1,T2>(objA: T1, objB: T2) {
            for(let key in objB){
                if(objB.hasOwnProperty(key)){
                    objA[key] = objB[key];
                }
            }
            return <T1&T2>objA;
        }

 

 

The solution is to replace T1 and T2 to any when defining the input variables:

 

        private extendObj<T1,T2>(objA: any, objB: any) {
            for(let key in objB){
                if(objB.hasOwnProperty(key)){
                    objA[key] = objB[key];
                }
            }
            return <T1&T2>objA;
        }

 

You can use Find & Replace in Files feature of Visual Studio Code to fix this problem on the 34 files.

 

 

pastedImage_1.png

 

 

Finally, if you compile again, you won't see any errors.

 

Creating the PI Web API AngularJS Module

 

 

Create a new PIWebApi.ts file under the src\ts folder with the following content:

 

class PIWebApi {


private basePath : string
private useKerberos : boolean
private username : string
private password : string
public defaultHeaders : any = {}
public analysis : OSIsoft.PIDevClub.PIWebApiClient.AnalysisApi
public analysisCategory : OSIsoft.PIDevClub.PIWebApiClient.AnalysisCategoryApi
public analysisRule : OSIsoft.PIDevClub.PIWebApiClient.AnalysisRuleApi
public analysisRulePlugIn : OSIsoft.PIDevClub.PIWebApiClient.AnalysisRulePlugInApi
public analysisTemplate : OSIsoft.PIDevClub.PIWebApiClient.AnalysisTemplateApi
public assetDatabase : OSIsoft.PIDevClub.PIWebApiClient.AssetDatabaseApi
public assetServer : OSIsoft.PIDevClub.PIWebApiClient.AssetServerApi
public attribute : OSIsoft.PIDevClub.PIWebApiClient.AttributeApi
public attributeCategory : OSIsoft.PIDevClub.PIWebApiClient.AttributeCategoryApi
public attributeTemplate : OSIsoft.PIDevClub.PIWebApiClient.AttributeTemplateApi
public attributeTrait : OSIsoft.PIDevClub.PIWebApiClient.AttributeTraitApi
public batch : OSIsoft.PIDevClub.PIWebApiClient.BatchApi
public calculation : OSIsoft.PIDevClub.PIWebApiClient.CalculationApi
public configuration : OSIsoft.PIDevClub.PIWebApiClient.ConfigurationApi
public dataServer : OSIsoft.PIDevClub.PIWebApiClient.DataServerApi
public element : OSIsoft.PIDevClub.PIWebApiClient.ElementApi
public elementCategory : OSIsoft.PIDevClub.PIWebApiClient.ElementCategoryApi
public elementTemplate :OSIsoft.PIDevClub.PIWebApiClient. ElementTemplateApi
public enumerationSet : OSIsoft.PIDevClub.PIWebApiClient.EnumerationSetApi
public enumerationValue : OSIsoft.PIDevClub.PIWebApiClient.EnumerationValueApi
public eventFrame : OSIsoft.PIDevClub.PIWebApiClient.EventFrameApi
public home : OSIsoft.PIDevClub.PIWebApiClient.HomeApi
public point : OSIsoft.PIDevClub.PIWebApiClient.PointApi
public securityIdentity : OSIsoft.PIDevClub.PIWebApiClient.SecurityIdentityApi
public securityMapping : OSIsoft.PIDevClub.PIWebApiClient.SecurityMappingApi
public stream : OSIsoft.PIDevClub.PIWebApiClient.StreamApi
public streamSet : OSIsoft.PIDevClub.PIWebApiClient.StreamSetApi
public system : OSIsoft.PIDevClub.PIWebApiClient.SystemApi
public table : OSIsoft.PIDevClub.PIWebApiClient.TableApi
public tableCategory : OSIsoft.PIDevClub.PIWebApiClient.TableCategoryApi
public timeRule : OSIsoft.PIDevClub.PIWebApiClient.TimeRuleApi
public timeRulePlugIn : OSIsoft.PIDevClub.PIWebApiClient.TimeRulePlugInApi
public unit : OSIsoft.PIDevClub.PIWebApiClient.UnitApi
public unitClass : OSIsoft.PIDevClub.PIWebApiClient.UnitClassApi
private httpService : any
private httpParamSerializer : any
private base64 : any




constructor(httpService : any, httpParamSerializer: any, base64 : any) {
this.httpService = httpService;
this.httpParamSerializer = httpParamSerializer;
this.base64 = base64;
}


public ConfigureInstance(basePath: string, useKerberos: boolean, username?: string, password?: string) {

this.basePath = basePath;
this.useKerberos = useKerberos;
if (this.useKerberos == false)
{
this.username = username;
this.password = password;
if (this.base64 != null)
{
var auth = this.base64.encode(this.username + ":" + this.password);
this.httpService.defaults.headers.common['Authorization'] = 'Basic ' + auth;
}
}
else
{
this.httpService.defaults.withCredentials = true;
this.httpService.defaults.useXDomain = true;
}
this.analysis = new OSIsoft.PIDevClub.PIWebApiClient. AnalysisApi(this.basePath, this.httpService, this.httpParamSerializer);
this.analysisCategory = new OSIsoft.PIDevClub.PIWebApiClient. AnalysisCategoryApi(this.basePath, this.httpService, this.httpParamSerializer);
this.analysisRule = new OSIsoft.PIDevClub.PIWebApiClient. AnalysisRuleApi(this.basePath, this.httpService, this.httpParamSerializer);
this.analysisRulePlugIn = new OSIsoft.PIDevClub.PIWebApiClient. AnalysisRulePlugInApi(this.basePath, this.httpService, this.httpParamSerializer);
this.analysisTemplate = new OSIsoft.PIDevClub.PIWebApiClient. AnalysisTemplateApi(this.basePath, this.httpService, this.httpParamSerializer);
this.assetDatabase = new OSIsoft.PIDevClub.PIWebApiClient. AssetDatabaseApi(this.basePath, this.httpService, this.httpParamSerializer);
this.assetServer = new OSIsoft.PIDevClub.PIWebApiClient. AssetServerApi(this.basePath, this.httpService, this.httpParamSerializer);
this.attribute = new OSIsoft.PIDevClub.PIWebApiClient. AttributeApi(this.basePath, this.httpService, this.httpParamSerializer);
this.attributeCategory = new OSIsoft.PIDevClub.PIWebApiClient. AttributeCategoryApi(this.basePath, this.httpService, this.httpParamSerializer);
this.attributeTemplate = new OSIsoft.PIDevClub.PIWebApiClient. AttributeTemplateApi(this.basePath, this.httpService, this.httpParamSerializer);
this.attributeTrait= new OSIsoft.PIDevClub.PIWebApiClient. AttributeTraitApi(this.basePath, this.httpService, this.httpParamSerializer);
this.batch = new OSIsoft.PIDevClub.PIWebApiClient. BatchApi(this.basePath, this.httpService, this.httpParamSerializer);
this.calculation= new OSIsoft.PIDevClub.PIWebApiClient. CalculationApi(this.basePath, this.httpService, this.httpParamSerializer);
this.configuration = new OSIsoft.PIDevClub.PIWebApiClient. ConfigurationApi(this.basePath, this.httpService, this.httpParamSerializer);
this.dataServer = new OSIsoft.PIDevClub.PIWebApiClient. DataServerApi(this.basePath, this.httpService, this.httpParamSerializer);
this.element = new OSIsoft.PIDevClub.PIWebApiClient. ElementApi(this.basePath, this.httpService, this.httpParamSerializer);
this.elementCategory= new OSIsoft.PIDevClub.PIWebApiClient. ElementCategoryApi(this.basePath, this.httpService, this.httpParamSerializer);
this.elementTemplate = new OSIsoft.PIDevClub.PIWebApiClient. ElementTemplateApi(this.basePath, this.httpService, this.httpParamSerializer);
this.enumerationSet = new OSIsoft.PIDevClub.PIWebApiClient. EnumerationSetApi(this.basePath, this.httpService, this.httpParamSerializer);
this.enumerationValue = new OSIsoft.PIDevClub.PIWebApiClient. EnumerationValueApi(this.basePath, this.httpService, this.httpParamSerializer);
this.eventFrame = new OSIsoft.PIDevClub.PIWebApiClient. EventFrameApi(this.basePath, this.httpService, this.httpParamSerializer);
this.home = new OSIsoft.PIDevClub.PIWebApiClient. HomeApi(this.basePath, this.httpService, this.httpParamSerializer);
this.point = new OSIsoft.PIDevClub.PIWebApiClient. PointApi(this.basePath, this.httpService, this.httpParamSerializer);
this.securityIdentity = new OSIsoft.PIDevClub.PIWebApiClient. SecurityIdentityApi(this.basePath, this.httpService, this.httpParamSerializer);
this.securityMapping = new OSIsoft.PIDevClub.PIWebApiClient. SecurityMappingApi(this.basePath, this.httpService, this.httpParamSerializer);
this.stream = new OSIsoft.PIDevClub.PIWebApiClient. StreamApi(this.basePath, this.httpService, this.httpParamSerializer);
this.streamSet = new OSIsoft.PIDevClub.PIWebApiClient. StreamSetApi(this.basePath, this.httpService, this.httpParamSerializer);
this.system = new OSIsoft.PIDevClub.PIWebApiClient. SystemApi(this.basePath, this.httpService, this.httpParamSerializer);
this.table = new OSIsoft.PIDevClub.PIWebApiClient. TableApi(this.basePath, this.httpService, this.httpParamSerializer);
this.tableCategory = new OSIsoft.PIDevClub.PIWebApiClient. TableCategoryApi(this.basePath, this.httpService, this.httpParamSerializer);
this.timeRule = new OSIsoft.PIDevClub.PIWebApiClient. TimeRuleApi(this.basePath, this.httpService, this.httpParamSerializer);
this.timeRulePlugIn = new OSIsoft.PIDevClub.PIWebApiClient. TimeRulePlugInApi(this.basePath, this.httpService, this.httpParamSerializer);
this.unit = new OSIsoft.PIDevClub.PIWebApiClient. UnitApi(this.basePath, this.httpService, this.httpParamSerializer);
this.unitClass = new OSIsoft.PIDevClub.PIWebApiClient. UnitClassApi(this.basePath, this.httpService, this.httpParamSerializer);
}
}

 

 

Create a new ngService.ts file under the src\ts folder with the following content:

 

/// <reference path="api.d.ts"/>

angular.module('ngPIWebApi',['base64']).factory('piwebapi', ['$http', '$httpParamSerializer', '$base64',function ($http: ng.IHttpService, $httpParamSerializer: any, $base64: any) {
    let piwebapi = new PIWebApi($http, $httpParamSerializer, $base64);
return piwebapi;
}]);

 

 

The code above creates a new AngularJS module called ngPIWebApi that required the base64 module to generate the Basic Authentication header. Therefore, let's add the base64 module to our bower components:

 

bower install angular-base64

 

The ConfigureInstance method allows you to define the PI Web API endpoint URL and set up which type of security you want to use (Anonymous, Basic or Kerberos). It will also map he piwebapi properties with the API objects. As a result, all API methods are available under the piwebapi object. If it is confused for now, don't worry. The last section of this post is about creating a web application using this library.

 

Using Gulp to concatenate and minify

 

According to Wikipedia:

 

Gulp is a build tool in JavaScript built on node streams. These streams facilitate the connection of file operations through pipelines.Gulp reads the file system and pipes the data at hand from its one single-purposed plugin to other through the .pipe() operator, doing one task at a time. The original files are not affected until all the plugins are processed. It can be configured either to modify the original files or to create new ones. This grants the ability to perform complex tasks through linking its numerous plugins. The users can also write their own plugins to define their own tasks.Unlike other task runners that run tasks by configuration, gulp requires knowledge of JavaScript and coding to define its tasks. Gulp is a build system which means apart from running tasks, it is also capable of copying files from one location to another, compiling, deploying, creating notifications, unit testing, linting etc.

 

Let's first install gulp and some other tools through npm:

 

npm install gulp gulp-concat gulp-uglify

 

Then, create a new file on the root named gulpfile.js with the following content:

 

var gulp = require('gulp');
var concat = require('gulp-concat');  
var uglify = require("gulp-uglify");


//script paths
var jsDest = 'dist';




gulp.task('default', ['concatenate', 'concatenateAndMinify', 'concatenateForPIVision', 'concatenateAndMinifyForPIVision']);


gulp.task('concatenateAndMinify', function() {  
    return gulp.src(['src/js/api/*.js','src/js/models/*.js', 'src/js/PIWebApi.js', 'src/js/ngService.js'])  
        .pipe(concat('angular-piwebapi.min.js'))
        .pipe(uglify())  
        .pipe(gulp.dest(jsDest));       
});



gulp.task('concatenate', function() {  
    return gulp.src(['src/js/api/*.js','src/js/models/*.js','src/js/PIWebApi.js', 'src/js/ngService.js'])  
        .pipe(concat('angular-piwebapi.js'))
        .pipe(gulp.dest(jsDest));       
});


gulp.task('concatenateAndMinifyForPIVision', function() {  
    return gulp.src(['src/js/api/*.js', 'src/js/models
/*.js','src/js/PIWebApi.js', 'src/js/ngServiceForPIVision.js'])  
        .pipe(concat('angular-piwebapi-kerberos.min.js'))
        .pipe(uglify())  
        .pipe(gulp.dest(jsDest));       
});




gulp.task('concatenateForPIVision', function() {  
    return gulp.src(['src/js/api/*.js', 'src/js/models/*.js','src/js/PIWebApi.js', 'src/js/ngServiceForPIVision.js']) 
        .pipe(concat('angular-piwebapi-kerberos.js'))
        .pipe(gulp.dest(jsDest));       
});

 

And change the .vscode\tasks.json content to:

 

{
    "version": "0.1.0",
    "command": "gulp",
    "isShellCommand": true,
    "args": [
        "--no-color"
    ],
    "tasks": [ {
  "taskName": "default",
  "isBuildCommand": true,
  "showOutput": "always"
  }
  ]
}

 

 

The code above will concatenate all JavaScript from src/ts  to generate the angular-piwebapi.js file to the dist folder. It also generate a minified version of this file (piwebapi.min.js). Build this project and check if both files were created on dist folder. This module requires the angular-base64.js and angular-base64.min.js JavaScript libraries. This is why I have manually copied those files to the dist folder.

 

Note: With this change, when pressing SHIFT + CTRL + B the TypeScript compiler won't be called anymore, unless you configure it on gulpfile.js to use gulp-typescript.

 

Developing a web application using AngularJS and PI Web API client libraries

 

In order to test this new client library, let's take the example from the blog post. First we need to edit the index.html:

 

    <script src="Scripts/angular.min.js"></script>
    <script src="Scripts/angular-base64.min.js"></script>
    <script src="Scripts/piwebapi.min.js"></script>
    <script src="Scripts/app.js"></script>

 

 

The original app.js is:

 

var piWebApiApp = angular.module("PiWebApiSampleApp", []);


piWebApiApp.controller("mainCtrl", function ($scope, piWebApiHttpService) {


    //declare and inicialize variables
    $scope.requestMode = true;
    $scope.getSnap = true;
    $scope.getRec = true;
    $scope.getInt = true;


    //options for the combobox on the initial page
    $scope.yesOrNoOptions = [{ "value": true, "name": "Yes" }, { "value": false, "name": "No" }];


    //update values when the default button is pressed
    $scope.defaultValues = function () {
        $scope.piServerName = "MARC-PI2014";
        $scope.piPointName = "SINUSOID";
        $scope.startTime = "*-1d";
        $scope.endTime = "*";
        $scope.interval = "1h";
        $scope.getSnap = $scope.yesOrNoOptions[0];
        $scope.getRec = $scope.yesOrNoOptions[0];
        $scope.getInt = $scope.yesOrNoOptions[0];
    }


    //get data by making http calls
    $scope.getData = function () {
        //switch div to display the results
        $scope.requestMode = false;
        //all HTTP requests are done through the  piWebApiHttpService factory object
        piWebApiHttpService.validPIServerName($scope.piServerName).then(function (response) {
            //this function will be executed in case of success
            $scope.piServerData = response.data;
            $scope.piServerExistsValue = true;
        }, function (error) {
            //this function will be executed in case of error
            $scope.piServerError = error.data;
            $scope.piServerExistsValue = false;
        });


        piWebApiHttpService.validPIPointName($scope.piServerName, $scope.piPointName).then(function (response) {
            $scope.piPointData = response.data;
            $scope.piPointExistsValue = true;
            //in case of success, we will get the webId of the PI Point which will be used by other requests
            $scope.webId = response.data.WebId;
            piWebApiHttpService.getSnapshotValue($scope.webId).then(function (response) {
                //Response of the snapshot is stored on the snapshotData
                $scope.snapshotData = response.data;
            }, function (error) {
                $scope.snapshotError = error.data;


            });
            //The following requests use the webId already stored
            piWebApiHttpService.getRecordedValues($scope.webId, $scope.startTime, $scope.endTime).then(function (response) {
                $scope.recordedData = response.data;
            }, function (error) {
                $scope.recordedError = error.data;
            });


            piWebApiHttpService.getInterpolatedValues($scope.webId, $scope.startTime, $scope.endTime, $scope.interval).then(function (response) {
                $scope.interpolatedData = response.data;
            }, function (error) {
                $scope.interpolatedError = error.data;
            });
        }, function (error) {
            $scope.piPointError = error.data;
            $scope.piPointExistsValue = false;
        });
    }
});

 

The new app.js looks like:

 

var piWebApiApp = angular.module("demo-app", ['ngPIWebApi']);


piWebApiApp.run(function (piwebapi) {
    piwebapi.ConfigureInstance("https://marc-web-sql.marc.net/piwebapi", true);
});




piWebApiApp.controller("mainCtrl", function ($scope, piwebapi) {   




    // //declare and inicialize variables
    $scope.requestMode = true;
    $scope.getSnap = true;
    $scope.getRec = true;
    $scope.getInt = true;


    // //options for the combobox on the initial page
    $scope.yesOrNoOptions = [{ "value": true, "name": "Yes" }, { "value": false, "name": "No" }];


    // //update values when the default button is pressed
    $scope.defaultValues = function () {
        $scope.piServerName = "MARC-PI2016";
        $scope.piPointName = "SINUSOID";
        $scope.startTime = "*-1d";
        $scope.endTime = "*";
        $scope.interval = "1h";
        $scope.getSnap = $scope.yesOrNoOptions[0];
        $scope.getRec = $scope.yesOrNoOptions[0];
        $scope.getInt = $scope.yesOrNoOptions[0];
    }


    // //get data by making http calls
    $scope.getData = function () {
        //switch div to display the results
        $scope.requestMode = false;
        //all HTTP requests are done through the  piWebApiHttpService factory object
        piwebapi.dataServer.getByPath('\\\\' + $scope.piServerName).then(function (response) {
            //this function will be executed in case of success
            $scope.piServerData = response.data;
            $scope.piServerExistsValue = true;
        }, function (error) {
            //this function will be executed in case of error
            $scope.piServerError = error.data;
            $scope.piServerExistsValue = false;
        });


        piwebapi.point.getByPath('\\\\' + $scope.piServerName + '\\' + $scope.piPointName, null, null).then(function (response) {
            $scope.piPointData = response.data;
            $scope.piPointExistsValue = true;
            //in case of success, we will get the webId of the PI Point which will be used by other requests
            $scope.webId = response.data.WebId;
            piwebapi.stream.getValue($scope.webId).then(function (response) {
                //Response of the snapshot is stored on the snapshotData
                $scope.snapshotData = response.data;
            }, function (error) {
                $scope.snapshotError = error.data;


            });


            piwebapi.stream.getRecorded($scope.webId, null, null, $scope.endTime, null, null, null, null, $scope.startTime).then(function (response) {
                $scope.recordedData = response.data;
            }, function (error) {
                $scope.recordedError = error.data;
            });


            piwebapi.stream.getInterpolated($scope.webId, null, $scope.endTime, null, null, $scope.interval, null, null, null, null, null, $scope.startTime).then(function (response) {
                $scope.interpolatedData = response.data;
            }, function (error) {
                $scope.interpolatedError = error.data;
            });
        }, function (error) {
            $scope.piPointError = error.data;
            $scope.piPointExistsValue = false;
        });
    }
});

 

Using the library, you don't need to write the piWebApiHttpService service. Just use this client library instead and it will work!

 

Conclusion

 

I really think that having PI Web API client libraries available for many different platforms with make our lives much easier. In this blog post I have described all the steps I had to do in order to generate the library. Nevertheless, you can just download it from this GitHub repository without having to generate it yourself. The next blog post will be about integrating this library in PI Vision! Stay tuned!