This project was conceived as a present for my friend Chris Lasher to commemorate his moving and beginning a graduate program in bioinformatics. Chris will be doing a lot of programming, and is an adherent of Pragmatic / Agile Programing, one of the principals of which is unit testing. While the unit tests of a program are running, it is nice to know if they are succeeding or failing, and which is predominant. Famously, some pragmatic programmers made a feedback system by controlling full-sized lava lamps from a unit testing framework by plugging together some off-the-shelf home control devices (it cost them over $60). The lamps allowed them to see whether tests were passing or failing, and the gradual heating up on one lamp allowed them to see which events were predominant. This is a cool idea, but I wanted to make Chris something that:
1) would control two small USB-powered lava lamps,
2) would be powered off Chris's fancy new laptop, and interface via USB (no legacy ports on newer computers, particularly laptops),
3) would be a bit more homemade and hacker-friendly,
4) would be allot cheaper.
Driving relays from a USB to serial port converter would seem to be a simple solution. There are many circuits available on-line for serial port control projects. One excellent project that I adapted was at http://www.windmeadow.com/node/4. Unfortunately, almost all USB to serial devices do not allow for low level bit banging (the manually toggling of control lines) that is required to use these circuits. Another approach would be to buy a USB interface circuit, or build one from a microcontroller. Either way, the project would require a good deal of microcontroller code and drivers (even using the pre-existing human interface drivers or a pre-made controller).
I chose to solve this problem with a salvaged USB keyboard, since they are relatively cheap, and contain everything that is needed for three simple on/off outputs, in the form of the number, caps, and scroll lock LEDs. Under Linux there are a number of mechanisms to toggle your LEDs from a program or command line (one is even referenced in Cryptonomicon). Setled is the simplest, and is pre-installed on almost all machines, ledd is built on a client-server model, and there is even a module in the Ruby programing language. Windows and Mac OSs, and other programming languages, should have comparable mechanisms - post them in the comments if you know how to toggle keyboard LEDs in other OSs or programming languages!
I gave Chris his present, and now he can not only see if his unit tests are passing, all the programmers in his new department can know what a cool DIY maker he is.
Step 1: Parts List
1 USB keyboard
(an apple keyboard would also allow you to salvage two USB jacks, making the hackery listed in the "poor man's USB jack" step unnecessary)
$0 for a scraped keyboard with a dead key or two, to $4 on-line (http://froogle.google.com/froogle?q=usb%20keyboard) to $30 at best buy)
2 reed switch relays (Radio Shack #275-233 $3.00, Mouser #677-OMR-112H $1.54)
all other electrical components should only cost a few dollars.
2 transistors (like a 2N2222) (Radio Shack #276-1617, Mouser #511-2N2222A)
2 resistors (Radio Shack #271-1124, Mouser #291-4.7k, yellow-violet-red-gold bands)
4 diodes, something like 1N404 (Radio Shack #276-1103, Mouser #512-1N414B)
1 power switch (SPST)
a little bit of wire
1 perfboard (Radio Shack #276-1395)
1 Altoids tin
some cardboard, a sheet of transparency/overhead film
soldering iron and / or wire wrap tool and wire
dremel tool or hand-tool and patience
drill and bits
a digital multimeter
red and green sharpie marker
Knowledge and skills:
Basic soldering and electronics knowledge. I highly recommend Forest Mimm's book if you are an electronics beginner and would like to know how circuits work.
This project took two evenings and an afternoon, including troubleshooting.
Step 2: Keyboard Evisceration
Step 3: Poor Man's Usb Plug
Step 4: Cut Enclosure and Perfboard
Step 5: Make Circuit
You will need to remove the LEDs from the keyboard circuit board and determine their polarity and which side is switched with a multimeter. Run one wire from each LED that will be involved in a switching circuit (these are labeled SCROLLLOCK and CAPSLOCK on the schematic). Desolder the +5v and ground from the keyboard circuit to provide power to the perfboard, and then run wires to return power to the board (this is the +5V and grounds on the schematic). Then follow the schematic to make the circuit, using the pinouts of the components to identify connections. Assemble this circuit on a breadboard first, and test the circuit. This was the step where I determined that the LEDs were pull-up instead of pull-down switched, and generally reached the point of maximum chaos on my workbench. When the circuit works (testable by hitting the Caps Lock Key or Scroll Lock Key and seeing if the lava lamps toggle), figure out how to pack the components onto the perfboard. Wirewrap can be used, but the simplest assembly method is to simply shove components through holes, wrap the leads together, and solder them together. Test that the assembled circuit works on the perfboard.
Step 6: Color USB Lava Lamps
Step 7: Final Assembly
Step 8: Code
setleds -L -caps +scroll < /dev/tty0 ;sleep 3s ;setleds -L +caps -scroll < /dev/tty0; sleep 3; setleds -L </dev/tty0
breaking this down:
#To turn on the red lamp:
setleds -L -caps +scroll < /dev/tty0
#to turn on the green lamp:
setleds -L +caps -scroll < /dev/tty0
#to return to the state where the LEDs display the keyboard settings
setleds -L </dev/tty0
You can include these system calls in your own program, or use the a phython unit test module that Chris wrote based on the PyUnit unit testing framework built into python. Just unpack the files from the tar archive (tar -xzvf lava_unittest.tar.gz from a console) and try the following commands from a console:
python lava_unittest.py test_lava_unittest-pass
python lava_unittest.py test_lava_unittest-fail
To run from a terminal emulators, uncomment the warning-flagged lines and try running it
as root from a terminal emulator.
With this code, all one needs to do is swap instances of "unittest" with "lava_unittest" in Python scripts written for unit testing. No re-coding is necessary.