MyGeotab API Adapter DM2
Support Document
0 mins to read
This document provides detailed information about the MyGeotab API Adapter solution along with instructions related to its deployment.
Solution and Implementation Guide
Latest Update: 2026-02-18
Revision History
Refer to the Change Log section for information about changes to the MyGeotab API Adapter solution and this document.
Introduction
Streaming of data from the MyGeotab platform into external systems via the Geotab API is accomplished using the data feed - a lightweight and highly-scalable incremental polling mechanism. Building a full-scale integration typically involves utilizing numerous data feeds to pull various types of data from a MyGeotab database. There are many complexities inherent in developing a solid integration.
The MyGeotab API Adapter solution serves as both an example of proper integration via data feeds and the potential foundation for those seeking to develop new integrations with the Geotab platform. Essentially, it uses data feeds to pull the most common data sets from a MyGeotab database and stream the data into tables within a SQL Server or PostgreSQL database; this could account for a significant portion of the work in terms of a unidirectional integration where the data from the database is further processed for integration into an external system.
This document provides detailed information about the MyGeotab API Adapter solution along with instructions related to its deployment.
Data Model 2 (DM2)
The original, now deprecated, data model, used exclusively prior to version 3.0.0 of the MyGeotab API Adapter (and supported through until version 3.14.0), was based on the premise of the adapter database serving only as a staging database where “raw” data extracted from the Geotab platform was deposited and there was a need to develop some sort of ETL process to move the data into some downstream “usable” format. Among other limitations, it did not contain indexes or physical relationships required to maintain query performance over time as data volume increases.
The Data Model 2 (DM2) version of the adapter database represents an evolution from the pure staging database paradigm. It is designed with greater performance, scalability and maintainability in mind. Specifically:
- It is normalized with many indexes and relationships between tables.
- Where possible, the string values of Geotab Entity Ids are converted to their underlying numeric values and used as the primary key on the subject table, facilitating fast queries even with many joins and large data volumes. See “GeotabId” and “id” Columns for more information.
- “Feed Data” tables are partitioned by month, week or day. See Database Partitioning for details.
- The MyGeotab API Adapter includes Automated Database Maintenance functionality that helps to keep tables and indexes optimized through regular maintenance while the application is in operation.
With the DM2 version of the adapter database, it is possible to achieve fast throughput speed while also providing the ability to query the data with fast results even with large data volumes.
MyGeotab API Adapter Highlights
When contemplating a new MyGeotab integration, there are many potential options. This section identifies some key features of the MyGeotab API Adapter solution which may serve both to highlight the benefit of its use as well as to identify likely requirements for a new integration being built from scratch.
In contrast to starting a brand new integration from the ground up, the most obvious benefit of utilizing the adapter solution is that it’s already available and open source on GitHub. So, it can be used as-is, or modified as necessary to meet specific requirements. A custom-built solution will most likely need to incorporate many of the features that are built into the MyGeotab API Adapter. Thus, at a bare minimum, the solution can serve to demonstrate ways by which such requirements may be implemented.
Highlights of the MyGeotab API Adapter solution are as follows:
Efficiency
- The number of MyGeotab API calls being made has been minimized via use of data feeds and caching to the extent possible.
- Chattiness with the MyGeotab API Adapter database has also been minimized.
- Asynchronous methods and parallel processing have been incorporated where possible.
Data Integrity
- Feed tokens are tracked and persisted to the MyGeotab API Adapter database.
- Write operations are executed within transactions to ensure all-or-none processing of FeedResult batches and tokens for individual feeds are persisted to the database only upon successful commit.
- Feeds will continue from the last feed versions upon restart of the MyGeotab API Adapter for any reason.
- Safeguards are in-place to prevent missing or duplicating data or inadvertently mixing data from multiple MyGeotab databases.
Database-Agnosticity
- The Dapper ORM (https://github.com/DapperLib/Dapper, https://dappertutorial.net/) is used to map .NET objects to rows in corresponding database tables.
- A repository pattern has been used - separating data-access code from application logic.
- A MyGeotab API Adapter database schema has been created for SQL Server (also Azure SQL) and PostgreSQL.
Resilience
- Mechanisms are in place to allow the MyGeotab API Adapter to continue operation if connectivity is lost either to the MyGeotab API or to the adapter database (e.g. planned maintenance, network issue, etc.) - in such events, the MyGeotab API Adapter will continuously try reconnecting and will resume where it left off once connectivity is re-established. Any partially completed operations are rolled-back and re-executed as noted under the Data Integrity point.
Configurability
- Via appsettings.json, it is possible to configure the MyGeotab API Adapter at a very granular level:
- Feeds can be configured for individual object types (LogRecord, StatusData, FaultData, Trip, ExceptionEvent, DVIRLog).
- Feed intervals can be set at a per-feed level.
- Individual feeds can be enabled or disabled as required.
- Update and refresh intervals can be set for individual caches of various object types (which also utilize feeds where available), including Controller, Device, Diagnostic, Defect, FailureMode, Group, Rule, UnitOfMeasure, User and Zone.
- Feed results may be filtered for specific devices and/or diagnostics so that only the data required for a given instance will be persisted to the adapter database.
- Feeds can be started at the current time, a specific time or based on the feed version, thereby enabling consumers to pull as little or as much data as desired into the adapter database.
- The above configuration options allow the MyGeotab API Adapter to reduce the number of MyGeotab API calls to only those that are required to meet the needs of a specific end-customer implementation, thereby easing the load on the MyGeotab platform as the solution is deployed for many customers.
Deployment Model
- The MyGeotab API Adapter is published using the self-contained deployment model targeting both the Windows 64-bit (win-x64) and the Linux 64-bit (linux-x64) runtimes.
- The solution is intended to be deployed on the basis of having one copy of the MyGeotab API Adapter with a paired adapter database per MyGeotab database.
Logging
- NLog has been incorporated as the logging mechanism.
- Log messages have been added strategically to assist with debugging issues once the solution has been deployed.
- Additional logging tools could be utilized for monitoring purposes.
Code Readability and Reusability
- One of the primary objectives in developing this solution was to ensure maximum reusability.
- In addition to creating this document, effort has been made to ensure extensive code commenting throughout in order to assist integrators.
Deploying the MyGeotab API Adapter
This section provides instructions on how to download and deploy the MyGeotab API Adapter.
Quick Start Guide
High-level steps are shown in the following table with details provided in the subsections below.
Step
Detail
1
Ensure that Prerequisites are Met:
- Ensure that all prerequisites are met. See 1 Prerequisites for details.
2
Download the MyGeotab API Adapter:
- Download the MyGeotab API Adapter application and database scripts. See 2 Download for details.
- Watch video:
3
Set Up the Adapter Database:
- Set up the adapter database into which data extracted from the Geotab platform will be written. See 3 Database Setup for details.
- Watch video:
4
Deploy and Configure the Application:
- Deploy and configure the MyGeotab API Adapter application. See 4 Application Deployment and Configuration for details.
- Watch video:
- Watch video:
- Watch video:
- Watch video:
1 Prerequisites
The MyGeotab API Adapter requires the following:
Item
Detail
Operating System
Windows 64-bit (win-x64) or Linux 64-bit (linux-x64).
- The deployment packages are self-contained and include the .NET runtime, libraries and dependencies needed to run on the respective platforms. As such, there is no need to pre-install any of these or worry about versions of .NET runtime, etc.
Database
SQL Server or PostgreSQL.
- The MyGeotab API Adapter application must be paired with a database into which data extracted from the Geotab platform is written.
- The solution was developed and tested with MS SQL Server 2019 and PostgreSQL (Postgres) 16. It is recommended to use a version equal to or greater than this for the respective database type chosen.
- Although Geotab cannot provide support, it is highly likely that cloud-based (i.e. Google, Amazon, Microsoft) versions of these databases are also suitable.
- In Azure, if SQL Server is chosen, Azure SQL Database is not supported due to the adapter database being partitioned. As-is, an Azure SQL Managed Instance or SQL Server on a VM are the supported options.
- If SQL Server is chosen, it is recommended to have access to a tool such as SQL Server Management Studio to view data that the adapter writes to the database.
- If PostgreSQL is chosen, it is recommended to have access to a tool such as pgAdmin to view data that the adapter writes to the database.
Networking / Firewall
- If the application and database will reside on separate servers, appropriate security and networking steps will need to be undertaken to ensure the ability of the application to interact with the database.
- The application must be able to make requests over HTTPS to the Geotab API (e.g.https://my.geotab.com/apiv1) in order to retrieve Geotab data.
MyGeotab Credentials
- MyGeotab credentials with all “View” clearances enabled on any MyGeotab database with which the MyGeotab API Adapter is to be used. It is recommended that a Service Account be set up for this purpose and assigned to Company Group. See the Service Account Guidelines document for more details. Specific clearances required by the service account used by the MyGeotab API Adapter include:
- List devices
- List Users/Drivers
- View Asset Inspection logs
- View binary data
- View device status information
- View engine diagnostics
- View engine failure modes
- View engine measurement related features
- View engine units of measurement
- View exception rules
- View exceptions
- View groups
- View trailers
- View zones
2 Download
Watch video:
The latest version of the MyGeotab API Adapter is available on GitHub as a pre-published release that can be deployed to Windows or Linux-based systems and use either PostgreSQL or SQL Server to store data extracted from the Geotab platform. Download instructions are as follows:
- Go to https://github.com/Geotab/mygeotab-api-adapter/releases
- The latest release will be shown first (at the top of the page). Scroll down to the Assets section under the latest release and download the required files. The following sections indicate which files are needed based on the deployment environment.
MyGeotab API Adapter - Application
The following table lists the files that should be downloaded based on the operating system of the machine where the MyGeotab API Adapter application is to be installed.
Operating System Type
FIle(s) to Download
Windows 64-bit
MyGeotabAPIAdapter_SCD_win-x64.zip
Linux 64-bit (Including Ubuntu)
MyGeotabAPIAdapter_SCD_linux-x64.zip
Database Scripts
The following table lists the files that should be downloaded based on the type of database that is to be used with the MyGeotab API Adapter application.
Database Type
FIle(s) to Download
SQL Server
SQLServer.zip
PostgreSQL
PostgreSQL.zip
3 Database Setup
Watch video:
Out-of-the-box, the MyGeotab API Adapter supports SQL Server and PostgreSQL for use as the database into which data retrieved via the MyGeotab API is written, as described in the Database section. Database setup procedures differ depending on the type of database and are outlined below.
! WARNING: It is possible for the database to grow very large very quickly, resulting in potential disk space and performance issues. In particular, the feed data tables can accumulate vast quantities of records within short periods of time. See the Database Maintenance section for more information.
PostgreSQL
If PostgreSQL is to be used with the adapter, it is necessary to have access to a PostgreSQL instance on which to set up the adapter database. Using pgAdmin, steps are provided in the following subsections:
Step 1: Create geotabadapter_client Login
Create a login/role named geotabadapter_client using the following script (first replacing
<Password>with the desired password):CREATE ROLE geotabadapter_client WITH
LOGIN
NOSUPERUSER
INHERIT
NOCREATEDB
NOCREATEROLE
NOREPLICATION
PASSWORD '<Password>';Step 2: Create Database
Create a database named geotabadapterdb. The following shows the basic statement to create the database:
✱ NOTE: Depending on the version of Postgres being used, it may be necessary to change the values of LC_COLLATE and LC_CTYPE (e.g. from ‘en_US.utf8’ tp ‘English_United States.1252’).
CREATE DATABASE geotabadapterdb WITH
OWNER = geotabadapter_client
ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
TABLESPACE = pg_default
CONNECTION LIMIT = -1
IS_TEMPLATE = FALSE;
Step 3: Set Default Permissions
Connect to the newly-created geotabadapterdb database and execute the following statements. This will ensure that the geotabadapter_client user will have access to all of the relevant objects that get created in the future.
-- Grant full privileges on all future sequences to the role
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO geotabadapter_client;
-- Grant execute privileges on all future functions to the role
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO geotabadapter_client;
Step 4: Modify and Execute PG_0.0.0.1_spManagePartitions.sql Script
The PG_0.0.0.1_spManagePartitions.sql script, which can be found along with the source code in the ..\mygeotab-api-adapter\MyGeotabAPIAdapter\Scripts\PostgreSQL\v2 folder (where mygeotab-api-adapter is the folder containing the MyGeotabAPIAdapter.sln solution file), is used to create the spManagePartitions function in the adapter database.
This function will partition the “feed data” tables in the adapter database on a monthly basis. Advanced users may wish to alter the partitioning scheme, in which case this function can be modified accordingly.
Execute the PG_0.0.0.1_spManagePartitions.sql script to create the spManagePartitions function in the adapter database.
Step 5: Execute Database Schema Creation Script
✱ NOTE: If a brand new adapter database is being set up and there are any database upgrade scripts available (as described in the next section), instead of having to run the initial schema creation script followed by the upgrade script(s), the PG_CumulativeSchemaCreation.sql can be run instead. This script will bring an empty database to the latest version of the adapter database. It is designed to simplify new deployments in the future when there may be many database upgrade scripts to run.
✱ NOTE: After the PG_CumulativeSchemaCreation.sql script has been run, when deploying future upgrades to the API Adapter, it will be necessary to run any applicable database upgrade scripts (see next section).
Connect to the geotabadapterdb database and execute the PG_3.0.0.0_InitialSchemaCreation.sql script. This will create all of the required tables, sequences, indexes, views, functions, etc. in the adapter database.
Step 6: [IF APPLICABLE] Modify and Execute Database Upgrade Script(s)
Over time, as changes are made to the adapter database schema, additional scripts will be provided to facilitate the upgrading of an existing adapter database. Such scripts will be prefixed with “PG_x.x.x.x_” where “x” is used as a placeholder for the API Adapter version. For example, if there were database schema changes for a hypothetical version 3.1.0.0 of the API Adapter, the associated database upgrade script would be named “
PG_3.1.0.0_<SomeDescription>.sql”.Execute any available adapter database upgrade scripts in sequential order (based on the versions in the script file names) up until and including the script where the version number matches that of the API Adapter application.
✱ NOTE: Not all updates of the API Adapter will include database schema changes. Database upgrade scripts are only provided for API Adapter versions that include database schema changes. As such, when running database upgrade scripts, simply ensure to run them up until and including the script where the version number matches that of the API Adapter application OR the closest version below the application version.
Step 7: Determine Data Collection Start Date and Execute spManagePartitions Function
! WARNING: Before proceeding with this step, it is important to determine the desired date from which Geotab data will be collected. Partition tables will be created for feed data tables for each month, week or day starting from that specified when executing the spManagePartitions function. Once this function has been executed, there is no easy way to make changes, other than deleting and recreating the adapter database and Geotab is unable to provide PostgreSQL support.
MinDateTimeUTC:
Determine the desired date from which Geotab data should be collected. This should correspond with the values specified for the FeedStartOption and FeedStartSpecificTimeUTC settings in the AppSettings - GeneralFeedSettings section of the appsettings.json file.
PartitionInterval:
Determine the interval by which database tables and indexes should be partitioned. Partition interval options include: monthly, weekly and daily. See Choosing the Right Partition Interval for more information.
Once the MinDateTimeUTC and PartitionInterval values have been decided, execute the spManagePartitions function to partition the database by modifying (replacing
<MinDateTimeUTC>and<PartitionInterval>with the desired values) and using the SQL below. For example, to start collecting data from January of 2022 and have the database partitioned on a monthly basis, the SQL statement would be changed to: SELECT public."spManagePartitions"('2022-01-01', 'monthly');SELECT public."spManagePartitions"('
<MinDateTimeUTC>', '<PartitionInterval>');Step 8: Verify Database Partitions
After executing the spManagePartitions function, verify that the database has been partitioned as expected. Assuming a hypothetical current date of 2024-10-17, when examining the FaultData2 table in pgAdmin, and expanding its Partitions item, the following partitions should be listed:
- FaultData2_202201
- FaultData2_202202
- FaultData2_202203
- (additional partitions for the months in-between)
- FaultData2_202409
- FaultData2_202410
- FaultData2_202411
Note that a partition is created for the month after the current month. This is to ensure that the partition will exist before any data needs to be allocated to it. The API Adapter will periodically execute the spManagePartitions function during normal operation to ensure the creation of future partitions.
The following query can also be used for further validation:
SELECT
parent_table.relname AS parent_table,
child_table.relname AS partition,
pg_catalog.pg_get_expr(child_table.relpartbound, child_table.oid) AS partition_bound
FROM
pg_inherits AS pi
JOIN
pg_class AS parent_table
ON pi.inhparent = parent_table.oid
JOIN
pg_class AS child_table
ON pi.inhrelid = child_table.oid
WHERE
parent_table.relkind = 'p'
AND child_table.relkind = 'r'
ORDER BY
parent_table.relname, child_table.relname;
SQL Server
Watch video:
If SQL Server is to be used with the adapter, it is necessary to have access to a SQL Server instance on which to set up the adapter database. Using SQL Server Management Studio, steps are provided in the following subsections:
✱ NOTE: In Azure, if SQL Server is chosen, Azure SQL Database is not supported due to the adapter database being partitioned. As-is, an Azure SQL Managed Instance or SQL Server on a VM are the supported options.
Step 1: Create Database
Create a database named geotabadapterdb. The following shows the basic statement to create the database:
CREATE DATABASE [geotabadapterdb];
Step 2: Set Database Collation
Ensure that the database collation is set to be case-sensitive by executing the following:
ALTER DATABASE [geotabadapterdb] COLLATE SQL_Latin1_General_CP1_CS_AS;
Step 3: Set Database Recovery Model
Unless there is a specific need for point-in-time recovery of the adapter database, the database recovery mode can be set to simple. This will reduce disk space usage. To switch the database to simple recovery mode, execute the following:
ALTER DATABASE [geotabadapterdb] SET RECOVERY SIMPLE;
Step 4: Create Client Login and User
Create a login named geotabadapter_client along with a user by the same name using the following script (first replacing
<Password>with the desired password):USE [master];
CREATE LOGIN [geotabadapter_client] WITH
PASSWORD=N'
<Password>',DEFAULT_DATABASE=[geotabadapterdb],
DEFAULT_LANGUAGE=[us_english],
CHECK_EXPIRATION=OFF,
CHECK_POLICY=OFF;
USE [geotabadapterdb];
CREATE USER [geotabadapter_client] FOR LOGIN [geotabadapter_client] WITH DEFAULT_SCHEMA=[dbo];
ALTER ROLE [db_owner] ADD MEMBER [geotabadapter_client];
Step 5: Modify and Execute MSSQL_0.0.0.1_spManagePartitions.sql Script
The MSSQL_0.0.0.1_spManagePartitions.sql script, which can be found along with the source code in the ..\mygeotab-api-adapter\MyGeotabAPIAdapter\Scripts\SQLServer\v2 folder (where mygeotab-api-adapter is the folder containing the MyGeotabAPIAdapter.sln solution file), is used to create the spManagePartitions stored procedure in the adapter database.
! WARNING: Before executing this stored procedure, ensure that the @filePath variable is set to the correct directory where your SQL Server data files should reside. By default, this variable is set to “C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\”. If this is not correct for your environment, change it and update the stored procedure before executing it.
This procedure will partition the adapter database into monthly files with daily partitions and all data files will be written to the default C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\ directory. Advanced users may wish to alter the partitioning scheme, in which case this procedure can be modified accordingly. Note that files are created on the machine where the database resides, regardless of whether the script is executed from that machine or another machine that is connected to the database server.
Execute the MSSQL_0.0.0.1_spManagePartitions.sql script to create the spManagePartitions stored procedure in the adapter database.
Step 6: Determine Data Collection Start Date and Execute spManagePartitions Stored Procedure
! WARNING: Before proceeding with this step, it is important to determine the desired date from which Geotab data will be collected. Data files will be created for each month, week or day starting from that specified when executing the spManagePartitions stored procedure. Once this procedure has been executed, there is no easy way to make changes, other than deleting and recreating the adapter database and Geotab is unable to provide SQL Server support.
MinDateTimeUTC:
Determine the desired date from which Geotab data should be collected. This should correspond with the values specified for the FeedStartOption and FeedStartSpecificTimeUTC settings in the AppSettings - GeneralFeedSettings section of the appsettings.json file.
PartitionInterval:
Determine the interval by which database tables and indexes should be partitioned. Partition interval options include: monthly, weekly and daily. See Choosing the Right Partition Interval for more information.
Once the MinDateTimeUTC and PartitionInterval values have been decided, execute the spManagePartitions function to partition the database by modifying (replacing
<MinDateTimeUTC>and<PartitionInterval>with the desired values) and using the SQL below. For example, to start collecting data from January of 2022 and have the database partitioned on a monthly basis, the SQL statement would be changed to: EXEC [dbo].[spManagePartitions] @MinDateTimeUTC = '2022-01-01', @PartitionInterval = 'monthly';EXEC [dbo].[spManagePartitions] @MinDateTimeUTC = '
<MinDateTimeUTC>', @PartitionInterval = '<PartitionInterval>';Step 7: Verify Database Partitions
After executing the spManagePartitions stored procedure, verify that the database has been partitioned as expected. Assuming a hypothetical current date of 2024-10-17, the C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\ folder should contain the following files:
- geotabadapterdb.mdf
- geotabadapterdb_log.ldf
- FG_geotabadapterdb_202201.ndf
- FG_geotabadapterdb_202202.ndf
- FG_geotabadapterdb_202203.ndf
- (additional files for the months in-between)
- FG_geotabadapterdb_202409.ndf
- FG_geotabadapterdb_202410.ndf
- FG_geotabadapterdb_202411.ndf
Note that a file is created for the month after the current month. This is to ensure that the partition file will exist before any data needs to be allocated to it. The API Adapter will periodically execute the spManagePartitions stored procedure during normal operation to ensure the creation of future partitions.
The following queries can also be used for further validation. Explanations can be found via SQL Server support:
-- Check FileGroup and Partition data:
select * from sys.filegroups;
select * from sys.partition_functions;
select * from sys.partition_range_values;
select * from sys.partition_schemes;
select * from sys.data_spaces;
select * from sys.dm_db_partition_stats;
Step 8: Execute Database Schema Creation Script
✱ NOTE: If a brand new adapter database is being set up and there are any database upgrade scripts available (as described in the next section), instead of having to run the initial schema creation script followed by the upgrade script(s), the MSSQL_CumulativeSchemaCreation.sql can be run instead. This script will bring an empty database to the latest version of the adapter database. It is designed to simplify new deployments in the future when there may be many database upgrade scripts to run.
✱ NOTE: After the MSSQL_CumulativeSchemaCreation.sql script has been run, when deploying future upgrades to the API Adapter, it will be necessary to run any applicable database upgrade scripts (see next section).
Execute the MSSQL_3.0.0.0_InitialSchemaCreation.sql script. This will create all of the required tables, indexes, views, stored procedures, etc. in the adapter database.
Step 9: [IF APPLICABLE] Modify and Execute Database Upgrade Script(s)
Over time, as changes are made to the adapter database schema, additional scripts will be provided to facilitate the upgrading of an existing adapter database. Such scripts will be prefixed with “MSSQL_x.x.x.x_” where “x” is used as a placeholder for the API Adapter version. For example, if there were database schema changes for a hypothetical version 3.1.0.0 of the API Adapter, the associated database upgrade script would be named “
MSSQL_3.1.0.0_<SomeDescription>.sql”.Execute any available adapter database upgrade scripts in sequential order (based on the versions in the script file names) up until and including the script where the version number matches that of the API Adapter application.
✱ NOTE: Not all updates of the API Adapter will include database schema changes. Database upgrade scripts are only provided for API Adapter versions that include database schema changes. As such, when running database upgrade scripts, simply ensure to run them up until and including the script where the version number matches that of the API Adapter application OR the closest version below the application version.
4 Application Deployment and Configuration
Watch video:
Watch video:
Watch video:
Watch video:
This section covers deployment and configuration of the MyGeotab API Adapter application.
Step 1: Deployment Prerequisites
To provide for a smooth deployment, the following steps should be taken beforehand:
- Ensure that permission has been granted by the owner of the MyGeotab database with which the adapter will be interacting.
- A service account should be established for use by the adapter. See the Service Account Guidelines document for more details.
- Take appropriate steps (networking, firewall, etc.) to ensure connectivity between the server on which the adapter will be deployed and the MyGeotab platform (e.g. https://my.geotab.com).
- Make sure that the adapter database setup has been completed per the instructions in the Database Setup section.
- Make sure that the server hosting the adapter database has enough disk space and that a database maintenance strategy is implemented to prevent unlimited growth.
Step 2: Install MyGeotab API Adapter Application
The MyGeotab API Adapter is rolled-up into a self-contained package that includes the .NET runtime and all other dependencies. As such, there is no complicated installation process. To “install” the application:
- Copy the zip file containing the application that was downloaded earlier to the desired location and extract (“unzip”) the contents which will be a single folder (e.g. “MyGeotabAPIAdapter_SCD_win-x64” if deploying to Windows).
Step 3: Configure MyGeotab API Adapter Application
The deployment folder that was extracted in the previous step contains two files that are used to configure the MyGeotab API Adapter: appsettings.json and nlog.config.
- Modify the appsettings.json file as needed. See the appsettings.json section in this guide for more information.
- The DatabaseSettings and LoginSettings sections are most important as they govern the application’s connectivity to the adapter database and the MyGeotab database.
- Review the nlog.config file and make any necessary changes. See the nlog.config section for more information.
Step 4: Run the MyGeotab API Adapter
There are multiple ways to run the API Adapter as shown below.
Option 1: Run Manually
For testing purposes, or in cases where there is a desire to only run the API Adapter for a limited period of time (e.g. to collect some data for ad-hoc analysis), the application can be launched by simply running the MyGeotab API Adapter application executable, MyGeotabAPIAdapter.exe (without the “.exe” extension if using the Linux version), which is contained in the folder that was “installed” earlier.
Option 2: Install as a Service
In situations where the API Adapter is intended to be run continuously, such as in a production environment, it is best to set the application up to run as a service. Instructions for doing so are provided for both Windows and Linux environments, below.
✱ NOTE: Before installing the MyGeotab API Adapter as a service in the steps below, the steps in the previous sections must be completed, including:
Windows
Watch video:
The MyGeotab API Adapter can be installed as a Windows Service by opening PowerShell or Command Prompt as an Administrator and executing the following commands:
Step
Detail
1
Create the Service:
✱ NOTE: Replace “C:\ABC” below with the path of the actual folder where the API Adapter was deployed.
sc.exe create MyGeotabAPIAdapter binPath="C:\ABC\MyGeotabAPIAdapter_SCD_win-x64\MyGeotabAPIAdapter.exe"
After creating the service, it can be managed (set to start automatically, etc.) from the Services console (services.msc). The commands in the next steps can also be used.
2
Start the Service:
sc.exe start MyGeotabAPIAdapter
3
Stop the Service:
sc.exe stop MyGeotabAPIAdapter
4
Delete the Service:
sc.exe delete MyGeotabAPIAdapter
Linux
To install MyGeotab API Adapter as a Linux (systemd) Service:
Step
Detail
1
Create a Service Unit File:
Use a text editor like nono or vim.
sudo nano /etc/systemd/system/mygeotabadapter.service
2
Create the Service:
Paste the following configuration into the file. Then, save and close the file.
✱ NOTES:
- In ExecStart and WorkingDirectory, replace “/mnt/c/ABC” with the path of the actual folder where the API Adapter was deployed.
- In User, replace
<User>with the user that the service should run as.
[Unit]
Description=MyGeotab API Adapter
[Service]
ExecStart=/mnt/c/ABC/MyGeotabAPIAdapter_SCD_linux-x64/MyGeotabAPIAdapter
WorkingDirectory=/mnt/c/ABC/MyGeotabAPIAdapter_SCD_linux-x64
User=<User>Restart=always
RestartSec=10
SyslogIdentifier=mygeotab-adapter
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
3
Reload the systemd Daemon:
sudo systemctl daemon-reload
4
Enable the Service to Start on Boot:
sudo systemctl enable mygeotabadapter.service
5
Start the Service:
sudo systemctl start mygeotabadapter.service
6
Check the Status of the Service:
sudo systemctl status mygeotabadapter.service
Option 3: Set-up a Scheduled Task / Cron Job
A third option for running the MyGeotab API Adapter is to set up a Scheduled Task (in Windows) or a cron job (in Linux). These will not be detailed further here since installing as a service is a better option.
Database Maintenance
! WARNING: It is possible for the database to grow very large very quickly, resulting in potential disk space and performance issues. For example, running the adapter against a MyGeotab database with a fleet of ~20,000 devices and pulling data for all supported feeds could result in an empty associated PostgreSQL database growing to ~40 GB in size within 7 days. In such a scenario, the database might include ~225,000,000 StatusData, ~65,000,000 LogRecord and ~10,000,000 Trip records.
The “DM2” (Data Model 2) version of the adapter database is designed with performance, scalability and maintainability in mind. Specifically:
- It is normalized with many indexes and relationships between tables.
- Where possible, the string values of Geotab Entity Ids are converted to their underlying numeric values and used as the primary key on the subject table, facilitating fast queries even with many joins and large data volumes. See “GeotabId” and “id” Columns for more information.
- “Feed Data” tables are partitioned by month, week or day. See Database Partitioning for details.
- The MyGeotab API Adapter includes Automated Database Maintenance functionality that helps to keep tables and indexes optimized through regular maintenance while the application is in operation.
With the DM2 version of the adapter database, it is possible to achieve fast throughput speed while also providing the ability to query the data with fast results even with large data volumes.
! WARNING: Although Geotab cannot provide database support and it is not covered in this guide, the Database Partitioning approach used with the adapter database makes it easier to implement database backup and retention strategies wherein older data can be backed-up and those partitions removed in order to allow for continued operation of the solution over extended timeframes.
Solution Information
This section provides detailed information about the architecture, database, configuration and logic of the MyGeotab API Adapter solution.
Solution Architecture
The following diagram provides an overview of the MyGeotab API Adapter solution architecture.

Geotab does not host the MyGeotab API Adapter. Rather, the solution must be hosted by the Geotab partner/reseller or customer. It consists of two components - the “API Adapter” application and the adapter database. The API Adapter is a collection of NET 9.0 Background Services (C#) that interface between the MyGeotab API and the database, essentially pulling data from the former and writing to tables in the latter. Each customer MyGeotab database must have a dedicated adapter and database pair; it is not possible to mix data from multiple MyGeotab databases. The Geotab partner/reseller or customer is responsible for integrating between the adapter database and any downstream applications or databases - potentially with assistance from a third-party solutions integrator.
Background Services
The MyGeotab API Adapter is essentially a collection of Background Services that operate in parallel while the application is running. Using the appsettings.json file, is possible to configure the various services - enabling the ones that are needed and disabling those that are not, setting thresholds and more.
Although there are a few different types of services, they largely operate in a very similar fashion using most of the same components. The following is an example of a “Feed Data” service that is responsible for continually retrieving Geotab data of a specific entity type and writing that data to the adapter database.

In the above diagram, there are a number of “generic” classes listed. These are single physical classes in the API Adapter source code that work with many types of entities. For example, the Generic Geotab Object Feeder is used to extract any type of entity from the Geotab platform via the GetFeed method. Using this approach instead of coding separate classes for each Geotab entity type is vastly more efficient and makes the solution much easier to maintain.
The general workflow of feed data processors is described below, using the numbered callouts in the above diagrams to draw attention to the relevant components.
1: Generic DB Object Caches
Generic DB Object Caches load data from “reference data” tables in the adapter database into application memory so that fast lookups can be executed without needing to query the adapter database for each lookup. This helps to greatly reduce “chattiness” of the application while improving efficiency. Using the StatusData Processor (StatusDataProcessor2) as an example, the list of diagnostics is cached in memory as the Ids of records in the DiagnosticIds2 table in the adapter database must be found in order to link to the DiagnosticId property of the StatusData object before it is inserted into the StatusData2 table in the adapter database.
2: Generic Geotab Object Feeders
After loading any required records from the adapter database into in-memory caches, the Background Service will use its Generic Geotab Object Feeder to retrieve a batch of Geotab entities from the MyGeotab database. The Generic Geotab Object Feeder uses the GetFeed method without any searches to retrieve data as quickly as possible and with the minimum possible impact on the overall performance of the MyGeotab database.
3: Geotab Object Filterers
The AppSettings - GeneralFeedSettings section in the appsettings.json file contains three settings - DevicesToTrack, DiagnosticsToTrack and ExcludeDiagnosticsToTrack - which are used to filter data of various entity types on Device Id and/or Diagnostic Id. After retrieving a batch of Geotab data using the Generic Geotab Object Feeder, the Background Service will engage one or more Geotab Object Filterers, if applicable, to discard unwanted records from the batch of data. This helps to ensure that only the desired data will be written to the adapter database.
4: Object Mappers
After retrieving and, if necessary, filtering a batch of Geotab entities, the Background Service utilizes an Object Mapper to create a DB Entity for each Geotab entity in the batch. There are Object Mappers for every type of Geotab Entity that gets written to the adapter database. An Object Mapper essentially maps properties of a Geotab entity to associated columns in an adapter database table, including performing any necessary data type conversions. The result is that the batch of Geotab entities is essentially converted into an equivalent batch of DB Entities.
5: Generic Entity Persisters
Finally, the Background Service takes the batch of DB Entities created by the Object Mapper and uses the Generic Entity Persister to write the entities to table(s) in the adapter database.
The Generic Entity Persister handles setting up database transactions and pushing the data down through a generic Base Repository which contains various database read/write methods - including bulk operations to make inserts and updates as fast as possible. From there, the Base Repository leverages Dapper (https://dappertutorial.net/) to perform much of the work involved in mapping C# objects (the “DB Entities”) to actual database records in the adapter database.
Data Enhancement Services
The MyGeotab API Adapter application contains numerous services that extract data from a MyGeotab database and write that data to corresponding tables in the adapter database.
- Services that process “reference data” are configured in the AppSettings - Caches section of the appsettings.json file.
- Services that process “feed data” are configured in the AppSettings - Feeds section of the appsettings.json file.
The AppSettings - DataEnhancementServices section of the appsettings.json file is used to configure services that enhance the data after it has been extracted from the Geotab platform and written to the adapter database. These services are described in the subsections below.
FaultData and StatusData Location Services
The FaultData and StatusData location services, configured via the AppSettings - DataEnhancementServices - FaultData and AppSettings - DataEnhancementServices - StatusData sections of the appsettings.json file, respectively, use LogRecords (“GPS data”) to interpolate location for FaultData and StatusData records.
The most complex and challenging part of the interpolation process is finding the closest lag (i.e. preceding) and lead (i.e. succeeding) LogRecords for each FaultData or StatusData record. Using a single StatusData record as an example, is is necessary to:
- Find the LogRecord for the subject Device with the closest preceding or equal DateTime to that of the StatusData record.
- Find the LogRecord for the subject Device with the closest succeeding DateTime to that of the StatusData record.
Complicating the process is the fact that these location services are running at the same time as the feed data services that are, in parallel, extracting LogRecords, FaultData and StatusData records from the MyGeotab database and bulk inserting them into tables in the adapter database. Challenges in this regard include:
- Data Density: Over a given period of time, there may be many more LogRecords than FaultData records, for example. This means that, when extracting historical data for each of the feeds in parallel at the maximum rate of 50,000 records per GetFeed call, and writing the results to the adapter database, the FaultData processor will be caught-up to the present time much more quickly than the LogRecord processor. As such, care needs to be taken to ensure that interpolation is only attempted for FaultData records where LogRecords for the the subject Devices have already been downloaded.
- Data Volume: Data volume can vary greatly by fleet size and by entity type. With a large fleet of 80,000 devices, for example, a batch of 100,000 “unprocessed” FaultData records might span 10 days, but in that same period, there might be tens of millions of LogRecords. Conversely, with a small fleet of 100 devices, the record counts might be trivial by comparison. Additionally, the sheer volume of data collected over time can present significant challenges with regard to query performance.
- Concurrency/Contention: With various processes reading and writing potentially large quantities of data involving the same database tables at the same time, there is a high possibility of this leading to contention issues whereby services reading and writing data end-up blocking each other with table and row locks causing cascading issues.
To address the above challenges and allow the location services to interpolate locations for FaultData and StatusData records as quickly as possible, a number of mechanisms are employed including:
- Database Partitioning: The Database Partitioning strategy employed helps to improve query performance by greatly reducing the amount of data that needs to be evaluated when querying to retrieve a batch of data for interpolation. By querying data within specific DateTime ranges, queries can be restricted to only the partitions containing the relevant records.
- Automated Database Maintenance: The Automated Database Maintenance functionality helps to keep statistics updated and indexes optimized, in turn, helping the database engines to execute queries as quickly as possible.
- EntityMetaData2 Table: The EntityMetadata2 table is used to store the combination of DeviceId + DateTime + EntityType + EntityId. Each time a record is inserted into one of the FaultData2, LogRecords2 or StatusData2 tables, a corresponding record is inserted into this table. It is used by stored procedures / functions (described below) that must relate these different entities based on DateTime and DeviceId to perform location interpolation. Having this information in a single table boosts query performance by reducing complex multi-table joins.
- Parameterized Stored Procedures / Functions: The spFaultData2WithLagLeadLongLatBatch and spStatusData2WithLagLeadLongLatBatch stored procedures (in SQL Server, or functions in Postgres) in the adapter database perform the heavy-lifting of retrieving batches of FaultData or StatusData records with lag and lead LogRecord information attached so that interpolation can take place. These procedures are parameterized with “MaxDaysPerBatch”, “MaxBatchSize” and “BufferMinutes” parameters that are configured in the appsettings.json file and allow the procedures to effectively be scaled to operate in a performant manner for fleets of various sizes. Using these parameters, the procedures can be configured to optimally leverage the database partitions for fast query performance. Note that there are some differences between the SQL Server versions and their PostgreSQL counterparts due to differences in how the two database engines operate.
Database
Out-of-the-box, the MyGeotab API Adapter supports SQL Server and PostgreSQL for use as the adapter database into which data retrieved via the MyGeotab API is written.
List of Tables
The following table lists all of the tables contained in the database along with descriptions that include the associated MyGeotab API objects, where applicable. Further detail relating to the structure and fields of individual tables can be found in the Data Dictionary section.
✱ NOTE: Each table is assigned to one of the following categories:
- Feed data: Records in feed data tables generally consist of data points collected using data feeds and are not modified once written to the database. These tables can accumulate vast quantities of records within short periods of time. It is highly recommended to have a data management strategy - especially for tables in this category.
- Reference data: These tables generally contain user-added data. Values are referenced by GeotabId in the feed data tables. Records in reference data tables can change over time and only the latest version of each record is maintained. Record counts in reference data tables tend to be small and relatively stable over time.
- Enhanced data: Tables in this category are populated by services that enhance/augment the raw data in associated “feed data” tables. For example, the StatusDataLocationService populates the StatusDataLocations2 table with location information to augment corresponding records in the StatusData2 feed data table.
- Commands: These tables are utilized for issuing data manipulation commands to the Geotab platform - for example, updating the repair status of DVIRDefects after related work orders have been completed in an external system. Rather than using the MyGeotab API Adapter to extract data from a MyGeotab database and then having to use the MyGeotab SDK to send updates back to the MyGeotab database, the details of these updates can simply be inserted as rows into the relevant commands tables and the adapter will take care of the SDK-related work.
- Command exceptions: For each commands table, there will be an associated command exceptions table. If a row is inserted into the commands table and it does not pass data validation checks, or if an exception occurs when the adapter attempts to execute the command, a copy of the original row in the commands table will be added to the command exceptions table along with the related error message. This is to assist in debugging and to provide feedback that would otherwise be provided in the responses to commands issued via the MyGeotab SDK.
- System info: These tables are used by the adapter and do not offer any other specific benefit.
! WARNING: It is possible for the database to grow very large very quickly, resulting in potential disk space and performance issues. In particular, the feed data tables can accumulate vast quantities of records within short periods of time. See the Database Maintenance section for more information.
Table Name | Category | Description |
Feed data | Contains data corresponding to MyGeotab BinaryData objects. | |
System Info | A system table used by the MyGeotab API Adapter. | |
System Info | A system table used by the MyGeotab API Adapter. | |
Feed data | Contains data corresponding to MyGeotab ChargeEvent objects. | |
Reference data | Represents the list of values in the MyGeotab DefectSeverity entity. | |
Reference data | Contains data corresponding to MyGeotab Device objects. | |
Reference data | Contains data corresponding to MyGeotab DeviceStatusInfo objects. | |
Reference data | Contains data corresponding to MyGeotab Diagnostic objects. | |
Reference data | Contains data corresponding to MyGeotab Diagnostic objects. | |
Feed data | Contains data corresponding to MyGeotab DriverChange objects. | |
Reference data | Contains data corresponding to MyGeotab DutyStatusAvailability objects. | |
Feed data | Contains data corresponding to MyGeotab DutyStatusLog objects. | |
Feed data | Contains data corresponding to MyGeotab DefectRemark objects. | |
Feed data | Contains data corresponding to defects associated with DVIRLogs. It includes data derived from MyGeotab DVIRLog, DVIRDefect, Defect and Group objects. | |
Feed data | Contains data corresponding to MyGeotab DVIRLog objects. | |
Feed data | Used to store the combination of DeviceId + DateTime + EntityType + EntityId. Each time a record is inserted into one of the FaultData2, LogRecords2 or StatusData2 tables, a corresponding record is inserted into this table. It is used by stored procedures / functions that must relate these different entities based on DateTime and DeviceId to perform location interpolation. Having this information in a single table boosts query performance by reducing complex multi-table joins. | |
Reference data | The EntityType enumeration is not represented in a physical table. It is used to identify MyGeotab Entity types. | |
Feed data | Contains data corresponding to MyGeotab ExceptionEvent objects. | |
Command exceptions | Contains copies of any records that were inserted into the DVIRDefectUpdates table and did not result in successful updates of DVIRDefects in the MyGeotab database. The FailureMessage column provides details about the reason why a given command failed. See the DVIRLog Manipulator section for more information. | |
Feed data | Contains data corresponding to MyGeotab FaultData objects. | |
Enhanced data | Contains interpolated location data for MyGeotab FaultData objects.For each record inserted into the FaultData2 table, a corresponding record is inserted into this table. If the FaultDataLocationService is enabled, records in this table will be updated with location information interpolated using data from the LogRecords2 table. | |
Feed data | Contains data corresponding to MyGeotab FuelAndEnergyUsed objects. | |
Reference data | Contains data corresponding to MyGeotab Group objects. | |
Feed data | Contains data corresponding to MyGeotab LogRecord objects. | |
System info | A system table used by the MyGeotab API Adapter. | |
System info | Contains software version information (obtained from MyGeotab API VersionInformation) about the MyGeotab server and database that the subject adapter database is associated with via the MyGeotab API Adapter. | |
System info | A system table used by the MyGeotab API Adapter. | |
Reference data | Represents the list of values in the MyGeotab RepairStatusType entity. | |
Reference data | Contains data corresponding to MyGeotab Rule objects. | |
Feed data | Contains data corresponding to MyGeotab StatusData objects. | |
Enhanced data | Contains interpolated location data for MyGeotab StatusData objects.For each record inserted into the StatusData2 table, a corresponding record is inserted into this table. If the StatusDataLocationService is enabled, records in this table will be updated with location information interpolated using data from the LogRecords2 table. | |
stg_* | System info | Tables with a “stg_” prefix (e.g. stg_Devices2) are staging tables used in the cache update/refresh process for corresponding unprefixed tables of the same names (e.g. Devices2). DO NOT use or alter data in any of the “stg_*” tables. |
Feed data | Contains data corresponding to MyGeotab Trip objects. | |
Commands | May be used to send DVIRDefect updates to the MyGeotab database with which the API Adapter is configured to communicate. See the DVIRLog Manipulator section for more information. | |
Reference data | Contains data corresponding to MyGeotab User objects. | |
Reference data | Contains data corresponding to MyGeotab Zone objects. | |
Reference data | Contains data corresponding to MyGeotab ZoneType objects. |
Data Dictionary
Although both the SQL Server and PostgreSQL databases are supported, for simplicity, any database-specific references such as data types will relate to the SQL Server version of the schema. For information such as schema details related to other supported database types, refer to the Database Setup section. The tables and views included in the adapter database schema are detailed in the following subsections.
“GeotabId” and “id” Columns
! WARNING: The information in this section relating to “GeotabId” and “id” columns applies only to tables with a “2” suffix (denoting data model #2). See the “GeotabId” and “id” Columns section in the original guide for information associated with the original data model.
Most of the tables in the adapter database have “GeotabId” and “id” columns.
The id is the unique identifier for the record in the adapter database table.
- In some cases, the id is also the value of the GeotabId converted to its underlying numeric value. This is done to facilitate indexes, relationships and faster query performance.
- In other cases, the id is generated automatically by the adapter database and is entirely unrelated to the Geotab system.
- Details about the id column are provided in the sections below for each table in the adapter database.
The id column is of the bigint data type. It is also indexed and defined (in combination with the DateTime column where applicable) as the primary key. One of Its purposes is to allow downstream processes to delete records (from the feed data tables) as part of the suggested strategy while maintaining optimal performance and avoiding database concurrency/contention issues that could arise (if the GeotabId were to be used) when trying to delete records while the adapter is actively inserting/updating records.
The GeotabId is a string representation of the unique identifier for the specific Entity object in the Geotab system; it must be used when relating objects back to the Geotab system.
Entity Relationship Diagrams
The sections below provide information about all of the tables in the adapter database and the columns within. If a given table contains one or more columns that are related to columns in other tables, a mini Entity Relationship Diagram (ERD) is also provided to show any relationships between the subject table and the table(s) with which it is directly associated.
The following diagram describes object representations used in these ERDs. Notes:
- Blue headers are used for “reference data” tables.
- Yellow headers are used for “feed data” tables.
- Black crow’s foot lines show physical relationships.
- Red crow’s foot lines show logical relationships (i.e. where columns in two tables are logically related, but a physical foreign key relationship has not been established).

BinaryData2
The BinaryData2 table contains data corresponding to MyGeotab BinaryData objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
BinaryType | nvarchar(50) | Yes | The BinaryDataType. |
ControllerId | nvarchar(50) | No | The Id of the Controller associated with the subject BinaryData. |
Data | varbinary(max) | No | The binary data for the subject BinaryData object. |
DateTime | datetime2(7) | No | The date and time of the logging of the data. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject BinaryData. |
Version | bigint | Yes | The version of the entity. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |

ChargeEvents2
The ChargeEvents2 table contains data corresponding to MyGeotab ChargeEvent objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
ChargeIsEstimated | bit | No | Indicates whether the charge values were estimated. |
ChargeType | nvarchar(50) | No | The ChargeType provided by the external power source. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject ChargeEvent. |
DurationTicks | bigint | No | The length of time the vehicle was charging as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
EndStateOfCharge | float | Yes | The ending state of charge for this ChargeEvent. |
EnergyConsumedKwh | float | Yes | The energy consumed during the ChargeEvent. |
EnergyUsedSinceLastChargeKwh | float | Yes | ✱ NOTE: This property is DEPRECATED in the MyGeotab API and this column is no longer populated. It has been kept for those with historical data. The amount of energy drawn from the battery since the last ChargeEvent. |
Latitude | float | Yes | The latitude of the location where the ChargeEvent occurred. |
Longitude | float | Yes | The longitude of the location where the ChargeEvent occurred. |
MaxACVoltage | float | Yes | The maximum AC Voltage over the ChargeEvent. |
MeasuredBatteryEnergyInKwh | float | Yes | The amount of energy in measured during charging. |
MeasuredBatteryEnergyOutKwh | float | Yes | The amount of energy out measured during charging. |
MeasuredOnBoardChargerEnergyInKwh | float | Yes | The total amount of energy in measured on board during charging. |
MeasuredOnBoardChargerEnergyOutKwh | float | Yes | The total amount of energy out measured on board during charging. |
PeakPowerKw | float | Yes | The peak power used during the ChargeEvent. |
StartStateOfCharge | float | Yes | The starting state of charge for this ChargeEvent. |
StartTime | datetime2(7) | No | The date and time at which the ChargeEvent started. |
TripStop | datetime2(7) | Yes | The time of the Trip.Stop from the Trip this ChargeEvent occurred in. |
Version | bigint | Yes | The version of the entity. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

DBMaintenanceLogs2
The DBMaintenanceLogs2 table is a system table used by the MyGeotab API Adapter. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
MaintenanceTypeId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. 1 = Level1. 2 = Level2. 3 = Partition. |
StartTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the database maintenance operation started. |
EndTimeUtc | datetime2(7) | Yes | A timestamp, in Coordinated Universal Time (UTC), indicating when the database maintenance operation completed. |
Success | nvarchar(1024) | Yes | Indicates whether the database maintenance operation completed successfully. Default is null. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
DBPartitionInfo2
The DBPartitionInfo2 table is a system table used by the MyGeotab API Adapter. It is populated by the spManagePartitions stored procedure the first time it is executed during initial database setup. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
InitialMinDateTimeUTC | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the lower DateTime boundary used for the first database partition. |
InitialPartitionInterval | nvarchar(50) | No | Indicates the time interval used for partitioning database tables and indexes. Must be monthly, weekly or daily. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |
DefectSeverities2
The DefectSeverities2 table contains records corresponding to values of the MyGeotab DefectSeverity entity. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | smallint | No | The underlying numeric value of the DefectSeverity. |
Name | nvarchar(50) | No | The name of the DefectSeverity. |
Devices2
The Devices2 table contains data corresponding to MyGeotab Device objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
ActiveFrom | datetime2(7) | Yes | The date the device is active from. |
ActiveTo | datetime2(7) | Yes | The date the device is active to. |
Comment | nvarchar(1024) | Yes | Free text field where any user information can be stored and referenced for this entity. |
DeviceType | nvarchar(50) | No | Specifies the GO or Custom DeviceType. |
Groups | nvarchar(max) | Yes | The list of Group(s) the subject entity belongs to. Presented in the form of a JSON array (e.g. [{"id":"GroupVehicleId"},{"id":"b2868"}]). Group Ids in this list correspond with GeotabId values in the Groups table. |
LicensePlate | nvarchar(50) | Yes | The vehicle license plate details of the vehicle associated with the device. |
LicenseState | nvarchar(50) | Yes | The state or province of the vehicle associated with the device. |
Name | nvarchar(100) | No | The display name assigned to the device. |
ProductId | int | Yes | The product Id. Each device is assigned a unique hardware product Id. |
SerialNumber | nvarchar(12) | Yes | The serial number of the device. |
VIN | nvarchar(50) | Yes | The Vehicle Identification Number (VIN) of the vehicle associated with the device. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
TmpTrailerGeotabId | nvarchar(50) | Yes | The unique identifier for the Trailer Entity associated with this Device Entity in the Geotab system. ✱ NOTE: This is a temporary column used to relate Trailers to corresponding Devices. It will be removed once the DVIRLog entity is updated such that the Trailer property is removed in favour of populating the Device (for both Devices and Trailers). |
TmpTrailerId | uniqueidentifier | Yes | The TmpTrailerGeotabId converted to its underlying numeric value. ✱ NOTE: This is also temporary column. |
DeviceStatusInfo2
The DeviceStatusInfo2 table contains data corresponding to MyGeotab DeviceStatusInfo objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | Equal to DeviceId. Since this table contains one record per Device with records being updated over time, the Id values of individual DeviceStatusInfo records offer no value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. ✱ NOTE: This value gets updated each time there is a new DeviceStatusInfo record for the subject Device. |
CurrentStateDuration | nvarchar(50) | no | The duration between the last Trip state change (i.e. driving or stop), and the most recent date of location information. |
DateTime | datetime2(7) | No | The most recent DateTime of the latest piece of status, GPS or fault data. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject DeviceStatusInfo. |
DriverId | bigint | Yes | The Id of the Driver (corresponding to the Id in the Users2 table) associated with the subject DeviceStatusInfo. |
IsDeviceCommunicating | bit | No | A value indicating whether the Device is communicating. |
IsDriving | bit | No | A value indicating whether the current Device state. If set true, is driving. Otherwise, it is stopped. |
IsHistoricLastDriver | bit | No | Indicates whether the Device has been assigned to "UnknownDriver" and the last Trip Driver is represented in the DriverId column. |
Latitude | float | No | The last known latitude of the Device. |
Longitude | float | No | The last known longitude of the Device. |
Speed | real | No | The current vehicle speed (in km/h). NaN represents an invalid speed. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

DiagnosticIds2
The DiagnosticIds2 table contains data corresponding to MyGeotab Diagnostic objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabGUIDString | nvarchar(100) | No | The underlying Globally Unique Identifier (GUID) of the Diagnostic. In the event that the GeotabId changes as a result of the assignment of a KnownId, this GeotabGUID will remain unchanged and can be used for reconciliation of Diagnostic Ids in any downstream integrations. |
GeotabId | nvarchar(100) | No | The unique identifier for the Entity in the Geotab system. |
HasShimId | bit | No | Indicates whether the Diagnostic is one that has a KnownId on the MyGeotab server side, but is unknown in the MyGeotab .NET API client (Geotab.Checkmate.ObjectModel NuGet package) used at the time of download. |
FormerShimGeotabGUIDString | nvarchar(100) | Yes | If there is an earlier version of the Diagnostic where HasShimId is true, this value lists the GeotabGUID of that earlier Diagnostic so that the two, along with any associated data, can be logically related. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

Diagnostics2
The Diagnostics2 table contains data corresponding to MyGeotab Diagnostic objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabId | nvarchar(100) | No | The unique identifier for the Entity in the Geotab system. |
GeotabGUIDString | nvarchar(100) | No | The underlying Globally Unique Identifier (GUID) of the Diagnostic. In the event that the GeotabId changes as a result of the assignment of a KnownId, this GeotabGUID will remain unchanged and can be used for reconciliation of Diagnostic Ids in any downstream integrations. |
HasShimId | bit | No | Indicates whether the Diagnostic is one that has a KnownId on the MyGeotab server side, but is unknown in the MyGeotab .NET API client (Geotab.Checkmate.ObjectModel NuGet package) used at the time of download. |
FormerShimGeotabGUIDString | nvarchar(100) | Yes | If there is an earlier version of the Diagnostic where HasShimId is true, this value lists the GeotabGUID of that earlier Diagnostic so that the two, along with any associated data, can be logically related. |
ControllerId | nvarchar(100) | Yes | The applicable Controller for the diagnostic. |
DiagnosticCode | int | Yes | The diagnostic parameter code number. |
DiagnosticName | nvarchar(max) | No | The name of this entity that uniquely identifies it and is used when displaying this entity. |
DiagnosticSourceId | nvarchar(50) | No | The Id of the Source of the Diagnostic. |
DiagnosticSourceName | nvarchar(255) | No | The Name of the Source of the Diagnostic. |
DiagnosticUnitOfMeasureId | nvarchar(50) | No | The Id of the UnitOfMeasure used by the Diagnostic. |
DiagnosticUnitOfMeasureName | nvarchar(255) | No | The Name of the UnitOfMeasure used by the Diagnostic. |
OBD2DTC | nvarchar(50) | Yes | The OBD-II Diagnostic Trouble Code (DTC), if the Diagnostic is from an OBD Source. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
DriverChanges2
The DriverChanges2 table contains data corresponding to MyGeotab DriverChange objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
DateTime | datetime2(7) | No | The date and time of the driver change. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject DriverChange. |
DriverId | bigint | Yes | The Id of the Driver (corresponding to the Id in the Users2 table) associated with the subject DriverChange. |
Type | nvarchar(50) | No | The DriverChangeType. |
Version | bigint | No | The version of the entity. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

DutyStatusAvailabilities2
The DutyStatusAvailabilities2 table contains data corresponding to MyGeotab DutyStatusAvailability objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also equal to the DriverId. Since there is one record per Driver in this table, the actual id returned by the API call is of no use. |
GeotabId | nvarchar(50) | No | The unique identifier of the Driver in the Geotab system. |
DriverId | bigint | No | The Id of the Driver (corresponding to the Id in the Users2 table) associated with the subject DutyStatusAvailability record. |
CycleAvailabilities | nvarchar(max) | Yes | Cycle available to the driver in the future. Presented in the form of a JSON array (e.g. [{"DateTime":"2021-01-14T05:00:00Z","Available":"00:00:00"},{"DateTime":"2021-01-15T05:00:00Z","Available":"00:00:00"},{"DateTime":"2021-01-16T05:00:00Z","Available":"00:00:00"},{"DateTime":"2021-01-17T05:00:00Z","Available":"00:00:00"},{"DateTime":"2021-01-18T05:00:00Z","Available":"20:18:55.6430000"},{"DateTime":"2021-01-19T05:00:00Z","Available":"1.20:18:55.6430000"},{"DateTime":"2021-01-20T05:00:00Z","Available":"2.12:00:00"}]). |
CycleDrivingTicks | bigint | Yes | The duration of cycle driving hours left as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
CycleTicks | bigint | Yes | The duration of cycle duty hours left as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
CycleRestTicks | bigint | Yes | The duration left before cycle rest must be taken. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
DrivingBreakDurationTicks | bigint | Yes | The duration of the driving break (USA only). Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
DrivingTicks | bigint | Yes | The duration left for driving. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
DutyTicks | bigint | Yes | The duration of total on-duty time left in a day. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
DutySinceCycleRestTicks | bigint | Yes | The duty hours left since Cycle Rest. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
Is16HourExemptionAvailable | bit | Yes | Indicates whether 16 hour exemption is available. |
IsAdverseDrivingApplied | bit | Yes | Indicates whether adverse driving exemption is applied. |
IsAdverseDrivingExemptionAvailable | bit | Yes | Indicates whether adverse driving exemption is available. |
IsOffDutyDeferralExemptionAvailable | bit | Yes | Indicates whether off-duty deferral exemption is available. |
IsRailroadExemptionAvailable | bit | Yes | Indicates whether railroad exemption is available. |
Recap | nvarchar(max) | Yes | Chronological array representing each day's On-duty time since the beginning of cycle. Presented in the form of a JSON array (e.g. [{"DateTime":"2021-01-07T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-08T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-09T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-10T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-11T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-12T05:00:00Z","Duration":"1.00:00:00"},{"DateTime":"2021-01-13T05:00:00Z","Duration":"15:41:04.3570000"}]). |
RestTicks | bigint | Yes | The duration left before rest break must be taken. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
WorkdayTicks | bigint | Yes | The duration of workday left in a day. Workday is a consecutive window that begins with first on-duty. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

DutyStatusLogs2
The DutyStatusLogs2 table contains data corresponding to MyGeotab DutyStatusLog objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
Annotations | nvarchar(max) | Yes | The list of AnnotationLog(s) which are associated with this log. |
CoDrivers | nvarchar(max) | Yes | The list of the co-driver User(s) (in the Users2 table) for this log. |
DateTime | datetime2(7) | No | The date and time the log was created. |
DeferralMinutes | int | Yes | The deferral minutes. |
DeferralStatus | nvarchar(50) | Yes | |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject DutyStatusLog. |
DistanceSinceValidCoordinates | real | Yes | The distance since last valid coordinate measurement. |
DriverId | bigint | Yes | The Id of the User (corresponding to the Id in the Users2 table) who created this log. |
EditDateTime | datetime2(7) | Yes | The date and time the log was edited. If the log has not been edited, this will not be set. |
EditRequestedByUserId | bigint | Yes | The Id of the User (corresponding to the Id in the Users2 table) that requested an edit to this log. |
EngineHours | float | Yes | The engine hours for the DeviceId at the DateTime of this log. The unit is seconds (not hours). |
EventCheckSum | bigint | Yes | The event checksum of this log. |
EventCode | int | Yes | The event code of this log (Table 6; 7.20 of the ELD Final Rule). |
EventRecordStatus | int | Yes | The record status number of this log 1 = active 2 = inactive - changed 3 = inactive - change requested 4 = inactive - change rejected. |
EventType | int | Yes | The event type number of this log 1 = A change in driver's duty-status 2 = An intermediate log 3 = A change in driver's indication of authorized personal use of CMV or yard moves 4 = A driver's certification/re-certification of records 5 = A driver's login/logout activity 6 = CMV's engine power up / shut down activity 7 = A malfunction or data diagnostic detection occurrence (Table 6; 7.25 of the ELD Final Rule). |
IsHidden | bit | Yes | Indicates whether the log is hidden. |
IsIgnored | bit | Yes | If the log is ignored. True means it will not affect the Driver's HOS availability. |
IsTransitioning | bit | Yes | A value indicating whether the log is in transitioning state. |
Location | nvarchar(max) | Yes | An object with the location information for the log data. |
LocationX | float | Yes | The longitude of the Location. |
LocationY | float | Yes | The latitude of the Location. |
Malfunction | nvarchar(50) | Yes | The DutyStatusMalfunctionTypes of this DutyStatusLog record. As a flag it can be both a diagnostic and malfunction state which is used to mark status based records (e.g. "D", "SB") as having a diagnostic or malfunction present at time of recording. |
Odometer | float | Yes | The odometer in metres for the DeviceId at the DateTime of this log. |
Origin | nvarchar(50) | Yes | The DutyStatusOrigin from where this log originated. |
ParentId | nvarchar(50) | Yes | The GeotabId of the parent DutyStatusLog. Used when a DutyStatusLog is edited. When returning history, this field will be populated. |
Sequence | bigint | Yes | The sequence number, which is used to generate the sequence ID. |
State | nvarchar(50) | Yes | The DutyStatusState of the DutyStatusLog record. |
Status | nvarchar(50) | Yes | The DutyStatusLogType representing the driver's duty status. |
UserHosRuleSet | nvarchar(max) | Yes | The linked UserHosRuleSet. Only used to link rulesets to log events that affect the driver's operating zone and/or cycle. (Canadian ELD) |
VerifyDateTime | datetime2(7) | Yes | The date and time the log was verified. If the log is unverified, this will not be set. |
Version | bigint | Yes | The version of the entity. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was created in this table. |

DVIRDefectRemarks2
The DVIRDefectRemarks2 table contains data corresponding to MyGeotab DefectRemark objects. Return toList of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
DVIRDefectId | uniqueidentifier | No | The Id of the DVIRDefect (in the DVIRDefects2 table) with which the subject DVIRDefect is associated. |
DVIRLogDateTime | datetime2(7) | No | The DateTime of the DVIRLog (in the DVIRLogs2 table) with which the DVIRDefect with which the subject DVIRDefectRemark is associated. ✱ NOTE: This column is duplicated here only because it is necessary for database partitioning purposes. |
DateTime | datetime2(7) | No | The date and time the remark was created. |
Remark | nvarchar(max) | Yes | The text content of the remark. |
RemarkUserId | bigint | Yes | The Id of the User (in the Users2 table) who created the remark. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
DVIRDefects2
The DVIRDefects2 table contains data corresponding to defects associated with DVIRLogs. It includes data derived from MyGeotab DVIRLog, DVIRDefect, Defect and Group objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
DVIRLogId | uniqueidentifier | No | The Id of the DVIRLog (in the DVIRLogs2 table) with which the subject DVIRDefect is associated. |
DVIRLogDateTime | datetime2(7) | No | The DateTime of the DVIRLog (in the DVIRLogs2 table) with which the subject DVIRDefect is associated. ✱ NOTE: This column is duplicated here only because it is necessary for database partitioning purposes. |
DefectListAssetType | nvarchar(50) | Yes | The asset type of the defect list. |
DefectListId | nvarchar(50) | Yes | The Id of the defect list (Group) that the defect belongs to. |
DefectListName | nvarchar(255) | Yes | The Name of the defect list (Group) that the defect belongs to. |
PartId | nvarchar(50) | Yes | The Id of the part (Group) that has the defect. |
PartName | nvarchar(255) | Yes | The Name of the part (Group) that has the defect. |
DefectId | nvarchar(50) | Yes | The Id of the Defect. |
DefectName | nvarchar(255) | Yes | The Name of the Defect. |
DefectSeverityId | smallint | Yes | The id of the DefectSeverity (in the DefectSeverities2 table) of the Defect. |
RepairDateTime | datetime2(7) | Yes | The date and time the DVIRDefect was repaired. |
RepairStatusId | smallint | Yes | The id of the RepairStatusType (in the RepairStatuses2 table) of the DVIRDefect. |
RepairUserId | bigint | Yes | The Id of the User (in the Users2 table) who repaired the DVIRDefect. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
DVIRLogs2
The DVIRLogs2 table contains data corresponding to MyGeotab DVIRLog objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
AuthorityAddress | nvarchar(255) | Yes | The authority address for the driver at the time of this log. |
AuthorityName | nvarchar(255) | Yes | The authority name for the driver at the time of this log. |
CertifiedByUserId | bigint | Yes | The Id of the User (in the Users2 table) who certified the repairs (or comments, if no repairs were made) to the Device or Trailer. |
CertifiedDate | datetime2(7) | Yes | The date and time that the Device or Trailer was certified. |
CertifyRemark | nvarchar(max) | Yes | The remark recorded by the User who certified the repairs (or no repairs made) to the Device or Trailer. |
DateTime | datetime2(7) | No | The date and time the log was created. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the DVIR. |
DriverId | bigint | Yes | The Id of the User (in the Users2 table) who created the log. |
DriverRemark | nvarchar(max) | Yes | The remark recorded by the driver for this log. |
DurationTicks | bigint | Yes | The total time spent to complete the DVIRLog as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
EngineHours | real | Yes | The engine hours, measured in seconds, of the Device at the time of this log. |
IsSafeToOperate | bit | Yes | Indicates whether the Device or Trailer was certified as safe to operate. |
LoadHeight | real | Yes | The load height, measured in meters, if it was manually recorded by the driver. |
LoadWidth | real | Yes | The load width, measured in meters, if it was manually recorded by the driver. |
LocationLatitude | float | Yes | The latitude of the location of the log. |
LocationLongitude | float | Yes | The longitude of the location of the log. |
LogType | nvarchar(50) | Yes | The DVIRLogType of the log. |
Odometer | float | Yes | The odometer or hubometer, measured in meters, of the vehicle or trailer. |
RepairDate | datetime2(7) | Yes | The date and time the Device or Trailer was repaired. |
RepairedByUserId | bigint | Yes | The Id of the User (in the Users2 table) who repaired the Device or Trailer. |
RepairRemark | nvarchar(max) | Yes | The remark recorded by the User who repaired the Device or Trailer. |
Version | bigint | Yes | The version of the entity. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

EntityMetadata2
The EntityMetadata2 table is used to store the combination of DeviceId + DateTime + EntityType + EntityId. Each time a record is inserted into one of the FaultData2, LogRecords2 or StatusData2 tables, a corresponding record is inserted into this table. It is used by stored procedures / functions that must relate these different entities based on DateTime and DeviceId to perform location interpolation. Having this information in a single table boosts query performance by reducing complex multi-table joins. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
DeviceId | bigint | No | The DeviceId value of the corresponding record in the FaultData2, LogRecords2 or StatusData2 table (which one is dependent on EntityType). Also the Id of the Device (in the Devices2 table) associated with the subject Entity. |
DateTime | datetime2(7) | No | The DateTime value of the corresponding record in the FaultData2, LogRecords2 or StatusData2 table (which one is dependent on EntityType). |
EntityType | tinyint | No | The Id of the EntityType enumeration. Indicates which table (FaultData2, LogRecords2 or StatusData2) the subject record’s corresponding record resides in. |
EntityId | bigint | No | The Id value of the corresponding record in the FaultData2, LogRecords2 or StatusData2 table (which one is dependent on EntityType). |
IsDeleted | bit | Yes | For future use. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |

EntityType (Enumeration)
The EntityType enumeration is not represented in a physical table. It is used to identify MyGeotab Entity types. Return to List of Tables.
Id | Name | Description |
1 | LogRecord | Represents the MyGeotab LogRecord entity type. |
2 | StatusData | Represents the MyGeotab StatusData entity type. |
3 | FaultData | Represents the MyGeotab FaultData entity type. |
ExceptionEvents2
The ExceptionEvents2 table contains data corresponding to MyGeotab ExceptionEvent objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
ActiveFrom | datetime2(7) | No | The start date and time of the ExceptionEvent; at or after this date and time. |
ActiveTo | datetime2(7) | Yes | The end date and time of the ExceptionEvent; at or before this date and time. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject ExceptionEvent. |
Distance | real | Yes | The distance (in KMs) travelled since the start of the ExceptionEvent. |
DriverId | bigint | Yes | The Id of the Driver (corresponding to the Id in the Users2 table) associated with the subject ExceptionEvent. |
DurationTicks | bigint | Yes | The duration of the ExceptionEvent as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
LastModifiedDateTime | datetime2(7) | Yes | The last time this ExceptionEvent was updated (in the MyGeotab database). |
RuleId | bigint | Yes | The Id of the Rule (corresponding to the Id in the Rules2 table) associated with the subject ExceptionEvent. |
State | int | Yes | The ExceptionEventState of the subject ExceptionEvent. 0 = Valid. 1 = Invalid. 2 = Dismissed. |
Version | bigint | Yes | The version of the entity. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

fail_DVIRDefectUpdateFailures2
The fail_DVIRDefectUpdateFailures2 table is associated with the upd_DVIRDefectUpdates2 table. If a row is inserted into the upd_DVIRDefectUpdates2 table and it does not pass data validation checks, or if an exception occurs when the adapter attempts to execute the command, a copy of the original row in the upd_DVIRDefectUpdates2 table will be added to the fail_DVIRDefectUpdateFailures2 table along with the related error message which will appear in the FailureMessage column. For more detail, refer to the DVIRLog Manipulator section of this guide. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in the adapter database table. Entirely unrelated to the Geotab system. |
DVIRDefectUpdateId | bigint | No | The value of the id field for the original row in the upd_DVIRDefectUpdates2 table that resulted in the failure. |
DVIRLogId | uniqueidentifier | No | The Id of the DVIRLog (in the DVIRLogs2 table) with which the subject DVIRDefect is associated. |
DVIRDefectId | uniqueidentifier | No | The Id of the DVIRDefect (in the DVIRDefects2 table) that is to be updated in the Geotab system |
RepairDateTimeUtc | datetime2(7) | Yes | The date and time the DVIRDefect was repaired, in Coordinated Universal Time (UTC). |
RepairStatusId | smallint | Yes | The Id of the RepairStatusType (in the RepairStatuses2 table) of this DVIRDefect. |
RepairUserId | bigint | Yes | The Id of the User (in the Users2 table) who repaired this DVIRDefect. |
Remark | nvarchar(max) | Yes | The remark text. |
RemarkDateTimeUtc | datetime2(7) | Yes | The date and time the remark was created, in Coordinated Universal Time (UTC). |
RemarkUserId | bigint | Yes | The Id of the User (in the Users2 table) who created the remark. |
FailureMessage | nvarchar(max) | Yes | The reason why this record failed to result in an update of the subject DVIRDefect in the MyGeotab database. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when this failure record was created in the table. |
FaultData2
The FaultData2 table contains data corresponding to MyGeotab FaultData objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
AmberWarningLamp | bit | Yes | Indicates whether the amber warning lamp is on. |
ClassCode | nvarchar(50) | Yes | The DtcClass code of the fault. |
ControllerId | nvarchar(100) | No | The Id of the Controller related to the fault code; if applicable. |
ControllerName | nvarchar(255) | Yes | The Name of the Controller related to the fault code; if applicable. |
Count | int | No | The number of times the fault occurred. |
DateTime | datetime2(7) | No | The date and time at which the event occurred. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject FaultData. |
DiagnosticId | bigint | No | The Id of the Diagnostic (in the DiagnosticIds2 table) associated with the subject FaultData. |
DismissDateTime | datetime2(7) | Yes | The date and time that the fault was dismissed. |
DismissUserId | bigint | Yes | The Id of the User (in the Users2 table) associated with the subject FaultData entity. |
EffectOnComponent | nvarchar(max) | Yes | The effect on component for enriched fault. |
FailureModeCode | int | Yes | The Failure Mode Identifier (FMI) associated with the FailureMode. |
FailureModeId | nvarchar(50) | No | The Id of the FailureMode associated with the subject FaultData entity. |
FailureModeName | nvarchar(255) | Yes | The Name of the FailureMode associated with the subject FaultData entity. |
FaultDescription | nvarchar(max) | Yes | The fault description for enriched fault. |
FaultLampState | nvarchar(50) | Yes | The FaultLampState of a J1939 vehicle. |
FaultState | nvarchar(50) | Yes | The FaultState code from the engine system of the specific device. |
FlashCodeId | nvarchar(255) | Yes | The Id of the Flashcode associated with the subject FaultData entity. |
FlashCodeName | nvarchar(255) | Yes | The Name of the Flashcode associated with the subject FaultData entity. |
MalfunctionLamp | bit | Yes | Indicates whether the malfunction lamp is on. |
ProtectWarningLamp | bit | Yes | Indicates whether the protect warning lamp is on. |
Recommendation | nvarchar(max) | Yes | The recommendation for enriched fault. |
RedStopLamp | bit | Yes | Indicates whether the red stop lamp is on. |
RiskOfBreakdown | float | Yes | The risk of breakdown associated with the fault. ✱ NOTE: This column is currently not populated as the associated property is not available in the .NET API client. Once it becomes available, this note will be removed. |
Severity | nvarchar(50) | Yes | The DtcSeverity of the fault. |
SourceAddress | int | Yes | The source address for enhanced faults. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |

FaultDataLocations2
The FaultDataLocations2 table contains interpolated location data for MyGeotab FaultData objects.For each record inserted into the FaultData2 table, a corresponding record is inserted into this table. If the EnableFaultDataLocationService setting is set to true, records in this table will be updated with location information interpolated using data from the LogRecords2 table. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The Id value of the corresponding record in the FaultData2 table. |
DeviceId | bigint | No | The DeviceId value of the corresponding record in the FaultData2 table. |
DateTime | datetime2(7) | No | The DateTime value of the corresponding record in the FaultData2 table. This column is only included in this table for database partitioning purposes. |
Latitude | float | Yes | The interpolated latitude of the corresponding record in the FaultData2 table. |
Longitude | float | Yes | The interpolated longitude of the corresponding record in the FaultData2 table. |
Speed | real | Yes | The interpolated speed (in km/h) of the corresponding record in the FaultData2 table. |
Bearing | real | Yes | The interpolated bearing (heading) in degrees of the corresponding record in the FaultData2 table. |
Direction | nvarchar(3) | Yes | The interpolated compass direction (e.g. “N”, “SE”, “WSW”, etc.) of the corresponding record in the FaultData2 table. |
LongLatProcessed | bit | No | Indicates whether the subject record has been processed for interpolation. |
LongLatReason | tinyint | Yes | If not null and LongLatProcessed = true, indicates the reason why it was not possible to interpolate Longitude and Latitude values for the subject record. See the LocationInterpolationResultReason enumeration for more information. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

FuelAndEnergyUsed2
The FuelAndEnergyUsed2 table contains data corresponding to MyGeotab FuelAndEnergyUsed objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | uniqueidentifier | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying GUID value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
DateTime | datetime2(7) | No | The date and time of the fuel and energy usage record. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject fuel and energy usage record. |
TotalEnergyUsedKwh | float | Yes | The total energy used, in kilowatt-hours (kWh). |
TotalFuelUsed | float | Yes | The volume of fuel used in liters. |
TotalIdlingEnergyUsedKwh | float | Yes | The total energy used while idling, in kilowatt-hours (kWh). |
TotalIdlingFuelUsedL | float | Yes | The volume of fuel used while idling, in liters. |
Version | bigint | Yes | The version of the entity. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

Groups2
The Groups2 table contains data corresponding to MyGeotab Group objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabId | nvarchar(50) | No | The unique identifier for the specific Entity object in the Geotab system. |
Children | nvarchar(max) | Yes | The GeotabIds of any direct children of the subject Group. Presented in the form of a JSON array (e.g. [{"id":"b3D88"},{"id":"b5F70"},{"id":"b2718"}]). |
Color | nvarchar(50) | Yes | The color used to render assets in the subject Group in the MyGeotab user interface. Presented in JSON format (e.g. {"a":255,"b":0,"g":0,"r":0}). |
Comments | nvarchar(1024) | Yes | A free text field where any user information can be stored and referenced for this entity. |
Name | nvarchar(255) | Yes | The name of this entity that uniquely identifies it and is used when displaying this entity. |
Reference | nvarchar(255) | Yes | The string reference to add to the database entry for this group. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in the adapter database. |
LocationInterpolationResultReason (Enumeration)
The LocationInterpolationResultReason enumeration is not represented in a physical table. It is used to identify reasons why location interpolation was not possible for a given Entity.
Id | Name | Description |
1 | LagLeadDbLogRecord2InfoNotFound | Lag/lead records were not found in the LogRecords2 table for an unknown reason. |
2 | LeadDateTimeLessThanLagDateTime | While attempting to interpolate coordinates, it was discovered that the lead DateTime value was less than the lag DateTime value. |
3 | TargetDateTimeGreaterThanLeadDateTime | While attempting to interpolate coordinates, it was discovered that the target DateTime value (for which location was to be interpolated) was greater than the lead DateTime value. |
4 | TargetDateTimeLessThanLagDateTime | While attempting to interpolate coordinates, it was discovered that the target DateTime value (for which location was to be interpolated) was less than the lag DateTime value. |
5 | TargetEntityDateTimeBelowMinDbLogRecord2DateTime | While attempting to interpolate coordinates, it was discovered that the target DateTime value (for which location was to be interpolated) was older than the earliest DateTime value of any record in the LogRecords2 table.
|
6 | TargetEntityDateTimeBelowMinDbLogRecord2DateTimeForDevice | While attempting to interpolate coordinates, it was discovered that the target DateTime value (for which location was to be interpolated) was older than the earliest DateTime value of any record in the LogRecords2 table for the subject Device.
|
LogRecords2
The LogRecords2 table contains data corresponding to MyGeotab LogRecord objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
DateTime | datetime2(7) | No | The date and time the log was recorded. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject FaultData. |
Latitude | float | No | The latitude of the log record. |
Longitude | float | No | The longitude of the log record. |
Speed | real | No | The logged speed or an invalid speed (in km/h). |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |

MiddlewareVersionInfo2
The MiddlewareVersionInfo2 table is a system table used by the MyGeotab API Adapter. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
DatabaseVersion | nvarchar(50) | No | The version of the adapter database. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |
MyGeotabVersionInfo2
The MyGeotabVersionInfo2 table contains software version information (obtained from MyGeotab API VersionInformation) about the MyGeotab server and database that the subject adapter database is associated with via the MyGeotab API Adapter. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
DatabaseName | nvarchar(58) | No | The name of the MyGeotab database. |
Server | nvarchar(50) | No | The server on which the MyGeotab database resides. |
DatabaseVersion | nvarchar(50) | No | The current version of the MyGeotab databases on the server. |
ApplicationBuild | nvarchar(50) | No | The MyGeotab application build. |
ApplicationBranch | nvarchar(50) | No | The MyGeotab application branch. |
ApplicationCommit | nvarchar(50) | No | The MyGeotab application commit. |
GoTalkVersion | nvarchar(50) | No | The Text to Speech firmware version provided by the server. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |
OServiceTracking2
The OServiceTracking2 table is a system table used by the MyGeotab API Adapter. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
ServiceId | nvarchar(50) | No | An identifier for the subject service. |
AdapterVersion | nvarchar(50) | Yes | The version of the MyGeotab API Adapter that the subject service is a part of. |
AdapterMachineName | nvarchar(100) | Yes | The name of the machine/server that is hosting the MyGeotab API Adapter instance that the subject service is a part of. |
EntitiesLastProcessedUtc | datetime2(7) | Yes | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject service processed any entities (data). |
LastProcessedFeedVersion | bigint | Yes | If applicable and the subject service uses the GetFeed method, the ToVersion of the last batch of records retrieved by the subject service. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
RepairStatuses2
The RepairStatuses2 table contains records corresponding to values of the MyGeotab RepairStatusType entity. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | smallint | No | The underlying numeric value of the RepairStatusType. |
Name | nvarchar(50) | No | The name of the RepairStatusType. |
Rules2
The Rules2 table contains data corresponding to MyGeotab Rule objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description ✱ NOTE: This i |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
ActiveFrom | datetime2(7) | Yes | Start date and time of the Rule's notification activity period. |
ActiveTo | datetime2(7) | Yes | End date and time of the Rule's notification activity period. |
BaseType | nvarchar(50) | Yes | The ExceptionRuleBaseType of the Rule. |
Comment | nvarchar(max) | Yes | Free text field where any user information can be stored and referenced for this entity. |
Condition | nvarchar(max) | Yes | The hierarchical tree of Condition(s) defining the logic of a Rule. A Rule should have one or more conditions in its tree. Presented in JSON form. |
Groups | nvarchar(max) | Yes | The list of Group(s) the subject entity belongs to. Presented in the form of a JSON array (e.g. [{"id":"b1769"},{"id":"b2858"}]). Group Ids in this list correspond with GeotabId values in the Groups2 table. |
Name | nvarchar(255) | Yes | The name of the rule entity that uniquely identifies it and is used when displaying this entity. |
Version | bigint | No | The version of the entity. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
StatusData2
The StatusData2 table contains data corresponding to MyGeotab StatusData objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
Data | float | Yes | The recorded value of the diagnostic parameter. |
DateTime | datetime2(7) | No | The date and time of the logged event. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject StatusData. |
DiagnosticId | bigint | No | The Id of the Diagnostic (in the DiagnosticIds2 table) associated with the subject StatusData. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when the subject record was inserted into this table. |

StatusDataLocations2
The StatusDataLocations2 table contains interpolated location data for MyGeotab StatusData objects.For each record inserted into the StatusData2 table, a corresponding record is inserted into this table. If the EnableStatusDataLocationService setting is set to true, records in this table will be updated with location information interpolated using data from the LogRecords2 table. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The Id value of the corresponding record in the StatusData2 table. |
DeviceId | bigint | No | The DeviceId value of the corresponding record in the FaultData2 table. |
DateTime | datetime2(7) | No | The DateTime value of the corresponding record in the StatusData2 table. This column is only included in this table for database partitioning purposes. |
Latitude | float | Yes | The interpolated latitude of the corresponding record in the StatusData2 table. |
Longitude | float | Yes | The interpolated longitude of the corresponding record in the StatusData2 table. |
Speed | real | Yes | The interpolated speed (in km/h) of the corresponding record in the StatusData2 table. |
Bearing | real | Yes | The interpolated bearing (heading) in degrees of the corresponding record in the StatusData2 table. |
Direction | nvarchar(3) | Yes | The interpolated compass direction (e.g. “N”, “SE”, “WSW”, etc.) of the corresponding record in the StatusData2 table. |
LongLatProcessed | bit | No | Indicates whether the subject record has been processed for interpolation. |
LongLatReason | tinyint | Yes | If not null and LongLatProcessed = true, indicates the reason why it was not possible to interpolate Longitude and Latitude values for the subject record. See the LocationInterpolationResultReason enumeration for more information. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

Trips2
The Trips2 table contains data corresponding to MyGeotab Trip objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. ✱ NOTE: Unlike other entities, with Trips, the GeotabId changes each time a Trip is updated. As such, it cannot be used as a unique identifier for Trips. |
AfterHoursDistance | real | Yes | The distance the vehicle was driven after work hours (in km). |
AfterHoursDrivingDurationTicks | bigint | Yes | The duration the vehicle was driven after work hours as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
AfterHoursEnd | bit | Yes | Whether the trip ends after hours. |
AfterHoursStart | bit | Yes | Whether the trip starts after hours. |
AfterHoursStopDurationTicks | bigint | Yes | The duration the vehicle was stopped after work hours as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
AverageSpeed | real | Yes | Average speed in km/h. This only includes the average speed while driving. |
DeletedDateTime | datetime2(7) | Yes | If the trip was deleted due to recalculation or reprocessing, the date and time that the trip was deleted. Otherwise, the value will be null. |
DeviceId | bigint | No | The Id of the Device (in the Devices2 table) associated with the subject Trip. |
Distance | real | No | The distance the vehicle was driven during the trip (in km). |
DriverId | bigint | Yes | The Id of the Driver (corresponding to the Id in the Users2 table) associated with the subject Trip. |
DrivingDurationTicks | bigint | No | The duration between the start and stop of the trip as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
IdlingDurationTicks | bigint | Yes | Total end-of-trip idling (idling is defined as speed being 0 with ignition on). It is calculated from the beginning of the current trip to the beginning of the next trip. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
MaximumSpeed | real | Yes | The maximum speed of the vehicle during this trip (in km/h). |
NextTripStart | datetime2(7) | No | The start date and time of the next trip. |
SpeedRange1 | int | Yes | The number of incidents where the vehicle reached the first range of speeding triggers. |
SpeedRange1DurationTicks | bigint | Yes | The duration where the vehicle drove in the first range of speeding triggers as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
SpeedRange2 | int | Yes | The number of incidents where the vehicle reached the second range of speeding triggers. |
SpeedRange2DurationTicks | bigint | Yes | The duration where the vehicle drove in the second range of speeding triggers as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
SpeedRange3 | int | Yes | The number of incidents where the vehicle reached the third range of speeding triggers. |
SpeedRange3DurationTicks | bigint | Yes | The duration where the vehicle drove in the third range of speeding triggers as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
Start | datetime2(7) | No | The date and time that the trip started. |
Stop | datetime2(7) | No | The date and time the trip stopped. |
StopDurationTicks | bigint | Yes | The duration that the vehicle was stopped at the end of the trip. This also includes any idling done at the end of a trip. Measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
StopPointX | float | Yes | The longitude of the Coordinate at which the Trip stopped. |
StopPointY | float | Yes | The latitude of the Coordinate at which the Trip stopped. |
WorkDistance | real | Yes | The distance the vehicle was driven during work hours (in km). |
WorkDrivingDurationTicks | bigint | Yes | The duration the vehicle was driven during work hours as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
WorkStopDurationTicks | bigint | Yes | The duration the vehicle was stopped during work hours as measured in ticks. A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

upd_DVIRDefectUpdates2
The upd_DVIRDefectUpdates2 table may be used to send DVIRDefect updates to the MyGeotab database with which the adapter is configured to communicate. If a record is inserted into this table and it fails to result in the subject DVIRDefect update being propagated to the MyGeotab database, a copy of the record will be inserted into the fail_DVIRDefectUpdateFailures2 table and the reason for the failure will be provided in the FailureMessage column. Once a record has been processed, it will be deleted from the upd_DVIRDefectUpdates2 table. For more detail, refer to the DVIRLog Manipulator section of this guide. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in the adapter database table. Entirely unrelated to the Geotab system. |
DVIRLogId | uniqueidentifier | No | The Id of the DVIRLog (in the DVIRLogs2 table) with which the subject DVIRDefect is associated. |
DVIRDefectId | uniqueidentifier | No | The Id of the DVIRDefect (in the DVIRDefects2 table) that is to be updated in the Geotab system |
RepairDateTimeUtc | datetime2(7) | Yes | The date and time the DVIRDefect was repaired, in Coordinated Universal Time (UTC). |
RepairStatusId | smallint | Yes | The Id of the RepairStatusType (in the RepairStatuses2 table) of this DVIRDefect. |
RepairUserId | bigint | Yes | The Id of the User (in the Users2 table) who repaired this DVIRDefect. |
Remark | nvarchar(max) | Yes | The remark text. |
RemarkDateTimeUtc | datetime2(7) | Yes | The date and time the remark was created, in Coordinated Universal Time (UTC). |
RemarkUserId | bigint | Yes | The Id of the User (in the Users2 table) who created the remark. |
RecordCreationTimeUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating when this record was created in the table. |
Users2
The Users2 table contains data corresponding to MyGeotab User objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(50) | No | The unique identifier for the Entity in the Geotab system. |
ActiveFrom | datetime2(7) | No | The date the user is active from. |
ActiveTo | datetime2(7) | No | The date the user is active to. |
CompanyGroups | nvarchar(max) | Yes | The list of Group(s) the subject entity belongs to. Presented in the form of a JSON array (e.g. [{"id":"b834"},{"id":"b9b1"}]). Group Ids in this list correspond with GeotabId values in the Groups table. |
EmployeeNo | nvarchar(50) | Yes | The employee number or external identifier. |
FirstName | nvarchar(255) | Yes | The first name of the user. |
HosRuleSet | nvarchar(MAX) | Yes | The HosRuleSet the user follows. Default: None. |
IsDriver | bit | No | Indicates whether the user is classified as a driver. |
LastAccessDate | datetime2(7) | Yes | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject user accessed the MyGeotab system. |
LastName | nvarchar(255) | Yes | The last name of the user. |
Name | nvarchar(255) | No | The user's email address / login name. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
Zones2
The Zones2 table contains data corresponding to MyGeotab Zone objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. ✱ NOTE: This is also the GeotabId converted to its underlying numeric value. |
GeotabId | nvarchar(100) | No | The unique identifier for the Entity in the Geotab system. |
ActiveFrom | datetime2(7) | Yes | The date the zone is active from. |
ActiveTo | datetime2(7) | Yes | The date the zone is active to. |
CentroidLatitude | float | Yes | The latitude of the geographic centre of the zone. |
CentroidLongitude | float | Yes | The longitude of the geographic centre of the zone. |
Comment | nvarchar(500) | Yes | A free text field where any user information can be stored and referenced for this entity. |
Displayed | bit | Yes | A value indicating whether this zone must be displayed when viewing a map or it should be hidden. |
ExternalReference | nvarchar(255) | Yes | Any type of external reference to be attached to the zone. May be used to link zones with corresponding entities in other systems. |
Groups | nvarchar(max) | Yes | The list of Group(s) the subject entity belongs to. Presented in the form of a JSON array (e.g. [{"id":"b1266"},{"id":"b2998"}]). Group Ids in this list correspond with GeotabId values in the Groups table. |
MustIdentifyStops | bit | Yes | Indicates whether this zone name must be shown when devices stop in this zone. If true, a "zone stop rule" (Rule with BaseType: ZoneStop) will automatically be created for this zone. This is to facilitate reporting on zone stops. The rule is not visible via the MyGeotab UI. |
Name | nvarchar(255) | No | The name of this entity that uniquely identifies it and is used when displaying this entity. |
Points | nvarchar(MAX) | Yes | The list of points (see Coordinate) that make up the zone. A zone should be closed (i.e. the first point should consist of the same set of coordinates as the last point). Presented in the form of a JSON array (e.g. [{"X":-79.68085479736328,"Y":43.517887115478516},{"X":-79.6830825805664,"Y":43.51841354370117},{"X":-79.6854019165039,"Y":43.5172004699707},{"X":-79.68214416503906,"Y":43.51369857788086},{"X":-79.6794204711914,"Y":43.51435470581055},{"X":-79.68085479736328,"Y":43.517887115478516}]). |
ZoneTypeIds | nvarchar(MAX) | No | The Id(s) of the ZoneType(s) that this zone belongs to. Presented in the form of a JSON array (e.g. [{"Id":"ZoneTypeOfficeId"},{"Id":"ZoneTypeCustomerId"}]). Ids correspond to GeotabId values in the ZoneTypes2 table. |
Version | bigint | Yes | The version of the entity. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |

ZoneTypes2
The ZoneTypes2 table contains data corresponding to MyGeotab ZoneType objects. Return to List of Tables.
Column Name | Data Type | Nullable | Description |
id | bigint | No | The unique identifier for the record in this table. Entirely unrelated to the Geotab system. |
GeotabId | nvarchar(100) | No | The unique identifier for the Entity in the Geotab system. |
Comment | nvarchar(255) | Yes | A free text field where any user information can be stored and referenced for this entity. |
Name | nvarchar(255) | No | The name of this entity that uniquely identifies it and is used when displaying this entity. |
EntityStatus | int | No | Indicates whether the subject corresponding object is active or deleted in the MyGeotab database. 1 = Active. 0 = Deleted. |
RecordLastChangedUtc | datetime2(7) | No | A timestamp, in Coordinated Universal Time (UTC), indicating the last time that the subject record was updated in this table. |
Database Partitioning
Depending on the fleet size and the length of time over which data is being collected, it is possible for certain tables to accumulate hundreds of millions or even billions of records. A partitioning strategy is employed to break these large tables into smaller and more manageable ones that help to improve performance, scalability and long-term maintainability. Specifically, tables are split into monthly partitions based on the “DateTime” columns. Indexes are also partitioned. The partitioning logic is contained in the SQL Server stored procedure named “spManagePartitions”, or the PostgreSQL function with the same name, and executed regularly as part of the Automated Database Maintenance functionality of the MyGeotab API Adapter. Each time it is executed, partitions will be created as needed up to and including for the month following that of the current day.
Choosing the Right Partition Interval
When using spManagePartitions to partition the adapter database during the initial creation steps, partition interval choices include monthly, weekly and daily. Although extensive testing and analysis has not been undertaken to define clear breakpoints, and recognizing that needs will vary with fleet size, the following table provides a general guideline for choosing an appropriate partition interval:
Fleet Size | Recommended Partition Interval |
Up to low thousands | monthly |
Low to mid tens of thousands | weekly |
Mid tens of thousands and over | daily |
✱ NOTE: The suggested partition interval choices above are only general guidelines and may not be ideal for any specific fleet. It may be a worthwhile exercise to set up a test environment, if possible, and experiment with the different partition intervals to see which one results in better query performance once a significant amount of data has been collected.
Database Partitioning - PostgreSQL
The PG_ClearDatabaseScript.sql script includes the queries shown below.
Aggregated Counts by Table
The following query provides record counts by table (with partition counts aggregated in the case of partitioned tables). Note that some tables have been excluded for simplicity:
/* Check counts */
--ANALYZE;
WITH partitioned_tables AS (
SELECT part.relname AS parent_table,
child.relname AS partition_table
FROM pg_partitioned_table p
JOIN pg_class part ON p.partrelid = part.oid
JOIN pg_inherits i ON part.oid = i.inhparent
JOIN pg_class child ON i.inhrelid = child.oid
WHERE part.relname NOT LIKE 'pg_%'
AND part.relname NOT LIKE 'sql_%'
AND child.relname NOT LIKE 'pg_%'
AND child.relname NOT LIKE 'sql_%'
),
table_counts AS (
SELECT relname AS table_name,
coalesce(SUM(n_live_tup), 0) AS record_count
FROM pg_stat_all_tables
WHERE relname NOT LIKE 'pg_%'
AND relname NOT LIKE 'sql_%'
GROUP BY relname
)
SELECT
CASE
WHEN pt.parent_table IS NOT NULL THEN pt.parent_table
ELSE tc.table_name
END AS TableName,
SUM(tc.record_count) AS RecordCount
FROM table_counts tc
LEFT JOIN partitioned_tables pt ON tc.table_name = pt.partition_table
GROUP BY TableName
ORDER BY TableName;
Results will be similar to the following example, in which there is a single count for the StatusData2 table:

Record Counts by Partition
The following query provides record counts by partition:
/* Check counts by partition */
--ANALYZE;
SELECT parent_table.relname AS parent_table,
child_table.relname AS partition,
pg_catalog.pg_get_expr(child_table.relpartbound, child_table.oid) AS partition_bound,
COALESCE(stats.n_live_tup, 0) AS record_count
FROM pg_inherits AS pi
JOIN pg_class AS parent_table
ON pi.inhparent = parent_table.oid
JOIN pg_class AS child_table
ON pi.inhrelid = child_table.oid
LEFT JOIN pg_stat_all_tables AS stats
ON stats.relname = child_table.relname
WHERE parent_table.relkind = 'p'
AND child_table.relkind = 'r'
ORDER BY parent_table.relname, child_table.relname;
Results will be similar to the following example, in which there is record count for each monthly partition of the StatusData2 table:

Database Partitioning - SQL Server
The MSSQL_ClearDatabaseScript.sql script includes the queries shown below.
Aggregated Record Counts by Table
The following query provides record counts by table (with partition counts aggregated in the case of partitioned tables):
/* Check counts */
--EXEC sp_updatestats;
SELECT t.name AS TableName,
SUM(p.rows) AS RecordCount
FROM sys.tables t
JOIN sys.partitions p ON t.object_id = p.object_id
WHERE t.type = 'U' -- User tables only
AND p.index_id IN (0, 1) -- 0 = heap, 1 = clustered index
GROUP BY t.name
ORDER BY t.name;
Results will be similar to the following example, in which there is a single count for the StatusData2 table:

Record Counts by Partition
The following query provides record counts by partition and includes the names of the individual filegroups:
/* Check counts by partition */
--EXEC sp_updatestats;
WITH PartitionInfo AS (
SELECT (SCHEMA_NAME(A.schema_id) + '.' + A.Name) AS TableName,
B.partition_number AS PartitionNumber,
B.row_count AS RecordCount,
FG.name AS FileGroupName,
ROW_NUMBER() OVER (PARTITION BY SCHEMA_NAME(A.schema_id), A.Name, B.partition_number ORDER BY B.partition_number) AS RowNum
FROM sys.dm_db_partition_stats B
LEFT JOIN sys.objects A
ON A.object_id = B.object_id
LEFT JOIN sys.partitions P
ON P.object_id = B.object_id
AND P.partition_id = B.partition_id
LEFT JOIN sys.allocation_units AU
ON P.partition_id = AU.container_id
LEFT JOIN sys.data_spaces DS
ON AU.data_space_id = DS.data_space_id
LEFT JOIN sys.filegroups FG
ON DS.data_space_id = FG.data_space_id
WHERE SCHEMA_NAME(A.schema_id) <> 'sys'
AND (B.index_id = 0 OR B.index_id = 1) -- 0 = heap, 1 = clustered index
)
SELECT TableName,
PartitionNumber,
RecordCount,
FileGroupName
FROM PartitionInfo
WHERE RowNum = 1
ORDER BY TableName, PartitionNumber;
Results will be similar to the following example, in which there is record count for each monthly partition of the StatusData2 table:

Automated Database Maintenance
There are many indexes on tables within the adapter database. These indexes facilitate high-performance querying, but become fragmented over time, leading to performance degradation if no maintenance is performed. The MyGeotab API Adapter includes automated database maintenance capabilities designed to perform database partitioning and index maintenance without the need for regular manual intervention. This should enable performance to remain strong even with millions or billions of records in the different tables.
✱ NOTE: If technical resources with sufficient database maintenance knowledge are available and there is a desire to implement more-advanced database maintenance strategies, the EnableLevel1DatabaseMaintenance and EnableLevel2DatabaseMaintenance settings in the DatabaseSettings section of the appsettings.json file can be used to disable the built-in capabilities of the MyGeotab API Adapter. However, the Database Partitioning procedure cannot be disabled.
✱ NOTE: Geotab cannot provide database support.
Database Partitioning
The Database Partitioning procedure is executed once daily by the DatabaseMaintenanceService2 service which runs continuously whenever the MyGeotab API Adapter is running. Each time it is executed, partitions will be created as needed up to and including for the month following that of the current day. This ensures that partitions will always be in-place when they are needed for any incoming data.
Level 1 Maintenance
“Level 1” database maintenance involves unobtrusive operations that can be executed while the MyGeotab API Adapter is “online” and operating normally. It can be configured via the EnableLevel1DatabaseMaintenance and Level1DatabaseMaintenanceIntervalMinutes settings in the DatabaseSettings section of the appsettings.json file. In all cases, Level 1 maintenance utilizes the vwStatsForLevel1DBMaintenance view in the adapter database.
Level 1 Maintenance - PostgreSQL
For PostgreSQL, Level 1 maintenance involves the following:
- VACUUM and ANALYZE: This is performed on tables meeting any of these criteria:
- Dead tuple ratio greater than 0.2
- Over 1,000 dead tuples
- ANALYZE Only: This is performed on tables where the modification ratio since the last analysis is greater than 0.1.
Level 1 Maintenance - SQL Server
For SQL Server, Level 1 maintenance involves the following:
- UPDATE STATISTICS: This is performed on tables where the modification ratio since the last analysis is greater than 0.1.
Level 2 Maintenance
“Level 2” database maintenance involves rebuilding indexes, which is more obtrusive and must be done within a database maintenance window during which the MyGeotab API Adapter services must be paused to avoid any issues. It can be configured via the EnableLevel2DatabaseMaintenance, Level2DatabaseMaintenanceIntervalMinutes, Level2DatabaseMaintenanceWindowStartTimeUTC and Level2DatabaseMaintenanceWindowMaxMinutes settings in the DatabaseSettings section of the appsettings.json file. In all cases, Level 2 maintenance utilizes the vwStatsForLevel2DBMaintenance view in the adapter database.
Level 2 Maintenance - PostgreSQL
For PostgreSQL, Level 2 maintenance involves the following:
- REINDEX: This is performed on indexes that are over 1,000 bytes in size and have a bloat ratio greater than 0.3.
Level 2 Maintenance - SQL Server
For SQL Server, Level 2 maintenance involves the following:
- REBUILD Entire Index: An entire index is rebuilt if more than half of its partitions are over 30 percent fragmented.
- REBUILD Index Partition: An index partition is rebuilt if it is over 30 percent fragmented (and not already captured as part of an entire index rebuild).
- REORGANIZE Index: An index partition (or an entire index if there is only one partition) is reorganized if it is between 10 and 30 percent fragmented (and not already captured as part of an entire index rebuild).
Longer-Term Data Retention Strategy
Despite the database partitioning and automated database maintenance capabilities offered in this solution, if the MyGeotab API Adapter or a derivative thereof is being deployed as part of a longer-term solution, it will be necessary to plan and implement a data retention strategy.
Eventually, the adapter database will have accumulated a large volume of data. For small fleets, it may take years, but for large fleets, data will accumulate very rapidly. Performance of the MyGeotab API Adapter as well as any other systems that may be interfacing with the adapter database will degrade over time as data volumes grow if left unchecked. Additionally, the associated data storage costs may become significant - particularly in cloud environments. As such, it is wise to plan a longer-term data retention strategy.
The fact that the adapter database is partitioned lends well to data retention strategies as it is much easier to separate older data by partition. Although no such functionality is built into the MyGeotab API Adapter due to the wide array of possible implementations, associated technologies and permissions considerations, the following sections broadly outline suggested longer-term data retention strategies for both PostgreSQL and SQL Server. In either case, automated processes can be developed and scheduled to perform this work on a routine basis. For example, let’s assume that there is a desire to keep only the last 12 months of data in the adapter database and archive older data.
Retention Strategy Example - PostgreSQL
- Identify and detach partitions older than 12 months from the parent tables.
- Backup the old partitions (to CSV, to an archive database, or using pg_dump).
- Drop the detached partitions after successful backup.
- Run ANALYZE and VACUUM FULL for cleanup and performance.
Retention Strategy Example - SQL Server
- Identify partitions older than 12 months and switch them to archive tables.
- Backup the archive tables (using SQL Backup or export to CSV).
- Drop the old partitions from the partition function.
Configuration Files
Two files, explained below, are used to configure the MyGeotab API Adapter - appsettings.json and nlog.config.
Service Interdependencies
Individual MyGeotab API Adapter services can be enabled or disabled using the Enable<EntityType>Cache settings for reference data tables and the Enable<EntityType>Feed settings for feed data tables. This provides the flexibility to download only the desired Geotab data, thereby affording potential cost savings in terms of CPU, memory and storage consumption. However, there are certain logical dependencies that must be enforced in order to make the Geotab data usable. For example, the LogRecord object has a Device property that contains the Id of the Device object with which it is associated. The LogRecord on its own is useless without knowing which Device it came from. Therefore, someone wishing to enable the LogRecordProcessor should also enable the DeviceProcessor.
To ensure that appropriate combinations of services are enabled, certain service interdependencies are enforced as shown in the following table. For each service, the list of direct service dependencies is provided. When a given service starts-up, checks are performed to ensure that any services on which it depends are already running. If not, warning messages will be written to the log file and the target service will keep checking intermittently until the services on which it depends are running. For example, if the StatusDataProcessor has been enabled, but the DeviceProcessor and DiagnosticProcessor have not been enabled, the log file will contain messages like the following:
2022-10-30 22:16:28.9799|INFO|"******** PAUSING SERVICE: MyGeotabAPIAdapter.StatusDataProcessor (v2.0.0.0) because of the following: > The prerequisite DeviceProcessor and DiagnosticProcessor have never been run. > The prerequisite DeviceProcessor and DiagnosticProcessor are not currently running. Please ensure that all prerequisite processors are running. The MyGeotabAPIAdapter.StatusDataProcessor (v2.0.0.0) will check again at 2022-10-31 2:16:38 AM (UTC) and will resume operation if all prerequisite processors are running at that time. |
✱ NOTE: There is a service orchestration and database partitioning process that occurs on application startup. Because all of the services start at the same time and some take longer than others to initialize, it is normal to see messages such as that in the above example when the MyGeotab API Adapter first starts. If services have been enabled, appropriately based on the table below, then these messages will stop appearing after the first few minutes of operation, once all of the services have come online.
In the above example, if the DeviceProcessor and DiagnosticProcessor have not been enabled, enable them both and restart the MyGeotab API Adapter to resolve the issue.
The following table lists the direct service dependencies for each service. Note that the dependencies might also have their own direct service dependencies.
Service | Direct Service Dependencies |
BinaryDataProcessor2 | DeviceProcessor2 |
ControllerProcessor2 | None |
ChargeEventProcessor2 | DeviceProcessor2 |
DeviceProcessor2 | None |
DeviceStatusInfoProcessor2 | DeviceProcessor2, UserProcessor2 |
DiagnosticProcessor2 | None |
DriverChangeProcessor2 | DeviceProcessor2, UserProcessor2 |
DutyStatusAvailabilityProcessor2 | UserProcessor2 |
DVIRLogManipulator2 | DVIRLogProcessor2 |
DutyStatusLogProcessor2 | DeviceProcessor2, UserProcessor2 |
DVIRLogManipulator2 | DVIRLogProcessor2 |
DVIRLogProcessor2 | DeviceProcessor2, UserProcessor2 |
ExceptionEventProcessor2 | DeviceProcessor2, RuleProcessor2, UserProcessor2 |
FailureModeProcessor2 | None |
FaultDataLocationService2 | None |
FaultDataProcessor2 | DeviceProcessor2, DiagnosticProcessor2 |
FuelAndEnergyUsedProcessor2 | DeviceProcessor2 |
GroupProcessor2 | None |
LogRecordProcessor2 | DeviceProcessor2 |
Orchestrator2 | None |
RuleProcessor2 | None |
StatusDataLocationService2 | None |
StatusDataProcessor2 | DeviceProcessor2, DiagnosticProcessor2 |
TripProcessor2 | DeviceProcessor2, UserProcessor2 |
UnitOfMeasureProcessor2 | None |
UserProcessor2 | None |
ZoneProcessor2 | None |
ZoneTypeProcessor2 | None |
appsettings.json
Aside from log-related items, all configuration settings governing operation of the MyGeotab API Adapter are found in the appsettings.json file, which is located in the same directory as the executable (i.e. MyGeotabAPIAdapter.exe). Individual settings are organized into sections for readability. The following tables provide information about the settings contained within each of these sections.
Environment Variables for DatabaseSettings and LoginSettings
In some cases, it may be necessary to store database connection strings and MyGeotab login credentials in environment variables rather than in the appsettings.json file itself. To do so, simply leave the appsettings.json settings as-is (i.e. do not change or delete the subject settings) and create the corresponding environment variables as in the following (Windows) example (note the double underscores “__”):

OverrideSettings
The OverrideSettings section contains settings used to override certain aspects of application logic.
Setting | Description |
DisableMachineNameValidation | Indicates whether machine name validation should be disabled. In most cases, the value should be false. It can be set to true only in cases where the application is deployed to a hosted environment in which machine names are not guaranteed to be static. ! WARNING: Extreme caution must be used when setting this value to true! Improper deployment could lead to application instability and data integrity issues! |
DatabaseSettings
The DatabaseSettings section contains settings used to connect to the adapter database that is paired with the MyGeotab API Adapter. It also includes settings that govern Automated Database Maintenance functionality.
Setting | Description |
EnableLevel1DatabaseMaintenance | Indicates whether Level 1 automated database maintenance should be enabled. Must be set to either true or false. |
Level1DatabaseMaintenanceIntervalMinutes | The interval, in minutes, at which Level 1 database maintenance is to be executed. (e.g. 30). Minimum: 10. Maximum: 43200 (30 days). Only used if EnableLevel1DatabaseMaintenance is true. |
EnableLevel2DatabaseMaintenance | Indicates whether Level 2 automated database maintenance should be enabled. Must be set to either true or false. |
Level2DatabaseMaintenanceIntervalMinutes | The interval, in minutes, at which Level 2 database maintenance is to be executed. (e.g. 30). Minimum: 30. Maximum: 43200 (30 days). Only used if EnableLevel2DatabaseMaintenance is true. |
EnableLevel2DatabaseMaintenanceWindow | If true, Level 2 database maintenance will only occur within a daily maintenance window defined by the Level2DatabaseMaintenanceWindowStartTimeUTC and Level2DatabaseMaintenanceWindowMaxMinutes settings. If false, Level 2 database maintenance will occur at regular intervals defined by Level2DatabaseMaintenanceIntervalMinutes. Must be set to either true or false. Only used if EnableLevel2DatabaseMaintenance is true. |
Level2DatabaseMaintenanceWindowStartTimeUTC | An ISO 8601 date and time string used to specify a time of day to serve as the basis upon which Level 2 database maintenance window start and end times are calculated. Only the time portion of the string is used; the date entered is irrelevant. To avoid time-zone related issues, Coordinated Universal Time (UTC) should be used (e.g. 2020-06-23T06:00:00Z). Only used if EnableLevel2DatabaseMaintenance is true. |
Level2DatabaseMaintenanceWindowMaxMinutes | The maximum number of minutes that a Level 2 database maintenance window can extend to. Once started, if Level 2 database maintenance is still underway when this number of minutes has elapsed, the database maintenance will stop, allowing normal operation of other services to resume. Only used if EnableLevel2DatabaseMaintenance is true. |
DatabaseProviderType | The database provider. Must be one of SQLServer or PostgreSQL. |
DatabaseConnectionString | The database connection string.
|
LoginSettings
The LoginSettings section is used to configure the credentials that the internal MyGeotab API object will use to authenticate to the MyGeotab database with which the current MyGeotab API Adapter instance is paired.
Setting | Description |
MyGeotabServer | The MyGeotab server (e.g. my.geotab.com). |
MyGeotabDatabase | The name of the MyGeotab database to authenticate against. ! WARNING: It is not possible to mix data from multiple MyGeotab databases within a single MyGeotab API Adapter database. Once data has been added to the adapter database, it is not possible to change the MyGeotabDatabase setting. |
MyGeotabUser | The MyGeotab username to be used for authentication. |
MyGeotabPassword | The password associated with the MyGeotab user. |
AppSettings - GeneralSettings
The GeneralSettings section under AppSettings includes settings that do not fall into any of the other categories.
Setting | Description |
TimeoutSecondsForDatabaseTasks | The maximum number of seconds allowed for an individual adapter database operation (select, insert, update, delete) to complete. If a database operation does not complete within this amount of time, it will be assumed that there is a loss of connectivity, the existing operation will be rolled-back and the MyGeotab API Adapter will resume normal operation after establishing that there is connectivity to the adapter database (e.g. 30). Minimum: 10. Maximum: 3600. |
TimeoutSecondsForMyGeotabTasks | The maximum number of seconds allowed for a MyGeotab API call to wait for a response. If a response is not received within this amount of time, it will be assumed that there is a loss of connectivity, the existing operation will be rolled-back and the MyGeotab API Adapter will resume normal operation after establishing that there is connectivity to the MyGeotab database via API (e.g. 300). Minimum: 10. Maximum: 3600. |
AppSettings - Caches
The Caches section under AppSettings includes sections that govern the timing and frequency by which the MyGeotab API Adapter updates and refreshes caches of entities obtained from the MyGeotab database configured in the LoginSettings section.
✱ NOTE: It is generally not necessary to adjust the settings for the various entity type caches. These settings are provided in case there are any special situations, but in most cases, the default values are sufficient.
In order to provide ultimate flexibility, each entity type has its own cache configuration section consisting of the following four settings which include the subject entity type name:
Setting | Description |
Enable | Indicates whether the cache for the subject entity type should be enabled. Must be set to either true or false. |
| An ISO 8601 date and time string used to specify a time of day to serve as the basis upon which cache update and refresh times are calculated using the associated interval settings. Only the time portion of the string is used; the date entered is irrelevant. To avoid time-zone related issues, Coordinated Universal Time (UTC) should be used (e.g. 2020-06-23T06:00:00Z). |
| The frequency, in minutes, by which the subject cache should be "updated" - capturing new and changed objects (e.g. 360). Minimum: 1. Maximum: 10080 (1 week). |
| The frequency, in minutes, by which the subject cache should be "refreshed" - dumped and repopulated to make identification of deleted entities possible, since deletes do not propagate from MyGeotab through the MyGeotab API data feeds (e.g. 1440). Minimum: 60 (1 hour). Maximum: 10080 (1 week). |
Cache Configuration Example:
As an example of cache configuration, in order to refresh the User cache at 2:00am EDT every day and update it every six hours (i.e. at 8:00am, 2:00pm and 8:00pm), the settings in the User cache section would be configured as follows:
...
"User": {
"EnableUserCache": true,
"UserCacheIntervalDailyReferenceStartTimeUTC": "2020-06-23T06:00:00Z",
"UserCacheUpdateIntervalMinutes": 360,
"UserCacheRefreshIntervalMinutes": 1440
},
...
! IMPORTANT: Cache refreshes and updates may occur slightly after the configured times due to the amount of time required to process cache and feed data during each iteration.
The following table outlines the various subsections included in the AppSettings > Caches section of the appsettings.json file. Each of these subsections follows the setting pattern described above.
Cache Subsection | Description |
Controller | Governs the cache of Controller entities. |
Device | Governs the cache of Device entities. |
Diagnostic | Governs the cache of Diagnostic entities. |
DVIRDefect | Governs the cache of DVIRDefect entities. ✱ NOTE: Not yet supported with Data Model 2. |
FailureMode | Governs the cache of FailureMode entities. |
Group | Governs the cache of Group entities. ✱ NOTE: Not yet supported. |
Rule | Governs the cache of Rule entities. ✱ NOTE: Not yet supported with Data Model 2. |
UnitOfMeasure | Governs the cache of UnitOfMeasure entities. |
User | Governs the cache of User entities. |
Zone | Governs the cache of Zone entities. |
ZoneType | Governs the cache of ZoneType entities. |
AppSettings - GeneralFeedSettings
The GeneralFeedSettings section under AppSettings contains settings that apply to all data feeds.
Setting | Description |
FeedStartOption | Alternate ways that polling via data feeds may be initiated. Must be set to one of the following values:
! WARNING: If any data has already been captured for a given feed, as determined by the existence of a corresponding entry in the OServiceTracking table in the adapter database, the FeedStartOption will automatically switch to FeedVersion - overriding any other value that may have been set. This mechanism is in place to avoid issues related to data duplication or gaps. |
FeedStartSpecificTimeUTC | Only used if the FeedStartOption parameter is set to SpecificTime. The UTC time (formatted as yyyy-MM-ddTHH:mm:ssZ) at which to start all data feeds (e.g. 2020-06-23T06:00:00Z). |
DevicesToTrack | A comma-separated list of device IDs that correspond to devices to be tracked. The default value of * indicates that data will be captured for all devices. Alternatively, if a comma-separated list of device IDs is provided (e.g. b1,b2), any feed data with relations to devices will be filtered such that only the data associated with the specified devices will be persisted to the adapter database. ! WARNING: In order to capture data related to all devices, the value of this setting must be *. |
DiagnosticsToTrack | A comma-separated list of diagnostic IDs that correspond to diagnostics (StatusData or FaultData) to be tracked. The default value of * indicates that data will be captured for all diagnostics. Alternatively, if a comma-separated list of diagnostic IDs is provided (e.g. DiagnosticOdometerId,DiagnosticFuelLevelId,DiagnosticFuelUnitsId,DiagnosticCrankingVoltageId,DiagnosticInvalidGpsMessagesReceivedId), any feed data with relations to diagnostics will be filtered such that only the data associated with the specified diagnostics will be persisted to the adapter database. ! WARNING: In order to capture data related to all diagnostics, the value of this setting must be *. |
ExcludeDiagnosticsToTrack | Indicates whether the DiagnosticsToTrack should be excluded, effectively inverting functionality. If false, only the data associated with the specified diagnostics will be persisted to the adapter database. If true, all data EXCEPT for the data associated with the specified diagnostics will be persisted to the adapter database. Must be set to either true or false. |
EnableMinimunIntervalSamplingForLogRecords | Indicates whether minimum interval sampling should be applied to the LogRecord feed. Only used if EnableLogRecordFeed is true. If set to true, a minimum interval defined by MinimumIntervalSamplingIntervalSeconds will be applied between LogRecords that are written to the LogRecords2 table. Must be set to either true or false. See the Minimum Interval Sampling section for more information. |
EnableMinimunIntervalSamplingForStatusData | Indicates whether minimum interval sampling should be applied to the StatusData feed. Only used if EnableStatusDataFeed is true. If set to true, a minimum interval defined by MinimumIntervalSamplingIntervalSeconds will be applied between StatusData entities with a Diagnostic Id included in the MinimumIntervalSamplingDiagnostics list that are written to the StatusData2 table. All StatusData entities with a Diagnostic Id included in the DiagnosticsToTrack list but not in the MinimumIntervalSamplingDiagnostics list will be persisted to the StatusData2 table. Must be set to either true or false. See the Minimum Interval Sampling section for more information. |
MinimumIntervalSamplingDiagnostics | A comma-separated list of diagnostic IDs for which minimum interval sampling will be applied to the StatusData feed. Only used if EnableStatusDataFeed is true. If set to true, a minimum interval defined by MinimumIntervalSamplingIntervalSeconds will be applied between StatusData entities with a Diagnostic Id included in this list that are written to the StatusData2 table. This list must be equal to the list provided in the DiagnosticsToTrack setting or a subset thereof. ExcludeDiagnosticsToTrack must be set to false. The placeholder wildcard value (*) cannot be used for the DiagnosticsToTrack setting nor this setting. See the Minimum Interval Sampling section for more information. |
MinimumIntervalSamplingIntervalSeconds | The minimum duration, in seconds, that should be applied between the DateTime values of entities that are written to their respective table(s) in the adapter database for any entity type that has minimum interval sampling enabled. Minimum: 1. Maximum: 3600 (1 hour). See the Minimum Interval Sampling section for more information. |
AppSettings - Feeds
The Feeds section under AppSettings includes sections that govern the use of data feeds for the various MyGeotab entity types that the MyGeotab API Adapter supports. In order to provide ultimate flexibility, each supported entity type has its own feed configuration section consisting of the following four settings which include the subject entity type name:
Setting | Description |
Enable | Indicates whether the data feed for the subject entity type should be enabled. Must be set to either true or false. |
| The minimum number of seconds to wait between GetFeed() calls for the subject entity type (e.g. 30). Minimum: 2. Maximum: 604800 (1 week). |
Certain feeds have additional settings to the ones listed above. Those additional settings are described in the following table:
Setting | Description |
DutyStatusAvailabilityFeedLastAccessDateCutoffDays | Used to reduce the number of unnecessary Get calls when retrieving DutyStatusAvailability information for all Drivers. Data is not queried for Drivers who have not accessed the Geotab system for more than this many days in the past. This value should be set to approximately twice the longest possible cycle for a HOS ruleset (e.g. 30). Minimum: 14. Maximum: 60. |
PopulateEffectOnComponentAndRecommendation | Used by the FaultData feed. Only used if EnableFaultDataFeed is set to true. Indicates whether the EffectOnComponent and Recommendation columns in the FaultData2 table will be populated. Setting this property to false will result in these columns being set to null, thereby potentially saving on disk space if these property values are not of interest. ! WARNING: There is no way to update these columns for records that have already been downloaded. |
TrackZoneStops | Used by the ExceptionEvent feed. Only used if EnableExceptionEventFeed is set to true. Indicates whether exceptions with an ExceptionRuleBaseType of ZoneStop are to be persisted to the adapter database. Must be set to either true or false. |
AppSettings - DataEnhancementServices
The DataEnhancementServices section under AppSettings includes sections that govern the use of services that enhance the data that has been extracted from the Geotab platform.
AppSettings - DataEnhancementServices - FaultData
The FaultData section under AppSettings > DataEnhancementServices includes settings that govern operation of the service that updates the FaultDataLocations2 table.
Setting | Description |
EnableFaultDataLocationService | Indicates whether the FaultDataLocationService2 service should be enabled. Must be set to either true or false. |
FaultDataLocationServiceOperationMode | If set to Continuous, the FaultDataLocationService2 service will keep running indefinitely. If set to Scheduled, the FaultDataLocationService2 service will run indefinitely, but pause operation outside of a daily time window defined by the FaultDataLocationServiceDailyStartTimeUTC and FaultDataLocationServiceDailyRunTimeSeconds settings. Must be set to either Continuous or Scheduled. |
FaultDataLocationServiceDailyStartTimeUTC | Only used if FaultDataLocationServiceOperationMode is set to Scheduled. An ISO 8601 date and time string used to specify a time of day to serve as the start time for the daily operation window of the FaultDataLocationService2 service. Only the time portion of the string is used; the date entered is irrelevant. To avoid time-zone related issues, Coordinated Universal Time (UTC) should be used (e.g. 2020-06-23T06:00:00Z). |
FaultDataLocationServiceDailyRunTimeSeconds | Only used if FaultDataLocationServiceOperationMode is set to Scheduled and FaultDataLocationServiceDailyStartTimeUTC is set to an appropriate value. The duration, in seconds, that the FaultDataLocationService2 service will run for each day, starting from the time defined in the FaultDataLocationServiceDailyStartTimeUTC setting (e.g. 21600 for 6 hours). Minimum: 300 (5 minutes). Maximum: 82800 (23 hours). |
FaultDataLocationServiceExecutionIntervalSeconds | While the FaultDataLocationService2 service is running, either continuously or within a daily operation window, if no records are processed in a given batch/iteration, the service will pause for this duration (in seconds) before proceeding with the next batch/iteration. If 1 or more records are processed in a given batch/iteration, the FaultDataLocationService2 will immediately retrieve the next batch of records for processing (e.g. 60). Minimum: 2. Maximum: 604800 (1 week). This throttling mechanism is designed to maximize throughput while preventing excessive CPU usage and database I/O when little or no data is returned as the service would otherwise needlessly iterate multiple times per second. |
FaultDataLocationServicePopulateSpeed | Indicates whether the FaultDataLocationService2 service should populate the Speed column in the FaultDataLocations2 table. Must be set to either true or false. |
FaultDataLocationServicePopulateBearing | Indicates whether the FaultDataLocationService2 service should populate the Bearing column in the FaultDataLocations2 table. Must be set to either true or false. |
FaultDataLocationServicePopulateDirection | Indicates whether the FaultDataLocationService2 service should populate the Direction column in the FaultDataLocations2 table. Must be set to either true or false. |
FaultDataLocationServiceNumberOfCompassDirections | Only used if FaultDataLocationServicePopulateDirection is set to true. Indicates the number of cardinal directions (on the compass rose) to use when determining direction based on the Bearing value. Must be one of 4, 8, or 16. |
FaultDataLocationServiceMaxDaysPerBatch | Used by the spFaultData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). The maximum number of days over which unprocessed FaultData records in a batch can span. Minimum: 1. Maximum: 10. |
FaultDataLocationServiceMaxBatchSize | Used by the spFaultData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). The maximum number of unprocessed FaultData records to retrieve for interpolation per batch. Minimum: 10000. Maximum: 500000. |
FaultDataLocationServiceBufferMinutes | Used by the spFaultData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). When getting the DateTime range of a batch of unprocessed FaultData records, this buffer is applied to either end of the DateTime range when selecting LogRecords to use for interpolation such that lag LogRecords can be obtained for records that are “early” in the batch and lead LogRecords can be obtained for records that are “late” in the batch. Minimum: 10. Maximum: 1440. |
AppSettings - DataEnhancementServices - StatusData
The StatusData section under AppSettings > DataEnhancementServices includes settings that govern operation of the service that updates the StatusDataLocations2 table.
Setting | Description |
EnableStatusDataLocationService | Indicates whether the StatusDataLocationService2 service should be enabled. Must be set to either true or false. |
StatusDataLocationServiceOperationMode | If set to Continuous, the StatusDataLocationService2 service will keep running indefinitely. If set to Scheduled, the StatusDataLocationService2 service will run indefinitely, but pause operation outside of a daily time window defined by the StatusDataLocationServiceDailyStartTimeUTC and StatusDataLocationServiceDailyRunTimeSeconds settings. Must be set to either Continuous or Scheduled. |
StatusDataLocationServiceDailyStartTimeUTC | Only used if StatusDataLocationServiceOperationMode is set to Scheduled. An ISO 8601 date and time string used to specify a time of day to serve as the start time for the daily operation window of the StatusDataLocationService2 service. Only the time portion of the string is used; the date entered is irrelevant. To avoid time-zone related issues, Coordinated Universal Time (UTC) should be used (e.g. 2020-06-23T06:00:00Z). |
StatusDataLocationServiceDailyRunTimeSeconds | Only used if StatusDataLocationServiceOperationMode is set to Scheduled and StatusDataLocationServiceDailyStartTimeUTC is set to an appropriate value. The duration, in seconds, that the StatusDataLocationService2 service will run for each day, starting from the time defined in the StatusDataLocationServiceDailyStartTimeUTC setting (e.g. 21600 for 6 hours). Minimum: 300 (5 minutes). Maximum: 82800 (23 hours). |
StatusDataLocationServiceExecutionIntervalSeconds | While the StatusDataLocationService2 service is running, either continuously or within a daily operation window, if no records are processed in a given batch/iteration, the service will pause for this duration (in seconds) before proceeding with the next batch/iteration. If 1 or more records are processed in a given batch/iteration, the StatusDataLocationService2 will immediately retrieve the next batch of records for processing (e.g. 60). Minimum: 2. Maximum: 604800 (1 week). This throttling mechanism is designed to maximize throughput while preventing excessive CPU usage and database I/O when little or no data is returned as the service would otherwise needlessly iterate multiple times per second. |
StatusDataLocationServicePopulateSpeed | Indicates whether the StatusDataLocationService2 service should populate the Speed column in the StatusDataLocations2 table. Must be set to either true or false. |
StatusDataLocationServicePopulateBearing | Indicates whether the StatusDataLocationService2 service should populate the Bearing column in the StatusDataLocations2 table. Must be set to either true or false. |
StatusDataLocationServicePopulateDirection | Indicates whether the StatusDataLocationService2 service should populate the Direction column in the StatusDataLocations2 table. Must be set to either true or false. |
StatusDataLocationServiceNumberOfCompassDirections | Only used if StatusDataLocationServicePopulateDirection is set to true. Indicates the number of cardinal directions (on the compass rose) to use when determining direction based on the Bearing value. Must be one of 4, 8, or 16. |
StatusDataLocationServiceMaxDaysPerBatch | Used by the spStatusData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). The maximum number of days over which unprocessed StatusData records in a batch can span. Minimum: 1. Maximum: 10. |
StatusDataLocationServiceMaxBatchSize | Used by the spStatusData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). The maximum number of unprocessed StatusData records to retrieve for interpolation per batch. Minimum: 10000. Maximum: 500000. |
StatusDataLocationServiceBufferMinutes | Used by the spStatusData2WithLagLeadLongLatBatch stored procedure (MSSQL) or function (Postgres). When getting the DateTime range of a batch of unprocessed StatusData records, this buffer is applied to either end of the DateTime range when selecting LogRecords to use for interpolation such that lag LogRecords can be obtained for records that are “early” in the batch and lead LogRecords can be obtained for records that are “late” in the batch. Minimum: 10. Maximum: 1440. |
AppSettings - Manipulators
The Manipulators section under AppSettings includes sections that govern services responsible for issuing data manipulation commands to the Geotab platform. Manipulators may be used in conjunction with feeds to facilitate bidirectional integration between the Geotab platform and external systems.
AppSettings - Manipulators - DVIRLog
The DVIRLog section under AppSettings > Manipulators includes settings that govern the use of the DVIRLogManipulator2 service which provides the capability to update DVIRLogs in the MyGeotab database configured in the LoginSettings section. See the DVIRLog Manipulator section for more information.
Setting | Description |
EnableDVIRLogManipulator | Indicates whether the DVIRLogManipulator2 service should be enabled. Must be set to either true or false. |
DVIRLogManipulatorIntervalSeconds | The minimum number of seconds to wait between starts of iterations of the DVIRLogManipulator2 processing logic(e.g. 30). Minimum: 2. Maximum: 604800 (1 week). |
nlog.config
The MyGeotab API Adapter utilizes the NLog LoggerProvider for Microsoft.Extensions.Logging to capture information and write it to log files for debugging purposes. NLog configuration settings are found in the nlog.config file, which is located in the same directory as the executable (i.e. MyGeotabAPIAdapter.exe).
Below is the content of the nlog.config file that is included with the MyGeotab API Adapter. It is followed by instructions that indicate how the highlighted settings may be adjusted.
version="1.0" encoding="utf-8" ?>
xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="LOG-MyGeotab_API_Adapter-internal.log"
internalLogLevel="Error" >
<targets>
xsi:type="File" name="target1" fileName="LOG-MyGeotab_API_Adapter.log" maxArchiveFiles="100" archiveAboveSize="5120000" archiveEvery="Day">
xsi:type="CsvLayout" delimiter="Pipe" withHeader="true">
name="Time" layout="${longdate}" />
name="Level" layout="${level:upperCase=true}"/>
name="Message" layout="${message}" />
name="Exception" layout="${exception}"/>
name="Logger" layout="${logger}" />
name="All Event Properties" layout="${all-event-properties}" />
</layout>
</target>
xsi:type="Console" name="target2"
layout="${date}|${level:uppercase=true}|${message} ${exception}|${logger}|${all-event-properties}" />
</targets>
<rules>
name="*" minlevel="Info" writeTo="target1,target2" />
</rules>
</nlog>
! IMPORTANT: Only the settings that are highlighted in the above content should be modified as described in the following table. Changing anything else could lead to unpredictable consequences.
The following table lists the NLog settings, highlighted above, that may be adjusted as required.
Setting | Description |
autoReload | Indicates whether the nlog.config file should be watched for changes and reloaded automatically when changed. Must be set to either true or false. |
maxArchiveFiles | Maximum number of archive files that should be kept. If maxArchiveFiles is less or equal to 0, old files aren't deleted. Default: 100. |
archiveAboveSize | Size in bytes above which log files will be automatically archived. Default: 5120000 (5 MB). |
archiveEvery | Indicates whether to automatically archive log files every time the specified time passes. Default: DAY. Possible values:
|
minlevel | Indicates the log level, which is the amount of detail to be written to log files. Default: Info. Possible values:
|
Minimum Interval Sampling
LogRecord and StatusData entities typically account for a very large proportion of the data volume in a MyGeotab database - hundreds of millions of records per day for fleets of over 100K devices, for example. In some cases, this massive data volume may be deemed excessive and there may be a preference to reduce data volume such that data points are no more frequent than one per device every x number of seconds. To address this need, “minimum interval sampling” capability has been added to the MyGeotab API Adapter via the EnableMinimunIntervalSamplingForLogRecords, EnableMinimunIntervalSamplingForStatusData, MinimumIntervalSamplingDiagnostics and MinimumIntervalSamplingIntervalSeconds settings in the AppSettings - GeneralFeedSettings section of the appsettings.json file.
! WARNING: Be careful before deciding to utilize the minimum interval sampling capability of the MyGeotab API Adapter. There is no way to later back-fill data if minimum interval sampling has been used other than clearing the adapter database, adjusting the appsettings.json file and re-running the extraction process.
✱ NOTE: Minimum interval sampling does not ensure that LogRecord or StatusData entities are are captured at a regular “polling interval” of one record every n seconds. Rather, it ensures that a minimum of n seconds exists between the DateTime values of LogRecord or StatusData entities that are written to the adapter database. Entities that fall within the interval are discarded instead of being written to the adapter database.
Minimum Interval Sampling for LogRecords
With regard to LogRecords, minimum interval sampling is applied on a per-Device basis and can be enabled based on the following rules:
- EnableLogRecordFeed must be set to true.
- EnableDeviceCache must be set to true. This is because the LogRecordProcessor requires the DeviceCache to be operational.
- EnableMinimunIntervalSamplingForLogRecords must be set to true. Otherwise, normal processing of LogRecords will occur.
- MinimumIntervalSamplingIntervalSeconds must be set to a value ranging from 1 through 3600.
- [Optional] DevicesToTrack can be used to limit the collection of LogRecords to a specific set of devices.
Take the following example highlighting a specific combination of values in the appsettings.json file:
...
"EnableDeviceCache": true,
"EnableDiagnosticCache": true,
...
"FeedStartOption": "SpecificTime",
"FeedStartSpecificTimeUTC": "2024-04-01T08:00:00Z",
"DevicesToTrack": "*",
"DiagnosticsToTrack": "DiagnosticOilPressureId,DiagnosticIgnitionId,DiagnosticEngineRoadSpeedId",
"ExcludeDiagnosticsToTrack": false,
"EnableMinimunIntervalSamplingForLogRecords": true,
"EnableMinimunIntervalSamplingForStatusData": true,
"MinimumIntervalSamplingDiagnostics": "DiagnosticOilPressureId,DiagnosticEngineRoadSpeedId",
"MinimumIntervalSamplingIntervalSeconds": 300
...
"EnableLogRecordFeed": true,
...
"EnableStatusDataFeed": true,
...
Based on the above setting configuration:
- The LogRecords2 table in the adapter database will be populated with data for all devices (that the MyGeotab user configured in the LoginSettings section of appsettings.json has access to).
- The minimum interval between successive LogRecords for a given device will be 300 seconds (5 minutes).
Minimum Interval Sampling for StatusData
With regard to StatusData, minimum interval sampling is applied on a per-Device + Diagnostic basis and can be enabled based on the following rules:
- EnableStatusDataFeed must be set to true.
- EnableDeviceCache and EnableDiagnosticCache must both be set to true. This is because the StatusDataProcessor requires the DeviceCache and DiagnosticCache to be operational.
- EnableMinimunIntervalSamplingForStatusData must be set to true. Otherwise, normal processing of StatusData will occur.
- MinimumIntervalSamplingIntervalSeconds must be set to a value ranging from 1 through 3600.
- DiagnosticsToTrack must be set to a comma-separated list of Diagnostic Ids. The default wildcard (*) value cannot be used if EnableMinimunIntervalSamplingForStatusData is set to true.
- ExcludeDiagnosticsToTrack must be set to false if EnableMinimunIntervalSamplingForStatusData is set to true.
- MinimumIntervalSamplingDiagnostics must be set to a comma-separated list of Diagnostic Ids that is either the same as the list provided in DiagnosticsToTrack, or a subset thereof. Minimum interval sampling will only be applied to StatusData records with Diagnostic Ids that are in this list. Normal processing will occur for StatusData records with Diagnostic Ids that are in the DiagnosticsToTrack list but not in the MinimumIntervalSamplingDiagnostics list.
- [Optional] DevicesToTrack can be used to limit the collection of LogRecords to a specific set of devices.
Take the following example highlighting a specific combination of values in the appsettings.json file:
...
"EnableDeviceCache": true,
"EnableDiagnosticCache": true,
...
"FeedStartOption": "SpecificTime",
"FeedStartSpecificTimeUTC": "2024-04-01T08:00:00Z",
"DevicesToTrack": "*",
"DiagnosticsToTrack": "DiagnosticOilPressureId,DiagnosticIgnitionId,DiagnosticEngineRoadSpeedId",
"ExcludeDiagnosticsToTrack": false,
"EnableMinimunIntervalSamplingForLogRecords": true,
"EnableMinimunIntervalSamplingForStatusData": true,
"MinimumIntervalSamplingDiagnostics": "DiagnosticOilPressureId,DiagnosticEngineRoadSpeedId",
"MinimumIntervalSamplingIntervalSeconds": 300
...
"EnableLogRecordFeed": true,
...
"EnableStatusDataFeed": true,
...
Based on the above setting configuration:
- The StatusData2 table in the adapter database will be populated with data for all devices (that the MyGeotab user configured in the LoginSettings section of appsettings.json has access to).
- Only StatusData records with the DiagnosticOilPressureId, DiagnosticIgnitionId and DiagnosticEngineRoadSpeedId Diagnostic Ids will be collected.
- All StatusData records with the DiagnosticIgnitionId Diagnostic Id will be collected.
- For StatusData records with the DiagnosticOilPressureId and DiagnosticEngineRoadSpeedId Diagnostic Ids, the minimum interval between successive StatusData records for a given device will be 300 seconds (5 minutes).
DVIRLog Manipulator
The DVIRLog Manipulator is a service that provides the ability to update DVIRLogs in the MyGeotab database.
Capabilities
Using the DVIRLog Manipulator, it is possible - without directly using the MyGeotab API - to:
- Add repair remarks to existing DVIRDefects
- Change the repair status of existing DVIRDefects
End-to-End Bidirectional Workflow Scenario
A practical example where the DVIRLog Manipulator could be used is an integration between Geotab and an enterprise asset management (EAM) system. In this scenario:
Step | Detail |
1 | Using the Geotab Drive app, drivers completing vehicle inspection reports (DVIRs) log any defects that they discover. |
2 | The MyGeotab API Adapter’s DVIRLog processor retrieves the DVIRLogs and writes them to tables (DVIRLogs2, DVIRDefects2, DVIRDefectRemarks2) in the adapter database. |
3 | A third-party integration service extracts the defect information from the adapter database and generates repair work orders in the EAM system. |
4 | As repair remarks are added to the work orders in the EAM and when the repair orders are closed upon completion of corrective maintenance activities, the third-party integration service writes these remarks and updates to the upd_DVIRDefectUpdates2 table in the adapter database. |
5 | The DVIRLog Manipulator service captures the repair remarks and status updates as they are written to the upd_DVIRDefectUpdates2 table and makes the appropriate updates to the corresponding DVIRLogs in the Geotab system. |
6 | Drivers using the Geotab Drive app as well as supervisors and fleet managers using the MyGeotab web-based application are able to keep up-to-date on the status of repairs as updates flow from the EAM system into the Geotab system via this workflow. |
The above workflow is illustrated with diagrams in the DVIRLog Manipulator section of the MyGeotab API Adapter presentation.
Usage
To use the DVIRLog Manipulator, simply ensure that the EnableDVIRLogFeed and EnableDVIRLogManipulator settings are both set to true before starting the adapter.
Repair remarks can be added to existing DVIRDefects and the repair status of existing DVRDefects can be updated in the Geotab system by simply inserting records into the upd_DVIRDefectUpdates2 table in the adapter database.
Rules for Insertion Into the upd_DVIRDefectUpdates2 Table
To ensure that updates can be successfully processed, the following rules must be adhered to when inserting these records into the upd_DVIRDefectUpdates2 table:
Rule | Detail |
1 | Values must always be provided for the DVIRLogId, DVIRDefectId and RecordCreationTimeUtc fields. |
2 | The value provided for the DVIRLogId field must correspond to the Id of the record in the DVIRLogs2 table which represents the DVIRLog to be updated in the MyGeotab database. |
3 | The value provided for the DVIRDefectId field must correspond to the Id of the record in the DVIRDefects2 table which represents the DVIRDefect to be updated in the MyGeotab database. |
4 | To add a remark to a DVIRDefect:
|
5 | To update the repair status of a DVIRDefect:
|
6 | To add a remark to a DVIRDefect and update the repair status of the DVIRDefect at the same time:
|
7 | The RepairStatusId of a DVIRDefect cannot be changed once it has been set to 1 (Repaired) or 2 (NotNecessary). |
8 | The only values that may be supplied for the RepairStatusId field are 1 (Repaired) or 2 (NotNecessary) (other than null when only a repair remark is to be added). |
9 | Values provided for the RepairUserId and RemarkUserId fields must correspond to the Ids of records in the Users2 table table which represent valid User Ids in the MyGeotab database. The same value can be provided for both fields; separate fields are provided for added flexibility. Additionally, the subject Users must have appropriate clearances in the MyGeotab database:
|
Feedback and Exceptions
DVIRLog updates made by the DVIRLog Manipulator service are captured by the DVIRLog Processor service and written to the adapter database as updates to the DVIRLogs2, DVIRDefects2 and DVIRDefectRemarks2 tables. Records that have been processed by the DVIRLog Manipulator service are deleted from the upd_DVIRDefectUpdates2 table in the adapter database.
Any rows in the upd_DVIRDefectUpdates2 table that do not pass validation checks or for which exceptions are encountered while attempting the associated DVIRLog updates will be copied to the fail_DVIRDefectUpdateFailures2 table before being deleted from the upd_DVIRDefectUpdates2 table.
! WARNING: Rows are never deleted from the fail_DVIRDefectUpdateFailures2 table. It is up to the integrator to delete rows from this table once the error messages have been evaluated and appropriate actions have been taken.
The FailureMessage column provides details about the reason why a given command failed. This is to assist in debugging and to provide feedback that would otherwise be provided in the responses to commands issued via the MyGeotab API.
Using the Adapter Database: Best Practices
This section includes information that is important when using the adapter database - including best practices that may be applicable in certain scenarios.
Future-Proofing Queries Against Changes to Diagnostic Ids
Occasionally, Diagnostic Ids change via the assignment of KnownIds by Geotab. For example, the Diagnostic named “Generic Adblue / diesel exhaust fluid (DEF) tank level” originally had a GeotabId of “aCDbCr55QuUu2GhWCSN0CkQ”, which was replaced with a KnownId of “DiagnosticGenericAdblueTankLevelId” at some point.
How Might Changing Diagnostic Ids be a Problem?
While the human-readable KnownIds are more user-friendly and readily identifiable, the changing of Diagnostic Ids can present a number of challenges for integrators who may be unaware of these Id changes and who may have queries that incorporate the original Diagnostic Ids. Let’s imagine that data has been extracted from a MyGeotab database via a near real-time feed for a year and the “Generic Adblue / diesel exhaust fluid (DEF) tank level” Diagnostic Id changed from “aCDbCr55QuUu2GhWCSN0CkQ” to “DiagnosticGenericAdblueTankLevelId” half way through the year. Let’s also imagine that a query has been designed as part of some downstream process. In this scenario:
- If the query selects StatusData using the original GeotabId (“aCDbCr55QuUu2GhWCSN0CkQ”), it would stop returning any data for the subject Diagnostic half way through the year.
- If the query selects StatusData using the new GeotabId (“DiagnosticGenericAdblueTankLevelId”), it would not return any data for the subject Diagnostic for the first half of the year.
- If the query were modified to include both GeotabIds for the subject Diagnostic, it would return all data for the year. However, that would require modification of the query and would likely happen only after it was noticed that one of the above two scenarios was occurring and an investigation found the reason.
To find out how this potential issue can be mitigated, keep reading.
Diagnostic GUIDs and Adapter Database Structure
Using the .NET API Client, it is possible to obtain the underlying Globally Unique Identifier (GUID) of a Diagnostic object, as shown in the following C# example:
var geotabGUID = diagnostic.Id.GetValue().ToString();
When a KnownId is assigned to an existing Diagnostic, this GUID does not change. As such, it is possible to detect changes to Diagnostic Ids and relate new Diagnostic Ids back to their previous values by using the GUID. The following diagram illustrates the adapter database table structure in relation to this particular solution (note that the FaultDataT table could be included as well, but was left out for brevity):

In this data structure:
- The Diagnostics2 table contains a single record for each Diagnostic in the MyGeotab database, including the various attributes.
- The DiagnosticIds2 table contains one record for each combination of GeotabGUIDString + GeotabId. The “id” column in this table is auto-generated when a record is inserted. This table is linked to the Diagnostics2 table via the “GeotabGUIDString” column.
- The “DiagnosticId” column in the StatusData2 table (same applies to the FaultData2 table) is linked to the “id” column in the DiagnosticIds2 table.
In the earlier example of the KnownId being assigned to the “Generic Adblue” Diagnostic:
- There will be one record for the subject Diagnostic in the Diagnostics2 table.
- The DiagnosticIds2 table will contain two records for the subject Diagnostic - one where the GeotabId is “aCDbCr55QuUu2GhWCSN0CkQ”, and another where the GeotabId is “DiagnosticGenericAdblueTankLevelId”.
- The StatusData2 table will contain some records (covering the first half of the year) for the subject Diagnostic that are linked to the first “id” for the subject Diagnostic in the DiagnosticIds2 table. It will also contain some records (covering the second half of the year) for the subject Diagnostic that are linked to the second “id” for the subject Diagnostic in the DiagnosticIds2 table.
How to Future-Proof Queries Against Changes to Diagnostic Ids
StatusData records are often used in queries and reports that analyze vehicle engine data. Such queries typically focus on a specific Diagnostic or set thereof and will incorporate the relevant Diagnostic Id(s). When querying the StatusData2 table, with the table structure described in the previous section, it is possible to build queries that filter on specific Diagnostic Ids and be confident that those queries will still work if any of the Diagnostic Ids happen to change (due to the assignment of KnownIds).
In the following examples, the StatusData2 table is queried for the Diagnostic named “Generic Adblue / diesel exhaust fluid (DEF) tank level” – which originally had a GeotabId of “aCDbCr55QuUu2GhWCSN0CkQ” that was later replaced with a KnownId of “DiagnosticGenericAdblueTankLevelId”.
Query Created Before Diagnostic Id Change
A query created before the KnownId was assigned would use the original Diagnostic Id:
SQL Server Version:
WITH RelatedDiagnosticIds AS (
SELECT did2.id
FROM DiagnosticIds2 did1
JOIN DiagnosticIds2 did2
ON did1.GeotabGUIDString = did2.GeotabGUIDString
WHERE did1.GeotabId = N'aCDbCr55QuUu2GhWCSN0CkQ'
)
SELECT sd.*
FROM StatusData2 sd WITH (NOLOCK)
JOIN RelatedDiagnosticIds rdid
ON sd.DiagnosticId = rdid.id
ORDER BY sd.DateTime;
PostgreSQL Version:
WITH "RelatedDiagnosticIds" AS (
SELECT did2."id"
FROM public."DiagnosticIds2" did1
JOIN public."DiagnosticIds2" did2
ON did1."GeotabGUIDString" = did2."GeotabGUIDString"
WHERE did1."GeotabId" = 'aCDbCr55QuUu2GhWCSN0CkQ'
)
SELECT sd.*
FROM public."StatusData2" sd
JOIN "RelatedDiagnosticIds" rdid
ON sd."DiagnosticId" = rdid."id"
ORDER BY sd."DateTime";
Query Created After Diagnostic Id Change
A query created after the KnownId was assigned would use the new Diagnostic Id:
SQL Server Version:
WITH RelatedDiagnosticIds AS (
SELECT did2.id
FROM DiagnosticIds2 did1
JOIN DiagnosticIds2 did2
ON did1.GeotabGUIDString = did2.GeotabGUIDString
WHERE did1.GeotabId = N'DiagnosticGenericAdblueTankLevelId'
)
SELECT sd.*
FROM StatusData2 sd WITH (NOLOCK)
JOIN RelatedDiagnosticIds rdid
ON sd.DiagnosticId = rdid.id
ORDER BY sd.DateTime;
PostgreSQL Version:
WITH "RelatedDiagnosticIds" AS (
SELECT did2."id"
FROM public."DiagnosticIds2" did1
JOIN public."DiagnosticIds2" did2
ON did1."GeotabGUIDString" = did2."GeotabGUIDString"
WHERE did1."GeotabId" = 'DiagnosticGenericAdblueTankLevelId'
)
SELECT sd.*
FROM public."StatusData2" sd
JOIN "RelatedDiagnosticIds" rdid
ON sd."DiagnosticId" = rdid."id"
ORDER BY sd."DateTime";
Query Results (Query Created Before vs. After Diagnostic Id Change)
The only difference between the query created before the Diagnostic Id change and the query created after the Diagnostic Id change is the GeotabId of the Diagnostic itself. As a result of structuring the query in the manner shown above:
- Both queries will return the same result – including StatusData2 records from both before and after the point when the Diagnostic Id changed from “aCDbCr55QuUu2GhWCSN0CkQ” to “DiagnosticGenericAdblueTankLevelId”.
What this means in practical terms is that:
- The changing of Diagnostic Ids will not have any impact on queries, views, reports, dashboards, applications, etc. that may have been configured to use the original Diagnostic Ids.
- Any queries specifying the new Diagnostic Ids will also work for StatusData that may have been collected with the original Diagnostic Ids.
If it is important for a particular purpose that queries involving Diagnostic Ids be resilient to changes caused by the potential assignment of KnownIds, any queries of the StatusData2 table that filter on Diagnostic Ids should be modeled on the above examples. The same applies for queries of the FaultData2 table that filter on Diagnostic Ids.
Using NOLOCK and READ UNCOMMITTED in Some Cases (SQL Server)
✱ NOTE: This section is applicable only if SQL Server is used for the adapter database. PostgreSQL behaves differently and does not have equivalent options.
! WARNING: Use caution if using the NOLOCK table hint. It is recommended to only use it for feed data tables. See Understanding the SQL Server NOLOCK hint for more explanation.
The MyGeotab API Adapter is constantly polling the Geotab platform for new data and writing that data to tables in the adapter database. With large fleets in particular, the effect is an almost constant stream of data flowing into feed data tables such as FaultData2, LogRecords2 and StatusData2. This can potentially slow things down when it comes to SELECT queries that pull data from feed data tables as they must wait for any locks held by inserting processes to be released first.
One potential option to boost performance might be to include the NOLOCK table hint for feed data tables included in SELECT queries as shown in the following example, where the NOLOCK table hint is applied to the StatusData2 (feed data) table:
WITH RelatedDiagnosticIds AS (
SELECT did2.id
FROM DiagnosticIds2 did1
JOIN DiagnosticIds2 did2
ON did1.GeotabGUIDString = did2.GeotabGUIDString
WHERE did1.GeotabId = N'DiagnosticGenericAdblueTankLevelId'
)
SELECT sd.*
FROM StatusData2 sd WITH (NOLOCK)
JOIN RelatedDiagnosticIds rdid
ON sd.DiagnosticId = rdid.id
ORDER BY sd.DateTime;
Note that the NOLOCK table hint is not used with the DiagnosticIds2 table because it is a “reference data” table and reference data tables get updated periodically, which can lead to potential issues related to “dirty data”. Since feed data tables only have data inserted, there is much less risk of issues related to dirty data.
Similar to the NOLOCK table hint, when developing stored procedures that SELECT data for downstream processing, it is possible to set the transaction isolation level to READ UNCOMMITTED as shown in the following snippet:
CREATE PROCEDURE [dbo].[spFaultData2WithLagLeadLongLatBatch]
@MaxDaysPerBatch INT,
@MaxBatchSize INT,
@BufferMinutes INT
AS
BEGIN
-- Use READ UNCOMMITTED to reduce contention. No writes are performed in this procedure
-- and new uncommitted data should not adversely affect results.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
DECLARE
-- Constants:
@minAllowed_maxDaysPerBatchValue INT = 1,
...
Leveraging System Tables/Catalogs Where Possible
Querying system tables (SQL Server) or catalogs (PostgreSQL) where possible provides a low-impact and highly-performant way to obtain information. For example, the following query can be used to obtain record counts for all tables in the adapter database:
SQL Server Version:
/* Check counts */
--EXEC sp_updatestats;
SELECT t.name AS TableName,
SUM(p.rows) AS RecordCount
FROM sys.tables t
JOIN sys.partitions p ON t.object_id = p.object_id
WHERE t.type = 'U' -- User tables only
AND p.index_id IN (0, 1) -- 0 = heap, 1 = clustered index
GROUP BY t.name
ORDER BY t.name;
PostgreSQL Version:
/* Check counts */
--ANALYZE;
WITH partitioned_tables AS (
SELECT part.relname AS parent_table,
child.relname AS partition_table
FROM pg_partitioned_table p
JOIN pg_class part ON p.partrelid = part.oid
JOIN pg_inherits i ON part.oid = i.inhparent
JOIN pg_class child ON i.inhrelid = child.oid
WHERE part.relname NOT LIKE 'pg_%'
AND part.relname NOT LIKE 'sql_%'
AND child.relname NOT LIKE 'pg_%'
AND child.relname NOT LIKE 'sql_%'
),
table_counts AS (
SELECT relname AS table_name,
coalesce(SUM(n_live_tup), 0) AS record_count
FROM pg_stat_all_tables
WHERE relname NOT LIKE 'pg_%'
AND relname NOT LIKE 'sql_%'
GROUP BY relname
)
SELECT
CASE
WHEN pt.parent_table IS NOT NULL THEN pt.parent_table
ELSE tc.table_name
END AS TableName,
SUM(tc.record_count) AS RecordCount
FROM table_counts tc
LEFT JOIN partitioned_tables pt ON tc.table_name = pt.partition_table
GROUP BY TableName
ORDER BY TableName;
Using the system tables/catalogs as shown above instead of “COUNT(*)” queries has benefits including:
- High-performance and reduced I/O load on the system since full table scans are avoided.
- Contention avoidance since this approach does not interfere with concurrent writes or block transactions.
- High-scalability because it works well for partitioned tables and high-throughput systems with large amounts of data.
The one drawback to this approach is that exact counts are not always provided - although, if the API Adapter is running while the “COUNT(*)” approach is used, by the time all of the results are returned, the counts will be out-dated as well.
Although use of the system tables/catalogs is limited to situations in which metadata is required (as opposed to actual data from the adapter database tables), doing so, where appropriate, will help to reduce overall load on the system while providing quick and useful results.
Incorporating DateTime Ranges in Queries to Leverage Partition Pruning
The adapter database utilizes a database partitioning strategy wherein database tables are partitioned by month, week or day – depending on how the database is set-up. With large fleets and/or data collected over a long period of time, certain tables might contain hundreds of millions or even billions of records.However, the individual monthly, weekly or daily partitions will contain far fewer records than the aggregate table. Where possible, queries should be designed to incorporate DateTime ranges as shown in the following example:
SQL Server Version:
SELECT * FROM dbo.LogRecords2
WHERE DateTime >= '2025-01-01 00:00:00'
AND DateTime < '2025-02-01 00:00:00';
PostgreSQL Version:
SELECT * FROM public."LogRecords2"
WHERE "DateTime" >= '2025-01-01 00:00:00'
AND "DateTime" < '2025-02-01 00:00:00';
In the above example:
- All records for the month of January, 2025 are returned from the LogRecords2 table.
- As a result of the DateTime range being specified, assuming that the database was partitioned on a monthly basis, this means that only one partition (i.e. one month of LogRecord data) needs to be scanned – even though the database might contain years worth of data.
- As a result of the database engine being able to prune partitions, this query will perform much more quickly than a query that needs to scan all partitions.
Of course, this is a very simplistic example intended to show the incorporation of a DateTime range into a query such that partition pruning can be taken advantage of. The real benefits come when DateTime ranges are incorporated into more complex queries. The key takeaway is to incorporate DateTime ranges into queries where possible to improve performance and avoid creating unnecessarily slow queries that scan entire tables of hundreds of millions of records.
Avoiding Unnecessary Transactions
! WARNING: Use caution when determining scenarios in which database transactions or “units of work” can be avoided as described in this section. Forego transactions only if no data integrity issues can arise as a result of doing so.
The MyGeotab API Adapter uses database transactions to group operations such as inserts into multiple tables into a single unit of work. This helps to ensure that all data in a transaction is successfully written to the database. If an exception occurs part way through, the transaction is rolled-back, thereby avoiding any data consistency issues that might otherwise result from partial writes (e.g. missing data or duplicate data). Database transactions place locks on tables and/or rows which can cause the overall system to slow-down since other processes that need to read or write data must wait for the locks to be released before proceeding.
To reduce system slowness and contention caused by competing transactions within the high-throughput context of this solution, the MyGeotab API Adapter avoids using transactions when they are not necessary. An example is shown in the code snippet below:
...
// Persist dbStatusDataLocation2s without using a transaction to avoid contention with other services. There is no real risk of data inconsistency in this case, since any DbStatusData2 records that are not processed during the current iteration will be picked up during the next iteration. While a UOW (transaction) is not used, a retry policy is still used to ensure that the database operations are retried in case of transient errors such as deadlocks.
await asyncRetryPolicyForDatabaseTransactions.ExecuteAsync(async pollyContext =>
{
try
{
await dbStatusDataLocation2EntityPersister.PersistEntitiesToDatabaseAsync(adapterContext, dbStatusDataLocation2s, cancellationTokenSource, Logging.LogLevel.Info, true, true);
}
catch (Exception ex)
{
exceptionHelper.LogException(ex, NLogLogLevelName.Error, DefaultErrorMessagePrefix);
throw;
}
}, new Context());
// Persist changes to database. Run tasks in parallel.
await asyncRetryPolicyForDatabaseTransactions.ExecuteAsync(async pollyContext =>
{
using (var adapterUOW = adapterContext.CreateUnitOfWork(Databases.AdapterDatabase))
{
try
{
var dbEntityPersistenceTasks = new List<Task>
{
// DbOServiceTracking:
serviceTracker.UpdateDbOServiceTrackingRecordAsync(adapterContext, AdapterService.StatusDataLocationService2, DbStatusData2BatchLastRetrievedUtc)
};
await Task.WhenAll(dbEntityPersistenceTasks);
// Commit transactions:
await adapterUOW.CommitAsync();
processorTrackingInfoUpdated = true;
}
catch (Exception ex)
{
exceptionHelper.LogException(ex, NLogLogLevelName.Error, DefaultErrorMessagePrefix);
await adapterUOW.RollBackAsync();
throw;
}
}
}, new Context());
...
In the above example, rather than including the persistence of updates to records in the StatusDataLocations2 table within the Unit of Work below (which uses a database transaction), these updates are persisted separately and without using a database transaction. The PersistEntitiesToDatabaseAsync method includes a “useStandaloneDbConnection” which is set to true in this case. The reason why a database transaction is not needed in this specific case is that even if the update fails part way through, any records that don’t get updated will simply be reprocessed on the next iteration of the service and there is no risk of data corruption.
When designing and processes that will interact with the adapter database, careful thought can be put into this idea and transactions can be avoided where it is determined that doing so would not cause any data integrity issues. This can result in better overall system performance.
Using the Adapter Database: Query Examples
This section provides information related to querying data in the adapter database.
✱ NOTE: To avoid accidental execution of costly queries in cases where the adapter database contains a lot of data, the sample queries in the following sections are generally limited to 100 records using “OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY” for SQL Server or “OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY” for PostgreSQL. Additionally, commented-out DateTime ranges have been included as a reminder to take advantage of partition pruning where possible.
These queries can be modified as needed, for example, by adding conditions to the WHERE clauses to filter by Users, Devices/Vehicles, Diagnostics, etc.
BinaryData Queries
This section demonstrates queries involving BinaryData.
Get BinaryData with Device Details for Target Groups and Time Period
The following query returns BinaryData along with associated Device detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredBinaryData AS (
SELECT
b.id, b.GeotabId, b.BinaryType, b.ControllerId, b.Data,
b.DateTime, b.DeviceId AS BinaryDataDeviceId, b.Version,
b.RecordCreationTimeUtc
FROM dbo.BinaryData2 b
INNER JOIN FilteredDevices fd
ON b.DeviceId = fd.DeviceId
WHERE b.DateTime >= '2025-01-01 00:00:00'
AND b.DateTime < '2025-02-01 00:00:00'
ORDER BY b.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fb.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber,
dv.VIN AS DeviceVin
FROM FilteredBinaryData fb
LEFT JOIN dbo.Devices2 dv
ON fb.BinaryDataDeviceId = dv.id
ORDER BY fb.DateTime;
PostgreSQL Version:
SELECT
fb.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin"
FROM (
SELECT
b."id", b."GeotabId", b."BinaryType", b."ControllerId", b."Data",
b."DateTime", b."DeviceId" AS "BinaryDataDeviceId", b."Version",
b."RecordCreationTimeUtc"
FROM public."BinaryData2" b
WHERE b."DateTime" >= '2025-02-01 00:00:00'
AND b."DateTime" < '2025-03-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = b."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY b."DateTime"
LIMIT 100
) fb
LEFT JOIN public."Devices2" dv
ON fb."BinaryDataDeviceId" = dv."id"
ORDER BY fb."DateTime";
DeviceStatusInfo Queries
This section demonstrates queries involving DeviceStatusInfo.
Get DeviceStatusInfo with Device and Driver Details for Target Groups
The following query returns DeviceStatusInfo along with associated Device and Driver detail for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredDeviceStatusInfos AS (
SELECT
dsi.id, dsi.GeotabId, dsi.Bearing, dsi.CurrentStateDuration, dsi.DateTime,
dsi.DeviceId AS DeviceStatusInfoDeviceId, dsi.DriverId AS DeviceStatusInfoDriverId,
dsi.IsDeviceCommunicating, dsi.IsDriving, dsi.IsHistoricLastDriver,
dsi.Latitude, dsi.Longitude, dsi.Speed, dsi.RecordLastChangedUtc
FROM dbo.DeviceStatusInfo2 dsi
INNER JOIN FilteredDevices fd
ON dsi.DeviceId = fd.DeviceId
LEFT JOIN dbo.Users2 u
ON dsi.DriverId = u.id
ORDER BY dsi.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fdsi.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
u.GeotabId AS DriverGeotabId, u.FirstName AS DriverFirstName,
u.LastName AS DriverLastName, u.Name AS DriverName
FROM FilteredDeviceStatusInfos fdsi
LEFT JOIN dbo.Devices2 dv
ON fdsi.DeviceStatusInfoDeviceId = dv.id
LEFT JOIN dbo.Users2 u
ON fdsi.DeviceStatusInfoDriverId = u.id
ORDER BY fdsi.DateTime;
PostgreSQL Version:
SELECT
fdsi.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin",
u."GeotabId" AS "DriverGeotabId",
u."FirstName" AS "DriverFirstName",
u."LastName" AS "DriverLastName",
u."Name" AS "DriverName"
FROM (
SELECT
dsi."id", dsi."GeotabId", dsi."Bearing", dsi."CurrentStateDuration", dsi."DateTime",
dsi."DeviceId" AS "DeviceStatusInfoDeviceId", dsi."DriverId" AS "DeviceStatusInfoDriverId",
dsi."IsDeviceCommunicating", dsi."IsDriving", dsi."IsHistoricLastDriver",
dsi."Latitude", dsi."Longitude", dsi."Speed", dsi."RecordLastChangedUtc"
FROM public."DeviceStatusInfo2" dsi
WHERE EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = dsi."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY dsi."DateTime"
LIMIT 100
) fdsi
LEFT JOIN public."Devices2" dv
ON fdsi."DeviceStatusInfoDeviceId" = dv."id"
LEFT JOIN public."Users2" u
ON fdsi."DeviceStatusInfoDriverId" = u."id"
ORDER BY fdsi."DateTime";
DriverChange Queries
This section demonstrates queries involving DriverChanges.
Get DriverChanges with Device and Driver Details for Target Groups and Time Period
The following query returns DriverChange along with associated Device and Driver detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredDriverChanges AS (
SELECT
dc.id, dc.GeotabId, dc.DateTime, dc.DeviceId AS DriverChangeDeviceId,
dc.DriverId AS DriverChangeDriverId, dc.Type, dc.Version, dc.RecordLastChangedUtc
FROM dbo.DriverChanges2 dc
INNER JOIN FilteredDevices fd
ON dc.DeviceId = fd.DeviceId
LEFT JOIN dbo.Users2 u
ON dc.DriverId = u.id
WHERE dc.DateTime >= '2025-01-01 00:00:00'
AND dc.DateTime < '2025-02-01 00:00:00'
ORDER BY dc.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fdc.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
u.GeotabId AS DriverGeotabId, u.FirstName AS DriverFirstName,
u.LastName AS DriverLastName, u.Name AS DriverName
FROM FilteredDriverChanges fdc
LEFT JOIN dbo.Devices2 dv
ON fdc.DriverChangeDeviceId = dv.id
LEFT JOIN dbo.Users2 u
ON fdc.DriverChangeDriverId = u.id
ORDER BY fdc.DateTime;
PostgreSQL Version:
SELECT
fe.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin",
u."GeotabId" AS "DriverGeotabId",
u."FirstName" AS "DriverFirstName",
u."LastName" AS "DriverLastName",
u."Name" AS "DriverName"
FROM (
SELECT
dc."id", dc."GeotabId", dc."DateTime", dc."DeviceId" AS "DriverChangeDeviceId",
dc."DriverId" AS "DriverChangeDriverId", dc."Type", dc."Version", dc."RecordLastChangedUtc"
FROM public."DriverChanges2" dc
WHERE dc."DateTime" >= '2025-01-01 00:00:00'
AND dc."DateTime" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = dc."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY dc."DateTime"
LIMIT 100
) fe
LEFT JOIN public."Devices2" dv
ON fe."DriverChangeDeviceId" = dv."id"
LEFT JOIN public."Users2" u
ON fe."DriverChangeDriverId" = u."id"
ORDER BY fe."DateTime";
DutyStatusAvailability Queries
This section demonstrates queries involving DutyStatusAvailability records in the DutyStatusAvailabilities2 table.
The Pseudo Data Feed for DutyStatusAvailability
The Geotab API's GetFeed method does not support the DutyStatusAvailability entity type and the results for DutyStatusAvailability Get requests are calculated dynamically, resulting in longer response times than are typical for pre-calculated data. It is also necessary to retrieve DutyStatusAvailability on a per-driver basis using batches of Get requests wrapped in MultiCall requests (in order to support larger fleets where the number of Get<DutyStatusAvailability> requests required to cover all drivers could not be made in a single MultiCall request). The result of the combination of these factors is that it can take some time for DutyStatusAvailability to be retrieved for all drivers in a fleet.
In order to avoid slowing the flow of data for other feeds, DutyStatusAvailability is handled by a separate worker service running in parallel to the main worker service and acting as a pseudo data feed to populate the DutyStatusAvailability table in the adapter database. This service runs in parallel to the main Worker service if the enableDutyStatusAvailabilityDataFeed setting in appsettings.json is set to true.
Maintaining Currency of Values Via Time Offsets
! WARNING: Duration values in the DutyStatusAvailability table are inaccurate (out-of-date). The amount of inaccuracy can be defined as the duration between the value of the RecordLastChangedUtc field and the current time, in Coordinated Universal Time (UTC). This offset must be applied to the duration values in order to improve currency of the data upon consumption. See below for details.
As a result of the pseudo data feed and inherent time required to update DutyStatusAvailability records for all drivers, by the time the last driver’s record is being updated, minutes may have elapsed since the first driver’s record was updated. The amount of time elapsed since a record was last updated will depend on a number of factors - particularly the number of drivers in the fleet.
Determining How Much Driving and On-Duty Time a Driver Has Left in the Day
The following example of a record from the DutyStatusAvailabilities2 table will be used to demonstrate how to work with data in this table. For this scenario, the objective is to determine how much driving and on-duty time a particular driver has remaining in the day.
Column Name | Data Value |
id | 1234 |
GeotabId | b123 |
DriverId | 4567 |
CycleAvailabilities | [{"DateTime":"2025-07-30T04:00:00Z","Available":"5.00:00:00","Gain":"00:00:00"}] |
CycleDrivingTicks | NULL |
CycleTicks | 4320000000000 |
CycleRestTicks | 11754454640000 |
DrivingBreakDurationTicks | NULL |
DrivingTicks | 452166240000 |
DutyTicks | 454808390000 |
DutySinceCycleRestTicks | 2520000000000 |
Is16HourExemptionAvailable | NULL |
IsAdverseDrivingApplied | 0 |
IsAdverseDrivingExemptionAvailable | 0 |
IsOffDutyDeferralExemptionAvailable | 0 |
IsRailroadExemptionAvailable | NULL |
Recap | [{"DateTime":"2025-07-29T04:00:00Z","Duration":"00:00:00","CycleTotal":"06:36:00","CycleRemaining":"4.17:24:00"}] |
RestTicks | NULL |
WorkdayTicks | 576000000000 |
RecordLastChangedUtc | 2025-07-29 13:29:10 |
Let’s assume that the current UTC date and time is 2025-07-29 13:32:10. Driving and on-duty time remaining can be determined using the following steps:
Step | Detail |
1 | Convert the DrivingTicks and DutyTicks values into corresponding durations: The manner by which this is accomplished depends on the technology being used (e.g. in .NET, the TimeSpan.FromTicks method can be used). ✱ NOTE: A tick is equal to 100 nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond and 10 million ticks in a second. For brevity, only the calculated durations will be shown. This .NET Fiddle demonstrates conversion of ticks to TimeSpans (hours:minutes:seconds.milliseconds here).
|
2 | Calculate the elapsed time since the subject record was updated:
|
3 | Subtract the calculated offset from the Driving and Duty durations:
|
As determined above, in this example, the subject driver has twelve hours and thirty minutes of driving time and twelve hours and thirty-five minutes of on-duty time remaining in the day.
! WARNING: Even if time offsets are calculated as noted above, availability values may occasionally still be inaccurate due to driver status changes that may occur in between successive updates.
DVIRLog Queries
This section demonstrates queries involving DVIRLogs.
Get DVIRLogs with Device, Driver, CertifiedByUser and RepairedByUser Details for Target Groups and Time Period
The following query returns DVIRLogs along with associated Device, Driver, CertifiedByUser and RepairedByUser detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredDVIRLogs AS (
SELECT
dl.id, dl.GeotabId, dl.AuthorityAddress, dl.AuthorityName,
dl.CertifiedByUserId, dl.CertifiedDate, dl.CertifyRemark,
dl.DateTime, dl.DeviceId AS DVIRLogDeviceId,
dl.DriverId AS DVIRLogDriverId, dl.DriverRemark, dl.DurationTicks,
dl.EngineHours AS EngineHoursInSeconds, dl.IsSafeToOperate,
dl.LoadHeight AS LoadHeightMeters,
dl.LoadWidth AS LoadWidthMeters, dl.LocationLatitude,
dl.LocationLongitude, dl.LogType, dl.Odometer AS OdometerMeters,
dl.RepairDate, dl.RepairedByUserId, dl.RepairRemark, dl.Version,
dl.RecordLastChangedUtc
FROM dbo.DVIRLogs2 dl
INNER JOIN FilteredDevices fd
ON dl.DeviceId = fd.DeviceId
WHERE dl.DateTime >= '2025-01-01 00:00:00'
AND dl.DateTime < '2025-02-01 00:00:00'
ORDER BY dl.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fdl.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber,
dv.VIN AS DeviceVin,
ud.GeotabId AS DriverGeotabId, ud.FirstName AS DriverFirstName,
ud.LastName AS DriverLastName, ud.Name AS DriverName,
uc.GeotabId AS CertifiedByUserGeotabId,
uc.FirstName AS CertifiedByUserFirstName,
uc.LastName AS CertifiedByUserLastName,
uc.Name AS CertifiedByUserName,
ur.GeotabId AS RepairedByUserGeotabId,
ur.FirstName AS RepairedByUserFirstName,
ur.LastName AS RepairedByUserLastName,
ur.Name AS RepairedByUserName
FROM FilteredDVIRLogs fdl
LEFT JOIN dbo.Devices2 dv
ON fdl.DVIRLogDeviceId = dv.id
LEFT JOIN dbo.Users2 ud
ON fdl.DVIRLogDriverId = ud.id
LEFT JOIN dbo.Users2 uc
ON fdl.CertifiedByUserId = uc.id
LEFT JOIN dbo.Users2 ur
ON fdl.RepairedByUserId = ur.id
ORDER BY fdl.DateTime;
PostgreSQL Version:
SELECT
fdl.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber" AS "DeviceSerialNumber",
dv."VIN" AS "DeviceVin",
ud."GeotabId" AS "DriverGeotabId",
ud."FirstName" AS "DriverFirstName",
ud."LastName" AS "DriverLastName",
ud."Name" AS "DriverName",
uc."GeotabId" AS "CertifiedByUserGeotabId",
uc."FirstName" AS "CertifiedByUserFirstName",
uc."LastName" AS "CertifiedByUserLastName",
uc."Name" AS "CertifiedByUserName",
ur."GeotabId" AS "RepairedByUserGeotabId",
ur."FirstName" AS "RepairedByUserFirstName",
ur."LastName" AS "RepairedByUserLastName",
ur."Name" AS "RepairedByUserName"
FROM (
SELECT
dl."id", dl."GeotabId", dl."AuthorityAddress", dl."AuthorityName",
dl."CertifiedByUserId", dl."CertifiedDate", dl."CertifyRemark",
dl."DateTime", dl."DeviceId" AS "DVIRLogDeviceId",
dl."DriverId" AS "DVIRLogDriverId", dl."DriverRemark",
dl."DurationTicks", dl."EngineHours" AS "EngineHoursInSeconds",
dl."IsSafeToOperate", dl."LoadHeight" AS "LoadHeightMeters",
dl."LoadWidth" AS "LoadWidthMeters", dl."LocationLatitude",
dl."LocationLongitude", dl."LogType",
dl."Odometer" AS "OdometerMeters", dl."RepairDate",
dl."RepairedByUserId", dl."RepairRemark", dl."Version",
dl."RecordLastChangedUtc"
FROM public."DVIRLogs2" dl
WHERE
dl."DateTime" >= '2025-01-01 00:00:00'
AND dl."DateTime" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = dl."DeviceId"
AND item->> 'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY dl."DateTime"
LIMIT 100
) fdl
LEFT JOIN public."Devices2" dv
ON fdl."DVIRLogDeviceId" = dv."id"
LEFT JOIN public."Users2" ud
ON fdl."DVIRLogDriverId" = ud."id"
LEFT JOIN public."Users2" uc
ON fdl."CertifiedByUserId" = uc."id"
LEFT JOIN public."Users2" ur
ON fdl."RepairedByUserId" = ur."id"
ORDER BY fdl."DateTime";
Get DVIRDefects Associated with a DVIRLog
The following query returns all DVIRDefects associated with the DVIRLog having an id of ‘62E29A4F-AC3A-4C92-B8B8-A215856B18C2’.
SQL Server Version:
SELECT
defect.id AS DVIRDefectId,
defect.GeotabId AS DVIRDefectGeotabId,
defect.DVIRLogId,
defect.DVIRLogDateTime,
defect.DefectListAssetType,
defect.DefectListId,
defect.DefectListName,
defect.PartId,
defect.PartName,
defect.DefectId,
defect.DefectName,
defect.DefectSeverityId,
defectSeverity.Name AS DefectSeverityName,
defect.RepairDateTime,
defect.RepairStatusId,
repairStatus.Name AS RepairStatusName,
defect.RepairUserId,
repairUser.Name AS DefectRepairUserName,
repairUser.EmployeeNo AS DefectRepairUserEmployeeNo,
repairUser.FirstName AS DefectRepairUserFirstName,
repairUser.LastName AS DefectRepairUserLastName,
defect.RecordLastChangedUtc AS DefectRecordLastChangedUtc
FROM dbo.DVIRDefects2 AS defect
INNER JOIN dbo.DVIRLogs2 AS log
ON defect.DVIRLogId = log.id
LEFT JOIN dbo.Users2 AS repairUser
ON defect.RepairUserId = repairUser.id
LEFT JOIN dbo.DefectSeverities2 AS defectSeverity
ON defect.DefectSeverityId = defectSeverity.id
LEFT JOIN dbo.RepairStatuses2 AS repairStatus
ON defect.RepairStatusId = repairStatus.id
WHERE log.id = '62E29A4F-AC3A-4C92-B8B8-A215856B18C2';
PostgreSQL Version:
SELECT
defect."id" AS "DVIRDefectId",
defect."GeotabId" AS "DVIRDefectGeotabId",
defect."DVIRLogId",
defect."DVIRLogDateTime",
defect."DefectListAssetType",
defect."DefectListId",
defect."DefectListName",
defect."PartId",
defect."PartName",
defect."DefectId",
defect."DefectName",
defect."DefectSeverityId",
"defectSeverity"."Name" AS "DefectSeverityName",
defect."RepairDateTime",
defect."RepairStatusId",
"repairStatus"."Name" AS "RepairStatusName",
defect."RepairUserId",
"repairUser"."Name" AS "DefectRepairUserName",
"repairUser"."EmployeeNo" AS "DefectRepairUserEmployeeNo",
"repairUser"."FirstName" AS "DefectRepairUserFirstName",
"repairUser"."LastName" AS "DefectRepairUserLastName",
defect."RecordLastChangedUtc" AS "DefectRecordLastChangedUtc"
FROM public."DVIRDefects2" AS defect
INNER JOIN public."DVIRLogs2" AS log
ON defect."DVIRLogId" = log."id"
LEFT JOIN public."Users2" AS "repairUser"
ON defect."RepairUserId" = "repairUser".id
LEFT JOIN public."DefectSeverities2" AS "defectSeverity"
ON defect."DefectSeverityId" = "defectSeverity".id
LEFT JOIN public."RepairStatuses2" AS "repairStatus"
ON defect."RepairStatusId" = "repairStatus".id
WHERE log.id = '62E29A4F-AC3A-4C92-B8B8-A215856B18C2';
Get DVIRDefectRemarks Associated with a DVIRDefect
The following query returns all DVIRDefectRemarks associated with the DVIRDefect having an id of ‘C3DF3159-41AF-4431-B5FD-EDA2557989F4’.
SQL Server Version:
SELECT
remark.id AS RemarkId,
remark.GeotabId AS RemarkGeotabId,
remark.DVIRDefectId,
remark.DVIRLogDateTime AS RemarkDVIRLogDateTime,
remark.DateTime AS RemarkDateTime,
remark.Remark,
remark.RemarkUserId,
remarkUser.Name AS RemarkUserName,
remarkUser.EmployeeNo AS RemarkUserEmployeeNo,
remarkUser.FirstName AS RemarkUserFirstName,
remarkUser.LastName AS RemarkUserLastName,
remark.RecordLastChangedUtc AS RemarkRecordLastChangedUtc
FROM dbo.DVIRDefectRemarks2 AS remark
LEFT JOIN dbo.Users2 AS remarkUser
ON remark.RemarkUserId = remarkUser.id
WHERE remark.DVIRDefectId = 'C3DF3159-41AF-4431-B5FD-EDA2557989F4'
ORDER BY remark.DateTime;
PostgreSQL Version:
SELECT
remark."id" AS "RemarkId",
remark."GeotabId" AS "RemarkGeotabId",
remark."DVIRDefectId",
remark."DVIRLogDateTime" AS "RemarkDVIRLogDateTime",
remark."DateTime" AS "RemarkDateTime",
remark."Remark",
remark."RemarkUserId",
"remarkUser"."Name" AS "RemarkUserName",
"remarkUser"."EmployeeNo" AS "RemarkUserEmployeeNo",
"remarkUser"."FirstName" AS "RemarkUserFirstName",
"remarkUser"."LastName" AS "RemarkUserLastName",
remark."RecordLastChangedUtc" AS "RemarkRecordLastChangedUtc"
FROM public."DVIRDefectRemarks2" AS remark
LEFT JOIN public."Users2" AS "remarkUser"
ON remark."RemarkUserId" = "remarkUser"."id"
WHERE remark."DVIRDefectId" = 'C3DF3159-41AF-4431-B5FD-EDA2557989F4'
ORDER BY remark."DateTime";
ExceptionEvent Queries
This section demonstrates queries involving ExceptionEvents.
Updates to ExceptionEvents
ExceptionEvents are generated in the MyGeotab database when Rules are broken/triggered. ExceptionEvents often occur over an extended duration instead of a discrete point in time. For example, a vehicle may be speeding over a defined threshold for a number of seconds or minutes. Since ExceptionEvents can be triggered by Rules made-up of conditions that are measured by data points from a variety of sources (LogRecords, StatusData, FaultData, Zones, etc.), there can be a number of updates for any given ExceptionEvent.
Fortunately, with DM2, the MyGeotab API Adapter takes care of this complexity by providing a single record per ExceptionEvent in the ExceptionEvents2 table.
Invalidated/Reprocessed ExceptionEvents
ExceptionEvents can sometimes be invalidated – either due to additional data points being received that result in one or more conditions of the associated Rule no longer being considered to have been broken, or because of data being reprocessed.
In cases where ExceptionEvents are invalidated or dismissed, the State of the subject ExceptionEvents will be updated in the ExceptionEvents2 table accordingly.
Get ExceptionEvents with Device and Driver Details for Target Groups, Rules and Time Period
The following query returns “Speeding” and “After Hours Usage” ExceptionEvents along with associated Device and Driver detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
Note that the “FilteredRules” portion uses the GeotabId column of the Rules2 table instead of the Name column (i.e. “aL-F0vzJo4US8DzGl-XVhXg” instead of “Speeding” and “RuleAfterHoursUsageId” instead of “After Hours Usage”). This is to provide more resilience against issues such as name changes, casing, etc.
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredRules AS (
SELECT *,
r.id AS RuleId
FROM dbo.Rules2 r
WHERE r.GeotabId IN ('aL-F0vzJo4US8DzGl-XVhXg', 'RuleAfterHoursUsageId')
),
FilteredExceptionEvents AS (
SELECT
e.id, e.GeotabId, e.ActiveFrom, e.ActiveTo,
e.DeviceId AS ExceptionEventDeviceId, e.Distance,
e.DriverId AS ExceptionEventDriverId, e.DurationTicks, e.LastModifiedDateTime,
e.RuleId AS ExceptionEventRuleId, e.State, e.Version, e.RecordLastChangedUtc
FROM dbo.ExceptionEvents2 e
INNER JOIN FilteredDevices fd
ON e.DeviceId = fd.DeviceId
INNER JOIN FilteredRules fr
ON e.RuleId = fr.RuleId
LEFT JOIN dbo.Users2 u
ON e.DriverId = u.id
WHERE e.ActiveFrom >= '2025-01-01 00:00:00'
AND e.ActiveFrom < '2025-02-01 00:00:00'
ORDER BY e.ActiveFrom
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fe.*,
r.GeotabId AS RuleGeotabId, r.Name AS RuleName,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
u.GeotabId AS DriverGeotabId, u.FirstName AS DriverFirstName,
u.LastName AS DriverLastName, u.Name AS DriverName
FROM FilteredExceptionEvents fe
LEFT JOIN dbo.Devices2 dv
ON fe.ExceptionEventDeviceId = dv.id
LEFT JOIN dbo.Rules2 r
ON fe.ExceptionEventRuleId = r.id
LEFT JOIN dbo.Users2 u
ON fe.ExceptionEventDriverId = u.id
ORDER BY fe.ActiveFrom;
PostgreSQL Version:
SELECT
fe.*,
r."GeotabId" AS "RuleGeotabId",
r."Name" AS "RuleName",
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin",
u."GeotabId" AS "DriverGeotabId",
u."FirstName" AS "DriverFirstName",
u."LastName" AS "DriverLastName",
u."Name" AS "DriverName"
FROM (
SELECT
e."id", e."GeotabId", e."ActiveFrom", e."ActiveTo",
e."DeviceId" AS "ExceptionEventDeviceId", e."Distance",
e."DriverId" AS "ExceptionEventDriverId", e."DurationTicks", e."LastModifiedDateTime",
e."RuleId" AS "ExceptionEventRuleId", e."State", e."Version", e."RecordLastChangedUtc"
FROM public."ExceptionEvents2" e
WHERE e."ActiveFrom" >= '2025-01-01 00:00:00'
AND e."ActiveFrom" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = e."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
AND EXISTS (
SELECT 1
FROM public."Rules2" r
WHERE r."id" = e."RuleId"
AND r."GeotabId" IN ('aL-F0vzJo4US8DzGl-XVhXg', 'RuleAfterHoursUsageId')
)
ORDER BY e."ActiveFrom"
LIMIT 100
) fe
LEFT JOIN public."Devices2" dv
ON fe."ExceptionEventDeviceId" = dv."id"
LEFT JOIN public."Rules2" r
ON fe."ExceptionEventRuleId" = r."id"
LEFT JOIN public."Users2" u
ON fe."ExceptionEventDriverId" = u."id"
ORDER BY fe."ActiveFrom";
FaultData Queries
This section demonstrates queries involving FaultData.
Get FaultData with Location, Device, Diagnostic and User Details
The following query returns records from the FaultData2 table along with interpolated location information from the FaultDataLocations2 table and information from the related Devices2, Diagnostics2 and Users2 tables.
SQL Server Version:
WITH FilteredFaultData AS (
SELECT
fd.id, fd.GeotabId, fd.AmberWarningLamp, fd.ClassCode, fd.ControllerId, fd.ControllerName, fd.Count, fd.DateTime, fd.DismissDateTime, fd.FailureModeCode, fd.FailureModeId, fd.FailureModeName, fd.FaultLampState, fd.FaultState, fd.MalfunctionLamp, fd.ProtectWarningLamp, fd.RedStopLamp, fd.Severity, fd.SourceAddress, fd.RecordCreationTimeUtc, fd.DeviceId, fd.DiagnosticId, fd.DismissUserId,
fdl.Latitude, fdl.Longitude, fdl.Speed, fdl.Bearing, fdl.Direction, fdl.LongLatProcessed, fdl.LongLatReason
FROM dbo.FaultData2 fd
INNER JOIN dbo.FaultDataLocations2 fdl
ON fd.id = fdl.id
--WHERE fd.DateTime >= '2025-01-01 00:00:00'
-- AND fd.DateTime < '2025-02-01 00:00:00'
ORDER BY fd.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT ffd.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType, dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
di.id AS DiagnosticId, di.GeotabId AS DiagnosticGeotabId, di.DiagnosticCode, di.DiagnosticName, di.DiagnosticSourceId, di.DiagnosticSourceName, di.DiagnosticUnitOfMeasureName, di.OBD2DTC,
u.id AS DismissUserId, u.GeotabId AS DismissUserGeotabId, u.Name AS DismissUserName
FROM FilteredFaultData ffd
LEFT JOIN dbo.Users2 u
ON ffd.DismissUserId = u.id
LEFT JOIN dbo.Devices2 dv
ON ffd.DeviceId = dv.id
LEFT JOIN dbo.Diagnostics2 di
INNER JOIN dbo.DiagnosticIds2 diid
ON di.GeotabGUIDString = diid.GeotabGUIDString
ON ffd.DiagnosticId = diid.id
ORDER BY ffd.DateTime;
PostgreSQL Version:
WITH "FilteredFaultData" AS (
SELECT
fd."id", fd."GeotabId", fd."AmberWarningLamp", fd."ClassCode", fd."ControllerId", fd."ControllerName", fd."Count", fd."DateTime", fd."DismissDateTime", fd."FailureModeCode", fd."FailureModeId", fd."FailureModeName", fd."FaultLampState", fd."FaultState", fd."MalfunctionLamp", fd."ProtectWarningLamp", fd."RedStopLamp", fd."Severity", fd."SourceAddress", fd."RecordCreationTimeUtc", fd."DeviceId", fd."DiagnosticId", fd."DismissUserId",
fdl."Latitude", fdl."Longitude", fdl."Speed", fdl."Bearing", fdl."Direction", fdl."LongLatProcessed", fdl."LongLatReason"
FROM public."FaultData2" fd
INNER JOIN public."FaultDataLocations2" fdl
ON fd."id" = fdl."id"
-- WHERE fd."DateTime" >= '2025-01-01 00:00:00'
-- AND fd."DateTime" < '2025-02-01 00:00:00'
ORDER BY fd."DateTime"
LIMIT 100
)
SELECT ffd.*,
dv."id" AS "DeviceId", dv."GeotabId" AS "DeviceGeotabId", dv."DeviceType", dv."Name" AS "DeviceName", dv."SerialNumber" AS "DeviceSerialNumber", dv."VIN" AS "DeviceVin",
di."id" AS "DiagnosticId", di."GeotabId" AS "DiagnosticGeotabId", di."DiagnosticCode", di."DiagnosticName", di."DiagnosticSourceId", di."DiagnosticSourceName", di."DiagnosticUnitOfMeasureName", di."OBD2DTC",
u."id" AS "DismissUserId", u."GeotabId" AS "DismissUserGeotabId", u."Name" AS "DismissUserName"
FROM "FilteredFaultData" ffd
LEFT JOIN public."Users2" u
ON ffd."DismissUserId" = u."id"
LEFT JOIN public."Devices2" dv
ON ffd."DeviceId" = dv."id"
LEFT JOIN public."Diagnostics2" di
INNER JOIN public."DiagnosticIds2" diid
ON di."GeotabGUIDString" = diid."GeotabGUIDString"
ON ffd."DiagnosticId" = diid."id"
ORDER BY ffd."DateTime";
The following diagram shows the tables used in the above query and their interrelationships specific to the query:

Get J1939 FMI & SPN
This section demonstrates how to obtain the J1939 Failure Mode Identifier (FMI) and Suspect Parameter Number (SPN).
In the Get FaultData with Location, Device, Diagnostic and User Details query:
- The FMI is found in the FailureModeCode column of the result set.
- The SPN is found in the DiagnosticCode column of the result set.
- The SPN description is found in the DiagnosticName column of the result set.
Get OBD-II DTC
In the Get FaultData with Location, Device, Diagnostic and User Details query, OBD-II Diagnostic Trouble Code (DTC) is included in the OBD2DTC column of the result set.
Alternatively, to get a list of all DTC codes along with associated Diagnostic properties, the following query can be used.
SQL Server Version:
SELECT di.OBD2DTC, diid.GeotabId AS DiagnosticGeotabId, di.GeotabGUIDString, di.ControllerId, di.DiagnosticCode, di.DiagnosticName, di.DiagnosticSourceId, di.DiagnosticSourceName, di.DiagnosticUnitOfMeasureId, di.DiagnosticUnitOfMeasureName
FROM dbo.DiagnosticIds2 diid
INNER JOIN dbo.Diagnostics2 di
ON diid.GeotabGUIDString = di.GeotabGUIDString
WHERE di.OBD2DTC IS NOT NULL
ORDER BY di.OBD2DTC, DiagnosticGeotabId;
PostgreSQL Version:
SELECT di."OBD2DTC", diid."GeotabId" AS "DiagnosticGeotabId", di."GeotabGUIDString", di."ControllerId", di."DiagnosticCode", di."DiagnosticName", di."DiagnosticSourceId", di."DiagnosticSourceName", di."DiagnosticUnitOfMeasureId", di."DiagnosticUnitOfMeasureName"
FROM public."DiagnosticIds2" diid
INNER JOIN public."Diagnostics2" di
ON diid."GeotabGUIDString" = di."GeotabGUIDString"
WHERE di."OBD2DTC" IS NOT NULL
ORDER BY di."OBD2DTC", "DiagnosticGeotabId";
FuelAndEnergyUsed Queries
This section demonstrates queries involving FuelAndEnergyUsed.
Since FuelAndEnergyUsed entities are calculated on a per-Trip basis, one of the most practical ways to query these entities is by relating them to Trips as shown in the Get Trips with Device, Driver and Fuel/Energy Used Details for Target Groups and Time Period example.
Group Queries
This section demonstrates queries involving Groups.
Get Devices in a Group
The following query returns a list of Devices belonging to the Vehicle group.
SQL Server Version:
SELECT
g.id AS GroupId,
g.GeotabId AS GroupGeotabId,
g.Name AS GroupName,
d.id AS DeviceId,
d.GeotabId AS DeviceGeotabId,
d.Name AS DeviceName
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name = 'Vehicle'
ORDER BY g.Name, d.id;
PostgreSQL Version:
SELECT
g.id AS "GroupId",
g."GeotabId" AS "GroupGeotabId",
g."Name" AS "GroupName",
d.id AS "DeviceId",
d."GeotabId" AS "DeviceGeotabId",
d."Name" AS "DeviceName"
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item
JOIN public."Groups2" g
ON item->>'id' = g."GeotabId"
WHERE g."Name" = 'Vehicle'
ORDER BY g."Name", d."id";
Get Devices in a List of Groups
The following query returns a distinct list of Devices belonging to one or more of a list of groups (“Vehicle” and “Diesel”).
SQL Server Version:
SELECT DISTINCT
d.id AS DeviceId,
d.GeotabId AS DeviceGeotabId,
d.Name AS DeviceName
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
ORDER BY d.id;
PostgreSQL Version:
SELECT DISTINCT
d.id AS "DeviceId",
d."GeotabId" AS "DeviceGeotabId",
d."Name" AS "DeviceName"
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item
JOIN public."Groups2" g
ON item->>'id' = g."GeotabId"
WHERE g."Name" IN ('Vehicle', 'Diesel')
ORDER BY d."id";
List Devices by Group
The following query returns a list of Devices by Group. All Groups having at least one Device assigned are listed. If a Device is assigned to multiple Groups, it will appear once for each Group that it is assigned to.
SQL Server Version:
SELECT
g.id as GroupId,
g.GeotabId as GroupGeotabId,
g.Name AS GroupName,
d.id AS DeviceId,
d.GeotabId AS DeviceGeotabId,
d.Name AS DeviceName
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(50)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
ORDER BY g.Name, d.id;
PostgreSQL Version:
SELECT
g."id" AS "GroupId",
g."GeotabId" AS "GroupGeotabId",
g."Name" AS "GroupName",
d."id" AS "DeviceId",
d."GeotabId" AS "DeviceGeotabId",
d."Name" AS "DeviceName"
FROM public."Devices2" d
CROSS JOIN LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item
JOIN public."Groups2" g
ON item->>'id' = g."GeotabId"
ORDER BY g."Name", d."id";
Filtering by Groups Within Larger Queries
The following query returns records from the StatusData2 table along with interpolated location information from the StatusDataLocations2 table and information from the related Devices2 and Diagnostics2 tables only for devices that belong to the“Vehicle” and “Diesel” groups.
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredStatusData AS (
SELECT
sd.id, sd.GeotabId, sd.Data, sd.DateTime, sd.DeviceId, sd.DiagnosticId, sd.RecordCreationTimeUtc,
sdl.Latitude, sdl.Longitude, sdl.Speed, sdl.Bearing, sdl.Direction, sdl.LongLatProcessed, sdl.LongLatReason
FROM dbo.StatusData2 sd
INNER JOIN FilteredDevices d
ON sd.DeviceId = d.DeviceId
INNER JOIN dbo.StatusDataLocations2 sdl
ON sd.id = sdl.id
--WHERE sd.DateTime >= '2025-01-01 00:00:00'
-- AND sd.DateTime < '2025-02-01 00:00:00'
ORDER BY sd.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fsd.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType, dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
di.id AS DiagnosticId, di.GeotabId AS DiagnosticGeotabId, di.DiagnosticCode, di.DiagnosticName, di.DiagnosticSourceId, di.DiagnosticSourceName, di.DiagnosticUnitOfMeasureName, di.OBD2DTC
FROM FilteredStatusData fsd
LEFT JOIN dbo.Devices2 dv
ON fsd.DeviceId = dv.id
LEFT JOIN dbo.Diagnostics2 di
INNER JOIN dbo.DiagnosticIds2 diid
ON di.GeotabGUIDString = diid.GeotabGUIDString
ON fsd.DiagnosticId = diid.id
ORDER BY fsd.DateTime;
PostgreSQL Version:
SELECT fsd.*,
dv."id" AS "DeviceId", dv."GeotabId" AS "DeviceGeotabId", dv."DeviceType", dv."Name" AS "DeviceName", dv."SerialNumber" AS "DeviceSerialNumber", dv."VIN" AS "DeviceVin",
di."id" AS "DiagnosticId", di."GeotabId" AS "DiagnosticGeotabId", di."DiagnosticCode", di."DiagnosticName", di."DiagnosticSourceId", di."DiagnosticSourceName", di."DiagnosticUnitOfMeasureName", di."OBD2DTC"
FROM (
SELECT
sd."id", sd."GeotabId", sd."Data", sd."DateTime", sd."DeviceId", sd."DiagnosticId", sd."RecordCreationTimeUtc",
sdl."Latitude", sdl."Longitude", sdl."Speed", sdl."Bearing", sdl."Direction", sdl."LongLatProcessed", sdl."LongLatReason"
FROM public."StatusData2" sd
INNER JOIN public."StatusDataLocations2" sdl
ON sd."id" = sdl."id"
WHERE sd."DateTime" >= '2025-01-01 00:00:00'
AND sd."DateTime" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = sd."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY sd."DateTime"
LIMIT 100
) fsd
LEFT JOIN public."Devices2" dv
ON fsd."DeviceId" = dv."id"
LEFT JOIN public."Diagnostics2" di
INNER JOIN public."DiagnosticIds2" diid
ON di."GeotabGUIDString" = diid."GeotabGUIDString"
ON fsd."DiagnosticId" = diid."id"
ORDER BY fsd."DateTime";
StatusData Queries
This section demonstrates queries involving StatusData.
Get StatusData with Location, Device and Diagnostic Details
The following query returns records from the StatusData2 table along with interpolated location information from the StatusDataLocations2 table and information from the related Devices2 and Diagnostics2 tables.
SQL Server Version:
WITH FilteredStatusData AS (
SELECT
sd.id, sd.GeotabId, sd.Data, sd.DateTime, sd.DeviceId, sd.DiagnosticId, sd.RecordCreationTimeUtc,
sdl.Latitude, sdl.Longitude, sdl.Speed, sdl.Bearing, sdl.Direction, sdl.LongLatProcessed, sdl.LongLatReason
FROM dbo.StatusData2 sd
INNER JOIN dbo.StatusDataLocations2 sdl
ON sd.id = sdl.id
--WHERE sd.DateTime >= '2025-01-01 00:00:00'
-- AND sd.DateTime < '2025-02-01 00:00:00'
ORDER BY sd.DateTime
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT fsd.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType, dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
di.id AS DiagnosticId, di.GeotabId AS DiagnosticGeotabId, di.DiagnosticCode, di.DiagnosticName, di.DiagnosticSourceId, di.DiagnosticSourceName, di.DiagnosticUnitOfMeasureName, di.OBD2DTC
FROM FilteredStatusData fsd
LEFT JOIN dbo.Devices2 dv
ON fsd.DeviceId = dv.id
LEFT JOIN dbo.Diagnostics2 di
INNER JOIN dbo.DiagnosticIds2 diid
ON di.GeotabGUIDString = diid.GeotabGUIDString
ON fsd.DiagnosticId = diid.id
ORDER BY fsd.DateTime;
PostgreSQL Version:
WITH "FilteredStatusData" AS (
SELECT
sd."id", sd."GeotabId", sd."Data", sd."DateTime", sd."DeviceId", sd."DiagnosticId", sd."RecordCreationTimeUtc",
sdl."Latitude", sdl."Longitude", sdl."Speed", sdl."Bearing", sdl."Direction", sdl."LongLatProcessed", sdl."LongLatReason"
FROM public."StatusData2" sd
INNER JOIN public."StatusDataLocations2" sdl
ON sd."id" = sdl."id"
-- WHERE sd."DateTime" >= '2025-01-01 00:00:00'
-- AND sd."DateTime" < '2025-02-01 00:00:00'
ORDER BY sd."DateTime"
LIMIT 100
)
SELECT fsd.*,
dv."id" AS "DeviceId", dv."GeotabId" AS "DeviceGeotabId", dv."DeviceType", dv."Name" AS "DeviceName", dv."SerialNumber" AS "DeviceSerialNumber", dv."VIN" AS "DeviceVin",
di."id" AS "DiagnosticId", di."GeotabId" AS "DiagnosticGeotabId", di."DiagnosticCode", di."DiagnosticName", di."DiagnosticSourceId", di."DiagnosticSourceName", di."DiagnosticUnitOfMeasureName", di."OBD2DTC"
FROM "FilteredStatusData" fsd
LEFT JOIN public."Devices2" dv
ON fsd."DeviceId" = dv."id"
LEFT JOIN public."Diagnostics2" di
INNER JOIN public."DiagnosticIds2" diid
ON di."GeotabGUIDString" = diid."GeotabGUIDString"
ON fsd."DiagnosticId" = diid."id"
ORDER BY fsd."DateTime";
The following diagram shows the tables used in the above query and their interrelationships specific to the query:

Trip Queries
This section demonstrates queries involving Trips.
Uniquely Identify Trips
Unlike other Geotab entity types where the Id property is the unique identifier, with the Trip entity, there are updates that occur throughout the duration of a Trip and each update, when captured in near real-time using the GetFeed method, will have a different Id value. A unique Trip can be identified by using the combination of DeviceId and Start.
Fortunately, with DM2, the MyGeotab API Adapter takes care of this complexity by providing a single record per Trip in the Trips2 table.
How it Works in the API Adapter
While processing the feed of Trip data:
- If a Trip entity is found to have a combination of DeviceId + Start that doesn’t exist in the Trips2 table, a new record will be created in the Trips2 table.
- The id of the new record is a unique identifier created by the database when the record is created. It serves as the unique identifier for the Trip within the adapter database.
- The GeotabId of the Trip record comes from the Geotab Trip entity. However, it is useless from an integration perspective because it will change when the record in the Trips2 table is updated as updates for the subject Trip are processed.
- If a Trip entity is found to have a combination of DeviceId + Start for which there is an existing record in the Trips2 table, that existing record will be updated with property values of the incoming Trip entity.
With the original data model, the API Adapter used to simply add each incoming Trip entity as a new record into the Trips table and it was up to integrators to handle uniquely identifying Trips. For more information about the legacy functionality, see the Multiple Records for a Single Trip Captured Live section in the original guide.
Identify Completed Trips
A completed trip will have a StopDurationTicks value greater than zero. This is because the StopDurationTicks is the duration (measured in ticks) the vehicle was stopped at the end of a Trip and can only be calculated once the next Trip starts.
Identifying Deleted/Invalidated Trips
Because Trips are dynamically-calculated based on various data points flowing from devices into the Geotab platform (see the Understanding trips and idling time section in the MyGeotab Product Guide for more information), Trips will sometimes be invalidated and deleted from the MyGeotab database as new information becomes available.
The DeletedDateTime column in the Trips2 table can be used to identify Trips that have been deleted from the MyGeotab database. Normally, the value will be null. If the subject Trip was deleted, a DateTime value will be present. This “soft delete” provides integrators the ability to propagate Trip deletions downstream.
Get Trips with Device and Driver Details for Target Groups and Time Period
The following query returns Trips along with associated Device and Driver detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredTrips AS (
SELECT
t.id, t.GeotabId, t.AfterHoursDistance, t.AfterHoursDrivingDurationTicks,
t.AfterHoursEnd, t.AfterHoursStart, t.AfterHoursStopDurationTicks,
t.AverageSpeed, t.DeletedDateTime, t.DeviceId AS TripDeviceId, t.Distance,
t.DriverId AS TripDriverId, t.DrivingDurationTicks, t.IdlingDurationTicks,
t.MaximumSpeed, t.NextTripStart, t.SpeedRange1, t.SpeedRange1DurationTicks,
t.SpeedRange2, t.SpeedRange2DurationTicks, t.SpeedRange3,
t.SpeedRange3DurationTicks, t.Start, t.Stop, t.StopDurationTicks,
t.StopPointX, t.StopPointY, t.WorkDistance, t.WorkDrivingDurationTicks,
t.WorkStopDurationTicks, t.EntityStatus, t.RecordLastChangedUtc
FROM dbo.Trips2 t
INNER JOIN FilteredDevices fd
ON t.DeviceId = fd.DeviceId
LEFT JOIN dbo.Users2 u
ON t.DriverId = u.id
WHERE t.Start >= '2025-01-01 00:00:00'
AND t.Start < '2025-02-01 00:00:00'
ORDER BY t.Start
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT ft.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
u.GeotabId AS DriverGeotabId, u.FirstName AS DriverFirstName,
u.LastName AS DriverLastName, u.Name AS DriverName
FROM FilteredTrips ft
LEFT JOIN dbo.Devices2 dv
ON ft.TripDeviceId = dv.id
LEFT JOIN dbo.Users2 u
ON ft.TripDriverId = u.id
ORDER BY ft.Start;
PostgreSQL Version:
SELECT
ft.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin",
u."GeotabId" AS "DriverGeotabId",
u."FirstName" AS "DriverFirstName",
u."LastName" AS "DriverLastName",
u."Name" AS "DriverName"
FROM (
SELECT
t."id", t."GeotabId", t."AfterHoursDistance", t."AfterHoursDrivingDurationTicks",
t."AfterHoursEnd", t."AfterHoursStart", t."AfterHoursStopDurationTicks",
t."AverageSpeed", t."DeletedDateTime", t."DeviceId" AS "TripDeviceId", t."Distance",
t."DriverId" AS "TripDriverId", t."DrivingDurationTicks", t."IdlingDurationTicks",
t."MaximumSpeed", t."NextTripStart", t."SpeedRange1", t."SpeedRange1DurationTicks",
t."SpeedRange2", t."SpeedRange2DurationTicks", t."SpeedRange3",
t."SpeedRange3DurationTicks", t."Start", t."Stop", t."StopDurationTicks",
t."StopPointX", t."StopPointY", t."WorkDistance", t."WorkDrivingDurationTicks",
t."WorkStopDurationTicks", t."EntityStatus", t."RecordLastChangedUtc"
FROM public."Trips2" t
WHERE t."Start" >= '2025-01-01 00:00:00'
AND t."Start" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = t."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY t."Start"
LIMIT 100
) ft
LEFT JOIN public."Devices2" dv ON ft."TripDeviceId" = dv.id
LEFT JOIN public."Users2" u ON ft."TripDriverId" = u.id
ORDER BY ft."Start";
Get Trips with Device, Driver and Fuel/Energy Used Details for Target Groups and Time Period
The following query returns Trips along with associated Device, Driver and Fuel/Energy used detail for January of 2025 for devices that belong to the“Vehicle” and “Diesel” groups (limited to the first 100 records).
SQL Server Version:
WITH FilteredDevices AS (
SELECT DISTINCT
d.id AS DeviceId
FROM dbo.Devices2 d
CROSS APPLY OPENJSON(d.Groups) WITH (id nvarchar(max)) AS item
JOIN dbo.Groups2 g
ON item.id = g.GeotabId
WHERE g.Name IN ('Vehicle', 'Diesel')
),
FilteredTrips AS (
SELECT
t.id, t.GeotabId, t.AfterHoursDistance, t.AfterHoursDrivingDurationTicks,
t.AfterHoursEnd, t.AfterHoursStart, t.AfterHoursStopDurationTicks,
t.AverageSpeed, t.DeletedDateTime, t.DeviceId AS TripDeviceId, t.Distance,
t.DriverId AS TripDriverId, t.DrivingDurationTicks, t.IdlingDurationTicks,
t.MaximumSpeed, t.NextTripStart, t.SpeedRange1, t.SpeedRange1DurationTicks,
t.SpeedRange2, t.SpeedRange2DurationTicks, t.SpeedRange3,
t.SpeedRange3DurationTicks, t.Start, t.Stop, t.StopDurationTicks,
t.StopPointX, t.StopPointY, t.WorkDistance, t.WorkDrivingDurationTicks,
t.WorkStopDurationTicks, t.EntityStatus, t.RecordLastChangedUtc
FROM dbo.Trips2 t
INNER JOIN FilteredDevices fd
ON t.DeviceId = fd.DeviceId
LEFT JOIN dbo.Users2 u
ON t.DriverId = u.id
WHERE t.Start >= '2025-01-01 00:00:00'
AND t.Start < '2025-02-01 00:00:00'
ORDER BY t.Start
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
SELECT ft.*,
dv.id AS DeviceId, dv.GeotabId AS DeviceGeotabId, dv.DeviceType,
dv.Name AS DeviceName, dv.SerialNumber AS DeviceSerialNumber, dv.VIN AS DeviceVin,
u.GeotabId AS DriverGeotabId, u.FirstName AS DriverFirstName,
u.LastName AS DriverLastName, u.Name AS DriverName,
feu.id AS FuelAndEnergyUsedId, feu.GeotabId AS FuelAndEnergyUsedGeotabId,
feu.DateTime AS FuelAndEnergyUsedDateTime, feu.DeviceId AS FuelAndEnergyUsedDeviceId,
feu.TotalEnergyUsedKwh, feu.TotalFuelUsed, feu.TotalIdlingEnergyUsedKwh,
feu.TotalIdlingFuelUsedL, feu.Version AS FuelAndEnergyUsedVersion,
feu.RecordLastChangedUtc AS FuelAndEnergyUsedRecordLastChangedUtc
FROM FilteredTrips ft
LEFT JOIN dbo.Devices2 dv
ON ft.TripDeviceId = dv.id
LEFT JOIN dbo.Users2 u
ON ft.TripDriverId = u.id
LEFT JOIN dbo.FuelAndEnergyUsed2 feu
ON ft.Stop = feu.DateTime AND ft.TripDeviceId = feu.DeviceId
ORDER BY ft.Start;
PostgreSQL Version:
SELECT
ft.*,
dv."id" AS "DeviceId",
dv."GeotabId" AS "DeviceGeotabId",
dv."DeviceType",
dv."Name" AS "DeviceName",
dv."SerialNumber",
dv."VIN" AS "DeviceVin",
u."GeotabId" AS "DriverGeotabId",
u."FirstName" AS "DriverFirstName",
u."LastName" AS "DriverLastName",
u."Name" AS "DriverName",
feu."id" AS "FuelAndEnergyUsedId",
feu."GeotabId" AS "FuelAndEnergyUsedGeotabId",
feu."DateTime" AS "FuelAndEnergyUsedDateTime",
feu."DeviceId" AS "FuelAndEnergyUsedDeviceId",
feu."TotalEnergyUsedKwh", feu."TotalFuelUsed",
feu."TotalIdlingEnergyUsedKwh", feu."TotalIdlingFuelUsedL",
feu."Version" AS "FuelAndEnergyUsedVersion",
feu."RecordLastChangedUtc" AS "FuelAndEnergyUsedRecordLastChangedUtc"
FROM (
SELECT
t."id", t."GeotabId", t."AfterHoursDistance", t."AfterHoursDrivingDurationTicks",
t."AfterHoursEnd", t."AfterHoursStart", t."AfterHoursStopDurationTicks",
t."AverageSpeed", t."DeletedDateTime", t."DeviceId" AS "TripDeviceId", t."Distance",
t."DriverId" AS "TripDriverId", t."DrivingDurationTicks", t."IdlingDurationTicks",
t."MaximumSpeed", t."NextTripStart", t."SpeedRange1", t."SpeedRange1DurationTicks",
t."SpeedRange2", t."SpeedRange2DurationTicks", t."SpeedRange3",
t."SpeedRange3DurationTicks", t."Start", t."Stop", t."StopDurationTicks",
t."StopPointX", t."StopPointY", t."WorkDistance", t."WorkDrivingDurationTicks",
t."WorkStopDurationTicks", t."EntityStatus", t."RecordLastChangedUtc"
FROM public."Trips2" t
WHERE t."Start" >= '2025-01-01 00:00:00'
AND t."Start" < '2025-02-01 00:00:00'
AND EXISTS (
SELECT 1
FROM public."Devices2" d,
LATERAL jsonb_array_elements(d."Groups"::jsonb) AS item,
public."Groups2" g
WHERE d."id" = t."DeviceId"
AND item->>'id' = g."GeotabId"
AND g."Name" IN ('Vehicle', 'Diesel')
)
ORDER BY t."Start"
LIMIT 100
) ft
LEFT JOIN public."Devices2" dv ON ft."TripDeviceId" = dv.id
LEFT JOIN public."Users2" u ON ft."TripDriverId" = u.id
LEFT JOIN public."FuelAndEnergyUsed2" feu ON ft."Stop" = feu."DateTime" AND ft."TripDeviceId" = feu."DeviceId"
ORDER BY ft."Start";
Feedback
Help us prioritize future efforts and better understand how the API Adapter is used! If you would like to provide any feedback about the MyGeotab API Adapter solution, please feel free to complete the 100% voluntary MyGeotab API Adapter - Usage Survey.
Change Log
This section tracks changes to the MyGeotab API Adapter solution over time by version number in reverse chronological order.
Get Notified About New Releases!
Any time a new release of the MyGeotab API Adapter is published to GitHub, an update will be posted to Geotab’s Integrator’s Hub. Click the Join Group button on the page to join and then choose the desired notification frequency (Every Post, Daily Digest, Weekly Digest, etc.)
Version 4.0.1.1
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 4.0.0 to version 4.0.1.1, see
- Bug Fix: Modified GenericGeotabGUIDCacheableDbObjectCache2 class:
- Added logic to prevent a “A DbDiagnostic2 with GeotabId ""..."" already exists in the geotabGuidFromGeotabIdCache. Duplicates are not allowed.” exception that will cause the application to crash.
- Bug Fix: Modified database partitioning procedure/function (spManagePartitions):
- SQL Server version: Added check to throw error if filePath is invalid to prevent creation of a partition with no associated FileGroup, which can happen during initial setup and cause partitioning issues if not handled.
- PostgreSQL version: No changes other than DB version upgrade to by consistent with MSSQL..
- Updated required adapter database version to 4.0.1.0.
- Updated NuGet packages to the latest stable release.
- Geotab.Checkmate.ObjectModel updated from version 11.98.302 to 11.109.349.
- Updated version to 4.0.1.1.
Version 4.0.1
- This release was immediately replaced with version 4.0.1.1. because the required database version was not correctly updated from 3.14.0.0 to 4.0.1.0. Ignore this release and go from version 4.0.0 directly to version 4.0.1.1.
Version 4.0.0
- NOTE: This build includes changes to the appsettings.json file.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.14.0 to version 4.0.0, see
- DEPRECATED THE ORIGINAL DATA MODEL. Related changes include the following:
- Removed the Data Optimizer. Its capabilities are included (and vastly improved) in the API Adapter’s Data Enhancement Services.
- Removed v1 database scripts.
- Removed the VSS Add-On. This was an extraneous feature that was not ported over to DM2.
- Removed Azure deployment scripts. The scripts were designed for DM1 and would not work with DM2 as a result of database partitioning complexities. Similar Azure deployment scripts supporting DM2 may be added in the future.
- Modified the appsettings.json file:
- Removed the UseDataModel2 setting.
- Removed the DebugData section (DebugData is not supported in DM2).
- Cleaned-up the solution by modifying code as needed and removing items no longer needed as a result of the above.
- Updated README.md file.
- Updated NuGet packages to the latest stable release.
- Geotab.Checkmate.ObjectModel updated from version 11.83.265 to 11.98.302.
- Updated version to 4.0.0.0.
Version 3.14.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.13.0 to version 3.14.0, see
- Bug Fix: Modified database partitioning procedure/function (spManagePartitions):
- SQL Server version: Fixed issue that could cause monthly partitions to become daily.
- PostgreSQL version: Changed function to ensure that daily/weekly/monthly partitions cover the entire next month.
- Updated version to 3.14.0.0.
Version 3.13.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.12.0 to version 3.13.0, see
- Migrated DVIRLog Manipulator to DM2.
- Added upd_DVIRDefectUpdates2 and fail_DVIRDefectUpdateFailures2 tables.
- Added DVIRLog Manipulator section to this guide to fully explain what it does and how to use it.
- Bug Fix: Modified the PostgreSQL version of the spMerge_stg_Trips2 function to include the missing Distance column when updating the Trips2 table. See the Re-Extract Trips Data if Necessary section in the upgrade guide for more information.
- Bug Fix: Added logic to ensure that database partitioning happens, if needed, on application startup before any other services write data to the adapter database.
- This is to prevent partitioning-related errors that could occur in situations such as where the API Adapter is started after having been stopped for an extended period.
- Added a section to PostgreSQL scripts to change ownership of all tables to geotabadapter_client to capture any that were not set previously and avoid any possible related issues.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.13.0.0.
Version 3.12.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.11.0 to version 3.12.0, see
- Added DutyStatusLogs2 table with associated data feed.
- Removed physical foreign key relationships associated with User, Device and Rule Ids to accommodate historic data and certain edge cases.
- Added handling for specific KnownIds including "NoDeviceId", "NoDriverId", “NoRuleId”, “NoUserId”, “NoZoneId” and "UnknownDriverId" via the introduction of sentinel records with placeholder values to represent these IDs in the relevant tables and logic in associated processors to perform the related ID substitutions.
- Made the ExceptionEvents2.RuleId column nullable.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.12.0.0.
Version 3.11.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.10.0 to version 3.11.0, see
- Added ability to install the MyGeotab API Adapter application (DM2) as a service (in Windows or Linux).
- Updated the Step 4: Run the MyGeotab API Adapter section in the guide to include instructions on installing the API Adapter as a service.
- Updated spMerge_stg_DVIRDefects2 and spMerge_stg_DVIRLogs2 stored procedures / functions to avoid FK violations caused when records must be deleted and re-inserted to move between database partitions.
- Modified GeotabTripDbTripObjectMapper (DM1) to ignore Trips with null Device.
- Updated README.md file.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.11.0.0.
- Added training video to the Quick Start Guide:
Version 3.10.0
- NOTE: This build includes changes to the schema of the adapter database and to the appsettings.json files.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.9.0 to version 3.10.0, see
- Added FuelAndEnergyUsed2 table with associated data feed.
- Added FuelAndEnergyUsed Queries section to the guide.
- Added DutyStatusAvailability Queries section to the guide.
- Modified the FaultData2 table:
- Added EffectOnComponent, FaultDescription, FlashCodeId, FlashCodeName, Recommendation and RiskOfBreakdown columns to include properties recently added to the FaultData entity.
- Modified the appsettings.json file:
- Added a section with settings for the new FuelAndEnergyUsed feed.
- Added a “PopulateEffectOnComponentAndRecommendation” setting to the FaultData feed section.
- Made related changes throughout the application.
- Updated NuGet packages to the latest stable release.
- Geotab.Checkmate.ObjectModel updated from version 11.68.266 to 11.83.265.
- Updated version to 3.10.0.0.
- Added training videos to the Quick Start Guide:
Version 3.9.0
- NOTE: This build includes changes to the schema of the adapter database and to the appsettings.json files.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.8.0 to version 3.9.0, see
- Added Feedback section to the guide with a link to the MyGeotab API Adapter - Usage Survey which provides a mechanism by which to provide feedback about the MyGeotab API Adapter solution.
- FIX: Modified stg_Diagnostics2 and Diagnostics2 tables:
- Increased length of DiagnosticName column from 255 to max to accommodate new Diagnostics with long names on the MyGeotab side.
- Added pseudo feed for DutyStatusAvailability along with associated DutyStatusAvailabilities2 table.
- Modified ExceptionEvent feed - setting IncludeInvalidated, IncludeDismissedEvents and IncludeDeleted all to true (previously, only IncludeInvalidated was set to true)
- Modified the appsettings.json files (for both API Adapter and Data Optimizer):
- Renamed “OverrideSetings” to “OverrideSettings” (to correct typo).
- Made related changes throughout the applications.
- Added macOS publish profile (to facilitate deployment to macOS systems)
- Updated NuGet packages to the latest stable release.
- Updated version to 3.9.0.0.
Version 3.8.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.7.0 to version 3.8.0, see
- Modified Devices2 table:
- Added TmpTrailerGeotabId and TmpTrailerId columns.
- Added DefectSeverities2 and RepairStatuses2 reference data tables.
- Added data feed for DVIRLogs along with associated DVIRLogs2, DVIRDefects2 and DVIRDefectRemarks2 tables.
- Added DVIRLog Queries section to the guide.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.8.0.0.
Version 3.7.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.6.0 to version 3.7.0, see
- Added DeviceStatusInfo2 table with associated data feed.
- Added DeviceStatusInfo Queries section to the guide.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.7.0.0.
Version 3.6.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.5.0 to version 3.6.0, see
- Added DriverChanges2 table with associated data feed.
- Added handling for database foreign key violations caused by race conditions. Essentially, if Processor B encounters an FK violation exception related to Processor A, Processor B will roll-back and wait until Processor A has completed another iteration (via monitoring the OserviceTracking2 table) before trying the next iteration in which it will re-execute the rolled-back actions.
- Bug Fix: Updated BackgroundServiceAwaiter WaitForConnectivityRestorationIfNeededAsync method to return bool indicating whether wait was needed. Updated relevant v2 services to set feedVersionRollbackRequired based on this bool so that feed version rollback works properly.
- Enhanced GenericGeotabObjectFeeder:
- Added Rollback method to simplify updating of LastFeedVersion and LastProcessedFeedVersion properties along with resetting FeedStartOption to ConfiguredFeedStartOption in cases where rollback occurs on the first GetFeed call for a given entity type.
- Modified services to use the new GenericGeotabObjectFeeder.Rollback method.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.6.0.0.
Version 3.5.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.4.0 to version 3.5.0, see
- Added ChargeEvents2 table with associated data feed.
- Modified Rules2 table: Added Condition column populated with the hierarchical tree of Condition(s) defining the logic of a Rule in JSON form.
- Modified FaultDataLocationService2 and StatusDataLocationService2 to include Polly retry wrappers around transactionless bulk updates of database tables to avoid crash in the event of a transient deadlock.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.5.0.0.
Version 3.4.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.3.0 to version 3.4.0, see
- Added BinaryData2 table with associated data feed.
- Added BinaryData Queries section to the guide.
- Updated NuGet packages to the latest stable release.
- Geotab.Checkmate.ObjectModel updated from version 11.62.237 to 11.68.266.
- Updated version to 3.4.0.0.
Version 3.3.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.2.0 to version 3.3.0, see
- Added ExceptionEvents2 table with associated data feed.
- Added ExceptionEvent Queries section to the guide.
- Updated the solution from .NET 8.0 to .NET 9.0. If deploying the solution, there are no issues as the solution is self-contained. If copying/cloning the source code to modify the solution, it will be necessary to install .NET 9.0 SDK on the development machine.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.3.0.0.
Version 3.2.0
- NOTE: This build includes changes to the schema of the adapter database.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.1.0 to version 3.2.0, see
- Added Rules2 table with associated data feed.
- Added Trips2 table with associated data feed.
- Added documentation, including query examples for both SQL Server and PostgreSQL, to help with optimally querying the adapter database.
- Added Trip Queries section to the guide.
- Added Group Queries section to the guide.
- Modified Database Maintenance Service to pause other services before partitioning the database in order to resolve possible deadlock-related issues.
- Changed WaitTimeoutMinutesForPausingOtherServices from 30 to 5.
- Bug fix: Updated database scripts (SQL Server and PostgreSQL) to remove certain unique constraints on staging tables that can prove problematic:
- Removed: PK_stg_Devices2, PK_stg_Users2, PK_stg_Zones2, UK_stg_Trips2_DeviceId_Start_EntityStatus
- Added: IX_stg_Trips2_DeviceId_Start_EntityStatus
- Modified database cleanup scripts to exclude staging tables from count results.
- Updated NuGet packages to the latest stable release.
- Updated version to 3.2.0.0.
Version 3.1.0
- NOTE: This build includes changes to the schema of the adapter database and appsettings.json file.
- To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.0.0 to version 3.1.0, see
- Added Groups2 table with associated data feed and related group columns to the Devices2, Users2 and Zones2 tables.
- Enhanced cache update/refresh process for reference data types by migrating from in-memory application logic to utilizing staging tables with merge procedures.
- Includes Devices, Diagnostics, Groups, Users, Zones and ZoneTypes.
- Dramatically improves initial startup performance of the application and is especially noticeable with larger fleets (more data).
- Also resolves an issue that was encountered on rare occasions where duplicate records got into one of the reference data tables causing the application to crash and requiring manual intervention to resolve.
- Modified DutyStatusLog feed to include a DutyStatusLogSearch with the IncludeModifications option set to true to include modification history of the DutyStatusLogs.
- Bug fix: Added Polly asyncRetryPolicyForDatabaseTransactions wrapper around database calls using standalone connections (in DatabaseMaintenanceService, FaultDataLocationService and StatusDataLocationService).
- Bug fix: Updated vwStatsForLevel1DBMaintenance in PostgreSQL scripts to only select from the public schema (avoiding a permissions issue when temp tables get selected otherwise).
- Updated NuGet packages to the latest stable release.
- Updated version to 3.1.0.0.
Version 3.0.0
- NOTE: This build includes changes to the schema of the adapter database and appsettings.json file.
Data Model 2 (DM2)
Version 3.0.0 represents the next evolution of the MyGeotab API Adapter solution. See the Data Model 2 (DM2) section for more information. Key points are as follows:
- A new data model – Data Model 2 (DM2) – has been added:
- DM2 is normalized and designed for greater performance and scalability.
- Database is partitioned (monthly, weekly, or daily).
- Includes Automated Database Maintenance.
- Support both SQL Server and PostgreSQL.
- Starting with version 3.0.0, the MyGeotab API Adapter will support SQL Server and PostgreSQL. Oracle database will not be supported moving forward due to very low usage combined with a high cost to develop and maintain.
- Data Optimizer deprecated – location interpolation capabilities moved directly into the adapter database with exponentially faster performance.
- MyGeotab API Adapter supports both the original data model and DM2:
- Initial version 3.0.0 release of DM2 includes support for a subset of the Geotab entities currently supported with the original data model.
- Additional entities will be ported over to DM2 in the coming months.
- Once DM2 supports all of the original data model entities, the original data model will be deprecated with a grace period of 6-12 months to allow integrators to migrate to DM2 if necessary.
- Refer to the FAQ section in the original guide for more information.
Other Updates
- Update CleanDatabaseScripts (both SQL Server and Postgres) to more efficiently clear data and use system tables/catalog to obtain approximate counts with no concurrency impact during operation of the API Adapter application.
- Updated DatabaseResilienceHelper to use ExceptionHelper to include StackTrace in exception logs. Also enhanced internal exception handling logic to include retry for PK constraint violation exceptions (that are due to TX issues and not actually duplicate PKs).
- Modified BaseRepository - added QueryAsync method for executing parameterized queries (including MSSQL stored procedures and Postgres functions) that return data.
- Added DatabaseValidator to validate adapter database version on application startup (DM2 only).
- Modified BaseRepository and GenericEntityPersister to allow for the optional use of “standalone” database connections (with no transactions and outside of units of work).
- Added capability for BackgroundServices to pause for database maintenance (DM2 only).
- Added BackgroundServiceAwaiter to consolidate wait logic on behalf of individual BackgroundServices and simplified those services (DM2 versions only) accordingly.
- Removed unnecessary trace method entry/exit logging from all BackgroundServices and various other classes.
- Modified DatabaseResilienceHelper - added retry for "current transaction aborted" exceptions.
- Modified StringHelper.IsValidIdentifierForDatabaseObject method to allow for dashes (as used in weekly partition names).
- Updated PrerequisiteServiceChecker and ServiceTracker classes with better logging logic for pauses related to waiting for other services (one pause message and one resumption message per paused service).
- Modified GenericGeotabObjectCacher to use AddOrUpdate instead of TryAdd to avoid throwing unnecessary exceptions if entities happen to be updated during the process of cache loading via GetFeed.
Earlier Versions
For information relating to earlier versions of the MyGeotab API Adapter solution, refer to the Change Log section in the original guide.