Chapter 10. Python and the Internet

Python has a very active community of developers who often share their work in the form of open source libraries that simplify complex tasks. Some of these libraries make it relatively easy for us to connect our projects to the Internet to do things like get data about the weather, send an email or text message, follow trends on Twitter, or act as a web server.

In this chapter, we’re going to take a look at a few ways to create Internet-connected projects with the Raspberry Pi. We’ll start off by showing you how to fetch data from the Internet and then move into how you can create your own Raspberry Pi–based web server.

Download Data from a Web Server

When you type an address into your web browser and hit Enter, your browser is the client. It establishes a connection with the server, which responds with a web page. Of course, a client doesn’t have to be a web browser; it can also be a mail application, a weather widget on your phone or computer, or a game that uploads your high score to a global leaderboard. In the first part of this chapter, we’re going to focus on projects that use the Raspberry Pi to act as a client. The code you’ll be using will connect to Internet servers to get information. Before you can do that, you’ll need to install a popular Python library called Requests that is used for connecting to web servers via  hypertext transfer protocol, or HTTP.

In order to use Requests in Python, you first need to import it. Within Terminal:

$ python
Python 2.7.3rc2 (default, May  6 2012, 20:02:25)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more 
  information.
>>> import requests
>>>

If you don’t get any kind of error message, you’ll know Requests has been imported in this Python session.

Now you can try it out:

>>> r = requests.get('http://www.google.com/')
>>>

You may be a bit disappointed at first because it seems like nothing happened. But actually, all the data from the request has been stored in the object r. Here’s how you can display the status code:

>>> r.status_code
200

The HTTP status code 200 means that the request succeeded. There are a few other HTTP status codes in Table 10-1.

Table 10-1. Common HTTP status codes
Code Meaning

200

OK

301

Moved permanently

307

Moved temporarily

401

Unauthorized

404

Not found

500

Server error

If you want to see the contents of the response (what the server sends back to you), try the following:

>>> r.text

If everything worked correctly, what will follow is a large block of text; you may notice some human-readable bits in there, but most of it will be hard to understand. This is the HTML of Google’s landing page, which is meant to be interpreted and rendered on screen by a web browser.

However, not all HTTP requests are meant to be rendered by a web browser. Sometimes only data is transmitted, with no information about how it should be displayed. Many sites make these data protocols available to the public so that we can use them to fetch data from and send data to their servers without using a web browser. Such a data protocol specification is commonly called an application programming interface, or API. APIs let different pieces of software talk to each other and are popular for sending data from one site to another over the Internet.

For example, let’s say you want to make a project that will sit by your door and remind you to take your umbrella with you when rain is expected that day. Instead of setting up your own weather station and figuring out how to forecast the precipitation, you can get the day’s forecast from one of many weather APIs out there.

Fetching the Weather Forecast

In order to determine whether or not it will rain today, we’ll show you how to use the API from Weather Underground.

To use the API, take the following steps:

  1. In a web browser, go to Weather Underground’s API homepage and enter your information to sign up.

  2. After you’ve logged in to your account, click Key Settings.

  3. Notice that there’s a long string of characters in the API key field (Figure 10-1). This is a unique identifier for your account that you’ll need to provide in each request. If you abuse its servers by sending too many requests, it can simply shut off this API key and refuse to complete any further requests until you pay for a higher tier of service.

  4. Click Documentation and then Forecast so you can see what kind of data you get when you make a forecast request. At the bottom of the page is an example URL for getting the forecast for San Francisco, CA. Notice that in the URL is your API key:

http://api.wunderground.com/api/YourAPIkey/forecast/q/CA/San_Francisco.json
gsrp 1201
Figure 10-1. Matt’s Weather Underground API account, with the API key in the upper right
  1. To make sure it works, go to this URL into your web browser, and you should see the weather forecast data in a format called JSON, or JavaScript Object Notation (see Example 10-1). Notice how the data is structured hierarchically.

Note
Even though the J stands for JavaScript, JSON is used in many programming languages, especially for communicating between applications via an API.
  1. To start off, try to get today’s local text forecast from within this data structure. Change the URL so that it matches your state and town and put it in a new Python script called text-forecast.py (Example 10-2).

  2. As you see from the code, in order to get the text forecast for today, we’ll have to fetch the right field from the hierarchy of the data structure (see Example 10-1). The text forecast can be found in forecasttxt_forecastforecastday0 (the first entry, which is today’s forecast)→fcttext.

  3. When you run the script from the command line, the output should be your local weather forecast for today, such as this: “Clear. High of 47F. Winds from the NE at 5 to 10 mph.”

Note
Keep in mind that not all APIs are created equal and you’ll have to review their documentation to determine if it’s the right one for your project. Also, most APIs limit the number of requests you can make, and some even charge you to use their services. Many times, the API providers have a free tier for a small amount of daily requests, which is perfect for experimentation and personal use.
Example 10-1. Partial JSON response from Weather Underground’s API
"response": {
  "version": "0.1",
  "termsofService":
    "http://www.wunderground.com/weather/api/d/terms.html",
  "features": {
    "forecast": 1
  }
},
"forecast":{ 1
  "txt_forecast": { 2
    "date":"10:00 AM EST",
    "forecastday": [ 3
      {
      "period":0,
      "icon":"partlycloudy",
      "icon_url":"http://icons-ak.wxug.com/i/c/k/
        partlycloudy.gif",
      "title":"Tuesday",
      "fcttext":
        "Partly cloudy. High of 48F. Winds from the NNE at 5 to 
          10 mph.", 4
      "fcttext_metric":
        "Partly cloudy. High of 9C. Winds from the NNE at 10 to 
          15 km/h.",
      "pop":"0"
      },
1

Forecast is the top-level parent of the data we want to access.

2

Within forecast, we want the text forecast.

3

Within the text forecast dataset, we want the daily forecasts.

4

fcttext, the text of the day’s forecast.

Example 10-2. Source code for text-forecast.py
import requests

key = 'YOUR KEY HERE' 1
ApiUrl = 'http://api.wunderground.com/api/' + key + 
  '/forecast/q/NY/New_York.json'

r = requests.get(ApiUrl) 2
forecast = r.json() 3
print forecast['forecast']['txt_forecast']['forecastday'][0]
  ['fcttext'] 4
1

Replace this with your API key.

2

Get the New York City forecast from Weather Underground (replace with your own state and city).

3

Take the text of the JSON response and parse it into a Python dictionary object.

4

“Reach into” the data hierarchy to get today’s forecast text.

So you now have a Python script that will output the text forecast whenever you need it. But how can your Raspberry Pi determine whether or not it’s supposed to rain today? On one hand, you could parse the forecast text to search for words like “rain,” “drizzle,” “thunderstorms,” “showers,” and so on, but there’s actually a better way. One of the fields in the data from Weather Underground API is labeled pop, which stands for probability of precipitation. With values ranging from 0 to 100%, it will give you a sense of how likely rain or snow will be.

For a rain forecast indicator, let’s say that any probability of precipitation value over 30% is a day that we want to have an umbrella handy:

  1. Connect an LED to pin 25, as you did in Figure 6-5.

  2. Create a new file called umbrella-indicator.py and use the code in Example 10-3. Don’t forget to put in your own API key and the location in the Weather Underground API URL.

  3. Run the script as root with the command sudo python umbrella-indicator.py.

Example 10-3. Source code for umbrella-indicator.py
import requests
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)

key = 'YOUR KEY HERE' 1
ApiUrl = 'http://api.wunderground.com/api/' + key + 
  '/forecast/q/NY/New_York.json'

while True:
   r = requests.get(ApiUrl)
   forecast = r.json()
   popValue = forecast['forecast']['txt_forecast']['forecastday']
     [0]['pop'] 2
   popValue = int(popValue) 3

   if popValue >= 30: 4
      GPIO.output(25, GPIO.HIGH)
   else: 5
      GPIO.output(25, GPIO.LOW)

   time.sleep(180) # 3 minutes 6
1

As before, change this to your API key.

2

Get today’s probability of precipitation and store it in popValue.

3

Convert popValue from a string into an integer so that we can evaluate it as a number.

4

If the value is greater than 30, then turn the LED on.

5

Otherwise, turn the LED off.

6

Wait three minutes before checking again so that the script stays within the API limit of 500 requests per day.

Press Ctrl-C to quit the program when you’re done.

The Weather Underground API is one of a plethora of different APIs that you can experiment with. Table 10-2 lists a few other sites and services that have APIs.

Table 10-2. Popular application programming interfaces
Site API Reference URL

Facebook

https://developers.facebook.com

Flickr

http://www.flickr.com/services/api

Foursquare

https://developer.foursquare.com

Reddit

https://www.reddit.com/dev/api

Twilio

http://www.twilio.com

Twitter

https://dev.twitter.com

YouTube

https://developers.google.com/youtube

Serving Pi (Be a Web Server)

Not only can you use the Raspberry Pi to get data from servers via the Internet, but your Pi can also act as a server itself. There are many different web servers that you can install on the Raspberry Pi. Traditional web servers, like Apache or lighttpd, serve the files from your board to clients. Most of the time, servers like these are sending HTML files and images to make web pages, but they can also serve sound, video, executable programs, and much more.

However, there’s a new breed of tools that extend programming languages like Python, Ruby, and JavaScript to create web servers that dynamically generate the HTML when they receive HTTP requests from a web browser. This is a great way to trigger physical events, store data, or check the value of a sensor remotely via a web browser. You can even create your own JSON API for an electronics project!

Flask Basics

We’re going to use a Python web framework called Flask to turn the Raspberry Pi into a dynamic web server. While there’s a lot you can do with Flask “out of the box,” it also supports many different extensions for doing things, such as user authentication, generating forms, and using databases. You also have access to the wide variety of standard Python libraries that are available to you.

Here’s how to install Flask and its dependencies:

$ sudo pip install flask

To test the installation, create a new file called hello-flask.py with the code from Example 10-4. Don’t worry if it looks a bit overwhelming at first; you don’t need to understand what every line of code means right now. The block of code that’s most important is the one that contains the string “Hello World!”

Example 10-4. Source code for hello-flask.py
from flask import Flask
app = Flask(__name__) 1

@app.route("/") 2
def hello():
   return "Hello World!" 3

if __name__ == "__main__": 4
   app.run(host='0.0.0.0', port=80, debug=True) 5
1

Create a Flask object called app.

2

Run the code below when someone accesses the root URL of the server.

3

Send the text “Hello World!” to the client.

4

If this script was run directly from the command line.

5

Have the server listen on port 80 and report any errors.

Note
Before you run the script, you need to know your Raspberry Pi’s IP address (see “The Network”). An alternative is to install avahi-daemon (run sudo apt-get install avahi-daemon from the command line). This lets you access the Pi on your local network through the address http://raspberrypi.local. If you’re accessing the Raspberry Pi web server from a Windows machine, you may need to put Bonjour Services on it for this to work.

Now you’re ready to run the server, which you’ll have to do as root:

$ sudo python hello-flask.py
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 238-627-191

From another computer on the same network as the Raspberry Pi, type your Raspberry Pi’s IP address into a web browser. If your browser displays “Hello World!”, you know you’ve got it configured correctly. You may also notice that a few lines appear in the terminal of the Raspberry Pi:

10.0.1.100 - - [19/Nov/2012 00:31:31] "GET / HTTP/1.1" 200 -
10.0.1.100 - - [19/Nov/2012 00:31:31] "GET /favicon.ico HTTP/
  1.1" 404 -

The first line shows that the web browser requested the root URL and our server returned HTTP status code 200 for “OK.” The second line is a request that many web browsers send automatically to get a small icon called a favicon to display next to the URL in the browser’s address bar. Our server doesn’t have a favicon.ico file, so it returned HTTP status code 404 to indicate that the URL was not found.

If you want to send the browser a site formatted in proper HTML, it doesn’t make a lot of sense to put all the HTML into your Python script. Flask uses a template engine called Jinja2 so that you can use separate HTML files with placeholders for spots where you want dynamic data to be inserted.

If you’ve still got hello-flask.py running, press Ctrl-C to kill it.

To make a template, create a new file called hello-template.py with the code from Example 10-5. In the same directory with hello-template.py, create a subdirectory called templates. In the templates subdirectory, create a file called main.html and insert the code from Example 10-6. Anything in double curly braces within the HTML template is interpreted as a variable that would be passed to it from the Python script via the render_template function.

Example 10-5. Source code for hello-template.py
from flask import Flask, render_template
import datetime
app = Flask(__name__)

@app.route("/")
def hello():
   now = datetime.datetime.now() 1
   timeString = now.strftime("%Y-%m-%d %H:%M") 2
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      } 3
   return render_template('main.html', **templateData) 4

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)
1

Get the current time and store it in now.

2

Create a formatted string using the date and time from the now object.

3

Create a dictionary of variables (a set of keys, such as title, that are associated with values, such as HELLO!) to pass into the template.

4

Return the main.html template to the web browser using the variables in the templateData dictionary.

Example 10-6. Source code for templates/main.html
<!DOCTYPE html>
   <head>
      <title>{{ title }}</title> 1
   </head>

   <body>
      <h1>Hello, World!</h1>
      <h2>The date and time on the server is: {{ time }}</h2> 2
   </body>
</html>
1

Use the title variable in the HTML title of the site.

2

Use the time variable on the page.

Now, when you run hello-template.py (as before, you need to use sudo to run it) and pull up your Raspberry Pi’s address in your web browser, you should see a formatted HTML page with the title “HELLO!” and the Raspberry Pi’s current date and time.

Note
While it’s dependent on how your network is set up, it’s unlikely that this page is accessible from outside your local network via the Internet. If you’d like to make the page available from outside your local network, you’ll need to configure your router for port forwarding. Refer to your router’s documentation for more information about how to do this.

Connecting the Web to the Real World

You can use Flask with other Python libraries to bring additional functionality to your site. For example, with the RPi.GPIO Python module (see Chapter 7), you can create a website that interfaces with the physical world. To try it out, hook up three buttons or switches to pins 23, 24, and 25 in the same way as the Simple Soundboard project in Figure 7-2.

The following code expands the functionality of hello-template.py, so copy it to a new file called hello-gpio.py. Add the RPi.GPIO module and a new route for reading the buttons, as we’ve done in Example 10-7. The new route will take a variable from the requested URL and use that to determine which pin to read.

You’ll also need to create a new template called pin.html (it’s not very different from main.html, so you may want to copy main.html to pin.html and make the appropriate changes, as in Example 10-8):

Example 10-7. Modified source code for hello-pgio.py
from flask import Flask, render_template
import datetime
import RPi.GPIO as GPIO
app = Flask(__name__)

GPIO.setmode(GPIO.BCM)

@app.route("/")
def hello():
   now = datetime.datetime.now()
   timeString = now.strftime("%Y-%m-%d %H:%M")
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      }
   return render_template('main.html', **templateData)

@app.route("/readPin/<pin>") 1
def readPin(pin):
   try: 2
      GPIO.setup(int(pin), GPIO.IN) 3
      if GPIO.input(int(pin)) == True: 4
         response = "Pin number " + pin + " is high!"
      else: 5
         response = "Pin number " + pin + " is low!"
   except: 6
      response = "There was an error reading pin " + pin + "."

   templateData = {
      'title' : 'Status of Pin' + pin,
      'response' : response
      }

   return render_template('pin.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)
1

Add a dynamic route with pin number as a variable.

2

If the code indented below raises an exception, run the code in the except block.

3

Take the pin number from the URL, convert it into an integer, and set it as an input.

4

If the pin is high, set the response text to say that it’s high.

5

Otherwise, set the response text to say that it’s low.

6

If there was an error reading the pin, set the response to indicate that.

Example 10-8. Source code for templates/pin.html
<!DOCTYPE html>
   <head>
      <title>{{ title }}</title> 1
   </head>

   <body>
      <h1>Pin Status</h1>
      <h2>{{ response }}</h2> 2
   </body>
</html>
1

Insert the title provided from hello-gpio.py into the page’s title.

2

Place the response from hello-gpio.py on the page inside HTML heading tags.

With this script running, when you point your web browser to your Raspberry Pi’s IP address, you should see the standard “Hello World!” page we created before. But add /readPin/24 to the end of the URL so that it looks something like http://10.0.1.103/readPin/24. A page should display showing that the pin is being read as low. Now hold down the button connected to pin 24 and refresh the page; it should now show up as high!

Try the other buttons as well by changing the URL. The great part about this code is that we only had to write the function to read the pin once and create the HTML page once, but it’s almost as though there are separate web pages for each of the pins!

Project: WebLamp

In Chapter 6, we showed you how to use Raspberry Pi as a simple AC outlet timer in “Project: Cron Lamp Timer”. Now that you know how to use Python and Flask, you can now control the state of a lamp over the Web. This basic project is simply a starting point for creating Internet-connected devices with the Raspberry Pi.

And just like how the previous Flask example showed how you can have the same code work on multiple pins, you’ll set up this project so that if you want to control more devices in the future, it’s easy to add:

  1. The hardware setup for this project is exactly the same as the “Project: Cron Lamp Timer”, so all the parts you need are listed there.

  2. Connect the PowerSwitch Tail II relay to pin 25, just as you did in the Cron Lamp Timer project.

  3. If you have another PowerSwitch Tail II relay, connect it to pin 24 to control a second AC device. Otherwise, just connect an LED to pin 24. We’re simply using it to demonstrate how multiple devices can be controlled with the same code.

  4. Create a new directory in your home directory called WebLamp.

  5. In WebLamp, create a file called weblamp.py and put in the code from Example 10-9.

  6. Create a new directory within WebLamp called templates.

  7. Inside templates, create the file main.html. The source code of this file can be found in Example 10-10.

In terminal, navigate to the WebLamp directory and start the server (be sure to use Ctrl-C to kill any other Flask server you have running first):

pi@raspberrypi ~/WebLamp $ sudo python weblamp.py

Open your mobile phone’s web browser and enter your Raspberry Pi’s IP address in the address bar, as shown in Figure 10-2.

gsrp 1202
Figure 10-2. The device interface, as viewed through a mobile browser
Example 10-9. Source code for weblamp.py
import RPi.GPIO as GPIO
from flask import Flask, render_template, request
app = Flask(__name__)

GPIO.setmode(GPIO.BCM)

pins = {
   24 : {'name' : 'coffee maker', 'state' : GPIO.LOW},
   25 : {'name' : 'lamp', 'state' : GPIO.LOW}
   } 1

for pin in pins: 2
   GPIO.setup(pin, GPIO.OUT)
   GPIO.output(pin, GPIO.LOW)

@app.route("/")
def main():
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin) 3
   templateData = {
      'pins' : pins 4
      }
   return render_template('main.html', **templateData) 5

@app.route("/<changePin>/<action>") 6
def action(changePin, action):
   changePin = int(changePin) 7
   deviceName = pins[changePin]['name'] 8
   if action == "on": 9
      GPIO.output(changePin, GPIO.HIGH) 10
      message = "Turned " + deviceName + " on." 11
   if action == "off":
      GPIO.output(changePin, GPIO.LOW)
      message = "Turned " + deviceName + " off."
   if action == "toggle":
      GPIO.output(changePin, not GPIO.input(changePin)) 12
      message = "Toggled " + deviceName + "."

   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin) 13

   templateData = {
      'message' : message,
      'pins' : pins
   } 14

   return render_template('main.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)
1

Create a dictionary called pins to store the pin number, name, and pin state.

2

Set each pin as an output and make it low.

3

For each pin, read the pin state and store it in the pins dictionary.

4

Put the pins dictionary into the template data dictionary.

5

Pass the template data into the template main.html and return it to the user.

6

The function below is executed when someone requests a URL with the pin number and action in it.

7

Convert the pin from the URL into an integer.

8

Get the device name for the pin being changed.

9

If the action part of the URL is “on,” execute the code indented below.

10

Set the pin high.

11

Save the status message to be passed into the template.

12

Read the pin and set it to whatever it isn’t (i.e., toggle it).

13

For each pin, read the pin state and store it in the pins dictionary.

14

Along with the pins dictionary, put the message into the template data dictionary.

Example 10-10. Source code for templates/main.html
<!DOCTYPE html>
<head>
   <title>Current Status</title>
</head>

<body>
   <h1>Device Listing and Status</h1>

   {% for pin in pins %} 1
   <p>The {{ pins[pin].name }} 2
   {% if pins[pin].state == true %} 3
      is currently on (<a href="/{{pin}}/off">turn off</a>)
   {% else %} 4
      is currently off (<a href="/{{pin}}/on">turn on</a>)
   {% endif %}
   </p>
   {% endfor %}

   {% if message %} 5
   <h2>{{ message }}</h2>
   {% endif %}

</body>
</html>
1

Run through each pin in the pins dictionary.

2

Print the name of the pin.

3

If the pin is high, print that the device is on and link to URL to turn it off.

4

Otherwise, print that the device is off and link to the URL to turn it on.

5

If a message was passed into the template, print it.

The best part about writing the code in this way is that you can very easily add as many devices that the hardware will support. Simply add the information about the device to the pins dictionary. When you restart the server, the new device will appear in the status list and its control URLs will work automatically.

There’s another great feature built in: if you want to be able to flip the switch on a device with a single tap on your phone, you can create a bookmark to the address http://ipaddress/pin/toggle. That URL will check the pin’s current state and switch it.

Going Further

Requests

The homepage for Requests includes very comprehensive documentation complete with easy-to-understand examples.

Flask

There’s a lot more to Flask that we didn’t cover. The official site outlines Flask’s full feature set.

Flask Extensions

Flask extensions make it easy to add functionality to your site.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset