The Button – AJAX and Raspberry Pi

Background

Rev.io (formerly Overgroup), the company I work for, provides Billing and Back-Office software for subscription-based companies – mainly telecom. We were at a point where we were ready for rapid growth. With that comes focus on marketing and sales. Because of this, a sales goal of 20 contracts was set over a period of six months.

To give this goal a physical and visual form I decided to build a “button” that can be pressed every time a contract was signed. A screen of some sort would display the number of contracts we have left and when the button is pressed the number would need to be decremented to show the how many we have left towards the goal. I wanted to have some flashing lights and maybe even sound effects of some sort, cheers and/or some kind of horn.

Goal

Display, in some manor, the number of contracts we have left to sign in order to reach our goal. Create a device that is comprised of at least one button, preferably a large one, that, when pressed, updates the displayed number of contracts left to sign.

Materials

Implementation

The Hardware

Button Circuit DiagramI didn’t really want to mess with a lot of soldering on this project as it won’t really be a permanent device. So I setup the circuit on a small breadboard from Sparkfun. A simple pull up design is used so that Pin 11 is constantly at 3.3 volts until the button is pressed, at which point it drops to ~0 volts.

The only soldering I had to do was on the button itself. The button had large terminal tabs and I needed to connect those to the breadboard somehow, so I soldered four wires to the appropriate terminals: the positive and negative terminals for the LED, located on either side of the LED stem; the common terminal, located on the bottom; and the NO terminal (Normally Open), located in the middle of the 3 silver terminals.

I also had to replace the inline resistor that’s tucked into the LED holder. The resistor built into the button, out of the box, was 600 Ohms. That’s because the button was geared for a 12 volt system, but the highest voltage you get out of the RPi, out of the GPIO and without modification, is 5 volts. LEDs, in general, like to run at a max of 20 mA. You can run them higher, but the life of the LED is dramatically reduced.

I used Ohms law to calculate the optimum resistance to get 20 mA out of a 5 volt system:

I=\frac{V}{R}

or

R=\frac{V}{I}=\frac{5\:V}{0.02\:A}=250\:Ohms

The resistor kit I got from RadioShack didn’t have a 250 Ohm resistor. The closest to that without going below 250 was a 270 Ohm resistor. That’s close enough not to matter, it will still be bright enough. Too much higher than that and the LED would be really dim or not light at all.

This slideshow requires JavaScript.

I used a fancy cardboard box from Ikea for the enclosure. I cut a hole for the button in the lid and a small hole at the bottom of one side of the lower, larger part of the box for the power cord. The mini breadboard comes with adhesive on the bottom so I just stuck it to one side in the box and setup the circuit as pictured in the diagram.

The Display

From the beginning I pictured the display being a web page. It’s what I know best, being that the software I work on for a living is web based. As a web page, it will also facilitate viewing from multiple displays as well. But ideally, the display needs to be updated in real time as the button is pressed, or as near enough to real time as to not notice any delay.

Right away I decided to use AJAX to monitor the count, polling the server on a regular basis for a change in value. To make this near enough to real time the poll would need to happen every second, at most. That’s easy enough to do, so now I just have to decide on what web server to use and what active server page language will relay the counter information.

Since I’m using a Raspberry Pi, I need to keep things as lightweight as possible due to its limited resources. It is certainly powerful enough to host a low-traffic web server, though. The many examples of programmatically interacting with the GPIO I’ve read all use Python. I know Python has several web server frameworks, many of which are “light weight”. So Python is what I’ll use.

To store the current count on disk I’ll use sqlite3. Its a lightweight SQL database engine and the latest version of Python comes with libraries to interact with it out of the box.

Install using apt-get:

$ sudo apt-get install sqlite3

Here are the third party libraries I’ll use for the software side of things:

  • RPi.GPIO – This may be installed on the Pi by default. Its an API exposing the 26 pins available for programming signals over (raising and lowering voltage).
    • $ sudo easy_install RPi.GPIO
  • sqlite3 – I didn’t have to install this one, it came with the current version of Python.
  • web – this is a lightweight web framework.
    • $ sudo easy_install web.py

The web.py framework is picky about the directory structure you use and where files are stored. All your python files and data files go in the root directory. The root directory has two sub directories: “static” and “templates” – they must be named exactly like that. All your images, CSS, and .js files go in the static directory. All your HTML files go in the templates folder. The reason it’s called “templates” is that before serving the HTML the server will first inject data passed in by your program. This reminds me of PHP and VB.ASP where you place special tags throughout the HTML that are replaced with data before serving.

Here’s a more visual representation of the directory structure:

~/myWebServer/
~/myWebServer/static/
~/myWebServer/templates/

Or if you want to download my source code you can do so here and follow along with the real files.

Before coding I need to setup the database that will be used to store the count long term. The database file will go in the root directory of the server so I start in that directory and run:

15Now I need “static” file resources. My coworker Sunita, who is an excellent graphic artist among other talents, put together 21 images representing each number in the count down, 0 to 20, with a circular progress bar around it. One of these images will be displayed on the web page depending on what number in the count we’re at. So these need to be placed in the “static” folder.

I’m also going to use jQuery for client-side scripting so I downloaded the latest version of that and placed it in the “static” folder too. Then I created a CSS file and put it in the “static” folder as well.

Next, the HTML file. I only need one, it’s a simple website. This goes in the “templates” directory:

Here’s the HTML that goes in this file:

The concept is simple, I have an img tag centered in the middle of the page that I’ll use jQuery to swap out the file source with the corresponding image.

I’m using AJAX to ping the server every second and swap the image without causing a “post back”, which would cause the page to blink or jump.

Now I need a web server to present this to the network. To keep it simple I’m going to do this in one Python file.

~/myWebServer/$ nano webserver.py

You can see the code here.

I have four classes:

  • Repository – This handles reading and writing to the database.
  • Button – This produces a thread that monitors a single pin on the GPIO of the Raspberry Pi. You pass it the pin number when instantiated. The “Pressed” accessor will read True if the pin’s voltage drops to ~0 Volts.
  • ButtonMonitor – This produces a thread that handles a Button Press event. When the event happens the current count is decremented by one and the database is updated with the new value.
  • salesstatus – This handles HTTP requests for salesstatus.html. This class has to be named exactly the same as the HTML file you use. If you have more than one file, you’d have more than one class.

To get the HTTP server part of this working there are some key things you must setup:

urls = ('/', 'salesstatus')

To be honest, I got the above line of code from an example, so I don’t fully understand what it’s doing here. What I gather from using this library, though, is that I’m telling it that it’s root directory is the same directory the python app runs in, and the name of the template handler classes we’re using.

render = web.template.render('templates/')

Then I instantiate a “rendering engine” and tell it where to find the folder that contains “renderable” content (.html files). This makes me think you could, in fact, name the “templates” folder something else as long as you tell it what it’s called here, but I didn’t test that theory.

app = web.application(urls, globals())

Then I instantiate the web server application object itself, passing in the instructions I setup on the first line.

The HTTP request handler class, “salesstatus”, needs two specific functions: Post and Get. You define in each of these what to do on with the corresponding HTTP request method. They should return a string and whatever is returned in that string is what is sent to the client to be rendered in a browser – so the final HTML to be displayed.

The initial request to load a page is a GET, so the Get function will be called first. This is where I render the template HTML file. If you wanted to pass in data to the rendering engine, you’d do that then and that data could be plugged into the HTML before it’s sent to the client. At one point I was using that feature to set the source for the image tag when it first loads. I left the code to do that in there so you can see where it’s passing in a string that represents the relative URL for the image to start with.

My AJAX call is using the POST method so when it makes it’s call the Post function will fire. This time I’m not rendering the whole page, just giving it some information so I only return the relative URL string that maps to the image I want to display next. The JavaScript takes it from there and swaps out the source attribute in the image tag.

To setup the GPIO interface I have to set the pin mode – there’s two different numbering schemes for some reason – and instantiate my button and monitor.

Then setup the “main” function that drives the program when started. In Python the main function is defined with if __name__ == '__main__':. All I do here is call the Run function from the web server application object to spin up it’s main thread.

Now I just make the .py file executable and run it. I can use a web browser to address the RPi’s IP on port 8080 and vuala:TheButtonAJAX_WebPage

Scaling

Unfortunately, right away, I notice an issue that will likely derail the scalability. By that I mean the ability to have more than one browser connect to the server. Because each browser will be pinging the server every second, using that AJAX call, every browser connecting will add significant load to the very limited resources of the Pi. I need to rethink how I’m implementing the communication between browser and server to make it more efficient.

Answer: Websockets

I’ll rebuild the server and web page using HTML5, CSS3, and the new WebSocket standard. You can see how this was done here.

Leave a Reply

Your email address will not be published. Required fields are marked *