Skip to main content
MyGeotab API Adapter DM2
This document provides detailed information about the MyGeotab API Adapter solution along with instructions related to its deployment.

Support Document

0 mins to read

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:

  1. It is normalized with many indexes and relationships between tables.
  2. 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.
  3. Feed Data” tables are partitioned by month, week or day. See Database Partitioning for details.
  4. 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.
  5. 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.

  6. MyGeotab API Adapter Highlights

  7. 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.

  8. 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.

  9. Highlights of the MyGeotab API Adapter solution are as follows:

  10. Efficiency

    1. The number of MyGeotab API calls being made has been minimized via use of data feeds and caching to the extent possible.
    2. Chattiness with the MyGeotab API Adapter database has also been minimized.
    3. Asynchronous methods and parallel processing have been incorporated where possible.
  11. Data Integrity

    1. Feed tokens are tracked and persisted to the MyGeotab API Adapter database.
    2. 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.
    3. Feeds will continue from the last feed versions upon restart of the MyGeotab API Adapter for any reason.
    4. Safeguards are in-place to prevent missing or duplicating data or inadvertently mixing data from multiple MyGeotab databases.
  12. Database-Agnosticity

    1. The Dapper ORM (https://github.com/DapperLib/Dapper, https://dappertutorial.net/) is used to map .NET objects to rows in corresponding database tables.
    2. A repository pattern has been used - separating data-access code from application logic.
    3. A MyGeotab API Adapter database schema has been created for SQL Server (also Azure SQL) and PostgreSQL.
  13. Resilience

    1. 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.
  14. Configurability

    1. Via appsettings.json, it is possible to configure the MyGeotab API Adapter at a very granular level:
      1. Feeds can be configured for individual object types (LogRecord, StatusData, FaultData, Trip, ExceptionEvent, DVIRLog).
      2. Feed intervals can be set at a per-feed level.
      3. Individual feeds can be enabled or disabled as required.
      4. 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.
      5. 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.
      6. 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.
      7. 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.
  15. Deployment Model

    1. 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.
    2. 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.
  16. Logging

    1. NLog has been incorporated as the logging mechanism.
    2. Log messages have been added strategically to assist with debugging issues once the solution has been deployed.
    3. Additional logging tools could be utilized for monitoring purposes.
  17. Code Readability and Reusability

    1. One of the primary objectives in developing this solution was to ensure maximum reusability.
    2. In addition to creating this document, effort has been made to ensure extensive code commenting throughout in order to assist integrators.
  18. Deploying the MyGeotab API Adapter

  19. This section provides instructions on how to download and deploy the MyGeotab API Adapter.

  20. Quick Start Guide

  21. High-level steps are shown in the following table with details provided in the subsections below.

  22. Step

    Detail

    1

    Ensure that Prerequisites are Met:

    1. Ensure that all prerequisites are met. See 1 Prerequisites for details.

    2

    Download the MyGeotab API Adapter:

    1. Download the MyGeotab API Adapter application and database scripts. See 2 Download for details.
    2. Watch video:

    3

    Set Up the Adapter Database:

    1. Set up the adapter database into which data extracted from the Geotab platform will be written. See 3 Database Setup for details.
    2. Watch video:

    4

    Deploy and Configure the Application:

    1. Deploy and configure the MyGeotab API Adapter application. See 4 Application Deployment and Configuration for details.
    2. Watch video:
    3. Watch video:
    4. Watch video:
    5. Watch video:
  23. 1 Prerequisites

  24. The MyGeotab API Adapter requires the following:

  25. Item

    Detail

    Operating System

    Windows 64-bit (win-x64) or Linux 64-bit (linux-x64).

    1. 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.

    1. The MyGeotab API Adapter application must be paired with a database into which data extracted from the Geotab platform is written.
    2. 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.
    3. Although Geotab cannot provide support, it is highly likely that cloud-based (i.e. Google, Amazon, Microsoft) versions of these databases are also suitable.
    4. 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.
    5. 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.
    6. 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

    1. 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.
    2. 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

    1. 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:
    2. List devices
    3. List Users/Drivers
    4. View Asset Inspection logs
    5. View binary data
    6. View device status information
    7. View engine diagnostics
    8. View engine failure modes
    9. View engine measurement related features
    10. View engine units of measurement
    11. View exception rules
    12. View exceptions
    13. View groups
    14. View trailers
    15. View zones
  26. 2 Download

  27. Watch video:

  28. 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:

    1. Go to https://github.com/Geotab/mygeotab-api-adapter/releases
    2. 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.
  29. MyGeotab API Adapter - Application

  30. 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.

  31. 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

  32. Database Scripts

  33. 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.

  34. Database Type

    FIle(s) to Download

    SQL Server

    SQLServer.zip

    PostgreSQL

    PostgreSQL.zip

  35. 3 Database Setup

  36. Watch video:

  37. 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.

  38. ! 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.

  39. PostgreSQL

  40. 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:

  41. Step 1: Create geotabadapter_client Login

  42. Create a login/role named geotabadapter_client using the following script (first replacing <Password> with the desired password):

  43. CREATE ROLE geotabadapter_client WITH

  44. LOGIN

  45. NOSUPERUSER

  46. INHERIT

  47. NOCREATEDB

  48. NOCREATEROLE

  49. NOREPLICATION

  50. PASSWORD '<Password>';

  51. Step 2: Create Database

  52. Create a database named geotabadapterdb. The following shows the basic statement to create the database:

  53. 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’).

  54. CREATE DATABASE geotabadapterdb WITH

  55. OWNER = geotabadapter_client

  56. ENCODING = 'UTF8'

  57. LC_COLLATE = 'en_US.utf8'

  58. LC_CTYPE = 'en_US.utf8'

  59. TABLESPACE = pg_default

  60. CONNECTION LIMIT = -1

  61. IS_TEMPLATE = FALSE;

  62. Step 3: Set Default Permissions

  63. 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.

  64. -- Grant full privileges on all future sequences to the role

  65. ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO geotabadapter_client;

  66. -- Grant execute privileges on all future functions to the role

  67. ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO geotabadapter_client;

  68. Step 4: Modify and Execute PG_0.0.0.1_spManagePartitions.sql Script

  69. 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.

  70. 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.

  71. Execute the PG_0.0.0.1_spManagePartitions.sql script to create the spManagePartitions function in the adapter database.

  72. Step 5: Execute Database Schema Creation Script

  73. 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.

  74. 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).

  75. 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.

  76. Step 6: [IF APPLICABLE] Modify and Execute Database Upgrade Script(s)

  77. 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”.

  78. 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.

  79. 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.

  80. Step 7: Determine Data Collection Start Date and Execute spManagePartitions Function

  81. ! 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.

  82. MinDateTimeUTC:

  83. 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.

  84. PartitionInterval:

  85. 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.

  86. 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');

  87. SELECT public."spManagePartitions"('<MinDateTimeUTC>', '<PartitionInterval>');

  88. Step 8: Verify Database Partitions

  89. 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:

    1. FaultData2_202201
    2. FaultData2_202202
    3. FaultData2_202203
    4. (additional partitions for the months in-between)
    5. FaultData2_202409
    6. FaultData2_202410
    7. FaultData2_202411
    8. 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.

    9. The following query can also be used for further validation:

    10. SELECT

    11. parent_table.relname AS parent_table,

    12. child_table.relname AS partition,

    13. pg_catalog.pg_get_expr(child_table.relpartbound, child_table.oid) AS partition_bound

    14. FROM

    15. pg_inherits AS pi

    16. JOIN

    17. pg_class AS parent_table

    18. ON pi.inhparent = parent_table.oid

    19. JOIN

    20. pg_class AS child_table

    21. ON pi.inhrelid = child_table.oid

    22. WHERE

    23. parent_table.relkind = 'p'

    24. AND child_table.relkind = 'r'

    25. ORDER BY

    26. parent_table.relname, child_table.relname;

    27. SQL Server

    28. Watch video:

    29. 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:

    30. 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.

    31. Step 1: Create Database

    32. Create a database named geotabadapterdb. The following shows the basic statement to create the database:

    33. CREATE DATABASE [geotabadapterdb];

    34. Step 2: Set Database Collation

    35. Ensure that the database collation is set to be case-sensitive by executing the following:

    36. ALTER DATABASE [geotabadapterdb] COLLATE SQL_Latin1_General_CP1_CS_AS;

    37. Step 3: Set Database Recovery Model

    38. 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:

    39. ALTER DATABASE [geotabadapterdb] SET RECOVERY SIMPLE;

    40. Step 4: Create Client Login and User

    41. 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):

    42. USE [master];

    43. CREATE LOGIN [geotabadapter_client] WITH

    44. PASSWORD=N'<Password>',

    45. DEFAULT_DATABASE=[geotabadapterdb],

    46. DEFAULT_LANGUAGE=[us_english],

    47. CHECK_EXPIRATION=OFF,

    48. CHECK_POLICY=OFF;

    49. USE [geotabadapterdb];

    50. CREATE USER [geotabadapter_client] FOR LOGIN [geotabadapter_client] WITH DEFAULT_SCHEMA=[dbo];

    51. ALTER ROLE [db_owner] ADD MEMBER [geotabadapter_client];

    52. Step 5: Modify and Execute MSSQL_0.0.0.1_spManagePartitions.sql Script

    53. 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.

    54. ! 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.

    55. 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.

    56. Execute the MSSQL_0.0.0.1_spManagePartitions.sql script to create the spManagePartitions stored procedure in the adapter database.

    57. Step 6: Determine Data Collection Start Date and Execute spManagePartitions Stored Procedure

    58. ! 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.

    59. MinDateTimeUTC:

    60. 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.

    61. PartitionInterval:

    62. 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.

    63. 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';

    64. EXEC [dbo].[spManagePartitions] @MinDateTimeUTC = '<MinDateTimeUTC>', @PartitionInterval = '<PartitionInterval>';

    65. Step 7: Verify Database Partitions

    66. 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:

    67. geotabadapterdb.mdf
    68. geotabadapterdb_log.ldf
    69. FG_geotabadapterdb_202201.ndf
    70. FG_geotabadapterdb_202202.ndf
    71. FG_geotabadapterdb_202203.ndf
    72. (additional files for the months in-between)
    73. FG_geotabadapterdb_202409.ndf
    74. FG_geotabadapterdb_202410.ndf
    75. FG_geotabadapterdb_202411.ndf
  90. 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.

  91. The following queries can also be used for further validation. Explanations can be found via SQL Server support:

  92. -- Check FileGroup and Partition data:

  93. select * from sys.filegroups;

  94. select * from sys.partition_functions;

  95. select * from sys.partition_range_values;

  96. select * from sys.partition_schemes;

  97. select * from sys.data_spaces;

  98. select * from sys.dm_db_partition_stats;

  99. Step 8: Execute Database Schema Creation Script

  100. 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.

  101. 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).

  102. 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.

  103. Step 9: [IF APPLICABLE] Modify and Execute Database Upgrade Script(s)

  104. 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”.

  105. 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.

  106. 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.

  107. 4 Application Deployment and Configuration

  108. Watch video:

  109. Watch video:

  110. Watch video:

  111. Watch video:

  112. This section covers deployment and configuration of the MyGeotab API Adapter application.

  113. Step 1: Deployment Prerequisites

  114. To provide for a smooth deployment, the following steps should be taken beforehand:

    1. Ensure that permission has been granted by the owner of the MyGeotab database with which the adapter will be interacting.
    2. A service account should be established for use by the adapter. See the Service Account Guidelines document for more details.
    3. 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).
    4. Make sure that the adapter database setup has been completed per the instructions in the Database Setup section.
    5. 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.
  115. Step 2: Install MyGeotab API Adapter Application

  116. 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:

    1. 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).
  117. Step 3: Configure MyGeotab API Adapter Application

  118. 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.

    1. Modify the appsettings.json file as needed. See the appsettings.json section in this guide for more information.
      1. The DatabaseSettings and LoginSettings sections are most important as they govern the application’s connectivity to the adapter database and the MyGeotab database.
    2. Review the nlog.config file and make any necessary changes. See the nlog.config section for more information.
  119. Step 4: Run the MyGeotab API Adapter

  120. There are multiple ways to run the API Adapter as shown below.

  121. Option 1: Run Manually

  122. 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.

  123. Option 2: Install as a Service

  124. 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.

  125. NOTE: Before installing the MyGeotab API Adapter as a service in the steps below, the steps in the previous sections must be completed, including:

    1. 1 Prerequisites
    2. 2 Download
    3. 3 Database Setup
    4. 4 Application Deployment and Configuration (Step 1: Deployment Prerequisites, Step 2: Install MyGeotab API Adapter Application, Step 3: Configure MyGeotab API Adapter Application)
  126. Windows
  127. Watch video:

  128. 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:

  129. 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

  130. Linux
  131. To install MyGeotab API Adapter as a Linux (systemd) Service:

  132. 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:

    1. In ExecStart and WorkingDirectory, replace “/mnt/c/ABC” with the path of the actual folder where the API Adapter was deployed.
    2. 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

  133. Option 3: Set-up a Scheduled Task / Cron Job

  134. 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.

  135. Database Maintenance

  136. ! 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.

  137. The “DM2” (Data Model 2) version of the adapter database is designed with performance, scalability and maintainability in mind. Specifically:

  138. It is normalized with many indexes and relationships between tables.
  139. 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.
  140. Feed Data” tables are partitioned by month, week or day. See Database Partitioning for details.
  141. 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.

document Image

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.

document Image

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.

  1. Services that process “reference data” are configured in the AppSettings - Caches section of the appsettings.json file.
  2. 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:

  1. Find the LogRecord for the subject Device with the closest preceding or equal DateTime to that of the StatusData record.
  2. 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:

  1. 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.
  2. 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.
  3. 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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

BinaryData2

Feed data

Contains data corresponding to MyGeotab BinaryData objects.

DBMaintenanceLogs2

System Info

A system table used by the MyGeotab API Adapter.

DBPartitionInfo2

System Info

A system table used by the MyGeotab API Adapter.

ChargeEvents2

Feed data

Contains data corresponding to MyGeotab ChargeEvent objects.

DefectSeverities2

Reference data

Represents the list of values in the MyGeotab DefectSeverity entity.

Devices2

Reference data

Contains data corresponding to MyGeotab Device objects.

DeviceStatusInfo2

Reference data

Contains data corresponding to MyGeotab DeviceStatusInfo objects.

DiagnosticIds2

Reference data

Contains data corresponding to MyGeotab Diagnostic objects.

Diagnostics2

Reference data

Contains data corresponding to MyGeotab Diagnostic objects.

DriverChanges2

Feed data

Contains data corresponding to MyGeotab DriverChange objects.

DutyStatusAvailabilities2

Reference data

Contains data corresponding to MyGeotab DutyStatusAvailability objects.

DutyStatusLogs2

Feed data

Contains data corresponding to MyGeotab DutyStatusLog objects.

DVIRDefectRemarks2

Feed data

Contains data corresponding to MyGeotab DefectRemark objects.

DVIRDefects2

Feed data

Contains data corresponding to defects associated with DVIRLogs. It includes data derived from MyGeotab DVIRLog, DVIRDefect, Defect and Group objects.

DVIRLogs2

Feed data

Contains data corresponding to MyGeotab DVIRLog objects.

EntityMetadata2

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.

EntityType (Enumeration)

Reference data

The EntityType enumeration is not represented in a physical table. It is used to identify MyGeotab Entity types.

ExceptionEvents2

Feed data

Contains data corresponding to MyGeotab ExceptionEvent objects.

fail_DVIRDefectUpdateFailures2

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.

FaultData2

Feed data

Contains data corresponding to MyGeotab FaultData objects.

FaultDataLocations2

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.

FuelAndEnergyUsed2

Feed data

Contains data corresponding to MyGeotab FuelAndEnergyUsed objects.

Groups2

Reference data

Contains data corresponding to MyGeotab Group objects.

LogRecords2

Feed data

Contains data corresponding to MyGeotab LogRecord objects.

MiddlewareVersionInfo2

System info

A system table used by the MyGeotab API Adapter.

MyGeotabVersionInfo2

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.

OServiceTracking2

System info

A system table used by the MyGeotab API Adapter.

RepairStatuses2

Reference data

Represents the list of values in the MyGeotab RepairStatusType entity.

Rules2

Reference data

Contains data corresponding to MyGeotab Rule objects.

StatusData2

Feed data

Contains data corresponding to MyGeotab StatusData objects.

StatusDataLocations2

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.

Trips2

Feed data

Contains data corresponding to MyGeotab Trip objects.

upd_DVIRDefectUpdates2

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.

Users2

Reference data

Contains data corresponding to MyGeotab User objects.

Zones2

Reference data

Contains data corresponding to MyGeotab Zone objects.

ZoneTypes2

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.

  1. 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.
  2. In other cases, the id is generated automatically by the adapter database and is entirely unrelated to the Geotab system.
  3. 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:

  1. Blue headers are used for “reference data” tables.
  2. Yellow headers are used for “feed data” tables.
  3. Black crow’s foot lines show physical relationships.
  4. 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).

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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

The DutyStatusDeferralType.

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

  1. It is highly unlikely that new LogRecords with older timestamps will come-in, since the MyGeotab API Adapter only moves forward in time once started.
  2. It is normal for devices to report some StatusData and/or FaultData information before reporting any LogRecords upon initial activation. Additionally, it is possible for some StatusData and/or FaultData records to be received before any LogRecords for a given Device when the MyGeotab API Adapter is first started (and starts collecting data from a given point in time).

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.

  1. The same points noted for #5 (TargetEntityDateTimeBelowMinDbLogRecord2DateTime) apply here as well on a per-device level.

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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.

document Image

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:

document Image

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:

document Image

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:

document Image

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:

document Image

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:

  1. VACUUM and ANALYZE: This is performed on tables meeting any of these criteria:
    1. Dead tuple ratio greater than 0.2
    2. Over 1,000 dead tuples
  2. ANALYZE Only: This is performed on tables where the modification ratio since the last analysis is greater than 0.1.
  3. Level 1 Maintenance - SQL Server
  4. For SQL Server, Level 1 maintenance involves the following:

    1. UPDATE STATISTICS: This is performed on tables where the modification ratio since the last analysis is greater than 0.1.
    2. Level 2 Maintenance

    3. “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.

    4. Level 2 Maintenance - PostgreSQL
    5. For PostgreSQL, Level 2 maintenance involves the following:

    6. REINDEX: This is performed on indexes that are over 1,000 bytes in size and have a bloat ratio greater than 0.3.
  5. Level 2 Maintenance - SQL Server
  6. For SQL Server, Level 2 maintenance involves the following:

  7. REBUILD Entire Index: An entire index is rebuilt if more than half of its partitions are over 30 percent fragmented.
  8. 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).
  9. 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

    1. Identify and detach partitions older than 12 months from the parent tables.
    2. Backup the old partitions (to CSV, to an archive database, or using pg_dump).
    3. Drop the detached partitions after successful backup.
    4. Run ANALYZE and VACUUM FULL for cleanup and performance.
  • Retention Strategy Example - SQL Server

    1. Identify partitions older than 12 months and switch them to archive tables.
    2. Backup the archive tables (using SQL Backup or export to CSV).
    3. 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 “__”):

    document Image

    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.

    1. SQL Server example: Server=<Server>;Database=geotabadapterdb;User Id=geotabadapter_client;Password=<password>;MultipleActiveResultSets=True;TrustServerCertificate=True
    2. PostgreSQL example: Server=<Server>;Port=<Port>;Database=geotabadapterdb;User Id=geotabadapter_client;Password=<password>

    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<EntityType>Cache

    Indicates whether the cache for the subject entity type should be enabled. Must be set to either true or false.

    <EntityType>CacheIntervalDailyReferenceStartTimeUTC

    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).

    <EntityType>CacheUpdateIntervalMinutes

    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).

    <EntityType>CacheRefreshIntervalMinutes

    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:

    1. CurrentTime: Data feeds will be started from the current point in time.
    2. SpecificTime: Data feeds will be started at the specific point in time (in the past) specified by the FeedStartSpecificTimeUTC parameter.
    3. FeedVersion: Each data feed will be started at the specific version captured in the OServiceTracking table in the adapter database. If the data feed for a specific object type has not yet been run, it will start at version zero, effectively allowing the feed to pull all of the respective data from the database.

    ! 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<EntityType>Feed

    Indicates whether the data feed for the subject entity type should be enabled. Must be set to either true or false.

    <EntityType>FeedIntervalSeconds

    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:

    1. Day: Archive daily.
    2. Hour: Archive every hour.
    3. Minute: Archive every minute.
    4. Month: Archive every month.
    5. None: Don't archive based on time.
    6. Year: Archive every year.
    7. Sunday: Archive every Sunday.
    8. Monday: Archive every Monday.
    9. Tuesday: Archive every Tuesday.
    10. Wednesday: Archive every Wednesday.
    11. Thursday: Archive every Thursday.
    12. Friday: Archive every Friday.
    13. Saturday: Archive every Saturday.

    minlevel

    Indicates the log level, which is the amount of detail to be written to log files. Default: Info.

    Possible values:

    1. Trace: Very detailed logs, which may include high-volume. information such as protocol payloads. This log level is typically only enabled during development.
    2. Debug: Debugging information, less detailed than trace, typically not enabled in a production environment.
    3. Info: Information messages, which are normally enabled in a production environment.
    4. Warn: Warning messages, typically for non-critical issues, which can be recovered or which are temporary failures.
    5. Error: Error messages - most of the time these are Exceptions.
    6. Fatal: Very serious errors!

    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:

    1. EnableLogRecordFeed must be set to true.
    2. EnableDeviceCache must be set to true. This is because the LogRecordProcessor requires the DeviceCache to be operational.
    3. EnableMinimunIntervalSamplingForLogRecords must be set to true. Otherwise, normal processing of LogRecords will occur.
    4. MinimumIntervalSamplingIntervalSeconds must be set to a value ranging from 1 through 3600.
    5. [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:

    1. 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).
    2. 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:

    1. EnableStatusDataFeed must be set to true.
    2. EnableDeviceCache and EnableDiagnosticCache must both be set to true. This is because the StatusDataProcessor requires the DeviceCache and DiagnosticCache to be operational.
    3. EnableMinimunIntervalSamplingForStatusData must be set to true. Otherwise, normal processing of StatusData will occur.
    4. MinimumIntervalSamplingIntervalSeconds must be set to a value ranging from 1 through 3600.
    5. 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.
    6. ExcludeDiagnosticsToTrack must be set to false if EnableMinimunIntervalSamplingForStatusData is set to true.
    7. 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.
    8. [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:

    1. 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).
    2. Only StatusData records with the DiagnosticOilPressureId, DiagnosticIgnitionId and DiagnosticEngineRoadSpeedId Diagnostic Ids will be collected.
    3. All StatusData records with the DiagnosticIgnitionId Diagnostic Id will be collected.
    4. 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:

    1. Add repair remarks to existing DVIRDefects
    2. 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:

    1. Values must be provided for the Remark, RemarkDateTimeUtc and RemarkUserId fields.

    5

    To update the repair status of a DVIRDefect:

    1. Values must be provided for the RepairDateTimeUtc, RepairStatusId and RepairUserId fields.

    6

    To add a remark to a DVIRDefect and update the repair status of the DVIRDefect at the same time:

    1. Values must be provided for the Remark, RemarkDateTimeUtc, RemarkUserId, RepairDateTimeUtc, RepairStatusId and RepairUserId fields.

    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:

    1. The User associated with the supplied RepairUserId must have “Mark Asset Inspection logs as repaired” and “Administer Asset Inspection logs” clearances.
    2. The User associated with the supplied RemarkUserId must have “Perform Asset Inspections” and “Administer Asset Inspection logs” clearances.

    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:

    1. 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.
    2. 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.
    3. 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):

    document Image

    In this data structure:

    1. The Diagnostics2 table contains a single record for each Diagnostic in the MyGeotab database, including the various attributes.
    2. 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.
    3. 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:

    1. There will be one record for the subject Diagnostic in the Diagnostics2 table.
    2. The DiagnosticIds2 table will contain two records for the subject Diagnostic - one where the GeotabId is “aCDbCr55QuUu2GhWCSN0CkQ”, and another where the GeotabId is “DiagnosticGenericAdblueTankLevelId”.
    3. 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:

    1. 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:

    1. 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.
    2. 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:

    1. High-performance and reduced I/O load on the system since full table scans are avoided.
    2. Contention avoidance since this approach does not interfere with concurrent writes or block transactions.
    3. High-scalability because it works well for partitioned tables and high-throughput systems with large amounts of data.
    4. 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.

    5. 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.

    6. Incorporating DateTime Ranges in Queries to Leverage Partition Pruning

    7. 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:

    8. SQL Server Version:

    9. SELECT * FROM dbo.LogRecords2

    10. WHERE DateTime >= '2025-01-01 00:00:00'

    11. AND DateTime < '2025-02-01 00:00:00';

    12. PostgreSQL Version:

    13. SELECT * FROM public."LogRecords2"

    14. WHERE "DateTime" >= '2025-01-01 00:00:00'

    15. AND "DateTime" < '2025-02-01 00:00:00';

    16. In the above example:

    17. All records for the month of January, 2025 are returned from the LogRecords2 table.
    18. 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.
    19. 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).

    1. DrivingTicks = 452166240000 ticks = 12:33:36.624
    2. DutyTicks = 454808390000 ticks = 12:38:00.839

    2

    Calculate the elapsed time since the subject record was updated:

    1. RecordLastChangedUtc = 2025-07-29 13:29:10
    2. Current UTC date and time = 2025-07-29 13:32:10
    3. Elapsed time = 00:03.000

    3

    Subtract the calculated offset from the Driving and Duty durations:

    1. Driving Duration = 12:33:36.624 - 00:03.000 = 12:30:36.624
    2. Duty Duration = 12:38:00.839 - 00:03.000 = 12:35:00.839

    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:

    document Image

    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:

    1. The FMI is found in the FailureModeCode column of the result set.
    2. The SPN is found in the DiagnosticCode column of the result set.
    3. 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:

    document Image

    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:

    1. 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.
      1. 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.
      2. 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.
    2. 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

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 4.0.0 to version 4.0.1.1, see
    2. Bug Fix: Modified GenericGeotabGUIDCacheableDbObjectCache2 class:
      1. 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.
    3. Bug Fix: Modified database partitioning procedure/function (spManagePartitions):
      1. 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.
      2. PostgreSQL version: No changes other than DB version upgrade to by consistent with MSSQL..
    4. Updated required adapter database version to 4.0.1.0.
    5. Updated NuGet packages to the latest stable release.
      1. Geotab.Checkmate.ObjectModel updated from version 11.98.302 to 11.109.349.
    6. Updated version to 4.0.1.1.
    7. Version 4.0.1

    8. 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.
    9. Version 4.0.0

    10. NOTE: This build includes changes to the appsettings.json file.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.14.0 to version 4.0.0, see
    11. DEPRECATED THE ORIGINAL DATA MODEL. Related changes include the following:
      1. Removed the Data Optimizer. Its capabilities are included (and vastly improved) in the API Adapter’s Data Enhancement Services.
      2. Removed v1 database scripts.
      3. Removed the VSS Add-On. This was an extraneous feature that was not ported over to DM2.
      4. 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.
      5. Modified the appsettings.json file:
        1. Removed the UseDataModel2 setting.
        2. Removed the DebugData section (DebugData is not supported in DM2).
      6. Cleaned-up the solution by modifying code as needed and removing items no longer needed as a result of the above.
    12. Updated README.md file.
    13. Updated NuGet packages to the latest stable release.
      1. Geotab.Checkmate.ObjectModel updated from version 11.83.265 to 11.98.302.
    14. Updated version to 4.0.0.0.
    15. Version 3.14.0

    16. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.13.0 to version 3.14.0, see
    17. Bug Fix: Modified database partitioning procedure/function (spManagePartitions):
      1. SQL Server version: Fixed issue that could cause monthly partitions to become daily.
      2. PostgreSQL version: Changed function to ensure that daily/weekly/monthly partitions cover the entire next month.
    18. Updated version to 3.14.0.0.
    19. Version 3.13.0

    20. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.12.0 to version 3.13.0, see
    21. Migrated DVIRLog Manipulator to DM2.
      1. Added upd_DVIRDefectUpdates2 and fail_DVIRDefectUpdateFailures2 tables.
      2. Added DVIRLog Manipulator section to this guide to fully explain what it does and how to use it.
    22. 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.
    23. 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.
      1. 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.
    24. 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.
    25. Updated NuGet packages to the latest stable release.
    26. Updated version to 3.13.0.0.
  • Version 3.12.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.11.0 to version 3.12.0, see
    2. Added DutyStatusLogs2 table with associated data feed.
    3. Removed physical foreign key relationships associated with User, Device and Rule Ids to accommodate historic data and certain edge cases.
    4. 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.
    5. Made the ExceptionEvents2.RuleId column nullable.
    6. Updated NuGet packages to the latest stable release.
    7. Updated version to 3.12.0.0.
  • Version 3.11.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.10.0 to version 3.11.0, see
    2. Added ability to install the MyGeotab API Adapter application (DM2) as a service (in Windows or Linux).
      1. Updated the Step 4: Run the MyGeotab API Adapter section in the guide to include instructions on installing the API Adapter as a service.
    3. 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.
    4. Modified GeotabTripDbTripObjectMapper (DM1) to ignore Trips with null Device.
    5. Updated README.md file.
    6. Updated NuGet packages to the latest stable release.
    7. Updated version to 3.11.0.0.
    8. Added training video to the Quick Start Guide:
  • Version 3.10.0

    1. NOTE: This build includes changes to the schema of the adapter database and to the appsettings.json files.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.9.0 to version 3.10.0, see
    2. Added FuelAndEnergyUsed2 table with associated data feed.
    3. Added FuelAndEnergyUsed Queries section to the guide.
    4. Added DutyStatusAvailability Queries section to the guide.
    5. Modified the FaultData2 table:
      1. Added EffectOnComponent, FaultDescription, FlashCodeId, FlashCodeName, Recommendation and RiskOfBreakdown columns to include properties recently added to the FaultData entity.
    6. Modified the appsettings.json file:
      1. Added a section with settings for the new FuelAndEnergyUsed feed.
      2. Added a “PopulateEffectOnComponentAndRecommendation” setting to the FaultData feed section.
      3. Made related changes throughout the application.
    7. Updated NuGet packages to the latest stable release.
      1. Geotab.Checkmate.ObjectModel updated from version 11.68.266 to 11.83.265.
    8. Updated version to 3.10.0.0.
    9. Added training videos to the Quick Start Guide:
  • Version 3.9.0

    1. NOTE: This build includes changes to the schema of the adapter database and to the appsettings.json files.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.8.0 to version 3.9.0, see
    2. 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.
    3. FIX: Modified stg_Diagnostics2 and Diagnostics2 tables:
      1. Increased length of DiagnosticName column from 255 to max to accommodate new Diagnostics with long names on the MyGeotab side.
    4. Added pseudo feed for DutyStatusAvailability along with associated DutyStatusAvailabilities2 table.
    5. Modified ExceptionEvent feed - setting IncludeInvalidated, IncludeDismissedEvents and IncludeDeleted all to true (previously, only IncludeInvalidated was set to true)
    6. Modified the appsettings.json files (for both API Adapter and Data Optimizer):
      1. Renamed “OverrideSetings” to “OverrideSettings” (to correct typo).
      2. Made related changes throughout the applications.
    7. Added macOS publish profile (to facilitate deployment to macOS systems)
    8. Updated NuGet packages to the latest stable release.
    9. Updated version to 3.9.0.0.
  • Version 3.8.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.7.0 to version 3.8.0, see
    2. Modified Devices2 table:
      1. Added TmpTrailerGeotabId and TmpTrailerId columns.
    3. Added DefectSeverities2 and RepairStatuses2 reference data tables.
    4. Added data feed for DVIRLogs along with associated DVIRLogs2, DVIRDefects2 and DVIRDefectRemarks2 tables.
    5. Added DVIRLog Queries section to the guide.
    6. Updated NuGet packages to the latest stable release.
    7. Updated version to 3.8.0.0.
  • Version 3.7.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.6.0 to version 3.7.0, see
    2. Added DeviceStatusInfo2 table with associated data feed.
    3. Added DeviceStatusInfo Queries section to the guide.
    4. Updated NuGet packages to the latest stable release.
    5. Updated version to 3.7.0.0.
    6. Version 3.6.0

    7. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.5.0 to version 3.6.0, see
    8. Added DriverChanges2 table with associated data feed.
    9. 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.
    10. 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.
    11. Enhanced GenericGeotabObjectFeeder:
      1. 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.
      2. Modified services to use the new GenericGeotabObjectFeeder.Rollback method.
    12. Updated NuGet packages to the latest stable release.
    13. Updated version to 3.6.0.0.
  • Version 3.5.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.4.0 to version 3.5.0, see
    2. Added ChargeEvents2 table with associated data feed.
    3. Modified Rules2 table: Added Condition column populated with the hierarchical tree of Condition(s) defining the logic of a Rule in JSON form.
    4. 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.
    5. Updated NuGet packages to the latest stable release.
    6. Updated version to 3.5.0.0.
  • Version 3.4.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.3.0 to version 3.4.0, see
    2. Added BinaryData2 table with associated data feed.
    3. Added BinaryData Queries section to the guide.
    4. Updated NuGet packages to the latest stable release.
      1. Geotab.Checkmate.ObjectModel updated from version 11.62.237 to 11.68.266.
    5. Updated version to 3.4.0.0.
    6. Version 3.3.0

    7. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.2.0 to version 3.3.0, see
    8. Added ExceptionEvents2 table with associated data feed.
    9. Added ExceptionEvent Queries section to the guide.
    10. 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.
    11. Updated NuGet packages to the latest stable release.
    12. Updated version to 3.3.0.0.
  • Version 3.2.0

    1. NOTE: This build includes changes to the schema of the adapter database.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.1.0 to version 3.2.0, see
    2. Added Rules2 table with associated data feed.
    3. Added Trips2 table with associated data feed.
    4. Added documentation, including query examples for both SQL Server and PostgreSQL, to help with optimally querying the adapter database.
      1. Added Trip Queries section to the guide.
      2. Added Group Queries section to the guide.
    5. Modified Database Maintenance Service to pause other services before partitioning the database in order to resolve possible deadlock-related issues.
      1. Changed WaitTimeoutMinutesForPausingOtherServices from 30 to 5.
    6. Bug fix: Updated database scripts (SQL Server and PostgreSQL) to remove certain unique constraints on staging tables that can prove problematic:
      1. Removed: PK_stg_Devices2, PK_stg_Users2, PK_stg_Zones2, UK_stg_Trips2_DeviceId_Start_EntityStatus
      2. Added: IX_stg_Trips2_DeviceId_Start_EntityStatus
    7. Modified database cleanup scripts to exclude staging tables from count results.
    8. Updated NuGet packages to the latest stable release.
    9. Updated version to 3.2.0.0.
  • Version 3.1.0

    1. NOTE: This build includes changes to the schema of the adapter database and appsettings.json file.
      1. To upgrade an existing installation of the MyGeotab API Adapter solution from version 3.0.0 to version 3.1.0, see
    2. Added Groups2 table with associated data feed and related group columns to the Devices2, Users2 and Zones2 tables.
    3. Enhanced cache update/refresh process for reference data types by migrating from in-memory application logic to utilizing staging tables with merge procedures.
      1. Includes Devices, Diagnostics, Groups, Users, Zones and ZoneTypes.
      2. Dramatically improves initial startup performance of the application and is especially noticeable with larger fleets (more data).
      3. 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.
    4. Modified DutyStatusLog feed to include a DutyStatusLogSearch with the IncludeModifications option set to true to include modification history of the DutyStatusLogs.
    5. Bug fix: Added Polly asyncRetryPolicyForDatabaseTransactions wrapper around database calls using standalone connections (in DatabaseMaintenanceService, FaultDataLocationService and StatusDataLocationService).
    6. Bug fix: Updated vwStatsForLevel1DBMaintenance in PostgreSQL scripts to only select from the public schema (avoiding a permissions issue when temp tables get selected otherwise).
    7. Updated NuGet packages to the latest stable release.
    8. Updated version to 3.1.0.0.
    9. Version 3.0.0

    10. 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:

    1. A new data model – Data Model 2 (DM2) – has been added:
      1. DM2 is normalized and designed for greater performance and scalability.
      2. Database is partitioned (monthly, weekly, or daily).
      3. Includes Automated Database Maintenance.
      4. Support both SQL Server and PostgreSQL.
        1. 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.
      5. Data Optimizer deprecated – location interpolation capabilities moved directly into the adapter database with exponentially faster performance.
    2. MyGeotab API Adapter supports both the original data model and DM2:
      1. Initial version 3.0.0 release of DM2 includes support for a subset of the Geotab entities currently supported with the original data model.
      2. Additional entities will be ported over to DM2 in the coming months.
      3. 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.
      4. Refer to the FAQ section in the original guide for more information.
  • Other Updates

    1. 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.
    2. 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).
    3. Modified BaseRepository - added QueryAsync method for executing parameterized queries (including MSSQL stored procedures and Postgres functions) that return data.
    4. Added DatabaseValidator to validate adapter database version on application startup (DM2 only).
    5. Modified BaseRepository and GenericEntityPersister to allow for the optional use of “standalone” database connections (with no transactions and outside of units of work).
    6. Added capability for BackgroundServices to pause for database maintenance (DM2 only).
    7. Added BackgroundServiceAwaiter to consolidate wait logic on behalf of individual BackgroundServices and simplified those services (DM2 versions only) accordingly.
    8. Removed unnecessary trace method entry/exit logging from all BackgroundServices and various other classes.
    9. Modified DatabaseResilienceHelper - added retry for "current transaction aborted" exceptions.
    10. Modified StringHelper.IsValidIdentifierForDatabaseObject method to allow for dashes (as used in weekly partition names).
    11. 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).
    12. 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.

    scroll-up