Sunday, June 30, 2013

Taking LEDs to the next level: web controlled GPIO ports

***UPDATE: github repository of code: https://github.com/bugbiteme/ledctrl.blog

In my last post I covered the basics on how to get an LED to turn on with a very simple Python script.  From there I created an application that turns on an LED if an IP address is detected on the network.

What I really want to do is be able to create a web based interface that can be used to control the GPIO outputs over the network. Being that my knowledge of Python is limited, I decided to take a break from the pi and hone some Python skills via the excellent (and FREE!) course over at learnpythonthehardway.org. And now I am back!

The Author of Learn Python the Hard Way assumes you are a complete n00b, and walks you all the way up to the grand finally project of creating a web based Python application. Perfect! Just what I needed!

I started at chapter one and went all the way to the end. After learning just enough to be dangerous, I put together a little web based app that displays a button for the green LED, a button for blue LED and a button for the red LED. Once a user clicks one of the three buttons, the corresponding LED lights up on the bread board and its status along with the other two lights after each click. A user can open the application on their mobile device (iPhone in my case) and control the LEDs via the web browser.

Here is an example of how it works:

Using by mobile phone, point to running app's url (all lights off here):


Click the green button and the green LED is turned on, and the web application is updated to show that it is on:



Click the red button and the red LED is turned on, and the web application updates to show that it and the green LED are now on, and so on and so forth...


The code for making LEDs turn on and off is simple enough, but getting the web framework working was the main hurdle for me, along with getting the code to generate dynamic web content on the fly.

The framework I used was web.py. This  framework was chosen due to the fact that it was used in the tutorials mentioned above, and plus, if it was good enough for Aaron Swartz, it's good enough for me. As I get more experience I may play with other frameworks such as django, but web.py seems tiny and simple enough for the pi.

Following the setup process here for installing the needed packages and setting up the directory structure, then working my way up to the chapter on getting user data from a web form (yes, I read every chapter and did every exercise in each one). I was able to get this thing going.

After many trials and errors, I was able to create a web application called ledctrl which does just what I want it to do.

The main code for my apps is located in the ledctrl/bin directory. The file is called app.py, which does all of the work. I decided to start using more of an object oriented approach in my Python coding, since that is what I'm used to doing in other languages. After the code snipped, I'll explain what I was thinking when I wrote it:


First of all, let's look at the class I created called LightSwitch

  • LightSwitch is a class I defined which initializes the GPIO and the current LED color being passed to it in the __init__() function, since these don't need to be global operations.


  •  flip_switch() is a method in LightSwitch which flips the current LED opposite of what it is already set to. This is done by checking the current status:
    • led_status = GPIO.input(self.LED)
      • if light-status is GPIO.LOW, then the LED is off already, so flip it to on, otherwise flip it off. Simple.
  • get_light_statuses() is a method in LightSwitch which returns the current statuses of all three LEDs as a dictionary data structure. The values in this dictionary are needed for generating the correct buttons in the dynamically generated HTML.


All of these class methods are executed from the Index class, which instantiates a LightSwitch object.

Any time the Index class renders the HTML form in either GET or POST, it passes the dictionary of LED statuses to the HTML template.

I also put in a global DEBUG flag, to print stuff out while I'm testing my code. Very helpful, and you can leave all your print statements in the code and set the DEBUG flag to "False" when you are ready to "go-live" ;)

The HTML form which passes information back and forth between my main python code looks like this (sorry for the formatting due to the long lines of HTML code):



The HTML form gets the dictionary of light_statuses. If the dictionary is valid, it looks at each LED color in the dictionary, and if the status for the LED is off (0) or on (1) display the corresponding HTML code for that color. Maybe there is a better way to generate this code (I'm sure there is), but this is what I got to work!

And here it is in action:

5 comments:

  1. Hi,

    Sorry if this is a potentially novice question, but I tried to run the files you provided in this post and for some reason I wasn't able to get it running. When I tried to access the page once I ran the files,the web page says "not found" and the output log says

    192.168.1.9:51162 - - [02/Jul/2013 18:50:57] "HTTP/1.1 GET /" - 404 Not Found
    192.168.1.9:51162 - - [02/Jul/2013 18:50:57] "HTTP/1.1 GET /favicon.ico" - 404 Not Found

    I messed around with the 'urls' variable in app.py and got some things to display, but never could get it to work fully. Any ideas why this is happening for me? Very cool demo, regardless.

    Thank you.

    ReplyDelete
  2. No problem. Novice myself, which is probably why my code sucks and you are getting that error.

    Try pointing your browser to http://ip_address:1234/hello

    My guess is that you pointed to http://ip_address:1234

    without the "/hello"

    ip_address is the ip address of your pi, of course!

    ReplyDelete
    Replies
    1. updated README file on github

      Delete
    2. Whoops. Can't believe I didn't think of that. Works perfectly. Thank you!

      Delete
  3. Hi,
    Thank you for work, but correct " <input type =" image "... "? the answer is no value = "green" (for example) is: 'led.x': u'225', 'led.y': u'51'.

    Thanks

    ReplyDelete