Jay Caines-Gooby

Back in 5 mins

Tweeting Brighton and Hove real-time bus departures


Tweet bird courtesy of Gopal Raju, bus photo Brighton & Hove Bus and Coach Company

Brighton & Hove have real-time departure boards showing when the next bus is due at most of their city-centre bus stops. There’s also good Google Maps integration, showing bus stops and departure times.

A recent addition to the city’s transport infrastructure, is the ability to text a bus stop code from your mobile and to receive back, by text, a list of the buses due at that stop. There’s a 25p charge for the service however, and as I often just want to quickly check what time I should leave work or home to catch the next bus, I thought I’d write a Twitter bot that I could tweet for the information instead.

There’s an excellent ruby library for writing Twitter bots called twibot that uses a Sinatra-inspired DSL for matching incoming tweets against routes that should respond to the tweet.

Data, data, data

The biggest hurdle in getting @bustweet up and running was data. I needed to get a list of all the bus top sms text codes – e.g. brimdgm – and the corresponding bus routes that serviced that stop. I knew it had to be there somewhere, because the slippy maps show you the bus stop, its text code and a list of buses that stop there. Time to dig out Firebug

It took me a couple of hours, but I was pretty certain that I could build something.

It turns out that the text codes are known as Naptan Codes, and although the codes themselves are assigned by the local authority, they’re a nationwide initiative and defacto standard. Indeed, I’m certainly not the first person to have a go at using the Naptan data; James Wheare built LiveBus.org from the various local authority transport data that’s available.

And once you know where to look, you can get a whole pile of JSON (wrapped up as Javascript) sent to you. JSON for services:

"var response = 
{
    service:
    {
        serviceId: \"29\",
         serviceName: \"11X\",
         serviceDescription: \"Hove Town Hall - Kings House - Thistle Hotel\",
         serviceAbbreviatedName: \"\",
         routes: 
        [
            {
                routeId: \"65\",
                 routeName: \"11X Hove - Brighton\"
            },
            {
                routeId: \"66\",
                 routeName: \"11X Brighton - Hove\"
            }
        ]
    }
}
;"

And routes and stops:

"var response = 
	{
	    routeid: \"65\",
	     stops: 
	    [
	        {
	            stopId: \"6915\",
	             stopName: \"Hove Town Hall\",
	             operatorsCode1: \"06915\",
	             operatorsCode2: \"06915\",
	             gpsStopName: \"Hove Town Hall N\",
	             naptanCode: \"brimpmg\",
	             Lat: \"50.828602\",
	             Lng: \"-.170563\"
	        },
	        {
	            stopId: \"6905\",
	             stopName: \"Kings House\",
	             operatorsCode1: \"06905\",
	             operatorsCode2: \"06905\",
	             gpsStopName: \"Kings House\",
	             naptanCode: \"brimpjw\",
	             Lat: \"50.824944\",
	             Lng: \"-.168752\"
	        },
	        {
	            stopId: \"6079\",
	             stopName: \"Brighton Centre\",
	             operatorsCode1: \"06079\",
	             operatorsCode2: \"06079\",
	             gpsStopName: \"Brighton Centre\",
	             naptanCode: \"briamta\",
	             Lat: \"50.820858\",
	             Lng: \"-.145890\"
	        },
	        {
	            stopId: \"6913\",
	             stopName: \"Thistle Hotel\",
	             operatorsCode1: \"06913\",
	             operatorsCode2: \"06913\",
	             gpsStopName: \"Thistle Hotel\",
	             naptanCode: \"brimpga\",
	             Lat: \"50.819883\",
	             Lng: \"-.140137\"
	        }
	    ]
	}
	;"	

I came up with a nice simple schema of three tables; services, routes and stops and populated these with data via a bit of shell scripted curling. As you can see from above, the JSON needed cleaning up too; I wanted to parse it with Ruby not Javascript, and even then, the keynames weren’t validly quoted. A quick pass through sed fixed that and meant I now had details on the 101 bus routes and the 7947 bus stops (who knew there were so many!) that service them.

The final part of the puzzle was getting the actual real-time data for a particular stop. The web-based departure boards are nice and self explanatory via querystring parameters, so I just need to screen scrape the result of any tweeted enquiry.

First I convert the text name for the stop to the stopId value that the departure board needs; a quick join across the database schema, and the resulting web page gets scraped with hpricot and the resulting bus times are tweeted back to the original enquirer.

Give it try! Tweet @bustweet with the text name of a bus stop, e.g. @bustweet brimdmt or with an optional route number to e.g. @bustweet brimdmt 5b

It’s still a little brittle and may well be up and down in the next few days, so please be a little patient.

If you’ve got any ideas for ways to enhance it, feel free drop me a line at jay@gooby.org or @jaygooby or leave a comment below.

Comments

once you’ve got the basics stable how about adding look-ups so you can return the stop codes for a given route or street?
Brilliant idea BTW :)

Gravatar icon
Friday July 24, 2009 @ 05:50 PM (BST)
New comment

required, won't be displayed

optional

Don't type anything here unless you're an evil robot:


And especially don't type anything here:

Basic XHTML (including links) is allowed, just don't try anything fishy. Your comment will be auto-formatted unless you use your own <p> tags for formatting. You're also welcome to use Textile.

Copyright © 2011 Jay Caines-Gooby. All rights reserved.
Powered by Thoth.