We enhanced parameter interval counter with method=distinct. Now it is able to add to the interval (e.g. trip) a list of all unique geofences visited, BLE beacons detected or DTC codes reported.
Of course It will also work with other parameter that you may have in device message.

Check the details in this KB article covering these use cases.

Now it is possible to add to the interval in one calculator aggregated data from intervals of another calculator. You can do this by utilizing two new methods for calculator counters of type=”calc”: aggregate and aggregate_by_field:

  • aggregate” will aggregate all intervals into a single resulting object.
  • aggregate_by_field” will take the first defined field as a key and aggregate all intervals with the same key into a single resulting object. The output of that counter will be an array of stats per each encountered key.

Also for counter type=”calc” we enabled the usage of flespi expressions in fields configuration. This is available for all methods, not only for aggregation.

You can read more information about the usage of this new functionality in a related KB article describing the method how to calculate aggregated time spent daily in each geofence.

    19 days later

    flespi analytics system received new intervals processing engine. This may affect how calculator's intervals are detected in real-time - created, updated and deleted.

    We implemented a huge set of tests to ensure seamless upgrade of this engine however in such complex system as telematics analytics anything can go wrong.

    We expect that it should now process data from your devices better and detect more complex edge cases but if you notice something strange with intervals detection please contact us in HelpBox with all details to look into your case.

      8 days later

      We enabled recently added geofences in analytics.

      In order to activate them you need to assign geofences to the calculator either directly or via groups.

      You have 2 options to use geofences in calculators.

      Option 1

      Use them to select intervals instead of explicitly defined geofences in calculator configuration:

      Option 2

      You may access the status of the device relative to geofence in any expression within the calculator. We implemented 2 new functions that you may use:

      • geofence() - will return the name of the geofence with the highest priority device is in now or null otherwise.
      • geofences() - will return the array of names device is currently in now.

      You may enhance that usage by specifying other fields (or even a few fields) to return from the active geofence by using optional argument to these functions: geofence("metadata.max_speed") will return the maximum speed defined by geofence’s metadata.

      For example to detect over-speeding intervals based on the maximum speed defined in geofence’s metadata you may use the following interval selector configuration:

      Or if you want to count how much time vehicle moved above specified speed limit for the geofence you can use this inside interval counter as well:

      Keep in mind that this functionality is not available in non-automated on-demand analytics mode - e.g. when you calculate intervals using REST API.

        5 months later

        We enabled geofences assigned directly to devices in flespi analytics.

        So right now there are 3 variants how you can control geofences with calculators:

        • assign geofences to calculator either directly or indirectly via groups;
        • assign geofences to device;
        • specify geofences geometry directly in interval selector (only to detect entrance/exit by the selector);

        When you hit test current message with geofence() or geofences() function in calculators' expressions both geofences linked to the device and calculator are analyzed together, based on their actual priority and geometry.

        To simplify the setup we recommend to use in your flespi-based project one of these methods only. However if both device and calculator have linked geofences you will have a combined hit-test result in expressions. Later we may add to calculators the configurable selection of geofences source (device, calculator or both) if there will be appropriate demand.

        • Edited

        We adjusted the behavior of interval activated and deactivated events in flespi analytics.

        Now activated event will be additionally generated when active interval ID has changed. For previous interval if it had active status beforehand additional deactivated event will be generated correspondingly.

        For example if you configured calculator to control multiple adjacent geofences with the same name and device is immediately transitioning from zone1 to zone2. Earlier activated event would be skipped because device state for calculator was already active (it was in zone1). Now it will generate deactivated event for interval related to zone1 and activated event for new interval related to zone2.

        This makes notification systems on top of flespi analytics easier to setup with more straightforward binding to flespi/interval/gw/calcs/{calc-id}/devices/{device-id}/activated,deactivated topic for all most important events.

        We implemented 2 new functions to work with JSON arrays inside expressions:

        • json_array_contains(X, Y): will return true if array X contains value Y or false otherwise. For string values wildcards can be used as well. For example next expression will test if DTC codes reported by device contain any DTC code that starts from "P": json_array_contains(dtc.codes, "P*").
        • json_array_find(X, Y): will apply expression Y to each item in JSON array X and return first matched item or null otherwise. For example to fetch BLE beacon with specific ID defined in device's metadata it is possible to use next construction: json_array_find(ble.beacons, "id == '" + tostring(metadata("sensor_id")) + "'"). If device's metadata contains sensor_id with value "ABCD" the function call will be equivalent of: json_array_find(ble.beacons, "id == 'ABCD'"). It's important to format expression in argument Y correctly, en-quoting all strings.

        When applying these functions we suggest to use special tool to test your expression before using it in calculator or plugin configuration to avoid syntax mistake.

        These new functions can be used in any flespi subsystem: calculators, plugins, webhooks, stream validators, REST API calls. The most common areas of application are DTC codes, BLE beacons and any other array structure reported by devices or constructed with plugins.

        13 days later

        We enhanced the flespi analytics system with the possibility to access values located in the previous interval when calculating or validating the next one.

        This functionality is available via counter type=”interval” and validate_interval expression.

        There you may operate with values calculated by current interval counters and apply some logic mixing values calculated/stored in previous interval. You can access such values using the previous(“interval-counter-or-property”) call.

        For example, to know the difference between the end of previous interval and beginning of current interval you may use the counter of type=”interval” and expression: if(previous('end'), begin - previous('end'), 0).

        Or if you would like to prevent intervals creation within 1 hour from the end of the previous interval you may put into validate_interval the following expression: begin - previous('end') >= 3600.

        As a bonus and for really complex cases previous function will allow you to retrieve the data not only calculated by the counter by also attached to the interval via PUT /gw/calcs/{calc_id}/devices/{device_id}/intervals/{previous-interval-id} call. For example you may attach to some interval user data and subsequently copy its value to all further intervals until the next user-data. For example, for counter name=”datacache”, type=”interval” you may use the next expression: if(previous('userdata'), previous('userdata'), previous('datacache')) and attach to the interval custom value under 'userdata' key.

        2 months later
        a month later

        Now it is possible to include intervals from another calculator that happened before or after the current interval's time range. You can do this by utilizing two new parameters for calculator counters of type="calc": lookup_time_before and lookup_time_after.

        • lookup_time_before - specify how many seconds to look back before interval begin to search for intervals
        • lookup_time_after - specify how many seconds to look forward after interval end to search for intervals

        Both parameters can be set up to 10 days and work in conjunction with existing allow_start_before and allow_finish_after boolean flags. This allows for precise control over which intervals to include in calculations.

        This functionality is particularly useful for Hours of Service (HoS) calculations where you need to analyze cumulative driving time. For example, you can add to the current trip interval the combined driving time from all trips that happened within the last 7 days, helping to ensure compliance with driving time regulations.

        The parameters complement the existing aggregation capabilities of calc counters, allowing not only to combine intervals within the current time range but also to look beyond it when needed.

        16 days later

        New Aggregation Methods for Message Counter in Calculators

        We've enhanced the calculator counter of type "message" with two powerful aggregation methods:

        • aggregate - combines multiple messages into a single value with summated fields
        • aggregate_by_field - groups messages based on the first field, then aggregates them into single values per group

        These new methods are particularly useful for analyzing and summarizing device data by specific identifiers. For example, you can now easily track driver activity statistics:

        {
          "type": "message",
          "name": "driver_stats",
          "method": "aggregate_by_field",
          "fields": [
            "driver.id",
            {
              "name": "drive_time",
              "expression": "position.speed > 0 ? (timestamp - previous(\"timestamp\")) : 0",
              "aggregate": "summary"
            },
            {
              "name": "distance",
              "expression": "mileage()",
              "aggregate": "summary"
            },
            {
              "name": "trips_count",
              "expression": "position.speed > 0 && previous(\"position.speed\") == 0 ? 1 : 0",
              "aggregate": "summary"
            }
          ],
          "validate_message": "exists('driver.id')"
        }

        This configuration will:

        1. Group all messages by driver ID
        2. Calculate total driving time for each driver
        3. Sum up the distance traveled by each driver
        4. Count the number of trips initiated by each driver

        The resulting interval JSON will contain an array of objects, each representing a unique driver with their activity metrics:

        {
          "driver_stats": [
            {"driver.id": "D12345", "drive_time": 14520, "distance": 187.5, "trips_count": 5},
            {"driver.id": "D67890", "drive_time": 9360, "distance": 112.8, "trips_count": 3}
          ]
        }

        This enhancement makes it much easier to create meaningful summaries of data grouped by specific identifiers without requiring complex post-processing.

        18 days later

        We've improved recently introduced aggregate_by_field method in message and calc counters to preserve the original data types of aggregated values. Previously, all aggregated field values were converted to strings, but now they retain their original data types (numbers, booleans, etc.).

        Example:

        When aggregating messages by voltage with this counter configuration:

        {
          "fields": [
            {
              "aggregate": "first",
              "expression": "floor(external.powersource.voltage)",
              "name": "voltage"
            }
          ],
          "method": "aggregate_by_field",
          "name": "voltages",
          "type": "message"
        }

        Before: Values were converted to strings

        "voltages":[{"voltage":"15"},{"voltage":"13"},{"voltage":"14"},{"voltage":"12"}]

        After: Values maintain their original type (numeric in this case)

        "voltages":[{"voltage":15},{"voltage":13},{"voltage":14},{"voltage":12}]
        Write a Reply...