Skip to main content
  1. Blog/

Sound the alarm!

My colleague and partner in crimes against PHP has “not a blog”-ed about a recent waste of my Friday afternoon at work. There’s a pretty awesome video of it in action as well. Kudos to GrahamB on the light-triggered panic in the background.

Essentially, this wonderous creation boils down to an off-the-shelf novelty fuzz-light connected to a 13A 4-way extension lead that was adapted to be controlled via a USB relay. Only simple modification needed (I don’t trust myself with anything electrical usually) – snip the neutral cable on the extension lead and run through the relay (even I can’t cock that up). Through the use of some really dodgy python (not PHP, as Tom alludes to, for a change) that was adapted from numerous tutorials – the relay can then be controlled via a HTTP GET request to the relevant port with /on or /off as the request string.

This is then hit via a command to our work IRC bot, so you can type !emergency into any channel to turn the light on, or !emergencyover to turn it back off again, which will create the appropriate HTTP hit, and return appropriate witticisms from the bot. I’m not going to paste that code here though. Make your own.

You may wonder what the point of this probably-lethal waste of money & time is. Good question. I’m still asking myself that, but it’s pretty damn fun to control a flashing light from your computer…

The pyweb/serial shonky python script used for control:

"""
USB Relay HTTP Control Script

Accepts HTTP GET requests to /on and /off, sends the requisite serial commandto the USB relay board

Matt Dyson, 2012
https://mattdyson.org/blog/2012/11/sound-the-alarm/
"""
import serial
import web
from struct import *

commands = {
    'relay_1_on': 0x65,
    'relay_1_off': 0x6F,
    'relay_2_on': 0x66,
    'relay_2_off': 0x70,
    'info': 0x5A,
    'relay_states': 0x5B,
}

urls = (
    '/(.*)', 'relay'
)
app = web.application(urls, globals())

class relay:
    def GET(self, arg):
        if not arg:
            return 'No action given'
        elif arg=='on':
                return 'Turning light on' + send(commands['relay_1_on'])
        elif arg=='off':
                return 'Turning light off' + send(commands['relay_1_off'])
        else:
                return 'Unknown action'

def send(cmd):
    ser = serial.Serial('/dev/ttyACM0', 9600)
    ser.write(chr(cmd)+'\n')
    ser.close()
    return ". Done"

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

The code still contains the necessary commands for getting information/relay states/relay 2 control (currently unused), but these aren’t exposed via HTTP. We’ve not dreamt up a use for the second relay yet, I suspect further evil will happen at some point again in the future.