In this project we take a Raspberry Pi 2 and use it to send some pH data to the Microsoft Cloud. The Raspberry Pi 2 seems like it might be overkill for this purpose but there are a few other nice things that we can do with this computer. We can write a few estimation algorithms to "clean up" the noisy output of the sensor. This work will mostly be done in Python while the work on the microsoft Azure side will be mostly in NodeJS for now. We use Microsoft's DocumentDB framework to store the data and retrieve it. We are also making the hardware side open source so feel free to also use "portal-0"

Embedded Code Overview

saveFile.py

The purpose of this file is to initialize the communication with the Atlas Scientific probe and then write it to a file. It just repeats this process endlessly. You should probably run it in the background. You could also take out the 'print' statements but I leave them in there so you can 'see' it working on the embedded side.

import serial # required for communication with boards
import time, datetime
from time import strftime # used for timestamps

#USB parameters
usbport = '/dev/ttyACM0'
ser = serial.Serial(usbport, 9600, timeout = 0) # sets the serial port to the specified port, with a 9600 baud rate
# Timeout = 0 tells the serial port to not wait for input if there is non 

# declare and initialize the data buffers
line = "" 
user_input = ""

#clear serial buffer
ser.write("\r")

#turn on LEDS
ser.write("L,1\r")

#enable streaming
ser.write("C,1\r")

def check_ph_level(line):
    # compares the ph reading to a value and displays if its higher or lower
    try:
        ph = float(line) # converts the string into a floating point number
        if(ph >= 7.5):
            print("High"+ "\n")
        if(ph < 7.5):
            print("Low"+ "\n")
    except ValueError:
        # if the string is not a valid floating point number, dont do anything
        pass
filename = "data.txt" ## "/hummingbirdembedded1/models/data.txt" ## "
#main loop
while True:
    # sensor receive
    data = ser.read() # get serial data
    if(data == "\r"): # if its terminated by a newline
        print("> " + strftime("%Y-%m-%d %H:%M:%S") + 
        " Received from sensor: " + line + "\n") #print the timestamp and received data to the main screen
        check_ph_level(line) # calls function to check ph levels
        with open(filename,"r+") as f:
            f.seek(0) 
            f.write("P " + line)
            f.close()
        line = "" # clears the input
        time.sleep(5)
        
    else:
        line  = line + data # if the line isn't complete, add the new characters to it
        time.sleep(5)

postData.py

Here is how you post the data. Like I said we are giving out the key for anyone to post to our service. You can also see the hash algorithm. This took awhile to figure out so I hope someone can benefit from it.

import re, requests, json ,datetime, time
import urllib
import hashlib
import hmac
import base64

class sensor(object):
    def __init__(self, sType=None, value=None, unit=None, status=None):
        self.sType = sType
        self.value = value
        self.unit = unit
        self.status = status
        
class Device(object):
    def __init__(self, power=None, sensor=sensor, ID=None, name=None, version=None, deviceStatus=None):
        self.deviceStaus = deviceStatus
        self.power = power
        self.sensor = sensor
        self.ID = ID
        self.name = name
        self.version=  version

def uploadData():
    sD = ""
    key = 'YOMfbmtih/oEERPw3u3ha2wazXR0N2uSFsN61+cKjpM='
    url = 'https://vivaplanetbusservicedev.servicebus.windows.net/hummingbirdqueue/messages'
    keyName = 'DevicePolicy'
    
    now = datetime.datetime.utcnow()
    then = datetime.datetime(1970, 1, 1, 0, 00, 00, 000000)
    expiry = str(int((now-datetime.datetime(1970,1,1)).total_seconds())) ##  '1440710529' ## 
    ##print str(expiry)
    
    resourceUri = urllib.quote_plus(url).lower()
    message = bytes(resourceUri).encode('utf-8') + '\n' + expiry
    ##print message
    
    secret = bytes(key).encode('utf-8')
    ##print secret
    
    signature = urllib.quote_plus(base64.b64encode(hmac.new(secret,message,hashlib.sha256).digest()))
    ##print signature
    
    signature = re.sub("(%[0-9A-F][0-9A-F])", lambda m: m.group(0).lower(), signature);
    ##print signature
    
    token = "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}".format(unicode(resourceUri,'utf-8'), unicode(signature,'utf-8'), unicode(expiry,'utf-8'),  unicode(keyName,'utf-8'))
    ##print token
    
    filename = "data.txt" ## "/hummingbirdembedded1/models/data.txt" ## "
    with open(filename,"r+") as f:
        d = str(f.readlines()) ## Get the datafile
        f.close()
    for s in d:
        sD = sD + s ## dump the line into a string    
    if "P" in sD:
        indL = d.index("P") ## get the index of the measurment in the array

        sensorList = []
        sensorList.append(sensor(d[indL],d[indL+2:indL+7],"pH","OK"))

        deviceStatus = []
        deviceStatus.append(Device("100", sensorList, "00PH-0000-0000-0000","000PH", "0.0.0.1"))
        
        payload = json.dumps({
                    'DeviceId' : deviceStatus[0].ID,
                    'Name': deviceStatus[0].name,
                    'DeviceStatus': 'Remove this field',
                    'PowerStatus': deviceStatus[0].power,
                    'SoftwareVersion': deviceStatus[0].version,
                    'Time' : str(now),
                    'Sensors':  {sensorList[0].sType : sensorList[0].value}
                    })
        
        print payload
        headers = {'Authorization':'%s' % token}
        r = requests.post(url, data=payload, headers=headers)
        print r.status_code
        time.sleep(60)
    else:
        print "file poorly formed. wait another cycle"
        time.sleep(60)

while True:
    uploadData()

The last step is to visit portal-0 and see the pH information you're uploading.