Summary

 

In this example, which is similar to blog posts by Barry Shang using Arduino Yun and Daphne Ng using Raspberry PI. However, in this blog post we will gather temperature data from a sensor and publish to Azure Event Hubs and then consume the data from the Event Hubs by a webservice client that will post the data to the PI Connector for UFL.

 

What you will need

 

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

 

Sensor: A simple temperature sensor was selected here as it provides a simple low voltage output linearly proportional to the Celcius temperature.

Development Board: The Arduino Yun is natively Ethernet and Wi-Fi capable.

Gateway device: The development board is connected via ethernet cable although Wi-Fi could do as well (as long as the router includes a Wi-Fi access point).

Cloud endpoint: Azure Event Hubs for publishing and consuming events from the sensor.

PI Connector for UFL: PI Connectors are the newest technology, similar to PI Interfaces, that collect data with minimal configuration interaction.

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

 

Here is a picture of the setup:

 

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

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

Arduino - TemperatureWebPanel

 

Code

The temperature sensor reading from the analogRead is picked up by the ATmega 32U4 processor. A bridge is then used to pass the analog reading to the AR9331 processor where it can be sent by WI-FI or ethernet to the Azure Event Hubs via the internet. Once the events are stored in the Event Hubs a webservice client consumes the data (see blog post on publishing and consuming events from Azure Event Hubs) and posts it to the PI Connector for UFL.

 

ATmega 32U4 code:

The code for the ATmega 32U4 is the same as the code in the previous post by Barry to pick up the sensor data with a call to analogRead(pin) that reads the voltage from the analog in on the Arduino Yun.

arduino-sketch-temperature · GitHub

 

#include <Bridge.h>
#include <Console.h>


const int temperaturePin = 0;


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


  while (!Console){
    ; // wait for Console port to connect.
  }
  Console.println("You're connected to the Console!!!!");
}


void loop()
{
  float voltage, degreesC, degreesF;


  voltage = getVoltage(temperaturePin);


  degreesC = (voltage - 0.5) * 100.0;


  degreesF = degreesC * (9.0/5.0) + 32.0;


  Console.print("voltage: ");
  Console.print(voltage);
  Console.print("  deg C: ");
  Console.print(degreesC);
  Console.print("  deg F: ");
  Console.println(degreesF);


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

 

AR9331 code:

The code below posts the temperature data read to Azure Event Hubs from the Arduino Yun.

arduino-temperature-to-azureeventhubs.py : GitHub

 

#!/user/bin/python


import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
import requests as req
import urllib2, random, time, hmac, hashlib, base64
from time import gmtime, strftime


from bridgeclient import BridgeClient as bridgeclient
client = bridgeclient()


def eventHub():
    print "python script is starting"


    url = 'https://<Event Hub namespace>.servicebus.windows.net/<Event Hub path>/messages'


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


    sas = _sign_string(url, '<Event Hub key>', '<Event Hub key name')


    req_headers = {'Content-Type': 'application/atom;type=entry;charset=utf-8', 'Accept': '*/*', 'Authorization': sas}
    
    while 1: 
        val = client.get('TEMP')
        ts = strftime('%Y-%m-%d %H:%M:%S', gmtime()) + 'Z'
        print ts, val


        req_data = {"Tag":"UFLOfficeTemp", "Timestamp": ts, "Value": val}


        response = req.post(url, json=req_data, headers=req_headers, verify=False);


        print response.text


        time.sleep(5)


# from https://gist.github.com/sedouard/8412cb51629ef9614fd4
def _sign_string(uri, key, key_name):


    '''
    100000 = milsecond expiry
    '''
    expiry = int(time.time() + 10000)


    string_to_sign = urllib2.quote(uri) + '\n' + str(expiry)
    print 'url: ' + uri
    print 'url encoded: ' + string_to_sign


    key = key.encode('utf-8')
    string_to_sign = string_to_sign.encode('utf-8')
    print 'url encoded: ' + string_to_sign
    signed_hmac_sha256 = hmac.HMAC(key, string_to_sign, hashlib.sha256)
    signature = signed_hmac_sha256.digest()
    signature = base64.b64encode(signature)


    return 'SharedAccessSignature sr=' + urllib2.quote(uri)  + '&sig=' + urllib2.quote(signature) + '&se=' + str(expiry) + '&skn=' + key_name


if __name__ == '__main__':
    eventHub()

 

The code below posts the events, consumed from Event Hubs, to the PI Connector UFL.

bpayne1/UFLWebClient · GitHub

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;


namespace UFLWebClient
{
    class Program
    {
        static string uri = "https://server:port/connectordata/Webservice"; //Address from UFL Connector Datasource configuration


        static void Main(string[] args)
        {
            string data = "servicetest,72.00," + DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss");
            Console.WriteLine("Data to send: " + data);
            byte[] fileToSend = Encoding.UTF8.GetBytes(data);
            ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(
               (object sender, X509Certificate certification, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { return true; });
            using (var wb = new WebClient())
            {
                var responsess = wb.UploadData(@uri, "PUT", fileToSend);
                string responses = Encoding.ASCII.GetString(responsess);
                Console.WriteLine(responses);
            }


            Console.ReadLine();
            Console.WriteLine("ReadLine");
        }
    }
}

 

You will need to have a configuration (ini) used by the UFL connector for proper processing of the data.

 

The resulting 24 hour temperatures in PI as seen in ProcessBook

 

Conclusion

 

Here we showed how to use a simple IoT device like an Arduino Yun and a basic temperature sensor to bring data into the PI System by sending the data to Azure Event Hubs as a temporary repository and then consume the events using a webservice client that posts the data to the PI Connector for UFL. I hope you thought this was interesting and any feedback is welcomed.