Martin's Drive by Clock

Photo Album
Videos
Huh? Why?
A long while ago I had a phone that had a nice bright LED that would light before it rang. Even when the phone was way off on the far edge of my peripheral vision I found myself reaching for it before I heard it. Shortly thereafter I noticed that when I got an IM or email I wouldn't notice it, even with the little screen animation. It seems that on screen animations don't attract my attention much anymore.
So was born the initial idea. A bright LED that's designed to only be on for very specific occasions. The "Drive by clock" part got added later when I found that I constantly had people stopping by my cubicle asking me for a "few minutes" and still couldn't get anything done. I wanted to record those "drive bys" chess clock style.
Final product overview
The Drive by Clock is a box that has 4 buttons, 2 large ones on top and
two smaller ones on the side. There's 4 multi color LEDs on the front.
The top has a pair LED bars and a pair of 8 segment LED numbers.
Additionally, since this used a USB port, I ended up putting 3 more USB
ports on the back.
Brief Tech Overview:
- Phidget LED driver for lighting LEDs.
- USB joystick for input.
- USB hub to put them together.
- python code to make it all work:
- pygame to drive the event loop and joystick input.
- ctypes to the phidgets library to drive the lights.
- dbus to grab events from pidgin.
Phidget USB LED controller
Phidgets sells a bunch of electronics
interface kits like servo and stepper motor controllers and things.
Among them is a USB
64 LED
controller. While this initially seemed overkill for what I was
looking for (one or two lights) I eventually realized I might be able to
extend my plans.
That's how I ended up being moving to having a whole bunch of LEDs on
it. Just a count:
- 4 multicolor LEDs ( 12 LEDs )
- 2 10 segment LED bars ( 20 LEDs )
- 2 8 segment LEDs ( 16 LEDs )
- 2 additional status LEDs
So, that's 50 LEDs all together. But, I can display all sorts of neat
information. I've got room for growth if I wanted it.
USB joystick
I wanted some form of input for the chessclock like functionality for
tagging my time vs. drive by coworker's time. I actually pondered this
for a while. Of course I could have used my keyboard or mouse, but
that's no fun. Some additional input method would make it entertaining,
but another USB mouse or keyboard wouldn't be any different and would
make coding around it a pain. That's when the idea of a joystick came to
me. USB joysticks are cheap and would probably be easy to hack into
this. It was. I just coopted a few of the standard buttons and soldered
wires onto the correct spots on the board and attached hard buttons.
USB Hub
I think by now you see where this fits in here and doesn't require much
discussion.
Python Code
Here's where it gets fun and useful.
pygame
Python has numerous interfaces for reading joystick inputs.
Pygame is the
one I was most (though not very) familiar with. I went with it. It turns
out to have been very easy because in addition to the easy handling of
joystick events, it also had a good basic event loop with handling that
I could easily make use of.
Controlling the Phidgets LED controller
This one lead to a lot of pain. First, I had to get the C library for
the LED driver working. But, it's buried in with all the rest of the
phidgets driver code. So, I had to build it all. This was so long ago,
that i don't even remember all the pain involved, but it took me quiet a
while. Testing took quite a while and I got to dive into some low level
C code which I haven't done in quite a while. Initially I was pondering
writing this whole thing in C, but the reminder of he low level C made
me realize I didn't want to go to that level.
Second, after I decided to write in Python, I had to figure out how to
interface. I had found several python modules that claimed to interface
to the Phidgets libraries. But, I realized that they were all for the
other Phidgets controllers, not the LED one. After a brief attempt at
writing the C interface for the LED library, I decided on ctypes.
Ctypes is basically a generic interface for all C libraries. It lets you
load up a precompiled library and then make calls directly into it from
python. It automatically does type conversions as required. My python
ctypes interface is about 60 lines of code.
Dbus
Dbus is just
a message passing system used by many things, including
Pidgin. I was rather amused that
googling "dbus" alone yielded many tutorials, several of which featured
pyton already. This was a good sign that I would be able to find what I
needed. And I mostly did, except for how to make the dbus required
mainloop and the pygame loop run side by side. Until I found the code
that gave me this snippet:
import gobject
import thread
dbus_loop = gobject.MainLoop()
gobject.threads_init()
thread.start_new_thread(dbus_loop.run, ())
The
gobject.threads_init() is the part that didn't seem to ever
be adequately explained. All it does is tell the python gobject to that
it should release the GIL when it's not need (and people still try to
tell me "Oh, the GIL isn't so bad!" Bullshit it's not). Anyway, the
basic point is that once you've told gobject to release the GIL when
it's not needed, you can shove the main loop into its own thread and
have it do things for you.
Final Notes
While I had a great time building this, I've learned a bit since
starting it. The most annoying thing is that since I started it, the
world of open source, cheap and easy to find USB connected hardware has
expanded a lot. Were I to rebuild this now, I would most likely do it
based on the
Arduino hardware
platform.