Click here to read Part 1 of this series >
In this 2nd tutorial of WebIOPi, we’ll use simple Python scripts and HTML/Javascript to create a button to control a light, which will be automatically turned on and off.
Please refer back to WebIOPi IOT Part 1 – Installation & LED Blinking for general information about WebIOPi.
Fortunately, the WebIOPi site already has tutorials and sample source code for making IoT apps.
First, let’s make a button that can turn an LED on and off following the tutorial. Then, we’ll look at Python codes to read analog values.
As previously stated, we’ll be making use of the sample code on the tutorial page as we proceed.
Since you can specify the file location in the WebIOPi configuration file, you should be able to put it anywhere you’d like without any problem. For our purposes, I created a “webiopi_sample” folder under the /home/pi/ directory following the tutorial and specified that as the file location.
I copied the Python and HTML sample code and pasted it into the below files.
/home/pi/webiopi_sample/python/script.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import webiopi import datetime GPIO = webiopi.GPIO LIGHT = 17 # GPIO pin using BCM numbering HOUR_ON = 8 # Turn Light ON at 08:00 HOUR_OFF = 18 # Turn Light OFF at 18:00 # setup function is automatically called at WebIOPi startup def setup(): # set the GPIO used by the light to output GPIO.setFunction(LIGHT, GPIO.OUT) # retrieve current datetime now = datetime.datetime.now() # test if we are between ON time and tun the light ON if ((now.hour >= HOUR_ON) and (now.hour < HOUR_OFF)): GPIO.digitalWrite(LIGHT, GPIO.HIGH) # loop function is repeatedly called by WebIOPi def loop(): # retrieve current datetime now = datetime.datetime.now() # toggle light ON all days at the correct time if ((now.hour == HOUR_ON) and (now.minute == 0) and (now.second == 0)): if (GPIO.digitalRead(LIGHT) == GPIO.LOW): GPIO.digitalWrite(LIGHT, GPIO.HIGH) # toggle light OFF if ((now.hour == HOUR_OFF) and (now.minute == 0) and (now.second == 0)): if (GPIO.digitalRead(LIGHT) == GPIO.HIGH): GPIO.digitalWrite(LIGHT, GPIO.LOW) # gives CPU some time before looping again webiopi.sleep(1) # destroy function is called at WebIOPi shutdown def destroy(): GPIO.digitalWrite(LIGHT, GPIO.LOW) |
/home/pi/webiopi_sample/html/index.html
1 2 3 |
WebIOPi | Light Control<script src="/webiopi.js" type="text/javascript"></script><script type="text/javascript">// <![CDATA[ webiopi().ready(function() { // Create a "Light" labeled button for GPIO 17 var button = webiopi().createGPIOButton(17, "Light"); // Append button to HTML element with ID="controls" using jQuery $("#controls").append(button); // Refresh GPIO buttons // pass true to refresh repeatedly of false to refresh once webiopi().refreshGPIO(true); }); // ]]></script> |
1 |
Figure 1
Wire up the LED to GPIO17 (pin 11) since that’s used in the sample code.
The WebIOPi configuration file is in /etc/webiopi/config.
Since you have to have administrator permissions to edit the configuration file, you should do your editing from the command line if logged in as anyone other than root. Since I’m logged in as the “pi” user, I did my editing in the nano editor.
sudo nano /etc/webiopi/config
We have to make edits in 2 places.
First, search for a heading called [SCRIPTS] around line 21.
/etc/webiopi/config (starting at line 21)
21 22 23 24 25 |
[SCRIPTS] # Load custom scripts syntax : # name = sourcefile # each sourcefile may have setup, loop and destroy functions and macros #myscript = /home/pi/webiopi/examples/scripts/macros/script.py |
Add the following in a new line:
25 |
myproject = /home/pi/webiopi_sample/python/script.py |
Set the path of “myproject” to the Python file that you just created.
The edits in the tutorial sample are limited to just “myproject”. I also set up “myscript” that was commented out in the tutorial code. (I’m not too sure what the difference is.)
Next, look for [HTTP] around line 29.
/etc/webiopi/config (starting at line 29)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
[HTTP] # HTTP Server configuration enabled = true port = 8000 # File containing sha256(base64("user:password")) # Use webiopi-passwd command to generate it passwd-file = /etc/webiopi/passwd # Change login prompt message prompt = "WebIOPi" # Use doc-root to change default HTML and resource files location #doc-root = /home/pi/webiopi/examples/scripts/macros # Use welcome-file to change the default "Welcome" file #welcome-file = index.html |
Like above, add the following in a new line:
42 |
doc-root = /home/pi/webiopi_sample/html |
Set the path of “doc-root” to the “html” directory. Unlike the previous case, note that you don’t put the file name here. Also, use line 42 that is commented out in the sample code as a reference for your formatting.
For the purpose of running the code, these settings are sufficient.
The tutorial sets a [REST] value but since we’re just using the GPIO settings, we can leave the default as is. If you’re going to build a robust application, you may adjust this value appropriately.
Ok, let’s do some debugging!
sudo webiopi -d -c /etc/webiopi/config
If you get an error after this command, WebIOPi may already be running. If WebIOPi is set to autorun, you need to stop WebIOPi and then run again using the above command. If it still doesn’t work, I would suggest temporarily removing the autorun setting.
Stop command
sudo /etc/init.d/webiopi stop
Command to remove autorun
sudo update-rc.d webiopi remove
When you start debugging, the console will automatically open.
Now, open up your browser and go to “http://raspberrypi:8000/”!
Figure 2
A “Light” button is displayed.
When you click it, the display of the button changes.
Figure 3
The LED lights up in the same way it does in this video! (I used the IP address since I was accessing it from a smartphone)
Once we confirm that no errors occur, enter Ctrl+C in the LX Terminal and terminate debug mode.
Next time WebIOPi starts, it will start on this screen. The same is true if the autorun is set.
At this point, I’ve successfully run the sample program but I still don’t really understand what most of the code does.
I don’t know anything about Python but maybe I can learn something by reading the detailed comments provided on the sample code.
To do some preliminary study, I looked at the Python Wikipedia article.
A special characteristic of python syntax is that it uses indentation. This attribute is rarely seen in other languages. So, please pay attention when you write codes.
Now, let’s take a look at the Python sample code (script.py).
We’ll review the overall structure:
It’s divided into 3 main parts. The “def” statements in the header are keywords used in defining functions in Python. The 3 functions defined in the Python program are shown below. Here’s what the comments indicate about them.
setup() | Function called automatically when WebIOPi starts |
loop() | Function called whenever WebIOPi has an iteration |
destroy() | Function called when WebIOPi closes |
Basically, the three are a setup function, a loop function, and a shutdown function. This is very similar to an Arduino program.
I want to check out the functions that start with “GPIO.” I thought these looked like functions used for WebIOPi. After poking around the WebIOPi site, I found some documentation!
Let’s look at some of the the functions used in the sample code.
14 |
GPIO.setFunction(LIGHT, GPIO.OUT) |
setFunction(channel, func)
Setup the given digital channel with the given function
channel (int) : digital channel number
func (int) : GPIO.IN or GPIO.OUT
REST API : Use setFunctionString instead.
In Line 14, the setFunction that appears in setup() sets the IN/OUT used for GPIO. The “LIGHT” variable is stored in “17” which translates to the command “Set GPIO17 to OUT” in line 14.
30 |
if (GPIO.digitalRead(LIGHT) == GPIO.LOW) |
digitalRead(channel)
Returns the value of the given digital channel.
REST API : GET /devices/name/channel/value
name (str) : device name from configuration file
channel (int) : digital channel number
digitalRead, used in conditional expressions in lines 30 and 35, is a function that reads values from GPIO. Since it’s reading digital values, these can be either HIGH or LOW.
21 |
GPIO.digitalWrite(LIGHT, GPIO.HIGH) |
digitalWrite(channel, digit)
Write the value of the given digital channel.
REST API : POST /devices/name/channel/value/digit
name (str) : device name from configuration file
channel (int) : digital channel number
digit (int) : digital value (0 or 1)
Unlike digitalRead, digitalWrite in line 21 sets values. It can set either GPIO.HIGH or GPIO.LOW.
The sample code uses this function to automatically turn the LED on and off.
In summary, the processing looks like the following:
・Between 08:00 and 18:00 turn on when started
・Turn on at 08:00
・Turn off at 18:00
・Turn off when WebIOPi terminates
As we continue, we’ll look at the HTML source code…but to be honest, there really isn’t much HTML. Basically all of the parts related to WebIOPi are written in Javascript. The WebIOPi site also has documentation on Javascript functions.
Luckily, there’s a link to it in the source code!
10 |
var button = webiopi().createGPIOButton(17, "Light"); |
createGPIOButton
Returns a button that change the state of a GPIO at each click.
(int) gpio : GPIO number from 0 to 53
(string) label : label of the button
“createGPIOButton” which appears in line 10, as the name suggests, is a function that creates a button that changes the state of GPIO. The first parameter is the pin number (e.g. It would be “17” if referring to pin 11 which is GPIO17). The second parameter passes the character string used as the label displayed on the button.
1 |
<button class="HIGH" type="button" id="gpio17">Light</button> |
The above HTML code displays the button. “id” is the pin number. “Class” corresponds to the GPIO state which can be set to LOW or HIGH. The color of the buttons can be changed using CSS.
13 |
$("#controls").append(button); |
The button created by createGPIOButton is displayed on the screen using jQuery on line 13. The parts to be used by WebIOPi basically follow this process.
There is no documentation for the “refreshGPIO” function on line 17 but it appears that this is required for the button to work. (When I tried removing this line, the button became unclickable).
The HTML (Javascript) manages the on-screen operation while the Python manages the automated switching ON/OFF of the LED corresponding to the time. It seems like the two sets of code are independent and are doing separate processings in regards to GPIO. How are values passed between the two? This important question will be addressed next time!
Rather than using the default screen like we did in the last article, making a program like this to run definitely feels like a progress. When it comes to electronics, it’s important for your project to be useful and easy to make.
I had an opportunity to learn Python while doing this project. Thanks to the complete documentation on the WebIOPi site and the useful functions already defined in the sample code; even a Python novice like myself was able to do some programming. The comments in the sample code in the tutorial were also very helpful. I can now call myself a total fan of WebIOPi!
Next time, we’ll implement few more functions to have WebIOPi receive input values from the browser. We’ll refer to the same WebIOPi tutorial. We’ll be using “macros” and trying to write a program that will accept input from a smartphone!