Lights Out

Idea:

Simply turn on/off lights using your phone (over WiFi).

Circuit:

Have a microcontroller connected to a relay that acts as a switch in the wiring loop. I didn't have a spare arduino and didn't have enough time to program one. So, I decided to use a BeagleBone Black instead. I have a wifi dongle attached to it and the relays are connected to one of the GPIOs.

Code:

I used Flask for accepting a POST request at a URI and triggered a bash script using the python module sh. It allows me to run commands directly without having to use subprocess.

Now the thing about the ARM processors is that they rely on device trees. Device tree in simple words "A structure for describing hardware". It's passed to the processor when you boot. Anyway, so dt that I am using on the BBB allows me to symlink the gpio with a /dev driver. And I can just write IN or OUT to describe the basic nature of the GPIO.

My flask script was rudimentary. Simply one URI that accepts a POST request with values OFF or ON and turns the relays off or on.

Here's my Flask server code

from flask import Flask, render_template, request, jsonify  
from sh import Command, cat  
app = Flask(__name__)

translation_dict = {  
    'out': 'on',
    'in': 'off',
}

def toggle_lights(state):  
    if state == 'on':
        turn_on = Command('/bin/bash')
        turn_on('/var/scripts/on.sh')
    if state == 'off':
        turn_off = Command('/bin/bash')
        turn_off('/var/scripts/off.sh')
    #current_state = cat('/sys/class/gpio/gpio67/direction')
    return get_current_state()

def get_current_state():  
    current_state =  cat('/sys/class/gpio/gpio67/direction')
    return translation_dict[current_state.stdout[:-1]]

@app.route('/', methods=["GET", "POST"])
def index():  
    if request.method == "POST":
        state = request.form['lights']
        toggle_lights(state)
    current_state = get_current_state()
    return render_template("toggle.html", current_state=current_state)

@app.route('/remote', methods=["GET", "POST"])

def remote_trigger():  
    if request.method == "GET":
        return get_current_state()
    elif request.method == "POST":
        state = request.form['lights']
        new_state = toggle_lights(state)
        return new_state 

app.debug = True

if __name__ == "__main__":  
    app.run('0.0.0.0')

As I mentioned, I am relying heavily on sh module.

Here's the simple template

<html>  
    <head>
        <title>Manager</title>
        <style>
            body{   
                margin: 0 auto;
                display: block;
            }

        </style>
    </head>
    <body>
        <div id="main">
        <h1>Light Manager ({{ current_state }})</h1>
        <form action="." method="POST">
            <input type="submit" value="on" name="lights" />
            <input type="submit" value="off" name="lights" />
        </form>
        </div>
    </body>
</html>  

And the device script that is located at /var/scripts/

gpio1=67  
state=out  
if [ ! -d /sys/class/gpio/$gpio1 ]; then echo $gpio1 > /sys/class/gpio/export; fi  
click() {  
    echo $state > /sys/class/gpio/gpio$1/direction
}

click $gpio1  
gpio1=67  
state=in

if [ ! -d /sys/class/gpio/$gpio1 ]; then echo $gpio1 > /sys/class/gpio/export; fi  
click() {  
    echo $state > /sys/class/gpio/gpio$1/direction
}

click $gpio1  

I have them as different scripts because it's easier to debug.

I then built a simple Tasker Scene that has two buttons that trigger the two tasks. The scene only triggers when it's on my home Wifi Network. So no accidental requests. The only problem is that Tasker didn't resolve BIND .local addresses. I had to give it an IP that it had on the network.

That's not too much of a problem because it's ON persistently. I have no reason to turn it off. I should however write an INIT script that boots up the server. I'll paste the code on github and link it later.

Oh now the next step is to use AutoVoice to control lights by saying "Ok Google".

Code is Lights Out is available on Github