Combining 3 transport APIs for one info screen

Last year, I blogged about how I turned an old eReader into an Information Screen.

I've since updated the display to show me three different sets of transport information.

An eInk screen which is displaying the times until the next bus, what delays there are on the tube, and then a bunch of train departure times.

At a glance, I can see the next bus, whether there are delays on the Elizabeth Line, and if my regular trains are running.

Here's how all three APIs work.


The bus is the easiest one of all. Transport for London (TfL) have a set of free APIs. No registration required!
You will need to know the ID of your local bus stop. Visit the TfL bus search page and search for your local stop. Click the stop on the map.

You'll be taken to a URl like - that will show you the Bus Stop ID (technically the NaPTAN ID). In this case 490000173RF.

You can then call this API: - which will return JSON like this:

    "$type": "Tfl.Api.Presentation.Entities.Prediction, Tfl.Api.Presentation.Entities",
    "id": "-119695796",
    "operationType": 1,
    "vehicleId": "LTZ1049",
    "naptanId": "490000173RF",
    "stationName": "Oxford Circus Stn  / Margaret Street",
    "lineId": "12",
    "lineName": "12",
    "platformName": "RF",
    "direction": "outbound",
    "bearing": "152",
    "destinationNaptanId": "",
    "destinationName": "Dulwich Library",
    "timestamp": "2023-06-29T10:40:18.3147535Z",
    "timeToStation": 1470,
    "currentLocation": "",
    "towards": "Trafalgar Square Or Green Park",
    "expectedArrival": "2023-06-29T11:04:48Z",
    "timeToLive": "2023-06-29T11:05:18Z",
    "modeName": "bus",
    "timing": {
        "$type": "Tfl.Api.Presentation.Entities.PredictionTiming, Tfl.Api.Presentation.Entities",
        "countdownServerAdjustment": "-00:00:02.7011995",
        "source": "2023-06-29T07:28:52.918Z",
        "insert": "2023-06-29T10:40:01.313Z",
        "read": "2023-06-29T10:39:58.591Z",
        "sent": "2023-06-29T10:40:18Z",
        "received": "0001-01-01T00:00:00Z"
}, {
    "$type": "Tfl.Api.Presentation.Entities.Prediction, Tfl.Api.Presentation.Entities",
    "id": "-1460579610",
    "operationType": 1,
    "vehicleId": "LTZ1447",
    "naptanId": "490000173RF",
    "stationName": "Oxford Circus Stn  / Margaret Street",
    "lineId": "12",
    "lineName": "12",

Hopefully the entity names are self-explanatory. If you need a specific route, you will need to filter on the lineId's value.

Personally, I use timeToStation to see how long until the bus arrives. If it's less than a couple of minutes, I don't display it.


Again, I am overjoyed that TfL have a free API which lets you check the status of various tube lines.

The Elizabeth Line's status can be found at - can you guess the URl for the other lines 😉?

And, again, we get back some fairly self-explanatory JSON:

    "$type": "Tfl.Api.Presentation.Entities.Line, Tfl.Api.Presentation.Entities",
    "id": "elizabeth",
    "name": "Elizabeth line",
    "modeName": "elizabeth-line",
    "disruptions": [],
    "created": "2023-06-27T12:37:57.107Z",
    "modified": "2023-06-27T12:37:57.107Z",
    "lineStatuses": [{
        "$type": "Tfl.Api.Presentation.Entities.LineStatus, Tfl.Api.Presentation.Entities",
        "id": 0,
        "lineId": "elizabeth",
        "statusSeverity": 9,
        "statusSeverityDescription": "Minor Delays",
        "reason": "Minor delays between Stratford and Shenfield due to a an earlier signal failure at Tottenham Court Road. GOOD SERVICE on the rest of the line. ",
        "created": "0001-01-01T00:00:00",
        "validityPeriods": [{
            "$type": "Tfl.Api.Presentation.Entities.ValidityPeriod, Tfl.Api.Presentation.Entities",
            "fromDate": "2023-06-29T10:30:50Z",
            "toDate": "2023-06-30T00:29:00Z",
            "isNow": true
        "disruption": {
            "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities",
            "category": "RealTime",
            "categoryDescription": "RealTime",
            "description": "Minor delays between Stratford and Shenfield due to a an earlier signal failure at Tottenham Court Road. GOOD SERVICE on the rest of the line. ",
            "affectedRoutes": [],
            "affectedStops": [],
            "closureText": "minorDelays"
    "routeSections": [],
    "serviceTypes": [{
        "$type": "Tfl.Api.Presentation.Entities.LineServiceTypeInfo, Tfl.Api.Presentation.Entities",
        "name": "Regular",
        "uri": "/Line/Route?ids=Elizabeth line&serviceTypes=Regular"
    "crowding": {
        "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities"

You can grab the text out of there for easy display.

Train Times

This is the only pain-in-the-arse service. It uses National Rail's Live Departure Boards Web Service (LDBWS). This is an XML SOAP API which requires credentials.

Register for an API token at National Rail's site.

Find the three letter CRS code for your departure and arrival station on the National Rail website.

I use the GetDepBoardWithDetailsHeader() API call. For example: GetDepBoardWithDetails(20, "WWA", "LBG", "to") gets the next 20 trains from Woolwich Arsenal to London Bridge.

There are OpenLDBWS libraries available in most major programming languages. Don't bother writing your own!

There's more discussion online about how to test and use OpenLDBWS.

Once you've got a response, you can filter it for the specific trains you're interested in.

Putting it all together

Well, that's up to you Sparky! Personally, I have a hodge-podge of PHP building it into a format suitable for my ancient eInk screen. You can do what you like!

Share this post on…

2 thoughts on “Combining 3 transport APIs for one info screen”

  1. says:

    This looks like a lightweight version (hacked together) of MagicMirror. I wonder if it would be feasible to have a proper project, with near as much features as MagicMirror, but for ancient devices. Most of the processing would need to be done on the server. Maybe an alternative would be a lightweight UI for Home Assistant, as the modern lovelace UI can be too heavy and too modern for ancient browsers.


What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">