Transport NSW / Sydney Bus, Ferry and Train schedule

There’s multiple platforms that can be used. The main issue is Gosford - I could be going North or South from there and it’s not necessarily a specific platform either. And it’s the same line/route.

I live near a station on the northern line and used this API to make a departure board a couple of months ago. I would have used this but I rolled my own without a component (you can use my example if you’re not too confident with custom components or don’t want to specify a route).

I used a few rest sensor to get departure times for all departures from my station:

- platform: rest
  resource: https://api.transport.nsw.gov.au/v1/tp/departure_mon?outputFormat=rapidJSON&coordOutputFormat=EPSG%3A4326&mode=direct&type_dm=stop&name_dm=10101200&departureMonitorMacro=true&TfNSWDM=true&version=10.2.1.42
  name: "nexttraina"    
  headers:
    Accept: application/json
    Authorization: apikey InsertAPIKeyHere
  value_template: '{{value_json.stopEvents.x.departureTimeEstimated}}'   

Where x = 0, 1, 2, 3, 4, 5

Then I made a few more sensors to get the platform ID:

  - platform: rest
    resource: https://api.transport.nsw.gov.au/v1/tp/departure_mon?outputFormat=rapidJSON&coordOutputFormat=EPSG%3A4326&mode=direct&type_dm=stop&name_dm=10101200&departureMonitorMacro=true&TfNSWDM=true&version=10.2.1.42
    name: "wheretraina"    
    headers:
      Accept: application/json
      Authorization: apikey InsertAPIKeyHere 
    value_template: '{{value_json.stopEvents.x.location.id}}' 

Where x = 0, 1, 2, 3, 4, 5

Then I made a very ugly looking automation for each of those trains:

  - alias: Build T1 message
    hide_entity: False
    trigger:
      platform: time
      seconds: '/20'
    action:
      - service: mqtt.publish
        data:
          topic: "/trains/1"
          payload_template: "{% if is_state('sensor.wheretraina', '2114171') %}(To City){% elif is_state('sensor.wheretraina', '2114172') %}(To City){% elif is_state('sensor.wheretraina', '2114173') %}(To Epping){% elif is_state('sensor.wheretraina', '2114174') %}(To Epping){% endif %} {% if (((as_timestamp(states.sensor.nexttraina.state) - as_timestamp(utcnow()) )  | float * 0.0167) | round(0) ) | float <= 0.0 %}Just left{% else %}{{ ((as_timestamp(states.sensor.nexttraina.state) - as_timestamp(utcnow()) )  | float * 0.0167) | round(0) }} min {% endif %}"

I know it looks confusing, but it’s just checking which platform the next train is, giving it a ‘friendly’ name and then tacking on the minutes to departure. The <0 is because trains get ‘sticky’ in my experience and sometimes go into 3-5 minutes of negative minutes until departure until the StopEvents list is updated, so I just replace it with a “Just Left”.

The result is my departure board:

Capture

I can see the platform from my computer so I can confirm that the timing is spot on. When I’m at the station and comparing it to the official departure boards it’s within 10 seconds. I then use google home to activate a script and it reads out my next train departures to me.

Does anybody have an idea on how I could split it up to only show departures, say, to the city? I can’t split by platform as the trains leave from both, but mostly one of them. I’m not really advanced enough to know about arrays and iterating through JSON values until a match is found (i.e. only display StopEvents 1, 3, 5 and 6 based on a platform match).

2 Likes

Great component @DownUnder, I just found it when trawling the forum. I set it up last night and is working great.

The stop I am at has multiple lines that service the city, L70, 270, 271, 273, 274. Is there anyway to group all these into one sensor or front end to only show the next bus overall rather than having to add multiple sensors?

Oh, and one more which I think may be a little much :slight_smile: Can you add the bus “fullness” for want of a better term. On Tripview and the websites it shows how many seats are filled (icon for one, two or three seats depending on how full the bus is)

Many thanks for your great work!

Cheers

See my post above. You can do it without this component.

If the GTFS data has the fullness (which I’m pretty sure most do), you can extract it from the JSON data.

1 Like

I’ve been configuring up this new component, and i have hit a bit of a snag, which maybe only applicable in my particular circumstance.

I note there are 4 configurable values.

stop_id & route (which are relevant in this case) and api_key and name

The problem I face is with the way the ferries work here on Sydney Harbour. The route always remains the same and the stop id is always the same regardless of which direction the ferry is heading.

So i can’t just display ferries heading to circular quay, and i won’t know which direction the ferry is heading.

If i put in a stop_id: 10102008 for Balmain Wharf

This all works fine, and lets me know how many minutes prior to the ferry arriving.
Unfortunately, unlike the train platforms that have stop_id: that only travels in one direction, the stop_id: 10102008 travels in 2 different directions. For example, towards the city and away from the city.
So i don’t seem to have a way to define or filter which direction the countdown timer is referring to.

if i define a route as ‘F8 Cockatoo Island’ thats fine, but that covers ferries heading in both directions

so i went to the nsw transport api site
https://opendata.transport.nsw.gov.au/node/601/exploreapi#!/default/tfnsw_dm_request

and put the stop_id: 10102008 in, and the returns do actually give me a little more data than i am able to define in my sensor

So some values i have that i can see that are unique, but not configurable are as follows
for example
destination": “name”: “Circular Quay”,
or
description “Circular quay to Cockatoo Island”

seem to be unique and would indicate the direction of travel, even though the stop id and route are the same for both returns

Perhaps a solution could lie in having a configurable value of “destination” that could be integrated into the sensor for transport_nsw ?

Or could someone think of another way to achieve what i’m after?

transport api response paste as below against stop_id: 10102008 showing 2 trips, returning same stop_id and same route, but heading in different directions

{
“version”: “10.2.1.42”,
“systemMessages”: [],
“locations”: [
{
“id”: “10102008”,
“name”: “Balmain Wharf, Balmain”,
“disassembledName”: “Balmain Wharf”,
“coord”: [
-33.85475,
151.18611
],
“type”: “stop”,
“matchQuality”: 100000,
“isBest”: false,
“parent”: {
“id”: “95333002|1”,
“name”: “Balmain”,
“type”: “locality”
},
“assignedStops”: [
{
“id”: “10102008”,
“name”: “Balmain Wharf”,
“type”: “stop”,
“coord”: [
-33.85475,
151.18611
],
“parent”: {
“name”: “Balmain”,
“type”: “locality”
},
“modes”: [
9
],
“connectingMode”: 100
}
]
}
],
“stopEvents”: [
{
“location”: {
“id”: “20413”,
“isGlobalId”: true,
“name”: “Balmain, Balmain Wharf”,
“type”: “platform”,
“coord”: [
-33.85456,
151.18627
],
“parent”: {
“id”: “10102008”,
“name”: “Balmain, Balmain Wharf”,
“disassembledName”: “Balmain Wharf”,
“type”: “stop”,
“parent”: {
“id”: “95333002|1”,
“name”: “Balmain”,
“type”: “locality”
}
}
},
“departureTimePlanned”: “2018-10-27T01:36:00Z”,
“transportation”: {
“id”: “nsw:090F8: :R:sj2”,
“name”: “Sydney Ferries Netwo F8 Cockatoo Island”,
“disassembledName”: “F8”,
“number”: “F8 Cockatoo Island”,
“iconId”: 10,
“description”: “Cockatoo Island to Circular Quay”,
“product”: {
“class”: 9,
“name”: “Sydney Ferries Netwo”,
“iconId”: 9
},
“operator”: {
“id”: “112”,
“name”: “Sydney Ferries”
},
“destination”: {
“name”: “Circular Quay”,
“type”: “stop”
},
“properties”: {
“tripCode”: 57,
“mtSubcode”: “0”
},
“origin”: {
“name”: “Cockatoo Island Wharf”,
“type”: “stop”
}
},
“hints”: [
{
“content”: “At low tide ramp gradients increase. Wheelchair assistance may be required.”
}
],
“properties”: {
“WheelchairAccess”: “true”,
“RealtimeTripId”: “nsw-9-F8- -sj2-3-16-AB53”,
“PlanLowFloorVehicle”: “1”,
“PlanWheelChairAccess”: “1”
}
},
{
“location”: {
“id”: “20413”,
“isGlobalId”: true,
“name”: “Balmain, Balmain Wharf”,
“type”: “platform”,
“coord”: [
-33.85456,
151.18627
],
“parent”: {
“id”: “10102008”,
“name”: “Balmain, Balmain Wharf”,
“disassembledName”: “Balmain Wharf”,
“type”: “stop”,
“parent”: {
“id”: “95333002|1”,
“name”: “Balmain”,
“type”: “locality”
}
}
},
“departureTimePlanned”: “2018-10-27T01:57:00Z”,
“transportation”: {
“id”: “nsw:090F8: :H:sj2”,
“name”: “Sydney Ferries Netwo F8 Cockatoo Island”,
“disassembledName”: “F8”,
“number”: “F8 Cockatoo Island”,
“iconId”: 10,
“description”: “Circular Quay to Cockatoo Island”,
“product”: {
“class”: 9,
“name”: “Sydney Ferries Netwo”,
“iconId”: 9
},
“operator”: {
“id”: “112”,
“name”: “Sydney Ferries”
},
“destination”: {
“name”: “Cockatoo Island”,
“type”: “stop”
},
“properties”: {
“tripCode”: 10,
“mtSubcode”: “0”
},
“origin”: {
“name”: “Circular Quay”,
“type”: “stop”
}
},
“hints”: [
{
“content”: “At low tide ramp gradients increase. Wheelchair assistance may be required.”
}
],
“properties”: {
“WheelchairAccess”: “true”,
“RealtimeTripId”: “nsw-9-F8-
-sj2-3-10-AA51”,
“PlanLowFloorVehicle”: “1”,
“PlanWheelChairAccess”: “1”
}
},

Hi Peter,

I will test it and might have to fix the sensor. Will let you know once i have done some testing.

Cheers

Works a treat now with ‘Destination’ Home assistant V83.1

transport_nsw

1 Like

Hello! incredible your project. Thanks for sharing it.

  • Do you think there is an API key for public transport timetables in Italy?
  • Can I use the same transport_nsw.py for a configuration in Italy?
    Thank’s!

@DavidFW1960 Thanks for the template, I expanded it slightly:

- platform: template
sensors:
trainmonitor_eleven:
  friendly_name_template: >-
    Platform 11 - {{ states.sensor.gosfordkariong.attributes.destination }}
  value_template: >-
    {% if is_state_attr('sensor.gosfordkariong', 'due', 'n/a') %}
      No schedule found
    {% else %}
      {% if (states.sensor.gosfordkariong.attributes.due > 60) %}
        {{ (states.sensor.gosfordkariong.attributes.due/60)|round }}hr
      {% else %}
        {{ states.sensor.gosfordkariong.attributes.due }}m (Next {{ states.sensor.gosfordkariong.attributes.next_due }}m)
      {%- endif %}
    {% endif %}
  entity_picture_template: >-
    {{ '/local/icons/' + states.sensor.gosfordkariong.attributes.line_name + '_train_img.png' }}

I’ve changed the py file slightly to get the next train as well, but will write a cleaner version to share over the next few days as I suspect there is a way we can reference the stops as follows:

{{states.sensor.gosfordkariong.attributes.next_train[0]}}'

Hello! Do you think there is even a way for Italian timetables? Could you please include them?

given this is written against an Australian state Government website, there will be only NSW transport info in this system.

You might be able to rework the python against an Italian system - should one exist?

probably exists but I’m not an expert in programming.

It does only work for NSW Australia as the underlying API only provides that data. You have to write different components for any new data source IF there is a public API available.

So, there is NO support for Italian transport and I also have no idea if it is even possible. Sorry, maybe someone comes up with a new sensor in the future.

Hi guys, this is still working?

Thanks!

Yes working fine

I was having problem but I solve it. There is a integration page on home-assistant.io if anyone else is interested!

Thanks david

I notice that the delay time can be seen on sites like AnyTrip, is it possible to retrieve the current eta as opposed to the scheduled eta?
I wish to track country trains which can be delayed significantly.

it reports due and a delay in the sensor
image
image

Thanks, I only just created this integration & the two trains I was watching today both had a delay of zero even though one was over 30 minutes late the other ontime.

However, now the delays are showing correctly for the next two trains.

Hey there, I am fairly new at this and I am having some trouble with getting this setup. I have the following configurations in my sensors file but I am being presented with n/a for all responses.

I wonder if anyone can assist with this?

- platform: transport_nsw
  name: Next train
  stop_id: "201710"
  destination: "Central Station"
  route: "Airport & South Line"
  api_key: !secret trip_planner_api