Scripted Trip & Idle Report with geofences

Trip and idling data can now be combined with tools available in Event Rules for use in Event Rule reports.

In this example, we will create a report that shows the total duration of a trip, time, and a total idling duration time within periods spent outside a geofence.

  • For a scripted Trip and Idle report with parking status, check this guide instead.


Being familiar with creating reports and using Script Expressions in Event Rules.

Trip/Idling in Script Expressions

Trip and Idling data is a part of reporting data available only if you set the Event Rule that you want to use it into Disabled. This way, the rule is not evaluated in live mode, but you can still generate reports for it.


In the Expressions section, add a Script Expression and edit it. The new report object can be used to access trip and idle information.


Click on elements of the “report” object in the “Exposed objects and test values” panel to see additional information (same goes for other items in the panel).

This new data could be used to regenerate a Trip & Idle-like report through events. This script would include:

  • creating events using
  • reporting the current duration by

    context.setVariable(report.tripIdle.previousState, report.tripIdle.duration);
  • ending the events on trip/idle state change by

    if (report.tripIdle.hasChanged) context.endEvent(report.tripIdle.previousState);

However, the key power of the newly available data is in combining it with the rest of the tools available in Script Expressions.

Example: Trip/Idling While Outside Geofences

Let us say that we want to collect the total duration of trip time and a total of duration idle time within periods spent outside a Geofence, and also track the time that has passed from the previous event.
This can be done using the script below. See the comments in the script to see what it does and why.

// skip possible invalid track points at the start and the end of the track
if (report.tripIdle.state == 'sleep') return false;
// shorthand aliases for current track point data
var lo = trackPoint.position.longitude;
var la = trackPoint.position.latitude;
var moving = trackPoint.velocity.speed > 0;
var utc = trackPoint.utcTimestamp.getTime(); // timestamp as a number in miliseconds
// acquire the state from previous message or initialize it for the first eligible message
var st = context.state || { prevActive: false, prevUtc: utc, duration: {run: 0, idle: 0, sleep: 0, off: 0} }
// time difference in seconds between this and previous track point
var diff = (utc - st.prevUtc)/1000;
// inside will be true if within the coordinates of a geofence in tag “tag1”
// for best performance, it is recommended to create a single tag for this purpose
// that will contain all eligible geofences
var inside = geofence.find(lo, la, "tag1").length > 0;
// should the event be active now?
// yes if not within a geofence
// or if the vehicle is back in the geofence but is still moving.
// i.e. only end the event when it stops there.
var active = !inside || (st.prevActive && moving);
// the calculation of period duration actually depends on the activity in the previous message.
// this is so that when a period ends with a current message,
// we can pick up the final time difference between the previous and that message,
// and add it to total duration of the finished period.
if (st.prevActive == false) {
  // previously inactive?
  // add the time difference between this and previous message
  // to the "off" duration counter only. += diff;
  // keep run and idle values at 0 as they are not calculated inside geofence. = 0;
  st.duration.idle = 0;
  // update the value of the "OFF" variable to be used in a report argument.
  // format() will put the number of seconds into time format (hh:mm:ss)
  context.setVariable('OFF', format(, 'SHORT_TIME_SPAN', false));
else {
  // previously active?
  // add the time difference between this and previous message
  // to the appropriate duration counter. the value used as index below,
  // "report.tripIdle.previousState", will be either 'run' or 'idle', depending
  // on whether the previous message belongs to a trip or idle segment.
  st.duration[report.tripIdle.previousState] += diff;
  // keep the "off" duration at 0, as it is only counted when the event is inactive. = 0;
  // update the values of "IDLE" and "RUN" variables to be used in report arguments.
  context.setVariable('IDLE', format(st.duration.idle, 'SHORT_TIME_SPAN', false));
  context.setVariable('RUN', format(, 'SHORT_TIME_SPAN', false));
// save the rest of the relevant current data to state
// to have it available for the next message
st.prevActive = active;
st.prevUtc = utc;
// save the state
// turn the event on/off depending on value of active
return active;


You may wish to remove the comments before saving the rule so as not to exceed the maximum allowed length of the script.

In the Notifiers section, add Report Argument notifiers corresponding to event variables set from the script, like in the picture below.


Using $FINAL(), we can correctly pick up the value of the variables set from the script even if they were set during an evaluation in which the event was switched off.

Now save the rule, and run the default “Event Rule” report for this rule.
The result should look something like this.


Additional Notes

  • You can use report.tripIdle.useParkedVariable(strVarName) at the beginning of a script to specify a mapped field that will be interpreted as an “Ignition” or “Engine” variable and further split the “idle” state into “idling” (stopped with the engine running) and “parked” (stopped with the engine off) states.
  • When testing the script from the editor using the Test Script button, enter the exact UTC time of an existing track point for the user selected in the vehicle list into the trackPoint.utcTimestamp field in the editor. For the test run, values in the report object should represent the expected values at that track point.