Skip navigation
All Places > PI Developers Club > Blog > 2015 > December
2015

Introduction

 

The purpose of the following blog posts is to show new ways of using the PI System data in Machine Learning. The majority of the PI Dev Club developers are used to writing application in C#. Although I love C#, F# is a more suitable choice for solving machine learning problems since it is simple and productive.

 

What is F#?

 

According to this MSDN web page:

 

F# is a programming language that provides support for functional programming in addition to traditional object-oriented and imperative (procedural) programming. The Visual F# product provides support for developing F# applications and extending other .NET Framework applications by using F# code. F# is a first-class member of the .NET Framework languages and retains a strong resemblance to the ML family of functional language..

 

One of the great benefits of using F# compared to C# is that it reduces the time required to run the application. In C#, whenever you need to edit the code, you must recompile your project, load OSIsoft.AFSDK.dll library, connect to the PI System, get the data, store values on memory and then process it. This operation can take a long time which means part of your time is waiting for data to load. As it will be demonstrated on the next section,

 

F# Interactively

 

Visual Studio comes with F# Interactive (FSI) which is great for testing your model and functions that process PI data. FSI window accepts user input and two semicolons (;;) should be used to let the compiler know that the statement is finished. Figure 1 shows FSI dock on Visual Studio.

 

 

 

Figure 1 - F# Interactive in Visual Studio

 

The problem of writing commands on FSI is that IntelliSense won’t be available. In order to use this feature, we will create an F# Script.

 

The PI AF SDK code snippet that we will migrate to F# is below:

 

        static void Main(string[] args)
        {
            PISystem piSystem = new PISystems()["MARC-PI2014"];
            AFDatabase db = piSystem.Databases["AFSDK Test"];
            AFElement element = db.Elements["Cdt158"];
            AFAttribute attribute = element.Attributes["Sinusoid"];
            AFValues values = attribute.Data.RecordedValues(new OSIsoft.AF.Time.AFTimeRange("*-1d", "*"), OSIsoft.AF.Data.AFBoundaryType.Inside, null, string.Empty, false);
            foreach (AFValue value in values)
            {
                Console.WriteLine(string.Format("{0} - {1}", value.ValueAsDouble(), value.Timestamp.LocalTime));
            }
        }

 

Open Visual Studio and create a new F# Console Application.

 

 

Figure 2 - Creating a new F# Console Application solution

 

 

Visual Studio will create a project with the Program.fs. Add the PI AF SDK reference as you are used to doing in C#. As we want to use our data to make a lot of tests, let's create an F# script file named test.fsx with the following content.

 

 

#r "OSIsoft.AFSDK"

let piSystems = new OSIsoft.AF.PISystems()
let piSystem = piSystems.Item("marc-pi2014")
let db = piSystem.Databases.Item("AFSDK Test")
let element = db.Elements.Item("Cdt158")
let attribute = element.Attributes.Item("Sinusoid")
let values = attribute.Data.RecordedValues(new OSIsoft.AF.Time.AFTimeRange("*-1d", "*"), OSIsoft.AF.Data.AFBoundaryType.Inside, null, "", false)

 

Please take a look at the F# code version. Although it may not be clear at first, F# is a strongly typed language as C# even though F# does not need an explicitly defined typed. There reason is F# is capable of inferring a type from the assigned value. If you are familiar with var from C#, let from F# is quite similar.

 

Although OSIsoft. AFSDK.dll was already referenced on the project,  #r needs to be used as well to reference the assembly when running the F# Script on FSI.

 

After selecting all the code snippet from the F# script file and right-clicking on it, select the "Execute In Interactive" option as shown on Figure 2.

 

fix.png

Figure 3 - Executing F# Script in interactive

 

This will run the code as a script like Windows PowerShell. All the values retrieved from the PI System are stored on this variable. Under F# Interactive, typing values.Count();; will display the number of values that the variable values has.

 

Figure 4 - Viewing the results on F# Interactive

 

 

Using For

 

Let's take this opportunity to show how to use the equivalent of for and foreach from C# in F#.

 

 

for i=0 to values.Count-1 do
    System.Console.WriteLine(values.[i].ValueAsDouble())


for value in values do
    System.Console.WriteLine(value.ValueAsDouble())

 

 

Seq

 

A sequence is F# is a logical series of elements of one type. Any type of variable that implements the IEnumerable interface can be used as a sequence. F# also has Lists and Arrays but in this blog post, we will work as Sequences only.

 

This is another way to find how many values there are within values.

 

values |> Seq.length

 

The exists function can check if there is at least one element of the sequence that satifies a certain condition. For instance, is there any value higher than 200 or 100?

 

values |> Seq.exists (fun n->n.ValueAsDouble()>200.0)
values |> Seq.exists (fun n->n.ValueAsDouble()>100.0)

 

The forall function can check if all elements of the sequence satisfies a certain condition. For instance, are all values greater than 3 or 0?

 

values |> Seq.forall (fun n->n.ValueAsDouble()>3.0)
values |> Seq.forall (fun n->n.ValueAsDouble()>0.0)

 

Filter all AFValue in values, whose numeric value is greater than 50. After that show the number of AFValue objects which fit this condition.

 

let filteredValues = values |> Seq.filter (fun n-> n.ValueAsDouble() > 50.0)
filteredValues  |> Seq.length

 

 

The map function is used to generate a new collection with the Sequence collection as an input. For each element of the Sequence AFValues collection,

 

let mappedValues = values |> Seq.map (fun n-> n.ValueAsDouble())
mappedValues  |> Seq.length

 

You can also find the max, min, sum and average using sequence functions as:

 

mappedValues |> Seq.max
mappedValues |> Seq.average
mappedValues |> Seq.min
mappedValues |> Seq.sum

 

The great advantage of using F# is that you don't need to compile every time you want to test new functions. When you are still developing your model with PI data, using F# scripts is very productive choice!

 

Functions

 

Finally, let's define functions f and g. The first one increments a given float number by 5.0 and the second function doubles a float value. It becomes more interesting to composite f an g to get a new function fg. If x=3.0, f(x)= 8, g(f(x)) = 16.

 

 

let f(x:float) = x+5.0
let g(x:float) = 2.0*x
let fg = f >> g


mappedValues |> Seq.map(fg)

 

Using the map function from the Seq, each element of the sequence can be converted using the fg function generating a new collection.

 

Conclusions

 

F# is a programming language for machine learning. As it is also a .NET Framework language, it is compatible with PI AF SDK which is currently the best option to get PI Data into this environment. Once data is on memory, F# makes your life easier when testing different model using PI data as input.

 

Stay tunned for the upcoming blog posts about machine learning and the PISystem.

Introduction

 

One my previous blog post Using PI Web API on HTML with AngularJS we have developed a web application with AngularJS that was able to make HTTP requests against PI Web API. On this blog post, I will show you how to unit test the sample application developed with AngularJS.

 

AngularJS was designed with testing in mind. The source code of the framework is tested really well and any code written using the framework is testable too. The built-in dependency injection mechanism makes every component written in AngularJS testable. Code in an AngularJS application can be unit tested using any JavaScript testing framework out there. The most widely used framework to test AngularJS code is Jasmine.

 

Prepare your environment

 

By default, Visual Studio does not test JavaScript code. Nevertheless, there is an extension named Chutzpah Test Adapter for the Test Explorer which enables Visual Studio to test JavaScript code. If you click on Tools --> Extensions and Updates..., you will be able to install the Chutzpah Test Adapter as shown on Figure 1. This project is available on GitHub if you want more information to refer to. After installation it, please restart Visual Studio.

 

 

Figure 1 - Adding Chutzpah as an extension from Visual Studio

 

 

Preparing the tests

 

The source code package from the sample application with tests developed on this blog posts is available on this GitHub repository. Please download this package and use the sample application from there. DO NOT use the sample application developed on the previous blog post.

 

Open the Visual Studio solution developed on the previous blog post and create a new Unit Test Project PIWebAPIwithAngularJS.Tests.

 

Figure 2 - Adding a new Unit Testing Project to the VS Solution

 

 

By default, the project comes with the UnitTest1.cs file which should be deleted as we will test JavaScript code. On this new test project, add a reference to the PIWebAPIwithAngularJS project which is the sample application.

 

Before writing tests, we need to download a framework to test JavaScript code called jasmine. Please open Package Console Manager and write:

 

Install-package jasmine

 

There are some other libraries available but jasmine was selected as AngularJS uses jasmine for their own testing,

 

Add a new item on the test project named mainTests.js.

 

The first thing to do is to add all the required libraries as references on the top of the main test script file.

 

 

/// <reference path="scripts/jasmine/jasmine.js" />
/// <reference path="../piwebapiwithangularjs/scripts/angular.js" />
/// <reference path="../piwebapiwithangularjs/scripts/angular-mocks.js" />
/// <reference path="../piwebapiwithangularjs/scripts/app.js" />
/// <reference path="../piwebapiwithangularjs/scripts/piwebapi.js" />

 

The script files app.js and piwebapi.js depends on AngularJS in order to jasmine run the test properly.

 

The file angular-mocks.js was added in order to mock our main controller and service.

 

Let's add some code snippet for preparing the tests. Please read the comments in order to understand the logic.

 


describe("Tests-> ", function () {


    var mockScope, $httpBackend; 


    //beforeEach allow us to run the code before starting the tests
    beforeEach(angular.mock.module("PiWebApiSampleApp"));


    beforeEach(angular.mock.inject(function ($injector) {


        //$httpBackend from angular mocks libraries lets you mock the backend. When you make HTTP requests, if it detects the existance of $httpBackend, it will call it instead of PI Web API.
        //$injector is the object from angular-mock that can resolve dependencies 
        $httpBackend = $injector.get("$httpBackend");


        //This how we add the responses to the $httpBackend according to the URL
        $httpBackend.when("GET", "https://marc-web-sql.marc.net/piwebapi/dataservers?name=MARC-PI2014").respond({ "WebId": "s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ", "Id": "c4d50921-e39c-4be9-a886-212b567a94aa", "Name": "MARC-PI2014", "IsConnected": true, "ServerVersion": "3.4.395.64", "Links": { "Self": "https://marc-web-sql.marc.net/piwebapi/dataservers/s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ", "Points": "https://marc-web-sql.marc.net/piwebapi/dataservers/s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ/points", "EnumerationSets": "https://marc-web-sql.marc.net/piwebapi/dataservers/s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ/enumerationsets" } });
        $httpBackend.when("GET", "https://marc-web-sql.marc.net/piwebapi/dataservers/s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ/points?nameFilter=SINUSOID").respond({ "Links": {}, "Items": [{ "WebId": "P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ", "Id": 1, "Name": "SINUSOID", "PointClass": "classic", "PointType": "Float32", "Future": false, "Links": { "Self": "https://marc-web-sql.marc.net/piwebapi/points/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ", "DataServer": "https://marc-web-sql.marc.net/piwebapi/dataservers/s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ", "Attributes": "https://marc-web-sql.marc.net/piwebapi/points/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/attributes", "Value": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/value", "InterpolatedData": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/interpolated", "RecordedData": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/recorded", "PlotData": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/plot", "SummaryData": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/summary", "EndValue": "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/end" } }] });
        $httpBackend.when("GET", "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/value").respond({ "Timestamp": "2015-11-30T12:42:48Z", "Value": 20.68641, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false });
        $httpBackend.when("GET", "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/recorded?starttime=*-1d&endtime=*").respond({ "Links": {}, "Items": [{ "Timestamp": "2015-11-29T12:48:18Z", "Value": 22.78819, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T12:54:18Z", "Value": 25.1654854, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T12:59:48Z", "Value": 27.41667, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:05:18Z", "Value": 29.7313862, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:10:48Z", "Value": 32.1043, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:15:48Z", "Value": 34.3074036, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:20:48Z", "Value": 36.5498962, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:25:48Z", "Value": 38.827507, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:30:48Z", "Value": 41.1359062, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:35:48Z", "Value": 43.47069, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:40:48Z", "Value": 45.8274269, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:45:48Z", "Value": 48.2016258, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:50:48Z", "Value": 50.58876, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:55:48Z", "Value": 52.9842949, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:00:48Z", "Value": 55.383667, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:05:48Z", "Value": 57.7823067, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:10:48Z", "Value": 60.17565, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:15:48Z", "Value": 62.5591431, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:20:48Z", "Value": 64.9282455, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:25:48Z", "Value": 67.27845, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:30:48Z", "Value": 69.6052856, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:35:48Z", "Value": 71.90431, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:40:48Z", "Value": 74.1711655, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:45:48Z", "Value": 76.40152, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:51:18Z", "Value": 78.8077, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:56:48Z", "Value": 81.15904, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:02:18Z", "Value": 83.45014, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:07:48Z", "Value": 85.675705, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:13:48Z", "Value": 88.02284, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:19:48Z", "Value": 90.27947, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:26:18Z", "Value": 92.6148453, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:32:48Z", "Value": 94.829216, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:39:48Z", "Value": 97.07046, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:47:18Z", "Value": 99.29742, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:55:48Z", "Value": 101.591522, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T16:05:18Z", "Value": 103.851753, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T16:16:48Z", "Value": 106.137573, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T16:31:48Z", "Value": 108.342873, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T17:43:18Z", "Value": 106.120163, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T17:54:48Z", "Value": 103.830032, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:04:18Z", "Value": 101.5664, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:12:48Z", "Value": 99.2694, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:20:18Z", "Value": 97.04001, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:27:18Z", "Value": 94.79662, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:33:48Z", "Value": 92.58036, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:40:18Z", "Value": 90.24322, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:46:18Z", "Value": 87.985054, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:52:18Z", "Value": 85.63648, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:57:48Z", "Value": 83.4097, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:03:18Z", "Value": 81.11748, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:08:48Z", "Value": 78.76511, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:14:18Z", "Value": 76.3579941, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:19:18Z", "Value": 74.12688, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:24:18Z", "Value": 71.85935, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:29:18Z", "Value": 69.55973, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:34:18Z", "Value": 67.2324, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:39:18Z", "Value": 64.88178, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:44:18Z", "Value": 62.51235, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:49:18Z", "Value": 60.12862, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:54:18Z", "Value": 57.7351265, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:59:18Z", "Value": 55.3364258, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:04:18Z", "Value": 52.937088, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:09:18Z", "Value": 50.5416756, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:14:18Z", "Value": 48.154747, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:19:18Z", "Value": 45.7808533, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:24:18Z", "Value": 43.4245071, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:29:18Z", "Value": 41.0901947, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:34:18Z", "Value": 38.78236, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:39:18Z", "Value": 36.5053978, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:44:18Z", "Value": 34.26364, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:49:18Z", "Value": 32.0613556, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:54:48Z", "Value": 29.6894341, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:00:18Z", "Value": 27.37581, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:05:48Z", "Value": 25.1258087, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:11:48Z", "Value": 22.7499123, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:17:48Z", "Value": 20.46241, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:24:18Z", "Value": 18.091301, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:30:48Z", "Value": 15.838913, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:37:48Z", "Value": 13.5543385, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:45:18Z", "Value": 11.2783623, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:53:18Z", "Value": 9.05724, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T22:02:18Z", "Value": 6.826517, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T22:12:48Z", "Value": 4.60025358, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T22:26:18Z", "Value": 2.36146951, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T22:51:18Z", "Value": 0.158477113, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T23:33:48Z", "Value": 2.375095, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T23:47:18Z", "Value": 4.61906433, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T23:57:48Z", "Value": 6.84918356, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:06:48Z", "Value": 9.083061, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:14:48Z", "Value": 11.3068552, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:22:18Z", "Value": 13.58521, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:29:18Z", "Value": 15.8718853, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:35:48Z", "Value": 18.1261139, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:42:18Z", "Value": 20.4989529, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:48:18Z", "Value": 22.7879467, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:54:18Z", "Value": 25.16523, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:59:48Z", "Value": 27.4164085, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:05:18Z", "Value": 29.7311172, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:10:48Z", "Value": 32.1040268, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:15:48Z", "Value": 34.30712, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:20:48Z", "Value": 36.54961, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:25:48Z", "Value": 38.8272171, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:30:48Z", "Value": 41.1356125, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:35:48Z", "Value": 43.4703979, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:40:48Z", "Value": 45.82713, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:45:48Z", "Value": 48.2013245, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:50:48Z", "Value": 50.58846, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:55:48Z", "Value": 52.9839935, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:00:48Z", "Value": 55.38397, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:05:48Z", "Value": 57.782608, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:10:48Z", "Value": 60.1759529, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:15:48Z", "Value": 62.5594444, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:20:48Z", "Value": 64.92854, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:25:48Z", "Value": 67.27875, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:30:48Z", "Value": 69.6055756, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:35:48Z", "Value": 71.9046, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:40:48Z", "Value": 74.17145, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:45:48Z", "Value": 76.4018, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:51:18Z", "Value": 78.8079758, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:56:48Z", "Value": 81.15931, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:02:18Z", "Value": 83.4504, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:07:48Z", "Value": 85.67596, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:13:48Z", "Value": 88.02309, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:19:48Z", "Value": 90.2797, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:26:18Z", "Value": 92.61506, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:32:48Z", "Value": 94.82942, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:39:48Z", "Value": 97.07065, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:47:18Z", "Value": 99.2976, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:55:48Z", "Value": 101.591682, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T04:05:18Z", "Value": 103.851891, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T04:16:48Z", "Value": 106.137688, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T04:31:48Z", "Value": 108.342949, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T05:43:18Z", "Value": 106.120056, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T05:54:48Z", "Value": 103.829895, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:04:18Z", "Value": 101.566238, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:12:48Z", "Value": 99.26922, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:20:18Z", "Value": 97.03982, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:27:18Z", "Value": 94.79642, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:33:48Z", "Value": 92.58014, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:40:18Z", "Value": 90.24299, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:46:18Z", "Value": 87.98482, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:52:18Z", "Value": 85.63623, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:57:48Z", "Value": 83.40944, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:03:18Z", "Value": 81.11721, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:08:48Z", "Value": 78.76483, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:14:18Z", "Value": 76.35772, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:19:18Z", "Value": 74.1265945, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:24:18Z", "Value": 71.85906, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:29:18Z", "Value": 69.55944, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:34:18Z", "Value": 67.2321, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:39:18Z", "Value": 64.881485, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:44:18Z", "Value": 62.51205, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:49:18Z", "Value": 60.12832, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:54:18Z", "Value": 57.7348251, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:59:18Z", "Value": 55.3361244, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:04:18Z", "Value": 52.9367867, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:09:18Z", "Value": 50.5413742, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:14:18Z", "Value": 48.15445, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:19:18Z", "Value": 45.7805557, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:24:18Z", "Value": 43.42421, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:29:18Z", "Value": 41.0899, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:34:18Z", "Value": 38.78207, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:39:18Z", "Value": 36.50511, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:44:18Z", "Value": 34.26336, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:49:18Z", "Value": 32.06108, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:54:48Z", "Value": 29.689167, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:00:18Z", "Value": 27.3755474, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:05:48Z", "Value": 25.125555, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:11:48Z", "Value": 22.7496681, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:17:48Z", "Value": 20.4621754, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:24:18Z", "Value": 18.0910759, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:30:48Z", "Value": 15.8387, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:37:48Z", "Value": 13.55414, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:45:18Z", "Value": 11.2781792, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:53:18Z", "Value": 9.057073, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T10:02:18Z", "Value": 6.826371, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T10:12:48Z", "Value": 4.600133, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T10:26:18Z", "Value": 2.36138177, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T10:51:18Z", "Value": 0.15845418, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T11:33:48Z", "Value": 2.37518287, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T11:47:18Z", "Value": 4.61918545, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T11:57:48Z", "Value": 6.84932947, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:06:48Z", "Value": 9.083227, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:14:48Z", "Value": 11.3070393, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:22:18Z", "Value": 13.5854092, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:29:18Z", "Value": 15.872098, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:35:48Z", "Value": 18.1263371, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:42:18Z", "Value": 20.4991875, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:42:48Z", "Value": 20.68641, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }], "UnitsAbbreviation": "" });
        $httpBackend.when("GET", "https://marc-web-sql.marc.net/piwebapi/streams/P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ/interpolated?starttime=*-1d&endtime=*&interval=1h").respond({ "Links": {}, "Items": [{ "Timestamp": "2015-11-29T12:43:09.1655089Z", "Value": 20.4991875, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T13:43:09.1655089Z", "Value": 45.8274269, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T14:43:09.1655089Z", "Value": 74.1711655, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T15:43:09.1655089Z", "Value": 97.07046, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T16:43:09.1655089Z", "Value": 108.342873, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T17:43:09.1655089Z", "Value": 108.342873, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T18:43:09.1655089Z", "Value": 90.24322, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T19:43:09.1655089Z", "Value": 64.88178, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T20:43:09.1655089Z", "Value": 36.5053978, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T21:43:09.1655089Z", "Value": 13.5543385, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T22:43:09.1655089Z", "Value": 2.36146951, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-29T23:43:09.1655089Z", "Value": 2.375095, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T00:43:09.1655089Z", "Value": 20.4989529, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T01:43:09.1655089Z", "Value": 45.82713, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T02:43:09.1655089Z", "Value": 74.17145, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T03:43:09.1655089Z", "Value": 97.07065, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T04:43:09.1655089Z", "Value": 108.342949, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T05:43:09.1655089Z", "Value": 108.342949, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T06:43:09.1655089Z", "Value": 90.24299, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T07:43:09.1655089Z", "Value": 64.881485, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T08:43:09.1655089Z", "Value": 36.50511, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T09:43:09.1655089Z", "Value": 13.55414, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T10:43:09.1655089Z", "Value": 2.36138177, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T11:43:09.1655089Z", "Value": 2.37518287, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }, { "Timestamp": "2015-11-30T12:43:09.1655089Z", "Value": 20.68641, "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }], "UnitsAbbreviation": "" });
        //You can get the responses from PI Web API directy or through PI Web API online help
    }));
    //The code above is executed for the piWebApiHttpService and mainCtrl tests


    //Tests for the piWebApiHttpService factory service


    //Tests for the mainController


});

 

 

 

Testing the piWebApiHttpService

 

The piWebApiHttpService factory object handles all HTTP requests. The code snippet for testing the piWebApiHttpService using $httpBackend  is:

 

 

    //Tests for the piWebApiHttpService factory service
    describe("piWebApiHttpService-> ", function () {
        var serviceSuccessCallback = function (data) {
            //if it receives 200 status code, it is a success
            expect(data.status).toEqual(200);
        }


        var serviceErrorCallback = function (error) {
            //error
            expect(1).toEqual(2);
        }




        it("PI Data Archive GET Request", function () {
            angular.mock.inject(function (piWebApiHttpService) {
                var piServerName = "MARC-PI2014";
                piWebApiHttpService.getPIDataArchive(piServerName).then(serviceSuccessCallback, serviceErrorCallback);
                $httpBackend.flush();
                //This call will wait until all HTTP calls are made
            });
        });




        it("PI Point GET Request", function () {
            angular.mock.inject(function (piWebApiHttpService) {
                var webId = "s0IQnVxJzj6UuohiErVnqUqgTUFSQy1QSTIwMTQ";
                var piPointName = "SINUSOID";
                piWebApiHttpService.getPIPoint(webId, piPointName).then(serviceSuccessCallback, serviceErrorCallback);
                $httpBackend.flush();
            });
        });






        it("Snapshot GET Request", function () {
            angular.mock.inject(function (piWebApiHttpService) {
                var webId = "P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ";
                piWebApiHttpService.getSnapshotValue(webId).then(serviceSuccessCallback, serviceErrorCallback);
                $httpBackend.flush();
            });
        });




        it("Recorded Values GET Request", function () {
            angular.mock.inject(function (piWebApiHttpService) {


                var webId = "P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ";
                var startTime = "*-1d";
                var endTime = "*";


                piWebApiHttpService.getRecordedValues(webId, startTime, endTime).then(serviceSuccessCallback, serviceErrorCallback);
                $httpBackend.flush();
            });
        });




        it("Get Interpolated Values GET Request", function () {
            angular.mock.inject(function (piWebApiHttpService) {
                var webId = "P0IQnVxJzj6UuohiErVnqUqgAQAAAATUFSQy1QSTIwMTRcU0lOVVNPSUQ";
                var startTime = "*-1d";
                var endTime = "*";
                var interval = "1h";


                piWebApiHttpService.getInterpolatedValues(webId, startTime, endTime, interval).then(serviceSuccessCallback, serviceErrorCallback);
                $httpBackend.flush();
            });
        });
    });

 

Testing the main controller

 

Please refer the code snippet below for testing the controller.

 

 //Tests for the mainController
    describe("mainCtrl-> ", function () {
        //this is how we instantiate our main controller using $rootScope,$controller, $rootScope, $http
        beforeEach(angular.mock.inject(function ($controller, $rootScope, $http) {
            mockScope = $rootScope.$new();
            $controller("mainCtrl", {
                $scope: mockScope,
                $http: $http
            });
        }));


        // Test to make sure that after clicking on the default values button, the variables under $scope are updated
        it("Default values", function () {
            mockScope.defaultValues();
            expect(mockScope.piServerName).toEqual("MARC-PI2014");
            expect(mockScope.piPointName).toEqual("SINUSOID");
            expect(mockScope.startTime).toEqual("*-1d");
            expect(mockScope.endTime).toEqual("*");
            expect(mockScope.interval).toEqual("1h");
            expect(mockScope.getSnap).toEqual(mockScope.yesOrNoOptions[0]);
            expect(mockScope.getRec).toEqual(mockScope.yesOrNoOptions[0]);
            expect(mockScope.getInt).toEqual(mockScope.yesOrNoOptions[0]);
        })




        //Make sure that all the five HTTP calls are made after clicking on GetData()
        it("Get data", function () {
            mockScope.defaultValues();
            mockScope.getData();
            expect(mockScope.requestMode).toEqual(false);
            $httpBackend.flush();
            expect(mockScope.piServerData).toBeDefined();
            expect(mockScope.piServerExistsValue).toBeDefined();
            expect(mockScope.piPointData).toBeDefined();
            expect(mockScope.piPointExistsValue).toBeDefined();


            expect(mockScope.snapshotData).toBeDefined();
            expect(mockScope.recordedData).toBeDefined();
            expect(mockScope.interpolatedData).toBeDefined();
        });
    });

 

If your tests run successfully after clicking on Tests-->Run-->All tests, all tests will pass on Test Explorer.

 

Figure 3 - Test explorer showing the final results

 

 

Conclusions

 

All applications are likely to have bugs and known issues. Unit testing is a great technique in order to minimize these risks. AngularJS is not only a great JavaScript framework but has great resources to integrate well with Jasmine, a JavaScript framework for testing.

 

 

In this scenario, Web Apps making HTTP request against PI Web API can be testing by mocking HTTP responses using $httpBackend dependency. This is great strategy for improving the code quality of your application.

 

 

Don't hesitate to post a comment!

Filter Blog

By date: By tag: