A simple Python webserver

Now I can control the stepper-motor from Python I need to be able to tell the Raspberry Pi to move the motor from my phone so that, for instance, when I get to work it can tell the motor to move the indicator hand to point to “Work”.

To do this, the easiest way seem to me to be using a web server on the Pi.  I want to make it so that if you GET the URL http://<raspberry.server>:8080/move?a=90 then it will move the hand to 90 degrees. This normally requires a web server and a CGI script but it seemed overkill to install Apache or even something lighter-weight such as lighttpd or nginx for such a simple task so I’ve written my own: much more interesting!

#!/usr/bin/env python

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

import socket
import re

# Standard socket stuff:
host = ''  # do we need socket.gethostname() ?
port = 8080
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
sock.listen(1)  # don't queue up any requests

# Loop forever, listening for requests:
while True:
    csock, caddr = sock.accept()
    print "Connection from: " + `caddr`
    req = csock.recv(1024)  # get the request, 1kB max
    print req
    # Look in the first line of the request for a move command
    # A move command should be e.g. 'http://server/move?a=90'
    match = re.match('GET /move\?a=(\d+)\sHTTP/1', req)
    if match:
        angle = match.group(1)
        print "ANGLE: " + angle + "\n"
        csock.sendall("""HTTP/1.0 200 OK
Content-Type: text/html

<html>
<head>
<title>Success</title>
</head>
<body>
Boo!
</body>
</html>
""")
    else:
        # If there was no recognised command then return a 404 (page not found)
        print "Returning 404"
        csock.sendall("HTTP/1.0 404 Not Found\r\n")
    csock.close()

This is about as simple as a web server gets. It sets up a server socket to listen on using port 8080 and doesn’t queue up any requests (it’s not going to get many…).  When a connection is made from the client (e.g. a web browser) the “sock.accept()” line (19) creates a client socket to communicate with the client on.  We then just read at most 1kB of data from the client, which is the HTTP headers saying what the client wants and using a regular expression (line 25) we see if it is a “move” request and pull out the angle.  If it was a move request then we print the angle to the console and return a simple web page by using “csock.sendall” on line 29.  Otherwise we return a 404 error (line 45).  Finally we close the client socket and loop round to the top again to wait for another connection.

If I run this script (e.g. “python server.py”) and go to the URL “http://<server>:8080/move?a=20″ then I see this on the console of the Pi:

Connection from: ('192.168.1.129', 54340)
GET /move?a=20 HTTP/1.1
Host: raspberry1.scphillips.com:8080
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

ANGLE: 20

Connection from: ('192.168.1.129', 54344)
GET /favicon.ico HTTP/1.1
Host: raspberry1.scphillips.com:8080
Connection: keep-alive
Accept: */*
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Returning 404

So we first get a connection from IP address 192.168.1.129 (my address on my home network) asking for “/move?a=20″ using HTTP version 1.1.  It then says that it wants that “page” from “Host: raspberry1.scphillips.com:8080″.  This is in case my web browser is talking to a proxy – the proxy needs to know where to get the page from (however, in this case there is no proxy).  There are then a load of other headers that describe what the client is and how it would like information sent to it (language, character set, etc).

The web server ignores all but the first line of the headers, spots that it’s a move request and prints out the angle to the console.  Immediately we then get a second request from the web browser asking for the “favicon.ico” – this just happens automatically.  The favicon is the little icon you see in the address bar of most websites.  Web browsers request them a lot. Our little web server just ignores this request and sends a 404 (page not found) so the web browser is happy.

On the web browser we get a page that says “Boo!”.

Next, this needs linking up with the Motor class from the last post.