OTP supports dynamic bike rental/bike sharing systems like Bixi. Station location and availability data is loaded on the fly from the various APIs. OTP does not recheck bike availability (make a web-request to an external page) every time someone makes an OTP request; instead we use a component that will periodically run updater modules listed in its Spring configuration. This updater component has an updateFrequency property which (if unspecified) defaults to 5 minutes. Updater modules will be run once at OTP startup, then at the specified frequency thereafter.
To use it, edit your application-context.xml in opentripplanner-api-webapp (in /org/opentripplanner/api/), adding a periodicGraphUpdater bean declaration before the closing tag:
<bean id="periodicGraphUpdater" class="org.opentripplanner.api.servlet.PeriodicGraphUpdater"> <property name="updateFrequency" value="[some number of milliseconds]" /> <property name="updaters"> <list> <bean class="org.opentripplanner.updater.bike_rental.BikeRentalUpdater"> <property name="bikeRentalDataSource"> <bean class="org.opentripplanner.updater.bike_rental.KeolisRennesBikeRentalDataSource"> <property name="url" value="[some URL]" /> </bean> </property> <property name="routerId" value="[this property is optional, but allows multiple graphs to be used with bike rental]" /> </bean> </list> </property> </bean>
If your config XML already defines a periodic updater component to fetch GTFS-realtime updates, you can just add the bike rental updater module to the existing "updaters" list.
If OTP cannot reach the bike rental API or the response data is corrupted, it generally interprets this as there being no new information available. Bike rental stations and availability information are then left as they were after the last successful update.
There are different bike rental providers, you need to tell OTP which type of feed you're providing. We support three bike rental APIs at present:
For example, if you want to use City Bikes, just change the class and URL above like so:
If your city's bike rental API is anything like Bixi or Keolis, it's trivial to add support for it by writing a new subclass.
If your city's bike rental API is like Velib (with a separate query needed for availability data, for no good reason), I would recommend simply not providing any availability data and assuming that all stops are available for pickup/dropoff. We haven't implemented Velib as apparently the people who run it get cranky when people use their API.
Realtime availability is only used for trips planned for times near now anyway; for future trips, we assume that everything is available.
You can also enable static bike rental data from OSM at graph build time, if you prefer. Just set the
staticBikeRental property on
true, and OTP will do the rest:
<bean id="osmBuilder" class="org.opentripplanner.graph_builder.impl.osm.OpenStreetMapGraphBuilderImpl"> <property name="staticBikeRental" value="true" /> ... </bean>
OTP gather bike rental stations from OSM nodes labelled as
amenity=bicycle_rental. Bicycle shops are sometimes wrongly labelled using this tag (they should use
shop=bicycle instead). Please check/correct local OSM data if needed.
OTP will also use OSM tags
operator (a comma-separated list of network operator(s)) to prevent renting and dropping off the same bike in two incompatible networks. Two bike-rental stations are considered compatible if they share at least one operator/network. (The meaning of both tags is not well determined in the OSM community, so we use both tags). OTP will not include OSM bike rental stations with no network defined, but the graph builder will print a warning if it drop a station. In the case this value is not set, please check/correct your OSM data.
When building your graph, you can also describe a bike rental system's fare structure. Here's an example:
<bean class="org.opentripplanner.graph_builder.impl.FareServiceGraphBuilderImpl" id ="fareBuilder"> <property name="service"> <bean class="org.opentripplanner.routing.bike_rental.TimeBasedBikeRentalFareService"> <property name="currency" value="USD" /> <property name="pricing"> <list value-type="java.lang.String"> <value>30:00,0</value> <value>1:00:00,200</value> <value>24:00:00,9400</value> </list> </property> </bean> </property> </bean>
This says that trips 30 minutes or less are free; trips of an hour or less cost $2, and trips less than 24 hours cost $94. Later, we'll probably add support for cost-per-minute systems.