How it works? Learn more about the API

telematics sdk location drive analytics

Features in TL KIT



Using patented AI connectivity and analytics, we enable you to wirelessly stream vehicle telematics data without the hassle of physical connectors. The smartphone provides a low cost, widely available platform to collect, evaluate and optimize driving behaviors that is on par with dedicated hardware solutions.

Drive Detection & Recording

Detect starts, stops and record all your routes

Fleet Management Solution

Get going with your own branded mobile workforce solution

Activity Recognition

Distinguish between stationary, pedestrian and driving activities

Always-on Location

Receive position updates 24/7 with minimal battery usage

Runs in the background

Keep working hands-free, no user interaction required

Driving Behavior Scoring & Analytics

Easily transform telematics data into driver scoring and analytics

Minimal battery impact

High-end features delivered over a low-power footprint

Data stream enablement SDKs

Allow your app to seamlessly collect and provision telematics data

Mobile Platform Consistency

Ensure features are consistent between Android & iOS

Crash Detection

When accidents happen, know the when, where and how

context kit SDK location awareness
Products
Telematics SDK for rich driver behavior analytics

Context Kit Telematics SDK supports apps to automatically detect the start of a drive, and accurately monitors the driving behavior from any smart phone. Our patented telematics and sensor fusion technology allows reliable drive-data collection with minimal battery impact. The rich telematics data will be pre-computed on the device and uploaded into our backend, allowing for data analytics and comprehensive driver-risk scoring.

Data points gathered include:

  • Start: date, time, place
  • Braking
  • Acceleration
  • Turning
  • End: date, time, place
  • Direction: North, East, South, West
  • Route
Driver Behavior Analytics App

Features:


Automatic Drive Detection SDK

Features:

Do you have an app that would benefit from accurately detecting that your users are driving, what time of day and to where?

Extracting this location and time data from from different devices using different platforms is difficult, costly and typically consumes a lot of battery power.

Tourmaline Labs has created a product called ContextKit DriMa (Driving Matters), providing a sophisticated and elegant solution.

ContextKit DriMa provides SDK APIs to receive location and drive information:
  • after the start of a ride (backdated to the startpoint of the ride)
  • after the end of a ride (backdated to the start­ and endpoint of the ride)
  • with route information, including date and time travelled


Drive Detection App
Always on Location SDK

Features:

You think location matters? We think so too! Apps often rely on location information to the benefit of the user experience. However, retrieving location data comes at a price - typically it comes with heavy battery consumption. Regardless of the brand and model of the device, minimizing location sampling while providing accurate positioning is difficult, time-consuming, and costly to develop.

Tourmaline Labs created a product called ContextKit LoMa (ContextKit Location Matters) providing a solution at a fraction of the cost.

ContextKit LoMa provides SDK APIs to receive location information
  • upon request
  • at specified time intervals
  • once a predefined distance has been travelled
  • once a predefined time interval has passed with no movement

Why us and not native location API?

Our SDK is always on, and consumes a fraction of the battery power compared to other products. Power consumption is minimized by using our patent pending sensor calibration. Benefit from our analysis tool and get insights into your user data.


Always On Location SDK
Activity Recognition SDK

Features:

Automatically recognize and record any driving, walking and periods of no movement done by your users. This ultra low power consumption tool is ready to be integrated in your app. View start and end times; place, duration and route for each activity. The SDK is always on, so there’s no need to start and stop it. End users of your app will benefit from enhanced activity recognition and location data features.

Data points gathered include:
  • Start: date, time, and place
  • End: date, time, and place
  • Route taken

How it works:

Our patent pending technology detects activities within moments of beginning. Setting the smartphone in motion triggers the accelerometer sensors built in the device and the SDK starts recording the activity right away. When the activity ends, the SDK falls back to hibernation waiting to be reawoken. Activity-detection information and location sampling will enable functions and services within your own app.

Why our SDK?

Our SDK is always on, provides accurate, reliable data, and consumes 80% less battery power compared to other products. You can benefit from our analysis tool and get insights into your user data.

Use case: Fleet management

The ContextKit SDK is the perfect hardware-free, easy-to-integrate solution for fleet management. The ready to use SDK can be integrated in any iPhone or Android app and is ready to operate. Driving activities are automatically recognized and accurate data is uploaded to the backend. This phone based solution helps maximize your vehicle efficiency. Safer, more efficient driving means less miles, less fuel and less downtime. Know where your workers are located for effective work order management. Boost ROI with better utilization, improved security and maintenance.



Technology Approach

Artificial Intelligence and Sensor Fusion

  • Which sensor should we use to learn what?
  • How noisy is the data, are the sensors calibrated?
  • Which sensor chipset is used, how is it different?
  • Which sensor to use, when and for how long?
  • How much power is consumed by each sensor?
  • How to detect vehicle vs. phone motion?
telematics platform model

Performance: Phone vs. OBDII Dongle

We compared mobile phone telematics data (from our SDK) with OBDII dongle data.

Test setup

  • Phones: 13 different Android smartphones & iPhones 5 and 6
  • App / SDK: Betterways App (available on Goggle-play and Itunes)
  • Dongle: OBDII
  • Vehicles: 9 different vehicles (Ford F150, Sprinter Van, Volvo S40, Range Rover HSE etc).
  • Phone positions: cup holder, center concoul, passenger seat, glove box, pockets etc (normal user behavior simulation)
  • Miles: 6,000 miles with 5 drivers in cities & highways
phone data vs OBDII

Test results

Accuracy Threshold < 0.06g < 0.1g
Phone vs. Hardware 95.3% 98.0%
Phone vs. Phone 98.6% 99.1%
phone data vs OBDII test results

API

Getting started with TLKit for iOS

Integrating TLKit framework into a project

Install TLKit using CocoaPods

We recommand installing TLKit using CocoaPods, which provides a simple dependency management system that automates the error-prone process of manually configuring libraries. First make sure you have CocoaPods installed (you will also need to have Ruby installed):

sudo gem install cocoapods
pod setup
			

Now create an empty file in the root of your project directory, and name it Podfile or just run the following command:

pod init
			

Open and edit the Podfile as follow:

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/tourmalinelabs/iOSTLKitSDK.git'

platform :ios, '9.0'

use_frameworks!

pod 'TLKit'
...
            

Finally, save and close the Podfile and run pod install to setup your CocoaPods environment and import TLKit into your project. Make sure to start working from the .xcworkspace file that CocoaPods automatically creates, not the .xcodeproj you may have had open.

That’s it! You can start coding!

Using TLKit

The heart of the TLKit is the Context Engine. The engine needs to be initialized with a registered user in order to use any of its features.

Registering and authenticating users.

TLKit needs to be initialized in order to use any of its features and starting TLKit requires passing an CKAuthenticationManagerDelegate instance to the engine which handles authenticating against the TL Server.

In a production environment authentication should be done between the Application Server and the TLKit server. This will prevent the API key from being leaked out as part of SSL proxying attack on the mobile device. See the Data Services api on how to register and authenticate a user.

For initial integration and evaluation purposes or for applications that do not have a server component we the CKDefaultAuth class which will provide registration and authentication services for the TL Server.

Initialization with the CKDefaultAuth is covered in the next section.

Starting, Stopping CKContextKit

An example of initializing the engine with the CKDefaultAuth is provided here:

#import 
...

[CKContextKit initWithApiKey:@"bdf760a8dbf64e35832c47d8d8dffcc0"
                             authMgr:[[CKDefaultAuth alloc]
                                 initWithApiKey:API_KEY
                                         userId:USERNAME
                                           pass:PASSWORD]
                       launchOptions:nil
                   withResultToQueue:dispatch_get_main_queue()
                         withHandler:^(BOOL successful, NSError *error) {
                             if (error) {
                                 NSLog(@"Failed to start TLKit with error: %@",
                                     error);
                                 return;
                             }
                         }];

CKContextKit attempts to validate permissions and see other necessary conditions are met when initializing the engine. If any of these conditions are not met it will fail with an error that can be used to debug the issue.

One example of where a failure would occur would be location permissions not being enabled for the application.

Once initialized there is no reason to destroy the engine unless you need to set a new CKAuthenticationManagerDelegate for a different user or password. In those cases, the engine can be destroyed as follows:

CKContextKit can be destroyed as follows:

[CKContextKit destroyWithResultToQueue:dispatch_get_main_queue()
                           withHandler:^(BOOL successful, NSError *error) {
                            if (error) {
                                NSLog(@"Stopping Contextkit Failed: %@", 
                                    error);
                                return;
                            }
                            NSLog(@"Stopped ContextKit!");
                        }];

Pre-authorize Location Manager access

CKContextKit utilizes GPS as one of it’s context sensor. As such it is best practice to request “Always” authorization from the user for accesssing location prior to initializing the engine.

Monitoring API

By default monitoring is disabled when the Engine is initialized. It needs to be explicitly enabled to track drives and locations. Enabling is done as follows:

CKContextKit.isMonitoring = YES;

Monitoring can be disabled at any time as follows:

CKContextKit.isMonitoring = YES;

If monitoring is enabled at any point during a drive that drive will be recorded.

Drive Monitoring

Drive monitoring functionality is accessed through the CKActivityManager

self.actMgr = [CKActivityManager new];

Starting, Stopping drive monitoring

Register a listener with the drive monitoring service as follows:

[self.actMgr 
    startDriveMonitoringToQueue:dispatch_get_main_queue()
                    withHandler:^(CKActivityEvent *evt, NSError * err) {
                                // Update UI
                                [weakSelf updateDataSource];
                                NSLog(@"Drive event: %@", evt);
                              }];

Note: multiple drive events may be received for the same drive as the drive progresses and the drive processing updates the drive with more accurate map points.

Drive events can be stopped as follows:

[self.actMgr stopDriveMonitoring];

Querying previous drives

Once started all drives will be recorded for querying either by date:

#import 
...

[self.actMgr queryDrivesFromDate:[NSDate distantPast]
                          toDate:[NSDate distantFuture]
                       withLimit:100
                         toQueue:dispatch_get_main_queue()
                     withHandler:^(NSArray *drives, NSError *error) {
                         if (!error) {
                             NSLog(@"Got drives: %@", drives);
                         }
                     }];

or by id:

NSUUID *driveId = ...;
[actMgr queryDriveById:driveId
               toQueue:dispatch_get_main_queue() 
           withHandler:^(NSArray *drives, NSError *err) {
               if (!error) {
                   NSLog(@"Found drive %@", drives[0]);
               }
           }];

Getting started with TLKit for Android

Integrating TLKit into a project

Add the TLKit library to a gradle project as follows:

repositories {
    maven{ url 'https://raw.githubusercontent.com/tourmalinelabs/AndroidTLKitSDK/master'}
}

Modify the build.gradle file as follows:

Add libs as a repository

Add the SDK as a dependency as well as it’s dependencies.

dependencies {
    compile "com.tourmalinelabs.android:TLKit:7.0.17032300@aar"

    compile 'com.android.support:appcompat-v7:25.3.0'
    compile 'com.google.android.gms:play-services-base:8.1.0@aar'
    compile 'com.google.android.gms:play-services-location:8.1.0'
}

Add user permissions to the manifest

Add the following the following permissions to the Manifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
....
</manifest>

Using TLKit

The heart of the TLKit is the Context Engine. The engine needs to be initialized with a registered user in order to use any of its features.

Registering and authenticating users

TLKit needs to be initialized in order to use any of its features and starting TLKit requires passing an AuthMgr instance to the engine which handles authenticating against the TL Server.

In a production environment authentication should be done between the Application Server and the TLKit server. This will prevent the API key from being leaked out as part of SSL proxying attack on the mobile device. See the Data Services api on how to register and authenticate a user.

For initial integration and evaluation purposes or for applications that do not have a server component we the DefaultAuthMgr class which will provide registration and authentication services for the TL Server.

Initialization with the DefaultAuthMgr is covered in the next section.

Initializing and destroying the engine

An example of initializing the engine with the DefaultAuthMgr is provided here:

Engine.Init( getApplicationContext(),
             ApiKey,
             new DefaultAuthMgr( this,
                                ApiKey,
                                "example@tourmalinelabs.com",
                                "password"),
             new CompletionListener() {
                 @Override
                 public void OnSuccess() { Engine.Monitoring(true); }

                 @Override
                 public void OnFail( int i, String s ) {}
             } );

Once initialized there is no reason to destroy the Engine unless you need to set a new AuthMgr for a different user or password. In those cases, the engine can be destroyed as follows:

Engine.Destroy(getApplicationContext(), 
               new CompletionListener() {
                    @Override
                    public void OnSuccess() {
                        Log.d(TAG, "Engine destroyed.");
                    }
                    @Override
                    public void OnFail( int i, String s ) {
                        Log.e(TAG, "Engine destruction failed.");
                    }
             });

Listening for Engine state changes

In addition to the completion listeners the engine also locally broadcasts lifecycle events which can be subscribed to via the Engine.ACTION_LIFECYCLE action as shown below.

LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this);
mgr.registerReceiver(
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent i) {
                int state = i.getIntExtra("state", -1);
                if (state == Engine.INIT_SUCCESS) {
                    Log.w(TAG, "Registering listeners on eng start");
                    tryToRestart = false;
                } else if (state == Engine.INIT_FAILURE) {
                    // Handle case of failure after the app is killed
                    // and restarted by the OS
                    String msg = i.getStringExtra("message");
                    int reason = i.getIntExtra("reason", 0);
                    if(!tryToRestart) {
                        Log.i( TAG,"Engine is trying to restart.");
                        tryToRestart = true;
                        StartEngine( );
                    } else {
                        Log.e( TAG, "Engine start KO after trying"
                               + " to restart -> nothing to do");
                        tryToRestart = false;
                    }
                    Log.w(TAG, "Eng start failed eng w/ reason "
                            + reason + ": " + msg);
                }
            }
        },
        new IntentFilter(Engine.ACTION_LIFECYCLE));

It is recommended to use this intent to register any listeners with the engine. This is because in event of an unexpected application termination the lifecycle registered listeners will be lost. When the engine automatically restarts with the app the intent will be the only notification that the engine is running.

Monitoring API

By default monitoring is disabled when the Engine is initialized. It needs to be explicitly enabled to track drives and locations. Enabling is done as follows:

Engine.Monitoring( true );

Monitoring can be disabled at any time as follows:

Engine.Monitoring( true );

If monitoring is enabled at any point during a drive that drive will be recorded.

Drive monitoring API

Listeners can be registered to receive Drive events. Note: They will only receive these events when monitoring is enabled. There is also an API for querying past drives.

Registering for drive events

Register a drive listener can be done as follows:

ActivityListener l = new ActivityListener() {
    @Override
    public void OnEvent( ActivityEvent e ) { Log.d(TAG, "Evt: " + e ); }

    @Override
    public void RegisterSucceeded() { Log.d(TAG, "Reg succeeded" ); }

    @Override
    public void RegisterFailed( int e ) { Log.w(TAG, "Reg err:" + e ); }
};
ActivityManager.RegisterDriveListener(l);

Multiple listeners can be registered via this API and all listeners will received the same events.

Note: Multiple events may be received for the same drive as the drive progresses and the drive processing updates the drive with more accurate map points.

To stop receiving drive monitoring unregister the listener as follows:

ActivityManager.UnregisterDriveListener(l);

Querying drive history

Some amount of drives are available for querying as follows:

ActivityManager.GetDrives( new Date( 0L),
                           new Date(),
                           new QueryHandler>() {
    @Override
    public void Result( ArrayList drives ) {
        Log.d("DriveMonitor", "Recorded drives:");
            for (DriveEvent e  : evts) {
                Log.d("DriveMonitor", e.toString());
            }
    }

    @Override
    public void OnFail( int i, String s ) {
        Log.e("DriveMonitor", "Query failed with err: " + i );
    }
});