Open data platform of the swiss public transport

Posted in development on December 13, 2016 by Adrian Wyssmann ‐ 6 min read

The public transport organization SBB recently opened platform for customer information data on public transport in Switzerland. Anyone can obtain obtain data on public transport free of charge and get access to specific public transport services for all licensed transport companies in Switzerland. The platform provides timetable, real-time and actual data.

Checkout opentransportdata.swiss where you also can find a Cookbook, but which is currently available only in German. They implemented API VDV 431 is not a REST-API but rather uses simple POST request to get information. The current API allows

First you have to register yourself so you get access to the Developer Portal so you can generate the necessary API Key

First steps

Let’s try to do a TripRequest following the cookbook and let’s see what we get when we query for a trip between Bern and Luzern the 24.th of Dec. 2016 at 0900 departure time. Frist we need to get the correct DiDok ID for the station - I had a look in the published Excel. There are some things you need to consider

  1. The current implementation of SBB only supports direct connections
  2. You need to aggregate 850 in front of the Dst.Nr. found in the Excel sheet to get the correct DiDok ID
  3. Select the correct Stations

I was looking for a connection between Bern Hauptbahnof (ID 7786) and Luzern Bahnhof (ID 8450)

{{ < img caption=“VDK DiDok Bern - Luzern” src=“VDK-API_DiDok_BernHbf_LuzernBhf.png” >}}

Unfortunately this query returned and empty results which according to the Cookbook means no result found. Therefore I check the table again and find this:

{{ < img caption=“VDK DiDok Bern - Luzern” src=“VDK-API_DiDok_Bern_Luzern.png” >}}

So I actually have to take code 7000 (Bern) and 5000 (Luzern) for the query, which I place in a xml file for later usage:

<Trias version="1.1" xmlns="http://www.vdv.de/trias" xmlns:siri="http://www.siri.org.uk/siri" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ServiceRequest>
        <RequestPayload>
            <TripRequest>
                <Origin>
                    <LocationRef>
                        <StopPointRef>8507000</StopPointRef>
                    </LocationRef>
                    <DepArrTime>2016-12-24T09:00:00</DepArrTime>
                </Origin>
                <Destination>
                    <LocationRef>
                        <StopPointRef>8505000</StopPointRef>
                    </LocationRef>
                </Destination>
                <Params>
                    <IncludeTrackSections>true</IncludeTrackSections>
                    <IncludeLegProjection>true</IncludeLegProjection>
                    <IncludeIntermediateStops>true</IncludeIntermediateStops>
                </Params>
            </TripRequest>
        </RequestPayload>
    </ServiceRequest>
</Trias>

The I simply use curl to run my request.

curl -i -X POST https://api.opentransportdata.swiss/trias \
 -H "Content-Type: text/xml" \
 -H "Authorization:<yourapikey>"  \
 --data-binary "triprequest_bern_luzern.xml"

Which returns a result, displaying several trips (click on “Code” to see the full response):

<?xml version="1.0" encoding="utf-8"?>
<Trias xmlns="http://www.vdv.de/trias" version="1.1">
  <ServiceDelivery>
    <ResponseTimestamp xmlns="http://www.siri.org.uk/siri">2016-12-13T18:14:10Z</ResponseTimestamp>
    <Status xmlns="http://www.siri.org.uk/siri">true</Status>
    <MoreData>false</MoreData>
    <Language>de</Language>
    <DeliveryPayload>
      <TripResponse>
        <TripResult>
          <ResultId>ID-D502E685-CE95-46FC-8D22-E111C9AB856E</ResultId>
          <Trip>
            <TripId>ID-D502E685-CE95-46FC-8D22-E111C9AB856E</TripId>
            <Duration>60</Duration>
            <StartTime>2016-12-24T07:00:00Z</StartTime>
            <EndTime>2016-12-24T08:00:00Z</EndTime>
            <Interchanges>0</Interchanges>
            <TripLeg>
              <LegId>1</LegId>
              <TimedLeg>
                <LegBoard>
                  <StopPointRef>8507000</StopPointRef>
                  <StopPointName>
                    <Text>Bern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T07:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>1</StopSeqNumber>
                </LegBoard>
                <LegIntermediates>
                  <StopPointRef>0000132</StopPointRef>
                  <StopPointName>
                    <Text>Neubaustrecke</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>2</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502001</StopPointRef>
                  <StopPointName>
                    <Text>Zofingen</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T07:27:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T07:28:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>3</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502007</StopPointRef>
                  <StopPointName>
                    <Text>Sursee</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T07:40:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T07:41:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>4</StopSeqNumber>
                </LegIntermediates>
                <LegAlight>
                  <StopPointRef>8505000</StopPointRef>
                  <StopPointName>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T08:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <StopSeqNumber>5</StopSeqNumber>
                </LegAlight>
                <Service>
                  <OperatingDayRef>2016-12-24</OperatingDayRef>
                  <JourneyRef>odp:59010:Y:H::2509</JourneyRef>
                  <LineRef>odp:59010:Y:H</LineRef>
                  <DirectionRef>outward</DirectionRef>
                  <Mode>
                    <PtMode>rail</PtMode>
                    <RailSubmode>undefined</RailSubmode>
                    <Name>
                      <Text>InterRegio</Text>
                      <Language>DE</Language>
                    </Name>
                  </Mode>
                  <PublishedLineName>
                    <Text></Text>
                    <Language>DE</Language>
                  </PublishedLineName>
                  <OperatorRef>odp:11</OperatorRef>
                  <OriginText>
                    <Text></Text>
                    <Language>DE</Language>
                  </OriginText>
                  <DestinationStopPointRef>
                  8505000</DestinationStopPointRef>
                  <DestinationText>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </DestinationText>
                </Service>
                <LegTrack>
                  <TrackSection>
                    <TrackStart>
                      <StopPointRef>8507000</StopPointRef>
                      <LocationName>
                        <Text>Bern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackStart>
                    <TrackEnd>
                      <StopPointRef>8505000</StopPointRef>
                      <LocationName>
                        <Text>Luzern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackEnd>
                    <Duration>60</Duration>
                  </TrackSection>
                </LegTrack>
              </TimedLeg>
            </TripLeg>
          </Trip>
        </TripResult>
        <TripResult>
          <ResultId>
          ID-BF79A254-3299-438E-B16C-484FB318499F</ResultId>
          <Trip>
            <TripId>
            ID-BF79A254-3299-438E-B16C-484FB318499F</TripId>
            <Duration>60</Duration>
            <StartTime>2016-12-24T08:00:00Z</StartTime>
            <EndTime>2016-12-24T09:00:00Z</EndTime>
            <Interchanges>0</Interchanges>
            <TripLeg>
              <LegId>1</LegId>
              <TimedLeg>
                <LegBoard>
                  <StopPointRef>8507000</StopPointRef>
                  <StopPointName>
                    <Text>Bern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T08:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>1</StopSeqNumber>
                </LegBoard>
                <LegIntermediates>
                  <StopPointRef>0000132</StopPointRef>
                  <StopPointName>
                    <Text>Neubaustrecke</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>2</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502001</StopPointRef>
                  <StopPointName>
                    <Text>Zofingen</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T08:27:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T08:28:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>3</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502007</StopPointRef>
                  <StopPointName>
                    <Text>Sursee</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T08:40:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T08:41:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>4</StopSeqNumber>
                </LegIntermediates>
                <LegAlight>
                  <StopPointRef>8505000</StopPointRef>
                  <StopPointName>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T09:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <StopSeqNumber>5</StopSeqNumber>
                </LegAlight>
                <Service>
                  <OperatingDayRef>2016-12-24</OperatingDayRef>
                  <JourneyRef>odp:59010:Y:H::2511</JourneyRef>
                  <LineRef>odp:59010:Y:H</LineRef>
                  <DirectionRef>outward</DirectionRef>
                  <Mode>
                    <PtMode>rail</PtMode>
                    <RailSubmode>undefined</RailSubmode>
                    <Name>
                      <Text>InterRegio</Text>
                      <Language>DE</Language>
                    </Name>
                  </Mode>
                  <PublishedLineName>
                    <Text></Text>
                    <Language>DE</Language>
                  </PublishedLineName>
                  <OperatorRef>odp:11</OperatorRef>
                  <OriginText>
                    <Text></Text>
                    <Language>DE</Language>
                  </OriginText>
                  <DestinationStopPointRef>
                  8505000</DestinationStopPointRef>
                  <DestinationText>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </DestinationText>
                </Service>
                <LegTrack>
                  <TrackSection>
                    <TrackStart>
                      <StopPointRef>8507000</StopPointRef>
                      <LocationName>
                        <Text>Bern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackStart>
                    <TrackEnd>
                      <StopPointRef>8505000</StopPointRef>
                      <LocationName>
                        <Text>Luzern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackEnd>
                    <Duration>60</Duration>
                  </TrackSection>
                </LegTrack>
              </TimedLeg>
            </TripLeg>
          </Trip>
        </TripResult>
        <TripResult>
          <ResultId>ID-865B5E11-48EB-4B53-86DF-840BF60FF903</ResultId>
          <Trip>
            <TripId>ID-865B5E11-48EB-4B53-86DF-840BF60FF903</TripId>
            <Duration>60</Duration>
            <StartTime>2016-12-24T09:00:00Z</StartTime>
            <EndTime>2016-12-24T10:00:00Z</EndTime>
            <Interchanges>0</Interchanges>
            <TripLeg>
              <LegId>1</LegId>
              <TimedLeg>
                <LegBoard>
                  <StopPointRef>8507000</StopPointRef>
                  <StopPointName>
                    <Text>Bern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T09:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>1</StopSeqNumber>
                </LegBoard>
                <LegIntermediates>
                  <StopPointRef>0000132</StopPointRef>
                  <StopPointName>
                    <Text>Neubaustrecke</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>
                    1970-01-01T00:00:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>2</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502001</StopPointRef>
                  <StopPointName>
                    <Text>Zofingen</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T09:27:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T09:28:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>3</StopSeqNumber>
                </LegIntermediates>
                <LegIntermediates>
                  <StopPointRef>8502007</StopPointRef>
                  <StopPointName>
                    <Text>Sursee</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T09:40:00Z</TimetabledTime>
                  </ServiceArrival>
                  <ServiceDeparture>
                    <TimetabledTime>2016-12-24T09:41:00Z</TimetabledTime>
                  </ServiceDeparture>
                  <StopSeqNumber>4</StopSeqNumber>
                </LegIntermediates>
                <LegAlight>
                  <StopPointRef>8505000</StopPointRef>
                  <StopPointName>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </StopPointName>
                  <ServiceArrival>
                    <TimetabledTime>2016-12-24T10:00:00Z</TimetabledTime>
                  </ServiceArrival>
                  <StopSeqNumber>5</StopSeqNumber>
                </LegAlight>
                <Service>
                  <OperatingDayRef>2016-12-24</OperatingDayRef>
                  <JourneyRef>odp:59010:Y:H::2513</JourneyRef>
                  <LineRef>odp:59010:Y:H</LineRef>
                  <DirectionRef>outward</DirectionRef>
                  <Mode>
                    <PtMode>rail</PtMode>
                    <RailSubmode>undefined</RailSubmode>
                    <Name>
                      <Text>InterRegio</Text>
                      <Language>DE</Language>
                    </Name>
                  </Mode>
                  <PublishedLineName>
                    <Text></Text>
                    <Language>DE</Language>
                  </PublishedLineName>
                  <OperatorRef>odp:11</OperatorRef>
                  <OriginText>
                    <Text></Text>
                    <Language>DE</Language>
                  </OriginText>
                  <DestinationStopPointRef>
                  8505000</DestinationStopPointRef>
                  <DestinationText>
                    <Text>Luzern</Text>
                    <Language>DE</Language>
                  </DestinationText>
                </Service>
                <LegTrack>
                  <TrackSection>
                    <TrackStart>
                      <StopPointRef>8507000</StopPointRef>
                      <LocationName>
                        <Text>Bern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackStart>
                    <TrackEnd>
                      <StopPointRef>8505000</StopPointRef>
                      <LocationName>
                        <Text>Luzern</Text>
                        <Language>DE</Language>
                      </LocationName>
                    </TrackEnd>
                    <Duration>60</Duration>
                  </TrackSection>
                </LegTrack>
              </TimedLeg>
            </TripLeg>
          </Trip>
        </TripResult>
      </TripResponse>
    </DeliveryPayload>
  </ServiceDelivery>
</Trias>

{{ < img caption=“SBB Trip Bern - Luzern” src=“SBB_Trip_Bern_Luzern-2.png” >}} So let’s examine the first trip and see what information we have:

Duration: 60 StartTime: 2016-12-24T07:00:00Z EndTime: 2016-12-24T08:00:00Z Interchanges = 0 Arrival   at "Neubaustrecke": 1970-01-01T00:00:00Z Departure at "Neubaustrecke": 1970-01-01T00:00:00Z Arrival   in Zofingen:        2016-12-24T07:27:00Z Departure in Zofingen:        2016-12-24T07:28:00Z Arrival   in Sursee:          2016-12-24T07:40:00Z Departure in Sursee:          2016-12-24T07:41:00Z Arrival   in Luzern:          2016-12-24T08:00:00Z

When looking at the dates, I assume the entry with “Neubaustrecke” we can ignore, as they are not really a stop but rather just information where the train passes trough. The times are returned in Zulu time, which is expected. But what I was actually expecting is the trips concerning the “Departure time” around 0900 as entered in the tag DepArrTime. Unfortunately this is not clearly specified and the documentation only mentions that tag DepArrTime refers to “Departure or Arrival time” but I can nowhere specify whether the time in tag DepArrTime is actually the “Arrival” or the “Departure” time. However, when I cross-check the information with the official timetable, I actually can see the same information.

Conclusion

The provided data is impressive, as you do not only have timetable information but also information regarding stations (train stations, bus stops … and its location).  The provided API - even so the API is limited and does not implement all features of the related standard - offers interested Developers to use the service to provide their own application while accessing accurate data. Really hats off for so much openess!

What is VDV-431

opentransportdata.swiss is referring to VDV-432 so I was wondering what this is. The VDV is an abbreviation for “Verband Deutscher Verkehrsunternehmen” (Association of German Transport Companies) and has a long history which goes back to 1846 as you can read on their page. The association organises  the more than 600 public transport companies in Germany.

It advises and supports its member companies and politicians, supports the exchange of experience and know-how between the members and prepares technical, operational, legal and economic principles

One of these technical principles is the project "IP-KOM-ÖV. This project defines concepts and architectures to provide IP-based communication platform for public transports using standardized ways. These concepts and architectures have been written down in the VDV documents which VDV-431 is one of them and is a a standard for real-time communication and information platform (Echtzeit Kommunikations- und Auskunftsplattform EKAP)¨.