Making the Software from Scratch

This page shows how to create the code for the weather station from scratch.You must have followed all except the final instruction (which downloads the full code) on the Setting Up the Pi Weather Station page, and also have built the electronic circuit with the sensor (instructions on the Constructing the Weather Station page). For help turning on your Pi and getting it to the interface, go to the Starting Up Your Pi page.

If you don’t want to go through the whole process, the finished fully-working code can be downloaded by typing the code:

git clone https://github.com/SheffieldPi/Sheffield-Pi-Weather-Station.git

Before you start, remember that code is very exact and capital letters and punctuation are very important. If your code begins to return errors, check to see if there are any mistakes.

This code has three uses – it writes the data to a text file, it uploads it to the Met Office’s Weather Observations Website (also known as WOW) and it streams the data directly to a graphing site called Plot.ly.

1. Start Python

To start to code, you need to be in the Python coding interface, which is different from LXTerminal. Go to an icon called “IDLE” on your desktop on the Pi and double click to open it. Once there, click “File” and then “New Window” to open up a new file. All the code will go into this.

2. Import all of the functions your code needs

These two lines of code access the time and the weather sensor respectively:

import time
import Adafruit_BMP.BMP085 as BMP085

These allow us to create and upload the Plot.ly plot:

import plotly.plotly as py
import plotly.tools as tls
from plotly.graph_objs import *

These allow the code to send and receive information using URLs, which we need for the WOW data upload.

import urllib
import urllib2

This creates the sensor as an object that can be called upon:

sensor = BMP085.BMP085()

3. Sort out the code which runs once at that beginning

A. Write the functions you need for WOW.

WOW requires that the temperature, pressure and time be uploaded in a particular format. The next few snippets of code are functions that will change our data to the format we need. The indents (the spaces at the start of some of the lines) are important and can be created by pressing the “Tab” button on your keyboard when at the beginning of the line. These indents let Python know that the code is part of the function. This first function converts the temperature from Celsius to Fahrenheit:

def tempfarenheit(Temperature):
    Temp = (float(Temperature)*9/5)+32
    return Temp

This function converts pressure in Pascals to Inches of Mercury:

def pressureinches(Pressure):
    Pres = float(Pressure)*0.000295333727
    return Pres

This returns “Timenow” and “Timeformat”. Timenow is the time in GMT in a format that is easily readable. Timeformat is the time formatted in the way required by WOW – with a “+” instead of a space and “%3A” instead of a colon (:). This is so that the site doesn’t get confused when processing the date and unintentionally doing something which could affect the site.

def Timeformatting(theTime):
    Timenow = time.strftime('%Y-%m-%d %H:%M:%S',theTime)
    Timeformat = Timenow.replace(':','%3A').replace(' ','+')
    return Timeformat,Timenow

B. Put your user details into the code so it can access them.

These are the details you need to run the code fully. The top line are details for WOW, and the bottom are details for Plot.ly. Find these details and replace the string of zero characters with them.

SiteID = "000000000"; AWSKey = "000000"; softwaretype = "my_software"
API_Key = "000000", Username = MyUsername; Stream_ID = "00000aaaaa"; Stream_ID_2 = "00000aaaaa"

This line of code calls upon some of the details to sign in to Plot.ly.

py.sign_in(Username,API_Key)

C. Create a function for the Plot.ly graph.

Now we need to format the Plot.ly graph. This code will create a function to do this – again, the indents are important and can be created by pressing the “Tab” button on your keyboard when at the beginning of the line.

def Plotter():
    trace1 = Scatter(
    x = [],
    y = [],
    name = 'Temperature Readings *C',
    stream = Stream(token = Stream_ID,
        maxpoints = 80)
    )
    trace2 = Scatter(
    x = [],
    y = [],
    name = 'Pressure Readings Pa',
    yaxis = 'y2',
    stream = Stream(token = Stream_ID_2,
        maxpoints = 80)
    )
    my_data = Data([trace1, trace2])
    my_layout = Layout(
        title = 'Temperature Readings from SheffieldPiStation',
        xaxis = {'title':'Date and Time, GMT'},
        yaxis = YAxis(title='Temperature, *C',
                    range = [23,25]
        ),
        yaxis2=YAxis(
            title = 'Pressure, Pa',
            range = [100500,100600],
            titlefont={'color':'rgb(148,103,189'},
            tickfont=Font(
                color='rgb(148,103,189)'
            ),
            side = 'right',
            overlaying = 'y'
        )
    )
    my_fig = Figure(data = my_data,layout = my_layout)
    unique_url = py.plot(my_fig,filename='Weather Data', fileopt='extend')
    s = py.Stream(Stream_ID)
    q = py.Stream(Stream_ID_2)
    return s,q

If you want Plot.ly to not automatically open the graph once it starts transmitting data, just add the line “ auto_open=False,” after “fileopt='extend'” towards the end of the code above. This will mean that you have to go to Plot.ly yourself to see your graph.

D. Set prompts so the user can define frequency and number of loops.

Usually the program needs to run for a set amount of times at different frequencies depending on the user and the required purpose. This next piece of code prompts the user to tell the program how many times to run and, if the amount is not one, then asks the user what frequency to run at.

n = raw_input("No of readings (n for infinite): ")
if float(n)>1 or n == "n":
    frequency = input('Frequency (s): ')

E. Open the Plot.ly graphs and write the data to them.

The first line calls the function Plotter, which formats the graphs. The next two lines of code open the two streams.

s,q = Plotter()
s.open()
q.open()

F. Set X to zero

X will be used later on to break the program’s loop after a certain amount of repetitions.

X = 0

4. Now create the “while” loop

A. The while loop format

A while loop will repeat until certain conditions occur. In the code written here, “while True” means repeat until the loops becomes false – this will not occur, and so the code will repeat until we either manually stop it or we create a point at which the code will stop itself (called a “break). The indents here are very important – everything that follows here, unless otherwise stated, needs to be indented underneath the “while True:” statement and above the “try:” statement.

while True:
    [[YOUR CODE HERE]]
    try:
        time.sleep(frequency)
    except:
        print "Process was terminated"
        break

B. Collect the data.

These lines of code collect the data from the sensor and print it out on your screen so that you can see the data(and also that there isn’t a problem with the sensor).

temperature = format(sensor.read_temperature())
pressure = format(sensor.read_pressure())
[Timeformat,Timenow] = Timeformatting(time.gmtime())
print temperature, pressure, Timenow

C. Convert your temperature and pressure data to the units WOW asks for

Temp = tempfarenheit(temp)
Pres = presinches(pressure)

D. Write the data to a file.

This opens the data file which will be stored on your system, and writes the data to it.

f = open("datafile.txt",'a')
f.write('%s %7s *C %14s Pa' % (Timenow, temperature, pressure))
f.close

E. Upload data to WOW.

This (extremely long, I’m afraid) website URL sends the data to WOW. Every time “%s” is written it is calling one of the values in the brackets at the end – the first “%s” is replaced by the Site ID, the second with AWSKey, and so on. This means you don’t have to manually write in the data values every time you want to send data. Note: This following code should be on a single line.

url = 'http://wow.metoffice.gov.uk/automaticreading?siteid=%s&siteAuthenticationKey=%s&dateutc=%s&tempf=%s&baromin=%.2f&softwaretype=%s' % (SiteID,AWSKey,Timeformat,Temp,Pres,softwaretype)

At this point you can write the code to send the URL (known as a “request”) to WOW. WOW takes the data out of the URL and uploads it to your site. If this process goes ok it will return “200”. Anything else means that there has been an uploading error – this is the basis of the “if” question in the code below.

request = urllib2.Request(url)
response = urllib2.urlopen(request).getcode()
if float(response) == 200:
    print "Data upload OK"
else:
    print "Data upload error"

F. Upload data to Plot.ly.

Now the code needs to access Plot.ly to upload your data there. The following lines of code will write that in for you.

s.write(dict(x=Timenow,y=temperature))
q.write(dict(x=Timenow,y=pressure))

G. Check to see if program should stop

Finally, before the “try” statement code, we’re going to make the loop check if it has reached the number of loops that you want it to run. This is done using an “if” loop which checks the “X” value that we set to zero at the beginning against the value of “n” which was the number of loops specified by the user. If it is lower than n, we add one to X and let it loop again. If it is equal to or higher then we break the loop and finish the program. The first line of code checks if you want it to run indefinitely – if so then the rest of the code will not run.

if n != "n":
    X += 1
    if X >= float(n):
            s.close()
            q.close()
            break

5. Check your code

Your code should now look like the code at the bottom of the page.

6. Save your code

Make sure you save it with the ending “.py”, or it will not run (for example, “FILENAME.py” instead of “FILENAME”. Remember the folder that it is in (called the “path”).

7. Run your code!

Now you need to go back to LXTerminal to run the script. First navigate to where your code is saved using this command, substituting the “FOLDER” with the folder that your code is in.

cd /home/pi/FOLDER

Now run your program, replacing “FILENAME.py” with the name of your code:

sudo python FILENAME.py

This is what your code should look like:

import time
import Adafruit_BMP.BMP085 as BMP085

import plotly.plotly as py
import plotly.tools as tls
from plotly.graph_objs import *

import urllib
import urllib2

sensor = BMP085.BMP085()

def tempfarenheit(Temperature):
    Temp = (float(Temperature)*9/5)+32
    return Temp

def pressureinches(Pressure):
    Pres = float(Pressure)*0.000295333727
    return Pres

def Timeformatting(theTime):
    Timenow = time.strftime('%Y-%m-%d %H:%M:%S',theTime)
    Timeformat = Timenow.replace(':','%3A').replace(' ','+')
    return Timeformat,Timenow

SiteID = "878216001"; AWSKey = "654789"; softwaretype = "my_software";
API_Key = "s4o7a7yvuy"; Username = "SheffieldPiStation"; Stream_ID = "o8pp3tvslu"; Stream_ID_2 = "w903s8st2m"
py.sign_in(Username,API_Key)

def Plotter():
    trace1 = Scatter(
    x = [],
    y = [],
    name = 'Temperature Readings *C',
    stream = Stream(token = Stream_ID,
        maxpoints = 80)
    )
    trace2 = Scatter(
    x = [],
    y = [],
    name = 'Pressure Readings Pa',
    yaxis = 'y2',
    stream = Stream(token = Stream_ID_2,
        maxpoints = 80)
    )
    my_data = Data([trace1, trace2])
    my_layout = Layout(
        title = 'Temperature Readings from SheffieldPiStation',
        xaxis = {'title':'Date and Time, GMT'},
        yaxis = YAxis(title='Temperature, *C',
                    range = [23,25]
        ),
        yaxis2=YAxis(
            title = 'Pressure, Pa',
            range = [100500,100600],
            titlefont={'color':'rgb(148,103,189'},
            tickfont=Font(
                color='rgb(148,103,189)'
            ),
            side = 'right',
            overlaying = 'y'
        )
    )
    my_fig = Figure(data = my_data,layout = my_layout)
    unique_url = py.plot(my_fig,filename='Weather Data', fileopt='extend')
    s = py.Stream(Stream_ID)
    q = py.Stream(Stream_ID_2)
    return s,q

n = raw_input("No of readings (n for infinite): ")
if float(n)>1 or n == "n":
    frequency = input('Frequency: ')

s,q = Plotter()
s.open()
q.open()

X=0

while True:
    temperature = format(sensor.read_temperature())
    pressure = format(sensor.read_pressure())
    [Timeformat,Timenow] = Timeformatting(time.gmtime())
    print temperature, pressure, Timenow

    Temp = tempfarenheit(temperature)
    Pres = pressureinches(pressure)

    f = open("datafile.txt",'a')
    f.write('%s %7s *C %14s Pa' % (Timenow, temperature, pressure))
    f.close

    url = 'http://wow.metoffice.gov.uk/automaticreading?siteid=%s&siteAuthenticationKey=%s&dateutc=%s&tempf=%s&baromin=%.2f&softwaretype=%s' % (SiteID,AWSKey,Timeformat,Temp,Pres,softwaretype)
    request = urllib2.Request(url)
    response = urllib2.urlopen(request).getcode()

    if float(response) == 200:
        print "Data upload OK"
    else:
        print "Data upload error"

    s.write(dict(x = Timenow,y = temperature))
    q.write(dict(x = Timenow,y = pressure))

    if n != "n":
        X += 1
        if X >= float(n):
                s.close()
                q.close()
                break
    try:
        time.sleep(frequency)
    except:
        print "Process was terminated"
        break


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s