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

Introduction

 

One blog post that developers on this community refer to when developing HTML5 application with jQuery that will access PI data through PI Web API is Using PI Web API on HTML with jQuery. That blog post shows how to make HTTP requests against PI Web API using jQuery $.ajax function overcoming authentication and CORS issues by selecting the correct inputs for $.ajax() method.

 

Although jQuery is a great library for manipulating the DOM and making Ajax request , AngularJS maintained by Google has become an interesting option for performing similar tasks.

 

What is AngularJS?

 

According to the AngularJS official documentation:

 

AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and lets you extend HTML's syntax to express your application's components clearly and succinctly. Angular's data binding and dependency injection eliminate much of the code you would otherwise have to write. And it all happens within the browser, making it an ideal partner with any server technology.

 

Angular is not a single piece in the overall puzzle of building the client-side of a web application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a well-defined structure. This makes Angular opinionated about how a CRUD (Create, Read, Update, Delete) application should be built. But while it is opinionated, it also tries to make sure that its opinion is just a starting point you can easily change.

Given the description above, we conclude that AngularJS is a great option to integrate your web application with the PI System using also PI Web API.

 

Sample Application

 

On this blog post, we will convert the sample application developed using jQuery to a similar one using AngularJS. You can download the source code package from this GitHub repository. Please follow the following steps to create the application:

 

  • Open Visual Studio and create a new ASP.NET Web Application.

Figure 1 - Creating an ASP.NET Web Application on Visual Studio.

 

 

  • Select the empty template as no server side code will be used.

 

Figure 2 - Select the Empty template

 

  • Open Package Manager Console and type "Install-package AngularJS.Core" in order to download and add the core AngularJS file to your project. Make sure the NuGet Packager Manager is installed as an extension of your Visual Studio.
  • Create a new file on the root of your project named index.html with the following content:

 

<!DOCTYPE html>


<!--This is where you define the name of your AngularJS app-->
<html ng-app="PiWebApiSampleApp">
<head>
    <title>PI Web API Sample App with AngularJS</title>
    <!--The file below was copied from the blog post sample app using jQuery to style the DOM elements-->
    <link href="default.css" rel="stylesheet" />      
</head>


<!--The mainContrl is our main AngularJS controller-->
<!--Variables declared within $scope will manipulate the DOM within the body node-->
<body ng-controller="mainCtrl">
    <!--The div below will appear only if $scope.requestMode == true-->
    <div ng-show="requestMode == true">
        <h1>Request PI Data</h1>
        <p>
            Please fill in your details below and click  on &quot;Get PI
            Data&quot;. Fields marked with an asterisk (*) are required.
        </p>
        <div>
            <div style="width: 30em;">
                <label for="piServerName">PI Server Name *</label>
                <!--The value of the input below is bound to the value of the $scope.piServerName.-->
                <input type="text" name="piServerName" id="piServerName" value="" ng-model="piServerName" />
                <label for="piPointName">PI Point name *</label>
                <input type="text" name="piPointName" id="piPointName" value="" ng-model="piPointName" />
                <label for="startTime">Start time *</label>
                <input type="text" name="startTime" id="startTime" value="" ng-model="startTime" />
                <label for="endTime">End time *</label>
                <input type="text" name="endTime" id="endTime" value="" ng-model="endTime" />
                <label for="interval">Interval *</label>
                <input type="text" name="interval" id="interval" value="" ng-model="interval" />


                <label for="getsnap">Get Snapshot?</label>  
                <select name="getsnap" id="getsnap" size="1" ng-model="getSnap" ng-options="option.name for option in yesOrNoOptions"> </select>
                
                <label for="getrec">Get Recorded Data?</label>
                <select name="getrec" id="getrec" size="1" ng-model="getRec" ng-options="option.name for option in yesOrNoOptions"> </select>


                <label for="getint">Get Interpolated Data?</label>
                <select name="getint" id="getint" size="1" ng-model="getInt" ng-options="option.name for option in yesOrNoOptions"> </select>


                <div style="clear: both;">
                    <!--This function will make Http request and store the results-->
                    <input type="submit" id="submitButton" value="Get PI Data!" ng-click="getData()" />
                    <!--This function will change the values declared on $scope which are bound to some DOM elements-->
                    <input type="button" id="DefaultButton" ng-click="defaultValues()" value="Default Values" style="margin-right: 20px;" />
                </div>
            </div>
        </div>
    </div>
    <!--After running $scope.getData(), $scope.requestMode will become equal to false. As a result the second div will be shown-->
    <div ng-show="requestMode != true">
        <h1>Displaying SINUSOID data</h1>


        <h2>Connection information</h2>
        <br />
        <table border="0" style="width: 20em; border: 1px solid #666;">
            <tr>
                <th>Property</th>
                <th>Value</th>
            </tr>


            <tr>
                <td>PI Server</td>
                <!--Using { {} } also binds the DOM with variables declared under $scope-->
                <td id="PIServerNameValue">{{piServerName}}</td>
            </tr>
            <tr>
                <td>PI Point</td>
                <td id="PIPointNameValue">{{piPointName}}</td>
            </tr>
            <tr>
                <td>Start time</td>
                <td id="StartTimeValue">{{startTime}}</td>
            </tr>
            <tr>
                <td>End time</td>
                <td id="EndTimeValue">{{endTime}}</td>
            </tr>
            <tr>
                <td>Interval</td>
                <td id="IntervalValue">{{interval}}</td>
            </tr>


            <tr>
                <td>Does the PI Server exist?</td>
                <td id="PIServerExistValue">{{piServerExistsValue}}</td>
            </tr>
            <tr>
                <td>Does the PI Point exist?</td>
                <td id="PIPointExistValue">{{piPointExistsValue}}</td>
            </tr>
        </table>


        <div id="errors">
            <!--If errors are detected, they will be displayed here-->
            <p ng-repeat="error in snapshotError.Errors">{{error}}</p>
            <p ng-repeat="error in recordedErrorError.Errors">{{error}}</p>
            <p ng-repeat="error in interpolatedError.Errors">{{error}}</p>
            <p ng-repeat="error in piServerError.Errors">{{error}}</p>
            <p ng-repeat="error in piPointError.Errors">{{error}}</p>
            <!--ng-repeat will iterate through all arrays-->
        </div>
        <!--The div below will appear if a webId is found and if the user has selected to get the snapshot on the previous screen-->
        <div ng-show="getSnap.value == true && webId != null">
            <h2 class="snapshot">Snapshot Value of Sinusoid</h2>
            <br />
            <table class="snapshot" border="0" style="width: 20em; border: 1px solid #666;">
                <tr>
                    <th>Value</th>
                    <th>Timestamp</th>
                </tr>
                <tr>
                    <td>{{snapshotData.Value}}</td>
                    <td>{{snapshotData.Timestamp}}</td>
                </tr>
            </table>
        </div>
        <br />
        <br />


        <div ng-show="getRec.value == true && webId != null">
            <h2 class="recorded">Recorded Values of Sinusoid</h2>
            <br />
            <table class="recorded" border="0" style="width: 20em; border: 1px solid #666;">
                <tr>
                    <th>Value</th>
                    <th>Timestamp</th>
                </tr>
                <!--Iterating through all the values received-->


                <tr ng-repeat="item in recordedData.Items">
                    <td>{{item.Value}}</td>
                    <td>{{item.Timestamp}}</td>
                </tr>
            </table>
        </div>
        <br />
        <br />
        <div ng-show="getInt.value == true && webId != null">
            <h2 class="interpolated">Interpolated Values of Sinusoid</h2>
            <br />
            <table class="interpolated" border="0" style="width: 20em; border: 1px solid #666;">
                <tr>
                    <th>Value</th>
                    <th>Timestamp</th>
                </tr>
                <tr ng-repeat="item in interpolatedData.Items">
                    <td>{{item.Value}}</td>
                    <td>{{item.Timestamp}}</td>
                </tr>
            </table>
            <br /><br />
        </div>
    </div>
    <script src="Scripts/angular.min.js"></script>
    <script src="Scripts/app.js"></script>
    <script src="Scripts/piwebapi.js"></script>
</body>
</html>

 

 

  • Under the Scripts folder, create a javascript file called app.js with the following content:

 

//Make sure the name below is the same declared on  <html ng-app="PiWebApiSampleApp">


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;
        });
    }
});

 

 

  • Still under the Scripts folder, create another javascript file named piwebapi.js with the following content:

 

'use strict'
piWebApiApp.factory('piWebApiHttpService', ['$http', '$q', function ($http, $q) {


    //This factory method works like a service in which all HTTP requests are made.
    var serviceBase = 'https://marc-web-sql.marc.net/piwebapi/';


    //Set withCredentials = true; if you need to type your credentais.
    $http.defaults.withCredentials = true;
    var piWebApiHttpServiceFactory = {};
    piWebApiHttpServiceFactory.validPIServerName = function (piServerName) {
        return $http.get(serviceBase + "dataservers?name=" + piServerName).then(function (response) {
            return response;
        });
    };


    piWebApiHttpServiceFactory.validPIPointName = function (piServerName, piPointName) {
        return $http.get(serviceBase + "points?path=\\\\" + piServerName + "\\" + piPointName).then(function (response) {
            return response;
        });
    };


    piWebApiHttpServiceFactory.getSnapshotValue = function (webId) {
        return $http.get(serviceBase + 'streams/' + webId + '/value').then(function (response) {
            return response;
        });
    };


    piWebApiHttpServiceFactory.getRecordedValues = function (webId, startTime, endTime) {
        return $http.get(serviceBase + 'streams/' + webId + '/recorded?starttime=' + startTime + '&endtime=' + endTime).then(function (response) {
            return response;
        });
    };


    piWebApiHttpServiceFactory.getInterpolatedValues = function (webId, startTime, endTime, interval) {
        return $http.get(serviceBase + 'streams/' + webId + '/interpolated?starttime=' + startTime + '&endtime=' + endTime + "&interval=" + interval).then(function (response) {
            return response;
        });
    };


    return piWebApiHttpServiceFactory;
}]);

 

  • Finally, If you want to improve the design and style, download the default.css file from the sample application developed with jQuery and paste it on the project root. You can download the sample application of this blog post directly as well.

 

The final look of the application on Google Chrome will look like Figure 3.

 

Figure 3 - Testing the sample web app on Google Chrome

 

Conclusions

 

I have found an interesting article with 10 reasons why web developers should learn AngularJS. I specially find it really useful in case you are developing Single Page Applications (this is actually the reason why I have learned it). Another great benefit is that it makes easier to manipulate the DOM when compared to jQuery. Just compare the source code from both sample applications and you will realize that the AngularJS version requires less lines of code.

 

I hope you have found this blog post informative! The following blog post will about Unit Testing JavaScript code.

Hello Everyone,

 

I am really happy today to introduce you to Clues, and I am hoping that this project will inspire you as much as me.

 

You may think that Clues is about the game? Well not really, but somewhat related .

A bit of it is certainly about finding clues to understand how the PI AF SDK works.

More seriously Clues stands for: Command Line Utility & ExampleS

 

Clues is a community project, hosted on GitHub, that provides a code-base to work with the PI AF SDK.

 

It has three main goals:

  • provide code examples
  • provide examples in a re-usable and useful form, for the day to day work
  • act as a container for quick prototyping

 

 

2015-12-01: I invite you to participate and give your idea with the poll: What should Clues to do next? , thanks for your vote

sherlock-holmes-147255_1280.png

Fork me on GitHub

If you can't wait to see all the technical details, you may go directly to the GitHub Repository:

osisoft/PI-AF-SDK-Clues · GitHub

 

Why Clues?

 

Code samples

The development support team writes a lot of code samples, and many of them may be re-used if written in a way that is generic enough. i.g. Connection to PI, Read Tag Value, etc.

We are certain that you are also writing code that could benefit to others right? Clues was created to centralize and make these samples in an easy format,  shareable and available in a command line form.

 

What if you could do this to test a connection to the PI Data Archive with AF SDK?

clues PIConnect -s PIServer01

 

You have heard of EventPipes but you could never test them?

clues PIDataPipeListener -p "optimus" -t simulator.random.15,sinusoid

 

This is now possible with a simple command line utility : clues

 

Re-Use and Prototyping

Clues contains a template that you can copy and paste into a new class and allows you to create a new command line applet on a snap:

You rename the class, give it a description, add the command line parameters, and you are ready to go to write your code in the Run() method.  For simple examples, this means only a single file to maintain.

So you can say goodbye to all those solution1 and Project1 that you have created from visual studio that are not re-usable! (that tells you something?)

 

Imagine that we all have our own personal-clues that (we have forked on GitHub) and we use for our personal testings and recurrent tasks.  When one of us comes up with a useful applet, this would make it much easier to share!

 

Sounds cool, isn't it?

 

What can I do with Clues now?

 

Currently Clues command line has the the following options, and based on your comments / contributions, it will evolve.  So I am not expecting that this list will stay in this post but will be kept up to date in the GitHub Readme.

 

  AFConnect Connects to a PI System (AF)

  AFCreateAttribute Creates an AF attribute on the specified element.
  Supports all standard attributes.

  AFDataPipeListener Illustrates the functionning of the AF Data Pipe, to
  get changes from AFAttributes as changes occurs

  AFElements List and create elements

  AFGetValue To get values from attribute(s) using the Path
  Syntax

  PIConnect Connects to a PI Data Archive Server

  PIConnectSettings This applet allows to change the timeouts of a PI
  Data Archive Connection.

  PIDataPipeListener Illustrates the functionning of the PI Data Pipe, to
  get changes from PI Tags as changes occurs

  PIDelete Deletes data in archive for specified tag(s) and for
  a specific time range.

  PIFindPoints Finds PIPoints based on tag name filter and
  optionally from point source.

  PIGetCurrentValue Reads the most recent value for the specified tag.

  PIGetCurrentValueBulk Reads the most recent value for multiple tags that
  match the search mask.

 

 

What will Clues do tomorrow?

Clues will definitely be an extent to Development Support and serve as a container for code that we believe can bring value in our day to day tasks and support scenarios.  And this is another way to say that Clues will do what you will be asking for , and if you feel even more geeky it will do what you will contribute for!

 

Want to contribute?

 

GitHub is still quite new for the community, so don't hesitate to create new questions on PI Square about it, this way we can start building knowledge about it.

You can also look at GitHub Guidelines  this should give you the main picture.

 

We cannot guarantee that all your contributions will be accepted, and it may require some back and forth before what you are proposing gets integrated in the repository, but this will only be for the best of clues

 

Ah! And in case you are not ready for GitHub yet (this can happen!), you may send the applet text file to pidevclub@osisoft.com, and we will take it from there.  I would not like to prevent any contributions because of technology!

 

 

Ready for GitHub?

A quick and easy explanation here:

GitHub Guides: Forking 4 minutes read

 

In summary:

  • Fork the repository
  • Clone this fork on your dev machine
  • Make the changes, add more code.
  • Commit the changes locally.
  • Push the changes back to your GitHub forked repository. ( in GitHub for Windows, you press the sync button)
  • Make pull request --> the pull request is where you will send back the contribution to our repository, it is optional, if you'd like to keep all the changes only for you, in your repository, this is up to you .  You may ask us to come and peak in yours that would work too!

 

--

 

I am looking forward for your comments and ideas!

 

Have a nice day,

bshang

PI AF SDK Basic Samples

Posted by bshang Employee Nov 24, 2015

Dear PI geeks,

 

A new Github repository has been created for newcomers to PI AF SDK.

 

PI-AF-SDK-Basic-Samples

 

osisoft/PI-AF-SDK-Basic-Samples · GitHub

 

This repository provides self-contained and reproducible samples of basic operations using PI AF SDK. The aim is to provide an accessible, hands-on learning experience with the PI AF SDK using code examples that are short, portable, and easy to follow. Many of the examples follow the Examples in the PI AF SDK online reference guide but in the context of a sample NuGreen AF Database.

 

Each example demonstrates a basic operation within the PI AF SDK. These examples present PI AF SDK as a set of basic building blocks. The goal is to enable the user to learn the basic operations of PI AF SDK so they then have the tools to build more specific applications and a foundation to learn more advanced PI AF SDK concepts.

 

The aim is not to cover the entire PI AF SDK, but just enough to get started and understand the broader picture. As experienced users may know, there are many ways to get to a result in PI AF SDK and these examples will only aim to cover a small, but relevant portion.

 

We'll be adding additional examples in the future and welcome any suggestions and contributions.

dng

Raspberry Pi to the PI System

Posted by dng Employee Nov 12, 2015

Yesterday, Barry posted a blog post about writing to the PI System using the Arduino Yun. I figured I’ll join in this Internet of Things fun by posting my experience on writing to PI using Raspberry Pi.

 

 

Setup

Similar to Barry’s set up, I am collecting temperature data via a temperature sensor. The temperature data is then sent to the PI System by posting to a public PI Web API endpoint. Instead of Arduino Yun, we are using Raspberry Pi here.

 

Here is the setup:

rpi_setup.JPG

 

  • Sensor: DS18B20 digital temperature sensor
    • The sensor was set up according to this tutorial with the help of James Dryden (thanks James!)
  • Development system: Raspberry Pi
    • I am using an older model of Raspberry Pi (Model B) running Raspbian.
  • Gateway device: Digi TransPort WR21 wireless router
    • This is a cellular router, allowing us to send data to the PI server via the cellular LTE network. This potentially allow us to install our sensor at any location as long as cellular network is available!
  • PI System: PI Web API with PI Data Archive 2015.
    • The PI Data Archive, as well as the PI Web API instance, is hosted on Azure. The PI Web API endpoint is publicly exposed.

 

 

Python Script

Once everything is set up, I used a simple Python script to write the temperature data to PI every 5 seconds.

 

WriteTemp.py (GitHub gist here):

 

import requests
import time
import os
import glob
import re

base_url = 'https://<PI Web API server>/piwebapi'
webId = '<WebId to PI Tag>'
base_dir = '/sys/bus/w1/devices/'
yes_pattern = re.compile(r'YES')
temp_pattern = re.compile('t=(\d+)')

def initialize_sensor():
    os.system('sudo modprobe w1-gpio')
    os.system('sudo modprobe w1-therm')

def get_sensor_file():
    device_folder = glob.glob(base_dir + '28-*')[0]
    return device_folder + '/w1_slave'

def read_temp_raw(file):
    f = open(device_file,'r')
    lines = f.read()
    f.close()
    return lines

def read_temp(file):
    lines = read_temp_raw(file)
    while not yes_pattern.search(lines):
        time.sleep(0.2)
        lines = read_temp_raw(file)
    temp_string = temp_pattern.search(lines).group(1)
    temp_c = float(temp_string) / 1000.0
    temp_f = temp_c * 9.0 / 5.0 + 32.0
    return temp_f

def post_pi_value(value):
    data = {'Value': value}
    headers = {'Content-Type': 'application/json'}
    response = requests.post(base_url + '/streams/' + webId + '/value', json=data, headers=headers, verify=False)
    return response

if __name__ == '__main__':
    initialize_sensor()
    device_file = get_sensor_file()
    while True:
        value = read_temp(device_file)
        response = post_pi_value(value)
        print(response)
        time.sleep(5)

 

In this script, I’m posting the temperature value to the PI Web API Stream controller > UpdateValue action every 5 seconds (timestamp is current time by default). The post_pi_value function is all we need to write to PI Web API! For more information on how to work with HTTP requests in Python, check out the Python library Requests. Regarding the code on on how to get temperature reading from the sensor, check out the tutorial for the DS18B20 temperature sensor.

 

 

Running on startup

Finally, I set this Python script to run on startup by editing the rc.local file at /etc/rc.local by including this line:

 

sudo python3 /path/to/WriteTemp.py > /dev/null 2>&1 &

 

 

Results

Running the script (which occurs automatically after rebooting the Raspberry Pi), we can see live temperature readings in the PI Data Archive!

 

On a normal day in the office:

 

On a particular warm day in the office:

 

We can clearly see the temperature going up at the beginning of business day! (heater kicking off? when people starting to come into the office?)

 

Conclusion

Through these simple set ups, we hope to show you the possibility of integrating the PI System with these IoT devices. Let us know your experience with IoT + PI!

bshang

Arduino To PI with PI Web API

Posted by bshang Employee Nov 11, 2015

Motivation

 

Internet of Things is all the craze these days. It's currently at the top of the Gartner hype cycle. It's only appropriate that I blog about it soon .

 

In this post, I will show a simple example that collects temperature data by my desk from a sensor, Arduino Yun, PI Web API, and a PI System. I will also show how something very simple helped us learn some interesting things about temperature behavior in the office.

 

Components

 

The components for a sensor-to-PI System data flow are as follows:

 

Sensor: For the sensor, I chose a simple temperature sensor here. It provides a simple low voltage output linearly proportional to the Celcius temperature.

Development Board: I chose the Arduino Yun because it is natively Ethernet and Wi-Fi capable. This component is the device that runs the code. To learn more about it, I encourage you to read the links shared before.

Gateway device: This is the device that offers Internet connectivity. It can be a home router, a cellular router, or another specialized gateway. In this example, we used a cellular router. The development board and router are connected via ethernet cable although Wi-Fi could do as well (as long as the router includes a Wi-Fi access point).

Cloud endpoint: PI Web API is the cloud endpoint here. Another choice could be Azure Event Hubs. The endpoint should be HTTP-accessible although other protocols could be used if the device supports it.

PI System: The PI System is the persistence layer that stores the temperature data.

 

Here is a picture of the setup:

arduino_setup.JPG

 

As you see, there are some additional components, such as a breadboard and wires. For the electronics setup, I followed the examples provided in the links below:

SIK Experiment Guide for Arduino - V3.2 - learn.sparkfun.com

Arduino - TemperatureWebPanel

 

Code

 

As seen in the diagram, The Arduino Yun actually contains two processors: an ATmega 32U4 and AR9331 Linux. The ATmega 32U4 does not include an operating system and can only support code written in the Arduino programming language (which has flavors of C).  The AR9331 runs a version of Linux that supports a Python interpreter so Python code can be written on it.

 

Analog inputs, such as those from the temperature sensor, can only be read via the ATmega 32U4. However, Ethernet and Wi-Fi are offered only via the AR9331. Therefore, a Bridge abstraction is used to pass data between the two processors so the analog input can be sent over Internet to PI Web API (This Bridge abstraction is actually implemented via custom TCP sockets but the end developer doesn't need to know too much about this, as you'll see later).

 

There are two Bridge libraries, one on each processor. These libraries can be used to pass data as key-value pairs between code running on the ATmega 32U4 and AR9331.

ATmega 32U4 Bridge library

AR9331 Bridge library (Python)

 

ATmega 32U4 code:

arduino-sketch-temperature · GitHub

 

#include <Bridge.h>

const int temperaturePin = 0;

void setup()
{
  Bridge.begin();
}


void loop()
{
  float voltage, degreesC, degreesF;
  voltage = getVoltage(temperaturePin);
  degreesC = (voltage - 0.5) * 100.0;
  degreesF = degreesC * (9.0/5.0) + 32.0;

  Bridge.put("TEMP", String(degreesF));

  delay(5000); // repeat once per 5 seconds (change as you wish!)
}


float getVoltage(int pin)
{
  return (analogRead(pin) * 0.004882814);
}

 

As you can see, analogRead(pinNumber) is all that's needed to reach from the analog input on the Arduino Yun. Bridge.put is used to pass the temperature to the Python code running on the other processor.

 

 

 

AR9331 code:

arduino-python-temperature.py · GitHub

 

#!/usr/bin/python

import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
import urllib2, urllib

import random
from time import gmtime, strftime, sleep

from bridgeclient import BridgeClient as bridgeclient

client = bridgeclient()

print "python script is starting"

url = 'https://<SERVER>/piwebapi/streams/{webId}/value'

password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, url, 'username', 'password')

auth = urllib2.HTTPBasicAuthHandler(password_manager) # create an authentication handler
opener = urllib2.build_opener(auth) # create an opener with the authentication handler
urllib2.install_opener(opener) # install the opener... 

req_headers = {'Content-Type': 'application/json'}

while 1:
    val = client.get('TEMP')

    ts = strftime('%Y-%m-%d %H:%M:%S', gmtime()) + 'Z'

    print ts, val

    #urllib2
    req_data = str({"Timestamp": ts, "Value": val})
    request = urllib2.Request(url, headers = req_headers) 
    request.add_data(req_data)

    try:
        response = urllib2.urlopen(request).read()
    except:
        print "Unexpected error:", sys.exc_info()[0]

    sleep(5)

 

We use the Python bridgeclient class to read the temperature passed from the ATmega. We then use the urllib2 Python library to make the REST call to PI Web API.

 

 

Office Temperature Data

 

Let's look at the temperature data collected over 4 days. Interestingly, there is a clear pattern in temperature throughout the day, although there are some differences between days as well. It gets warmer during the afternoon (just in time for a nap) and for the past two days, the heater was turned on the morning.

 

San Leandro:

blog_temp.PNG

 

We also collected temperature data with a Raspberry Pi in the Philadelphia office and compared office desk temperatures.

 

San Leandro (green) vs. Philadelphia (cyan):

blog_temp_compare.PNG

 

Clearly, there is a large difference in temperature between the two office desks (the Philadelphia sensor is also more accurate). There are also some patterns in temperature behavior in the Philadephia office but they are less pronounced, and the temperature variations are smoother. Such insight likely cannot be gained from temperature data from a building management system, which likely gives a more global or averaged view of temperature. There are likely temperature variations within a building, and even on a single floor, depending on closeness to windows, etc. Here, with small sensors and development boards, we can get finer spatial resolution to understand how temperature behaves locally near distributed office desks.

 

Conclusion

 

We showed how simple IoT devices like Arduinos and basic sensors could be used to bring data into the PI System, via PI Web API. We then showed some interesting insights that could be gained from only a few days worth of data collection from two temperature streams. Much more can probably be learned via data collected at the scale of industrial IoT. This concludes the blog post and I hope you may find it helpful for your research. As always, questions/comments are welcome below.

Filter Blog

By date: By tag: