Switching Mains Equipment with a Raspberry Pi - Part 2

Part 1 of the mains switching project covered the hardware and this section covers the software.

The control software is a small Python program called fence.py built around the Raspberry PI GPIO and web.py libraries.  This provides a web interface on port 80 through which the solid state relay connected to GPIO 7 can be toggled.

 

#!/usr/bin/env python
import web
import RPi.GPIO as GPIO
import atexit

CTRL_FENCE_POWER = 7
WEB_PWD = "qwerty"

GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(CTRL_FENCE_POWER, GPIO.OUT)
GPIO.output(CTRL_FENCE_POWER, False)

class webservice:
    def isvalid(self):
        request = web.input()
        return True if ("id" in request and request["id"] == WEB_PWD) else False

    def render(self):
        return render.index("on",WEB_PWD) if GPIO.input(CTRL_FENCE_POWER) else render.index("off",WEB_PWD)

class root(webservice):
    def GET(self):
        if self.isvalid():
            return self.render()
        else:
            return web.notfound()

class fence(webservice):
    def GET(self,name):
        if self.isvalid():
            if name == "on":
                GPIO.output(CTRL_FENCE_POWER, True)
            elif name == "off":
                GPIO.output(CTRL_FENCE_POWER, False)
            return self.render()
        else:
            return web.notfound()

@atexit.register
def shutdown():
    GPIO.cleanup()


if __name__ == "__main__":
    urls = ('/','root','/fence/(.+)','fence')
    app = web.application(urls,globals())
    render = web.template.render('/home/pi/fence/templates/')
    app.run()
 
Three URLs are recognized by fence.py
 
The root URL will display the status of the fence and the toggle button to allow the state to be changed.
 
e.g
 
http://localhost
 
The /fence URL supports two named commands (on and off) which change the GPIO state and displays the new status of the fence.
 
e.g
 
http://localhost/fence/on and http://localhost/fence/off
 
Because I wanted to make the application accessible from the internet I added very simple security where all requests require the provision of an id in the URL.
 
e.g
 
http://localhost/fence/on?id=qwerty
Failure to provide the ID will return a "Not Found" Error (404).  Good enough security to stop someone finding the incoming port and playing.
 
 
The status page is rendered using a web.py template.
$def with (state,WEB_PWD)
<html>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
    a { text-decoration: none; }
    .button {
        padding: 5px 10px;
        display: inline;
        background: #777 url(button.png) repeat-x bottom;
        border: none;
        color: #fff;
        cursor: pointer;
        font-weight: bold;
        border-radius: 5px;
        -moz-border-radius: 5px;
        -webkit-border-radius: 5px;
        text-shadow: 1px 1px #666;
    }
    .button.off { background-color: #000000; }
    .button.on { background-color: #000000; }
    .button.large { font-size: 125%; padding: 7px 12px; }
    .label { font-size: 100%; color: #fff; }
</style>
<br/><br/><br/><br/><br/>
$if state=="on":
    <body bgcolor="red">
    <center><a href="/fence/off?id=$WEB_PWD" class="button large on">TURN OFF</a></center>
$elif state=="off":
    <body bgcolor="green">
    <center><a href="/fence/on?id=$WEB_PWD" class="button large off">TURN ON</a></center>
$else:
    Fence state not known.
<br/><br/>
<center><p class="label">James' Electric Fence</p></center>
</body>
</html>
 
The Raspberry Pi is configured to start the fence.py program when it boots.  
 
This is done using the following /etc/init.d/fence script:
 
### BEGIN INIT INFO
# Provides: Electric Fence AC Power Controller
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Electric Fence
# Description: AC Power Controller
### END INIT INFO

#! /bin/sh
export HOME
case "$1" in
start)
echo "Starting Fence"
sudo /home/pi/fence/fence.py 80 &
;;

stop)
echo "Stopping Fence"
FENCE_PID=`ps auxwww | grep fence.py | head -1 | awk '{print $2}'`
kill -9 $FENCE_PID
FENCE_PID=`ps auxwww | grep fence.py | head -1 | awk '{print $2}'`
kill -9 $FENCE_PID
;;
*)
echo "Usage: /etc/init.d/fence {start|stop}"
exit 1
;;
esac
exit 0

Starting and stopping the fence service can be done with the commands:
 
sudo /etc/init.d/fence start

sudo /etc/init.d/fence stop
 
sudo is required both here and in /etc/init.d/fence because fence.py accesses the GPIO ports which is only possible as an administrator.
 
Hope this proves useful for someone.
 
 
 
 

Powered by Easytagcloud v2.1

Contact Andrew Quinn

jaquinn@ihug.co.nz http://twitter.com/jaquinn