How to Build a Realtime Public Transit Schedule App

There is a place where transportation and the Internet of Things (IoT) meet. Let’s call it the IoTT; the Internet of Transportation Things. There are blue-chip companies, such as IBM and Cisco, looking to cash-in on “Intelligent Transportation”. The IoTT is the next step in connecting transportation.

All of this talk sounds exciting, but what does this mean for you as a developer? How do you get involved? This is where a realtime data stream network like PubNub comes into play. In the future you could develop software that allows devices to connect to a channel and speak to each other. Messages could broadcast current locations or destination. This information could group transportation for efficiency. Ok, well how do we get there?

You need to start with a simple example. Our current place and time in history is an interesting one. Public data is ripe and available for the picking! For example you can search for public zoning data or subway times, and many larger cities offer public data in easy to consume APIs. In this article, we’ll use the BART (Bay Area Rapid Transit) API that delivers a wide variety of metrics, statistics, and schedules for the Bay Area’s largest rail system.

Programming Scope

timesFor this article you will learn how to access the BART API to build a realtime public transit schedule app. You’ll take station locations and convert them into geohashes.

After gathering the geohashes, you’ll get the user’s location in San Francisco, or spoof it in our case.Then you’ll match the user’s location with nearby stations. This will require more API calls for the relevant data.

Once you get the estimated times of departure, you will display the times on a map infobox.

**The source code for this application tutorial in its entirety is available here for download (click to download).**

Getting Started

The setup is similar to our previous tutorial on JavaScript geohashing.

To simplify the example you’ll split data retrieval and displaying the data in the browser. First you’ll need “node” and “npm”. If these are strange words, then take a look at PubNub’s excellent introduction to Node.js. The node packages used are:

  • Browserify to use node packages in the browser.
  • ngeohash to encode latitude and longitude into a string.
  • request for http requests outside of the browser.
  • xml2js to convert XML returns into JSONs.

If you look at the example code, you’ll see that these packages are missing. Navigate to the project base folder and type npm install in the command line. This will install the packages by looking at the requirements inpackage.json.

Next set up index.html. This is where you will configure PubNubjQuery, and GoogleMaps.

You should add one more script.

By using Browserify, you can use node packages in the browser.

app.js is the name of the main file. There will be more on that later.

Retrieving the Data

Retrieving data with JavaScript can be tricky. It’s most efficient to query and then store the data locally as a file. Unfortunately, in the browser, JavaScript cannot write to the filesystem.

This is for good security reasons. This means you need something server-side. For example you could call a Ruby script to do the file i/o. In this case, you will use node’s abilities separate from the client web application.

The code example has allstations.js in the js folder. This file uses xml2js, fs, path, and request.

Make a “GET” request to the BART API for information on all its stations.

Set up a method that parses the XML response.

Inside the method:

xml2js parsed the XML response to a JSON. Then you want to covert that JSON to a string for text storage. This gives you string_result.

Write to the file system.

JSON Output to File

If you look in data/ you should see allstations.json. Next you want to pull the necessary information for each station location.

Alllll Aboard! (Station Locations)

Create app.js in the js/ folder. With each change you need to use the Browserify command stated earlier in the article. Because jQuery is accessible from index.html you will use this to open allstations.json.

The callback calls the “main” method. Inside “main” you call all your separate methods. Note that to simplify scope “that” has been set to “this” for app.js. Take a look at the main pieces of data you get from parsingallstations.json.

This is how you format the JSON.

The JSON From the Dev Console

For each station get the lat, lng, name, and abbreviation of the station. Then make a separate object and push it to an array. This is how you encode the coordinates for each station into hash strings.

Note that the extractHash method needs to use ngeohash. This is via the geoToHash method written below.

According to the wikipedia article on geohash, 4 characters gives a +/- 20km error. This should allow you to see multiple stations, which can be a few miles from each other. You now have all the station hashes stored asthat.hash_table. Let’s assume you found your user’s hash. Compare the two with this function.

User Hash and Map Locations

HTML5 has a geolocator built-in. This allows you to get the user’s location based on IP address.

If the browser has geolocation support then get the user’s current position. Assume your user is in the Bay area and spoof their location for testing purposes.

Import app.js to access the station data to display on the map.

Set local variables for the data.

Load PubNub and GoogleMaps

pubs() is called from line 130.

To get your unique pub/sub keys, you’ll first need to sign up for a PubNub account. Once you sign up, you can get your unique PubNub keys in the PubNub Developer Dashboard. Our free Sandbox tier should give you all the bandwidth you need to build and test your messaging app with the web messaging API.

gmap.js has been borrowed from one of the previous articles. The PubNub connection listens for coordinate messages sent to the channel “mymaps”. It then moves the user’s marker based on this information.


Note that GoogleMaps calls initialize(). This function adds properties to the map. The important part here is adding a marker for each hash_match.

Then add an event listener for info windows.


Searching for Train Times

You have covered the basics of displaying items on the map. The next question is how to add info on departure times. Go back to app.js. After calculating the hash_matches you would need to get data for each of the matches.

In this example only data for Millbrae has been saved. Use another ajax call on the Millbrae data.

This calls main_two, which formats the data and prepares it for GoogleMaps. This JSON is really deep and confusing. This is an example tree to get estimated departures.

Using this tree. Loop through the arrays and pull the relevant information.

Displaying Times

Go back to gmap.js. You need to loop through the different destination names. In this case “Millbrae” has been hard-coded but this could be a variable that tries to match abbreviations between “hash_matches” and “destinations” to display the relevant times.

Create a string for the destination times.

Specify the info window.


And that’s it! If you want more on realtime mapping and geolocation using mapping APIs like MapBox, MapKit and Google Maps, we’ve got a ton of other tutorials. Check them out!

Try PubNub Today

Share this on facebookShare this on TwitterShare this on Linkedin