GitHub - adamjames/busmap: A live UK bus (and aircraft) map

5 min read Original article ↗

UK Bus Map

A screenshot at ground level, showing buses

Features

  • Near-real time bus map covering the UK.
  • Optional street-level routing predictions based on OpenStreetMap data (via secondary container.)
  • Optional live aircraft overlay (you'll need a source of ADSB data)
  • Distinct icons courtesy of tar1090, and aircraft route data from ADSB.lol
  • Client behaviour adjustment based on zoom level & vehicle volume. Geolocation, following, orientation.
  • Early affordances for small screens, like the ability to minimise UI elements.
  • Client-level and global rate limits to discourage malicious use.
  • Back-end API gateway for BODS/OSRM/ADSB/Cap requests, for protection of sensitive data.
  • Hosting in Docker via Tailscale Funnel, to make deployment on commodity hardware easy.
  • .env environment configuration (mostly - some internal stuff still needs cleaning up!)

This project uses data from UK Bus Open Data Service (BODS) to produce a near real-time map. The raw API provides point-to-point updates. Self-hosted OpenStreetMap integration enhances this with street-level routing, animated through linear interpolation.

I also track aircraft, so I added those in too. Look up!

An instance of this application is (sometimes) live at https://busmap.tail5c8e3.ts.net/.

How? Why?

I'm just a sucker for visualising real-time data that reflects the real world. I've long thought about it, but finally put some time in to make a cool thing, I guess!

The content of the earliest commit was outlined over a couple of sleepless weekends in December of 2015, and Claude was used heavily early on.

I was asked by some friends to publish the code after early demos, so I've reluctantly done so in spite of it being a bit of an AI fever dream. My intent now is to improve on what exists by hand - I've seen what happens when Claude is asked to "improve" things. Way too much boilerplate. Unlike that early software, this was written entirely manually. <3

A few days work has already gone into polish, and a few hours into prepping this for release. There are still plenty of rough edges, though. Caveat emptor.

Licence, attributions & thanks

This "weekend" project was only possible because others are solving harder problems and choosing to publish their software under open licences.

My thanks to anyone whose support got things off the ground, and to those whose GPL contributions undoubtedly fed the LLM that saved my hands from drudgery.

The following people and projects get a special mention for one reason or another:

This project is hereby licenced under the GPLv3, the full text of which can be found in LICENSE.md (misspelt for Github) or online at https://www.gnu.org/licenses/gpl-3.0.txt.

Relevant licence information has been collated below on a best-effort basis. Feel free to contact me if needed.

Third-party projects & commercial services

Name Service Type Licence URL
OpenStreetMap Routing Machine (OSRM) Routing Engine BSD 2-Clause Link / Image
Cap Standalone CAPTCHA Engine (Back-end) Apache-2.0 Docs / Github
Tailscale VPN Service Mixed (Client: BSD 3-Clause, Service: Commercial) Open Source / Client
Unpkg NPM CDN MIT, Community Github
tar1090 Aircraft Tracking Visualisation GPL v2 or later Github
ADS-B.im Probably the easiest turnkey RTLSDR-ADSB feeder around Community Project Website
ADS-B.lol Provide a great REST API to contributors Community Project Website
SDR Enthusiasts Ultrafeeder ADS-B Data Collection & Feeding GPL-3.0 Github

Software dependencies

Python

Name Version Licence Licence URL
defusedxml 0.7.1 Python Software Foundation Licence Link
Flask 3.1.2 BSD-3-Clause Link
python-dotenv 1.2.1 BSD-3-Clause Link
requests 2.32.5 Apache-2.0 Link

JavaScript

Name Version Licence Licence URL
Leaflet 1.9.4 BSD 2-Clause Link
Leaflet.markercluster 1.5.3 MIT Link
tar1090 markers.js N/A GPL v2 or later Link
Cap.js N/A Apache-2.0 Link

Can I use it myself?

Sure!

Cap Captcha

You may want to set a Cap key, to (somewhat, maybe) protect against use of your BODS API key by bots:

  1. Launch in docker with docker compose --profile public up -d --build
  2. Open http://localhost:3000 in browser
  3. Log in with the admin key (default: changeme, or whatever you set CAP_ADMIN_KEY to in .env)
  4. Click "Create Site Key" in the dashboard
  5. Copy the Key ID and Secret it generates
  6. Add to .env:
   CAP_KEY_ID=<the key id>
   CAP_KEY_SECRET=<the secret>
   CAP_URL=http://cap:3000
   CAP_PUBLIC_URL=http://<your-tailscale-hostname>:3000 

OSRM (Optional)

You may want an OSRM instance, for routing. First you need to preprocess the map data (one-time, ~30min for UK). Make a docker-compose.yml file:

 # You will want this *not* on an RPi, at least not yet.
 osrm:
   image: osrm/osrm-backend
   container_name: osrm
   restart: unless-stopped
   ports:
     - "5001:5000"
   volumes:
     - osrm-data:/data
   command: osrm-routed --algorithm mld /data/great-britain-latest.osrm

Then, alongside that file, make a folder and prepare the container:

   mkdir -p osrm-data && cd osrm-data
   wget https://download.geofabrik.de/europe/great-britain-latest.osm.pbf
   docker run -t -v $(pwd):/data osrm/osrm-backend osrm-extract -p /opt/car.lua /data/great-britain-latest.osm.pbf
   docker run -t -v $(pwd):/data osrm/osrm-backend osrm-partition /data/great-britain-latest.osrm
   docker run -t -v $(pwd):/data osrm/osrm-backend osrm-customize /data/great-britain-latest.osrm

docker compose up -d should now start the container.

To test it: curl localhost:5001/5001/route/v1/driving/-0.0877,51.5079;-0.0900,51.5100?geometries=geojson"

Should give you something like:

   {"code":"Ok","routes":[{"geometry":{"coordinates":[[-0.087641,51.507892],[-0.088322,51.506128],[-0.089951,51.504807],<snip>

In the primary docker-compose.yml, extra-hosts needs mitre:10.0.0.120 swapping to wherever you are hosting OSRM, to allow the container to communicate with it.

Environment

Now, set up the variables in .env.example (as .env)

Run

Launch in Docker with docker compose up -d --build for local access only, or docker compose --profile public up -d --build to include Tailscale and Cap for public access.