Mobility On-Demand Technical Solution Paper

Post Dropoff Processing

After the ride is complete, you can implement a number of processes, such as reviewing the driver/passenger, leaving comments, and payment, depending on your business mdoel. For the payment step, you might want to find out exactly which route the driver took, and whether or not he incurred any toll costs along that route.

The typical workflow for determining what route a driver took and checking for additional toll costs is as follows:
  • Match the GPS trace recorded by your driver app and sent to your backend with the route.
  • Calculate toll cost for route.
The figure below illustrates the elements in the workflow related to the HERE services.
Figure 1. Request Details On Performed Drive Request Details On Performed Drive

Determining Route Taken by Driver

To determine the route the driver took:

  1. Using data retrieved from tracking the driver's location as he or she was driving, assemble those location updates into a trace file. Currently the supported formats are: CSV, GPX and NMEA.
  2. Send a POST request to the resource matchroute in the Route Match Extension API with the following parameters and the assembled trace:
    • routemode with the value car to indicate the route was taken by a car

    The response contains a list of the RouteLinks the driver used, as well as a list of Warnings that can alert you of any potentially incorrect driving behavior, such as U-turns where they are not allowed, going in the wrong direction on a one-way street.

    The sample code below demonstrates how to transform a log of GPS position into a GPX file and upload it to the Route Matching Extension:
    const https = require('https');
    const _ = require('lodash');
    const builder = require('xmlbuilder');
    
    /**
     * This function transforms a gps track into GPX format
     *
     * gpsLog  Array of position updates
     */
    function buildGpx(gpsLog) {
      // Create <gpx version="1.1"> root element
      var xml = builder.create('gpx').att('version', '1.1');
      // Create <trk><trkseg>...</trkseg></trk> tags
      var segment = xml.ele('trk').ele('trkseg');
      gpsLog.forEach(element => {
        // Create <trkpt lat=X lon=Y><time>Z</time></trkpt> tags within trkseg element
        segment.ele('trkpt', { 'lat': element.lat, 'lon': element.lon }).ele('time', {},
        element.timestamp);
      });
      // Convert xml to string
      var xmlString = xml.doc().end();
      return Promise.resolve(xmlString);
    }
    
    /**
     * Builds a POST request for the Route Matching Extension API.
     * 
     * routeMode  The routing mode ('car' or 'pedestrian')
     */
    function buildMatchRouteRequestOptions(routeMode) {
      var requestParams = _({
                  'routemode': routeMode,
                  'app_id': {YOUR_APP_ID},
                  'app_code': {YOUR_APP_CODE}
                }).map((value, key) => {
                  return key + '=' + encodeURIComponent(value);
                }).join('&');
      return {
        method: 'POST',
        hostname: 'rme.cit.api.here.com',
        path: ['/2/matchroute.json', requestParams].join('?')
      };
    }
    
    /**
     * Calls the Route Matching Extension API to match a GPX trace to links in the HERE data
     * See buildMatchRouteRequestOptions for an explanation of the parameters
     */
    function matchGpx(routeMode, gpx) {
      return new Promise((fulfill, reject) => {
        var options = buildMatchRouteRequestOptions(routeMode);
        var req = https.request(options, (res) => {
          var data = "";
          res.on('data', (d) => {
            data += d;
          });
          res.on('end', () => {
            var json = JSON.parse(data);
            if(res.statusCode >= 400) {
              reject(new Error(data));
            }
            else
            {
              var links = [];
              if(json.RouteLinks) {
                links = json.RouteLinks.map(link => link.linkId);
              }
              fulfill(links);
            }
          })
        });
        req.write(gpx);
        req.on('error', (err) => {
          reject(err);
        });
    
        req.end();
      });
    }
    
    // Example GPS log as recorded by tracking solution
    const berkeleyToSf = [
      {"timestamp": "2016-05-19T00:15:39", "lat": 37.870018333, "lon": -122.270135000},
      {"timestamp": "2016-05-19T00:15:45", "lat": 37.870003333, "lon": -122.270240000},
      ...
      {"timestamp": "2016-05-19T00:48:15", "lat": 37.779980000, "lon": -122.404860000}
    ];
    
    buildGpx(berkeleyToSf)
      .then(gpx => matchGpx('car', gpx))
      .then(console.log)
      .catch(console.error);
    /** Output:
      [ -798712120,
        23665445,
        1152950609,
        921170882,
        ... ]
     */
  3. Check the resulting list of RouteLinks the driver used to see the route followed.

For more information, see the API Reference.

Calculating Route Costs

Using the previously retrieved RouteLinks from the Route Match Extension API, calculate any toll cost the driver paid in order to correctly compensate them for those costs.

To calculate the potential toll costs:

  1. Specify a driven route using a list of link ids specified by the linkId attribute of the RouteLinks previously provided by the Route Match Extension API.
  2. Concatenate these link ids, using a semicolon (;) as separator.
  3. Send a request to the resource tollcost in the Toll Cost Extension API with the following query parameters:
    • currency 3 characters (ISO 4217) currency code for the currency used in the response (for instance USD).
    • route Concatenated semicolon-separated string containing all link ids along the route.
    • start_ts Start timestamp of the route.
    • vspec with the characteristics of the vehicle: tollVehicleType, trailerType, trailersCount, vehicleNumberAxles, trailerNumberAxles, hybrid, emissionType, height, trailerHeight, vehicleWeight, limitedWeight, disabledEquipped, minimalPollution, hov, passengersCount, tiresCount, commercial, shippedHazardousGoods, heightAbove1stAxle.

      For instance, 2;0;0;2;0;0;5;167;0;1739;1739;0;0;0;4;0;0 with the 4 being the number of passengers.

  4. Use the detailed costs associated with each toll structure the route passes through in the response to calculate the total toll cost incurred by the driver.
The sample code below shows how to use the Toll Cost Extension API to request the toll cost:
const https = require('https');
const _ = require('lodash');

/**
 * Builds a GET request for the tollcost.json endpoint of the Toll Cost Extension API.
 * The tollcost.json endpoint return detailed toll cost information associated with
 * given linkids
 * 
 * mode     The routing mode (e.g. 'fastest;car;traffic:enabled')
 * currency   The currency in which to return toll cost information
 *        (three-letter code, e.g. 'USD')
 * vspec    A string describing the vehicle's attributes. See the Toll Cost Extension's
 *        API Reference for more information on this parameter
 * links    An array of link ids that were traversed as part of the route
 *        (in order of traversal)
 */
function buildTollCostLinksRequestOptions(mode, currency, vspec, links) {
    var requestParams = _({
                            'mode': mode,
                            'vspec': vspec,
                            'currency': currency,
                            'route': links.join(';'),
                            'app_id': {YOUR_APP_ID},
                            'app_code': {YOUR_APP_CODE}
                        }).map((value, key) => {
                            return key + '=' + encodeURIComponent(value);
                        }).join('&');
    return {
        method: 'GET',
        hostname: 'tce.cit.api.here.com',
        path: ['/2/tollcost.json', requestParams].join('?')
    };
}

/**
 * Calls the Toll Cost Extension API to calculate toll costs associated with given links
 * See buildTollCostLinksRequestOptions for an explanation of the parameters
 */
function costForLinks(mode, currency, vspec, links) {
    return new Promise((fulfill, reject) => {
        var options = buildTollCostLinksRequestOptions(mode, currency, vspec, links);
        var req = https.request(options, (res) => {
            var data = "";
            res.on('data', (d) => {
                data += d;
            });
            res.on('end', () => {
                if(res.statusCode >= 400) {
                    reject(new Error(data));
                }
                else
                {
                    var json = JSON.parse(data);
                    fulfill(json);
                }
            })
        });
        req.on('error', (err) => {
            reject(err);
        });

        req.end();
    });
}

// Routing mode (fastest car route accounting for traffic)
var mode = 'fastest;car;traffic:enabled';
// The currency to use for the Toll Cost Extension
var currency = 'USD';
// Number of passengers
var numPassengers = 1;
// Vehicle specification, refer to TCE documentation for format information
var vehicleSpec = '3;0;0;2;0;0;6;350;0;10000;10000;0;0;0;'+numPassengers+';8;0;0';
// Array of links along the route
var route = [748873330, 68614309, 17357322, 748938713, 76719821, 17357323]

costForLinks(mode, currency, vehicleSpec, route)
    .then(console.log)
    .catch(console.error);
/** Output:
  {
    "errors": [
      
    ],
    "warnings": [
      
    ],
    "countries": [
      {
        "name": "FRA",
        "roadSectionsCosts": [
          {
            "linksIds": [
              748938713,
              76719821
            ],
            "conditions": [
              {
                "time": null,
                "pass": null,
                "currency": "EUR",
                "methodsOfPayment": 151,
                "daylightHours": 2,
                "discountAvailable": 0,
                "tollSystemsIds": "5016",
                "amount": 7.5
              }
            ],
            "tollStructures": [
              {
                "linkId1": 748938713,
                "linkId2": 76719821,
                "name": "LE TOURNEAU",
                "lngCode": "FRE",
                "latitude": 47.9931,
                "longitude": 2.67762,
                "tollStructureConditionId": 703489345
              }
            ]
          }
        ],
        "adminAdmissionCosts": null,
        "usageFeeRequiredLinks": {
          "linksIds": [
            748873330,
            68614309
          ],
          "conditions": null,
          "tollStructures": [
            {
              "linkId1": 748873330,
              "linkId2": 68614309,
              "name": "FLEURY-EN-BIERE",
              "lngCode": "FRE",
              "latitude": 48.42819,
              "longitude": 2.5403,
              "tollStructureConditionId": 55877247
            }
          ]
        },
        "tollSystemsNames": [
          {
            "id": 5016,
            "names": [
              {
                "languageCode": "ENG",
                "name": "APRR"
              }
            ]
          }
        ]
      }
    ],
    "onError": false
  }
*/

For more information, see the API Reference.

You cannot use this account to purchase a commercial plan on Developer Portal, as it is already associated to plans with different payment methods.

To purchase a commercial plan on Developer Portal, please register for or sign in with a different HERE Account.

Something took longer than expected.

The project should be available soon under your projects page.

Sorry, our services are not available in this region.

Something seems to have gone wrong. Please try again later.

We've detected that your account is set to Australian Dollars (AUD).
Unfortunately, we do not offer checkouts in AUD anymore.
You can continue using your current plan as normal, but to subscribe to one of our new plans,
please register for a new HERE account or contact us for billing questions on selfservesupport@here.com.