Skip to main content

Ambient bus arrival monitor from hacked Linksys WRT54GL

London's Transport for London has a wonderful service called Countdown that can give live bus arrival times. For example, here's a page showing live buses passing No. 10 Downing St.

Underlying this is a simple JSON API that, while not public, seems to be usable by the average programmer as long as I'm not abusive. So with its details deciphered (hardly hard since the web site uses the API) I set about building an ambient bus monitor into a model London bus. The idea is that I can glance at the bus and see the times of up to the next two buses that I'm likely to want to catch and know when to leave the house.

Here's a picture of the completed unit:

To make that work I needed a computer of some kind and I'd originally planned on using a eRaspberry Pi. But with the delay in being able to buy one I switched to another host: a hacked Linksys WRT54GL. It's possible to reflash the Linksys with a custom Linux installation that lets me control the box completely (and still use it as a wireless router). There are various project, but I used OpenWRT.

With OpenWRT it's possible to SSH into the box and treat it as any Linux server (albeit a rather slow one). But there's plenty of power to grab bus times and update an LED display connected to the WRT54GL's serial port. Yes, there's a serial port inside the WRT54GL that uses TTL levels and can be easily accessed by soldering on three wires.

First you remove the cover of the router. It's easy because it simply pulls apart, but first you have to cut through a sticker warning you that your warranty is about to end.

The front part pulls away easily to reveal the circuit board:

And the back is just as easy to remove leaving you with the circuit board itself (you must remove the two antennas at the back):

The two serial ports are conveniently easy to access at the edge of the board:

The LED module I'm using is from SparkFun and accepts TTL levels and needs a 3.3V power supply.

Happily the WRT54GL's serial port is TTL and has Vcc and GND, so three wires supply all that's needed:

(Yes, those wires are rather large because I'm using up surplus wire from my homemade matrix display made from hacked Christmas lights).

A quick test with the multimeter showed that I was getting about the right voltage:

Next I used a standard three pin 'headphone' socket and drilled a hole in the front of the Linksys for it:

And put it all back together it makes a neat little unit that's got a serial port on the front:

To wire up the display I took an old sound card cable that came with a PC and cut one end off and soldered the wires to the display. The plug end goes into the Linksys. Here is it showing a number for the first time:

With the hardware half done (no bus yet for the display) it was time for software. The code for the project (written in Lua, which is installed by default as part of OpenWRT) is here.

It relies on STTY so install it with apt-get install coreutils-stty so that it can set the serial port up correctly. On my box that second serial port is /dev/ttyS1.

The program has three parameters: a comma separated list of bus routes, a bus stop number and a 'walking time'. For example, it's possible to do:
lua ambibus.lua 3,12 50906 2
Which means get the times for buses 3 and 12 arriving at stop 50906 (close to No. 10 Downing St.) and allow me two minutes to walk there. The program will find the buses, adjust the times by 2 minutes to allow you to arrive and once a minute update the display with the times of the next two buses.

Next up is a nice case for the display. What better than a London bus. I chose a Plaxton Pointer as it was the right size for LED display to show through the side windows.

If you collect model buses you may want to avert your eyes as I decapitate the bus, gut it, cut out some seats and then put it back together again.

I prised the top off using a screwdriver to reveal the plastic window piece:

Then I removed the windows themselves to reveal the seats:

And then removed the seats to get access to the 'engine' at the back which I removed to make a space for the cable to pass out of the bus.

Then I wired in the display with a small hole cut in the back seats to allow the cable to pass through:

The display was glued in (upside down because of the available clearance: a problem which is fixed in the code) and a few seats cut out to make space.

Then put it all back together and power on the display for a quick test:

And here it is running. The display is capable of showing two buses, but here there was only one bus coming in four minutes:


Anonymous said…
Great! The model bus adds a nice touch. I've been contemplating doing something similar using the Helsinki transport system, but the electronics component is what scares me off.
Luke Closs said…
This is so awesome! Thank you not only for describing the project but also for the detailed instructions to re-purpose this hack! I can think of many ideas that I'd like to apply this to!

Thank you for taking the time to write this up!
Vijay Raj said…

I am interested in electronics hacking, but a n00b. How did you know that those were the serial ports on the router? Also, any advice on getting more knowledge to help in these?
Bijan said…
This was absolutely fascinating for me. I've been reading Charles Petzold's book Code and taking a course on circuits and this is the first time I've actually gotten to see a modern practical usage behind some of the concepts presented in a digestible way.

Thanks for the post. It's inspiring work.
ngupta said…
I think in the following photo you are showing a wrong connection to pin hole number 7. It should be pin hole number 3.
ngupta said…
I think in the following picture, you are showing a wrong connection to pin hole number 7. It should be pin number 3.
@ngupta. You are correct that it should be pin 3 and pin 7. I must have taken that photograph before I realized that I'd screwed it up.
Anonymous said…
Vijay Raj > I am interested in electronics hacking, but a n00b. How did you know that those were the serial ports on the router?

You should probably ask in the OpenWRT forum:
LeuMund said…
Great idea! I built a Busstop Lamp, which is indicating with green light the right time to leave the appartment to catch the bus. My lamp is based on Arduino Ethernet which is fine to collect json information from the internet. Here is my <a href=" article in german</a>. I think i should do a english version too.

Popular posts from this blog

Your last name contains invalid characters

My last name is "Graham-Cumming". But here's a typical form response when I enter it:

Does the web site have any idea how rude it is to claim that my last name contains invalid characters? Clearly not. What they actually meant is: our web site will not accept that hyphen in your last name. But do they say that? No, of course not. They decide to shove in my face the claim that there's something wrong with my name.

There's nothing wrong with my name, just as there's nothing wrong with someone whose first name is Jean-Marie, or someone whose last name is O'Reilly.

What is wrong is that way this is being handled. If the system can't cope with non-letters and spaces it needs to say that. How about the following error message:

Our system is unable to process last names that contain non-letters, please replace them with spaces.

Don't blame me for having a last name that your system doesn't like, whose fault is that? Saying "Your last name …

All the symmetrical watch faces (and code to generate them)

If you ever look at pictures of clocks and watches in advertising they are set to roughly 10:10 which is meant to be the most attractive (smiling!) position for the hands. They are actually set to 10:09.14 if the hands are truly symmetrical. CC BY 2.0image by Shinji
I wanted to know what all the possible symmetrical watch faces are and so I wrote some code using Processing. Here's the output (there's one watch face missing, 00:00 or 12:00, because it's very boring):

The key to writing this is to figure out the relationship between the hour and minute hands when the watch face is symmetrical. In an hour the minute hand moves through 360° and the hour hand moves through 30° (12 hours are shown on the watch face and 360/12 = 30).
The core loop inside the program is this:   for (int h = 0; h <= 12; h++) {
    float m = (360-30*float(h))*2/13;
    int s = round(60*(m-floor(m)));
    int col = h%6;
    int row = floor(h/6);
    draw_clock((r+f)*(2*col+1), (r+f)*(row*2+1), r, h, floor(m…

Importing an existing SSL key/certificate pair into a Java keystore

I'm writing this blog post in case anyone else has to Google that. In Java 6 keytool has been improved so that it now becomes possible to import an existing key and certificate (say one you generated outside of the Java world) into a keystore.

You need: Java 6 and openssl.

1. Suppose you have a certificate and key in PEM format. The key is named host.key and the certificate host.crt.

2. The first step is to convert them into a single PKCS12 file using the command: openssl pkcs12 -export -in host.crt -inkey host.key > host.p12. You will be asked for various passwords (the password to access the key (if set) and then the password for the PKCS12 file being created).

3. Then import the PKCS12 file into a keystore using the command: keytool -importkeystore -srckeystore host.p12 -destkeystore host.jks -srcstoretype pkcs12. You now have a keystore named host.jks containing the certificate/key you need.

For the sake of completeness here's the output of a full session I performe…