How to calculate aggregated time spent daily in each geofence?

Using advanced intervals aggregation capabilities to solve non-trivial tasks with flespi calculators.

One of the common tasks in telematics is geofencing. And together with notification about entering/exit the geofence by a vehicle, one of the most popular tasks there is to calculate aggregated information about geofences visits.

For example you have zones: A, B, C, D, …, Z. And you want to calculate during the day or the trip how much time you spent in each geofence, how many kilometers driven, how many stops you made there and finally how much time you spend outside of all geofences.

This task can be easily solved with flespi calculators. The information about the status of the vehicle in the current trip or day will be updated in real time, with each new reported point. And you can even easily render it using the MQTT Tiles dashboard.

The general algorithm for the data flow will be the following:

  • Calculator A will calculate detailed information about each geofence visit including mileage and time spent.

  • Calculator B will aggregate this information and provide daily statistics for each geofence.

First you need to set up geofences control. Geofences in flespi can be controlled either with a msg-geofence plugin which will add geofence information to each message or using geofence selector in the calculator. In both ways to perform aggregation you have to calculate each geofence independently with one calculator and use a second calculator that will provide aggregated data.

For simplicity and cost control (plugins cost money, while calculators are included in each plan for free) lets define all geofences in the Calculator A directly.

The configuration of Calculator A is simple. You use a selector of type geofence, set there a number of geofences and provide each geofence a name. We will aggregate information in Calculator 2 by that name and this is up to you to make the geofence name unique or let it be shared (e.g. class of geofences) between multiple. 

After you defined geofences in the selector, you will need two counters: one to report a name of geofence and another to calculate mileage spent:

Here is counters configuration JSON that you may copy to your calculator:

  "counters": [
    {
      "expression": "mileage()",
      "method": "summary",
      "name": "mileage",
      "type": "expression"
    },
    {
      "name": "zone",
      "type": "geofence"
    }
  ],

The configuration and output of this calculator is pretty straightforward. If you assign device to it and look into intervals generated by such calculator you will see detailed information about visited geofence including duration of stay and the mileage:

Typical interval JSON produced by the calculator will look the following way:

{"begin":1713507363,"duration":908,"end":1713508271,"id":14961,"mileage":3.706391,"timestamp":1713539022.552774,"zone":"Zone C"}

OK, now is the most interesting task. You see that on the same day there are a lot of visits to zones B and C. How to aggregate this data per day?

To solve this task we will create Calculator B with daytime selector (split intervals by day) and will add to it a few counters of type=”calc” to reference intervals generated by Calculator A for the same device.

The counters configuration of this interval is the following (remember to replace calc_id with ID of your Calculator A):

"counters": [
    {
      "calc_id": 1692207,
      "fields": [
        "zone",
        {
          "name": "duration",
          "aggregate": "summary"
        },
        {
          "name": "mileage",
          "aggregate": "summary"
        },
        {
          "aggregate": "summary",
          "expression": "1",
          "name": "count"
        }
      ],
      "method": "aggregate_by_field",
      "name": "zones",
      "type": "calc"
    }
  ],

Method “aggregate_by_field” will take the value of the first defined field and aggregate all intervals with the same first field value (zone in our case) separately, providing combined stats for each zone about mileage, time spent and how many visits occurred.

The output of interval for the day in Calculator B will contain array of all visited zones and total duration and mileage per each zone:

{"begin":1713560402,"end":1713581572,"duration":21170,"zones":[{"zone":"Zone C","duration":4911,"mileage":21.025169,"count":6},{"zone":"Zone B","duration":2651,"mileage":21.384594,"count":6}], "timestamp":1713581576.154436,"id":14991}

And how to calculate time outside of all geofences in the day?

This can be implemented with 2 more counters in Calculator B. One counter with type=”calc" will perform total aggregation to have time spent in all zones in a single value. And another counter with type=”interval” will perform extra calculation of time outside of all geofences using all data that is available in the interval.

Here is the final configuration JSON for counters of Calculator B:

 "counters": [
    {
      "calc_id": 1692207,
      "fields": [
        "zone",
        {
          "aggregate": "summary",
          "name": "duration"
        },
        {
          "aggregate": "summary",
          "name": "mileage"
        },
        {
          "aggregate": "summary",
          "expression": "1",
          "name": "count"
        }
      ],
      "method": "aggregate_by_field",
      "name": "zones",
      "type": "calc"
    },
    {
      "calc_id": 1692207,
      "fields": [
        {
          "aggregate": "summary",
          "name": "duration"
        },
        {
          "aggregate": "summary",
          "name": "mileage"
        }
      ],
      "method": "aggregate",
      "name": "total_in_zones",
      "type": "calc"
    },
    {
      "expression": "duration - total_in_zones[\"duration\"]",
      "name": "duration_outside_of_zones",
      "type": "interval"
    }
  ],

The selector of Calculator B of course can be of any type, for example it can detect trips. In that case you may aggregate some per-trip data like visited geofences or any other information calculated by another calculator. With powerful flespi expressions which you can use inside fields and validate_interval configuration options of calculator's counter you can do really complex aggregations and calculations.


See also
Define virtual geographic boundaries that can be flexibly linked to plugins, streams, calculators, and device groups to enable powerful location-based rules and notifications.
Adding information about BLE beacons, DTC codes or visited geofences to the calculator's interval JSON?