Annoyatron - Part II: The Code

After explaining the hardware build in Part I, it is finally time to get crackin on a description of the software that runs the Annoyatron. The Linkit Smart 7688 computer that is the brains of the Annoyatron is running OpenWRT Linux and this means that I had my choice of programming languages with which to hack together some code. I opted for Python.

To control the relays via GPIO, it was first necessary to create a class to represent the GPIO pins. The Smart 7688 ships with the MRAA library that provides easy asccess to GPIO functionality. However, for the basic needs of this project, a 3rd party library wasn't needed.

The Class to Control the IO for the Relays

Nothing too fancy here, it is mostly just a bunch of writing to a file.
class relay_pin:
  value_path = ""
  #init the pin with a GPIO number
  def __init__(self,num):
    #convert the number to a string
    num = str(num)
    #unexport the pin by writing the pin number to /sys/class/gpio/export
    f = open("/sys/class/gpio/unexport",'w')

    #export the pin by writing the pin number to /sys/class/gpio/export
    f = open("/sys/class/gpio/export",'w')

    pin_path = "/sys/class/gpio/gpio"+num
    self.value_path = pin_path+"/value"

    #set the direction
    f = open(pin_path+"/direction", "w")
    #default to off      

  def set_high(self):
    f = open(self.value_path, "w")

  def set_low(self):
    f = open(self.value_path, "w")

  #setting 'low' turns on
  def on(self):

  def off(self):

  #turn off if the class is destroyed
  def __del__(self):

The Main loop of the Code

In order to know when to turn GPIO pins on or off, the main controller for the Annoyatron runs a loop which will:

  1. look for a file containing commands
  2. parse commands from the file
  3. run the commands
  4. delete the file
The commands are in PIN_NUMBER BINARY_VALUE format, and there is one command per line.
#!/usr/bin/env python
import sys, signal, os, time
from relay_pin import relay_pin

#where is this script?
script_dir = os.path.dirname( os.path.realpath(__file__) )
#what is the path to the command file?
cmd_file = os.path.join(script_dir, 'cmd_file')

#function to run when CTRL+c is pressed
def ctrl_c_quit(signal, frame):
  print "so long, buddy!"

#connect ctrl+c to the quit function
signal.signal(signal.SIGINT, ctrl_c_quit)

#create the relay pins
relay_1 = relay_pin(0)
relay_2 = relay_pin(3)

loop = True
print "starting main loop... \n"
while loop:
 #does the file exist
  if os.path.isfile(cmd_file):
    #open the file for reading
    f = open(cmd_file, 'r')
    #loop through the lines
    for L in f:
      l = L.strip()
      #### get the data
      # data is in `PIN_NUM BINARY_VALUE`
      #default to no value for the Pin and Binary val
      p = b = None
        (p,b) = l.split(" ")
        # if the line can't be split, the data is bunk
      #are p and b not None?
      if p !=None and p!=None:
        if p == '1':
          if b=='1':
            print "1 on"
          elif b=='0':
            print "1 off"

        elif p =='2':
          if b=='1':
            print "2 on"
          elif b=='0':
            print "2 off"
    #close the file 
    #delete the file

A Web Server/API for Writing Commands to the Command File

What good is the ability to control GPIO from commands in a file if there is no way for a user to create the file? Since Python is already running the main code for the Annoyatron, I decided to use Python again for creating a web API to write the commands file.

Using the [Bottle]( micro-framework, a rather small bit of code quickly gave me a working API as well as the ability to serve static content.

#!/usr/bin/env python

from bottle import Bottle, run, static_file, redirect

app = Bottle()

def write_cmd_file(string):
  f = open('cmd_file', "w")

def root():
  return static_file('index.html', root='public')

def action(relay, value):
  #convert value to an int and then a string
  v = str(int(value))
  if relay == "both":
    cmd = "1 %s\n2 %s" % (v,v)
    r = str(int(relay))
    cmd = "%s %s" % (r,v)
run(app, host='', port=8080)

A Web UI for the Web Server

Now to make some static HTML and CSS content to load into a web browser.
          <meta content='width=device-width, initial-scale=1' name='viewport'>
          <style type='text/css'>
            body {
              color: white;
            .btn {
              border-radius: 5px;
              border: 2px solid green;
              padding: 3px 10px;
              color: white;
              text-decoration: none;
            h2 {
              margin-bottom: 5px;
              padding: 0px;
            .group {
              margin-bottom: 10px
        <body bgcolor='black'>
          <div class='group'>
            <a class='btn' href='both/1'>On</a>
            <a class='btn' href= 'both/0'>Off</a>
          <div class='group'>
            <a class='btn' href='1/1'>On</a>
            <a class='btn' href= '1/0'>Off</a>
          <div class='group'>
            <a class='btn' href='2/1'>On</a>
            <a class='btn' href= '2/0'>Off</a>

The Web Interface in Firefox on Android

Simple, and it gets the job done.
Jezra :)