Skip to main content

A web of Pies

Have you given this a proper thought?  How will your Grandma - Nancy - move Rosie around the house to transport her dentures.  Just like we've been doing, of course, using a computer with a SSH client, logging onto Linux (Raspbian OS) remotely, and running Python commands from the Linux shell.  Easy-peasy.  Why would you even ask that?

'What?!' you hear her shout.  'I'll never do that,' she adds.  'Me and my friends play online bingo using Firefox on our nursing home computers.  I use Skype on my Android tablet to talk to grandchildren that I never knew I had.  Didn't you know?  It's all about HTTP and web-based services these days?  I want to be able to get my dentures, anywhere, anytime, from any device... with a few taps of the screen.  I demand Rosie-as-a-Service!'

Deep down, you know she's right.  Nancy, your irritating littler brother, your friends - they are never going to be able to play with Rosie if she stays like this.  Besides, we don't want any of those people actually logging into Rosie's brain, and breaking things.  They type 'rm', instead of 'python' (as you told them to, literally, millions of times), and suddenly your masterpiece is gone, forever.

The solution?  Let's convert our program into a little web application, and instead of using arrow keys on the keyboard, allow Rosie's movements to be controlled remotely using the magic of HTTP.  All using an appallingly bad easy to use web page showing only the buttons Grandma actually needs.

Denture-Express 2000, here we come!

You will need to have these:

  • Raspberry Pi 3 (kitted out with wheels and sensors), and Raspbian running on SDHC card
  • Computer from which you are connecting to the Raspberry Pi remotely
  • Other devices on your home network from which you would like to control Rosie. They need to have a browser installed, like Chrome, Safari, Firefox, Internet Explorer, Edge, etc, etc.

You will need to have done these things:

  1. I’ve got Pi(3) brain
  2. Why-Fi-ght the Wi-Fi?
  3. Hurrah-ndom inventions
  4. Don't reinvent the eel
  5. Achoo! Crash-choo! Episode I
  6. Achoo! Crash-choo! Episode II

You will need to do this:

  • Install Flask using Pip 
  • Modify code to use Flask and handle HTTP
  • Create a HTML template and a CSS stylesheet
  • Start application and control Rosie using your favourite device

What do you get after all this?

Let's get this concern out of the way first: we're not making Rosie available on the Internet. That would be pretty unwise, you know, with all 'em hackers around the world, waiting to hack your Internet-connected vacuum cleaner, intelli-fridge and electronic toothbrush that brushes your teeth while you're sleeping. We will be turning the code we've written into a little web application, but it will only be reachable on your home network. On the other hand, it does mean that your family and friends (when visiting) will be able to control Rosie if they know her web address. Well, that was the whole point of this exercise wasn't it?

Here are the various technologies at play.  Hypertext Transfer Protocol (HTTP) is a Protocol used pretty much everywhere on the Internet. It's the reason why when you enter http or https in a web browser, followed by an address of a web site, things are helpfully returned to your screen.  Essentially, HTTP allows the user (also called client) and application (also called server) to communicate in an agreed language (protocol), using known rules, and pass information back and forth. All, over a network.  That's right; you can thank HTTP for your daily dose of cat falling off bicycle videos, and for allowing you to Google pretty much anything that you don't know, and then afterwards, pretend that you do. This client-to-server model, using HTTP, is used extensively for machine to machine communication as well, in the form of Application Programming Interfaces (APIs).  It's something that will definitely be useful, when we eventually want Rosie-01 to talk to Rosie-02.

But hold your horses. Let's get you talking to Rosie first, using HTTP. And implement the web page that Grandma Nancy wants to use to get Rosie to deliver her trusted prosthetic teeth.

But here's another fact.  You could spend all year coding a website from scratch. Writing hundreds of pages in Hypertext Markup Language (HTML), a language used to build the structure of web pages (what you see on screen), or Cascading Style Sheets (CSS), which is a different language used to make those pages look pretty.  Or, even, writing actual application code itself that - probably - a million others would need to be writing as well.  After all, everyone wants to do something with the web.  And chances are, someone has already helpfully come up with all the building blocks that you need.

That's why most people use Frameworks. Because with frameworks, someone else has already thought about all the basic components that you need to build a web application, and agreed on a standard, documented it, and made it available for everyone else to use and improve. Frameworks allow you to concentrate on the bits of your application that matters the most, functionality, and allows you to (mostly) forget about the boring bits that everyone needs.

If sticking with Python, Flask and Django are two of the more popular web Frameworks. Flask is very simple, lightweight, and a doddle to get working. Django is arguably more difficult to learn, and is a little more complex, large, but more powerful.  We think for what we want to be able to do here (a single web page with control buttons), Flask is good enough.

And oh yes, the result won't look super pretty; like a web page that has been written by a colour-blind monkey who has had one too many piña coladas. But who cares if it means that Grandma will be able to get her dentures, using her iPhone, from the comfort of her own sofa.  And by using HTML and CSS, it can be tweaked/prettified/improved/fixed easily, to your heart's content.

This is simply too much detail:

So Flask, you say. Do we have that already? Probably not... so we'll have to check. What do we need to have to check to see if we have Flask? We need Pip. Aargh. Can we just get on with it please?

Pip is a Python package manager, which - in simple terms - allows you to install and manage Python software.  If you want to make use of a lot of great things that cleverer people have done with Python (like a web framework), and you intend to download and use them in your projects, it's best to let Pip manage those packages for you.  Some packages are dependent on other packages, and even in some cases, certain versions of those packages.  Keeping track of all of this simply shouldn't be a human task.

Pip was already on our version of Linux (Raspbian OS).  Check that it exists, by running:

pip --version
...checks version of Pip installed

One down, another to go.  Let's now check to see if we have the Flask package, again, using Pip.
pip list
...lists all installed Python packages

No Flask?  Plenty of other things there though.  Well, let's install it.  If you already had it, it would have appeared in the list like this:

Before we proceed, it's worth remembering (for the future) that on computers where we have many Python projects on the go, we are likely to want to have different versions of the same Python packages installed.  We might even need to maintain different versions of Python itself.  There are packages that allow you to do just that - such as virtenv or virtualenvwrapper.  For now, we are going to proceed without them as we're feeling... not very ambitious.

We're going to build a very primitive web application.  It won't have any form of authentication, and therefore anyone who can reach her on your local network will be able to control Rosie, remotely, using the buttons.

Let's install Flask.

pip install Flask
...downloads and installs the Flask package.  Make sure your Pi has an Internet connection beforehand!

Once complete, run 'pip list' again to make sure you have successfully installed Flask.  There?  Good.  We're ready to go.  Let's create a new directory in which to store our web application, and create a Python file in it, aptly named ''.  Because it'll be a web application, get it?

cd /home/pi/rosie
mkdir rosie-web
cd rosie-web

We'll be needing two additional directories in which Flask will look for some files, so let's create them now before we forget.

mkdir templates
mkdir static

'Templates' will contain HTML files that define how our web pages are structured.  'Static' will contain the CSS files that define how those pages look in your browser (like fonts, colours, sizes of buttons, and stuff).

We're ready to now populate '' with our code, and make use of Flask.  Here is the simple code that we eventually settled on.

First of all, we stripped out all of the keyboard related code that we had before in ''.  It's no longer needed.  We're going all out web.  In its place, however, are a number of new Flask-related additions.

Like with any other module, before we do anything with it, we need to import Flask, and the functions that we'll be using.

from flask import Flask, render_template, request, url_for, redirect

We then create an instance of our Flask application.  This is the Python code to do just that.

app = Flask(__name__)

We've decided to have two Flask-related functions that handle requests from the HTTP client (in our example, Nancy's browser).  We know they are Flask functions, as we have a decorator at the start - @app.route().  This effectively tells the code that if any HTTP requests arrive at that web address, trigger the function that follows.

First of the two functions is for root (/).  If users land at the root (/) of our site (for example http://rosie-01:5000/), they will simply be shown an 'index' page (index.html).  This index page will just contain the buttons needed to move Rosie.  You know, the kind of buttons that you need to press on a train company website when you want to submit a complaint about your train being late (again).

def index():
    return render_template("index.html")

The second of our Flask functions will be used to define what happens when the buttons are pressed in index.html.  The browser will submit a value using what's known as a 'POST' request.  This value will be the direction in which Rosie is expected to move.  When we receive that value (at /control address, for example http://rosie-01:5000/control), we read it, then step through the same Python code that we used when reacting to keyboard arrow keys.  The final action in this function (return redirect(url_for())) is to simply redirect the user's browser back to the index.html page.  This isn't the most elegant of solutions, as the web page is refreshing every time you are sending a command... but it's crude and simple.

@app.route("/control", methods = ["POST"])
def control_rosie():
    control = request.form.get('control')
    if control == "Forward":
        #...code to move motors
        #...repeat for other directions
    return redirect(url_for("index")) 

Lastly, in the main section of the program, we will start the Flask web application. = "")

This starts a built-in 'development' web server (included with Flask), which then allows users to access the application over the network, see our wonderful index.html page, and start submitting HTTP requests.  Remember that this is a development server.  If you want to sell Denture-Express 2000 on Amazon, or make it available to millions of people over the Internet, you will want to run the same Flask code, but on a more 'production-ready' web server, like Apache HTTPD, or nginx.  Great.  More strange words to Google!

Now, there are two non-Python things left for us to complete.  We need to create the 'index.html' file, so that we have a page that can be displayed in the browser.  This file is expected in the 'templates' directory created earlier.

cd templates
touch index.html

The HTML code we've used is shown below.  In short, we have a form, which contains a number of buttons arranged in a table.  Each button corresponds to a direction for Rosie.  When the button is pressed, its value is submitted to the '/control' address, and is therefore handled by @app.route("/control", methods = ["POST"]) we defined for Flask earlier.  This, of course, means that Rosie moves, just like it did when we were pressing keyboard keys.

        <link rel="stylesheet" href="/static/style.css" />
        <h1>Welcome to Rosie's controls</h1>
        <form action="/control" method="post">
            <table border=0>
                    <td><button class="button-control" type="submit" name="control" value="Forward">&uarr;Forward</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Left">&larr;Left</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Stop">Stop</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Right">Right&rarr;</button></td>
                    <td><button class="button-control" type="submit" name="control" value="Reverse">&darr;Reverse</button></td>

HTML is used with all web technologies, Python or not, so its strange way of describing a web page's structure and content is well worth learning.  

Finally, create a CSS file called 'style.css' in the 'static' folder.  This file was referenced in the <head> tag of the index.html file.  Cascading Style Sheets (CSS) allow HTML files to be visually presented in the way that you want.  This is where you can be creative, and spend many hours applying different colours, fonts, effects, etc to your web page.

cd ../static/
touch style.css

For now, we are going to apply a splash of colour to the background of the page, and change the colour of the font.  We will also make the buttons square, large and colourful (remember, this is for Grandma?)

body {
 background: #ff4141;
 color: #532619;

.button-control {
 height: 100px;
 width: 100px;
 background: #eec6c6;
 color: #532619;
 border-radius: 5px;

.button-control:active {
 color: #eec6c6;
 background: #532619;

Finally, the moment of truth.  Let's start our application.

cd /home/pi/rosie/rosie-web

Now, from a browser on another device on your home network, navigate to address 'http://rosie-01:5000'.  You should be presented with your HTML page, styled using your CSS.  And when you press the buttons, your POST HTTP requests will be fired at your Flask functions, which will (hopefully) move Rosie around as expected.

It's extremely primitive, and it's totally not fit for purpose.  After all, where is the login page?  Why can't we see some of Rosie's messages on the page?  What happens if we lose connection to Rosie, even momentarily?  Of course, there's plenty of ways in which it can be improved. But, all things considered, we have achieved quite a lot with the help of Flask.  Rosie is web-enabled, and this will keep Grandma Nancy happy (for a little while).

Even more reading:

Official Flask documentation can be found here:


  1. Another fun Posie adventure (Rosie Mind Meld) - thanks. There is so much to investigate, and so many ways to do things, that learning from other robots is the only way my bot "grows up".

    For some reason, I had to browse to the stylesheet to get it to update after changes, but I got it all to work well, and pretty, in the end.

    Posie nearly went berserk once, bogged down with repeated alerts and web commands. (I have several other threads going, including another thread reading the ultrasonic sensor. )

    I added time limits to the control commands since Posie can only "see" forward, and the bump direction sensors are not integrated into my simulated rrb3 motors API.

    Thank you. Thank You! THANK YOU.


Post a Comment


LoRa-Wan Kenobi

In the regurgitated words of Michael Bublé: It's a new dawn .  It's a new day .  It's a new Star Wars film .  For me .  And I'm (George Lucas, and I'm) feeling good .  Unfortunately for Canadian Mike, the Grammy that year was won by the novelty disco classic with the famous refrain: We love IoT, even in Planet Tatooine * . *Not true. Clearly, the Star Wars producers didn't sincerely mean the last Jedi the previous time around.  Return of the Jedi, released during the decade that spearheaded cultural renaissance 2.0 with the mullet and hair-metal , was less economic with the truth.  Either way, we're going to take inspiration from the impressive longevity of the money-spinning space-opera and reboot our franchise with some Jedi mind tricks.  Except this particular flick doesn't require an ever-growing cast of unrecognisable characters, unless ASCII or UTF counts.  In place of an ensemble gathering of Hollywood stars and starlets, we will b

Battle of BLEtain

The trolling . The doxing . An army of perplexing emojis. And endless links to the same - supposedly funny - viral video of a cat confusing a reflection from a dangling key for a golden hamster, while taking part in the mice bucket challenge. Has social media really been this immense force for good? Has it actually contributed significantly to the continued enlightenment of the human (or feline) race? In order to answer these poignant existential questions about the role of prominent platforms such as Critter, StinkedIn and Binterest, employing exceptional scientific rigour equal to that demonstrated by Theranos , we're going to set up a ground-breaking experiment using the Bluetooth Low Energy feature of MicroPython v1.12, and two ESP32 development boards with inexplicable hatred for one another.  And let them hurl quintessentially British expressions (others call them abuse) at each other like two Wiltshire residents who have had their internet access curbed by the co

Hard grapht

You would all be forgiven for assuming that bar , pie and queue line are favourite pastimes of the British .  Yet, in fact – yes, we did learn this back in GCSE maths – they are also mechanisms through which meaningless, mundane data of suspect origin can be given a Gok Wan -grade makeover, with the prime objective of padding out biblical 187-page PowerPoint presentations and 871-page Word reports (*other Microsoft productivity tools are available).  In other words, documents that nobody has the intention of ever reading.  But it becomes apparent over the years; this is perhaps the one skill which serves you well for a lifetime in certain careers.  In sales.  Consultancy.  Politics.  Or any other profession in which the only known entry requirement is the ability to chat loudly over a whizzy graph of dubious quality and value, preferably while frantically waving your arms around. Nevertheless, we are acutely conscious of the fact that we have spent an inordinate amount