In the realm of modern automotive technology, accessing and interpreting vehicle data is crucial for diagnostics, performance monitoring, and developing innovative applications. The On-Board Diagnostics II (OBDII) system, mandated in most vehicles today, provides a standardized interface to retrieve this wealth of information. At the heart of this data communication lies the Controller Area Network (CAN) bus, a robust network that facilitates communication between various electronic control units (ECUs) within a vehicle. Parsing this CAN data effectively is the key to unlocking valuable insights from your vehicle’s systems.
This guide introduces the obd-parser
module, a powerful tool designed to simplify the process of interacting with vehicle OBDII systems via ELM327 connections, specifically focusing on parsing CAN data. Whether you are a seasoned automotive engineer, a software developer exploring vehicle data applications, or a hobbyist interested in understanding your car’s inner workings, obd-parser
offers a user-friendly approach to accessing and interpreting OBDII data. This article will walk you through installation, usage, supported functionalities, and the API of obd-parser
, empowering you to leverage OBDII CAN data parsing in your projects.
Installation
Getting started with obd-parser
is straightforward using npm (Node Package Manager). To install the core obd-parser
module, use the following command:
npm install obd-parser --save
This badge indicates the current build status of the obd-parser project using CircleCI, ensuring code stability and reliability.
To establish a connection with your vehicle’s ECU (Engine Control Unit), you will need a connector module. Currently, obd-parser-serial-connection
is available, which facilitates connection via a USB to OBDII adapter. These adapters, often utilizing the ELM327 chip, are readily available online. Examples include these OBDII USB adapters on Amazon.
Install the serial connection module with:
npm install obd-parser-serial-connection --save
This setup provides the necessary foundation to begin parsing OBDII CAN data from your vehicle.
Usage
Let’s explore how to use obd-parser
to interact with your vehicle’s OBDII system. The following example, written in TypeScript, demonstrates how to poll for RPM (Revolutions Per Minute) data. For JavaScript users, the equivalent code is available in the examples folder of the obd-parser
repository and is also provided below for your convenience.
// In your code this should be changed to 'obd-parser'
import * as OBD from 'obd-parser';
// Use a serial connection to connect
var getConnector = require('obd-parser-serial-connection');
// Returns a function that will allow us to connect to the serial port
var connectorFn:Function = getConnector({
// This might vary based on OS - this is the Mac OSX example
serialPath: '/dev/tty.usbserial',
// Might vary based on vehicle. This is the baudrate for a MK6 VW GTI
serialOpts: { baudrate: 38400 }
});
// Need to initialise the OBD module with a "connector" before starting
OBD.init(connectorFn)
.then(function () {
// We've successfully connected. Can now create ECUPoller instances
const rpmPoller:OBD.ECUPoller = new OBD.ECUPoller({
// Pass an instance of the RPM PID to poll for RPM
pid: new OBD.PIDS.Rpm(),
// Poll every 1500 milliseconds
interval: 1500
});
// Bind an event handler for anytime RPM data is available
rpmPoller.on('data', function (output: OBD.OBDOutput) {
console.log('==== Got RPM Output ====');
// Timestamp (Date object) for wheb the response was received
console.log('time: ', output.ts);
// The bytes returned from the ECU when asked from RPM
console.log('bytes: ', output.bytes);
// A value that's usuall numeric e.g 1200
console.log('value: ', output.value);
// This will be a value such as "1200rpm"
console.log('pretty: ', output.pretty);
});
// Start polling (every 1500ms as specified above)
rpmPoller.startPolling();
});
An example illustrating a typical OBDII port location in a vehicle. The OBDII port is usually located within easy reach of the driver, often under the dashboard.
This code snippet demonstrates the fundamental steps to initialize the obd-parser
, establish a serial connection, create an ECUPoller
instance for RPM data, and handle incoming data. Key aspects to note:
- Connector Function: The
getConnector
function fromobd-parser-serial-connection
handles the serial port connection. TheserialPath
andserialOpts
may need adjustment based on your operating system and vehicle communication protocol. - OBD Initialization:
OBD.init(connectorFn)
initializes theobd-parser
with the connection function. This step is crucial before any data polling can commence. - ECUPoller: The
ECUPoller
class is responsible for periodically polling the ECU for specific Parameter IDs (PIDs). In this example, we are polling for RPM usingnew OBD.PIDS.Rpm()
. - Data Event: The
data
event listener on therpmPoller
instance is triggered whenever new RPM data is received from the ECU. Theoutput
object contains valuable information, including the timestamp, raw bytes, numerical value, and a human-readable “pretty” value.
Supported PIDs for OBDII CAN Data Parsing
The obd-parser
module currently supports a selection of commonly used PIDs (Parameter IDs) for OBDII CAN data parsing. PIDs are codes used to request specific data parameters from the vehicle’s ECU. Expanding PID support is an ongoing effort, and contributions are welcomed. Adding new PID definitions is straightforward by creating new PID classes within the lib/pids/pid.ts
directory. For detailed information on OBDII PIDs, the Wikipedia page on OBD-II PIDs is a valuable resource.
For the most up-to-date list of supported PIDs, please refer to the pid.ts directory on GitHub. As of this writing, the following PIDs are supported:
ENGINE_COOLANT_TEMPERATURE
(PID 05)FUEL_LEVEL_INPUT
(PID 2F)ENGINE_RPM
(PID 0C)VEHICLE_SPEED
(PID 0D)
If you are using TypeScript, your IDE’s IntelliSense feature will also provide a convenient list of available OBD.PIDS
options as you type.
API Reference for OBDII Interaction
The obd-parser
module exposes a concise and well-defined API to facilitate interaction with OBDII systems and parsing CAN data. Let’s delve into the key components of this API.
OBD.init(connectorFn)
This function is essential for initializing the obd-parser
module. The connectorFn
argument should be a connector function obtained from a module like obd-parser-serial-connection
. This function establishes the communication pathway between your application and the vehicle’s ECU.
OBD.ECUPoller(args: PollerArgs) (Class)
The ECUPoller
class is central to polling specific PIDs from the ECU. To create an ECUPoller
instance, you need to provide an args
object with the following properties:
pid
: An instance of a PID class, such asnew OBD.PIDS.Rpm()
. This specifies the parameter you wish to monitor.interval
: The polling interval in milliseconds whenstartPolling()
is invoked. This determines how frequently the ECU is queried for data.
It’s generally recommended to create only one ECUPoller
instance per PID to avoid potential conflicts or flooding the ECU with requests, unless you have a specific reason for multiple pollers.
ECUPoller.poll()
This method sends a single poll request to the ECU for the PID associated with the ECUPoller
instance. It returns a Promise that resolves with an OBDOutput
object upon receiving a response from the ECU. Alternatively, you can utilize the data
event listener for asynchronous data handling.
ECUPoller.startPolling() and ECUPoller.stopPolling()
startPolling()
initiates a continuous polling loop, querying the ECU at intervals defined by the interval
argument provided during ECUPoller
instantiation. To prevent overwhelming the ECU, new poll requests are only sent after a response is received from the previous request, respecting the specified interval as closely as possible. stopPolling()
halts the ongoing polling loop.
OBD.PIDS
OBD.PIDS
is an object that serves as a container for available PID classes. Here’s how you can instantiate different PIDs:
import * as OBD from 'obd-parser';
new OBD.PIDS.FuelLevel();
new OBD.PIDS.Rpm();
new OBD.PIDS.VehicleSpeed();
new OBD.PIDS.CoolantTemp();
// Base PID class for extension
new OBD.PIDS.PID();
The PID
class serves as a base class for creating custom PID implementations. If you develop new PID classes, consider contributing them back to the obd-parser
project!
OBD.OBDOutput
OBDOutput
is an interface (primarily used in TypeScript) that defines the structure of the data emitted through the data
event and resolved by the poll()
Promise. It provides type safety and clarity when working with OBDII data.
Pure JavaScript Example for OBDII Data Parsing
For developers working with pure JavaScript, here’s the equivalent example to the TypeScript code presented earlier:
'use strict';
var OBD = require('obd-parser');
var getConnector = require('obd-parser-serial-connection');
var connect = getConnector({
serialPath: '/dev/tty.usbserial',
serialOpts: { baudrate: 38400 }
});
OBD.init(connect)
.then(function () {
var rpmPoller = new OBD.ECUPoller({
pid: new OBD.PIDS.Rpm(),
interval: 1500
});
rpmPoller.on('data', function (output) {
console.log('==== Got RPM Output ====');
console.log('time: ', output.ts);
console.log('bytes: ', output.bytes);
console.log('value: ', output.value);
console.log('pretty: ', output.pretty);
});
rpmPoller.startPolling();
});
This JavaScript example mirrors the TypeScript version in functionality and structure, providing a readily usable code snippet for JavaScript-based OBDII CAN data parsing projects.
CHANGELOG
- 0.2.1
- Ensured definition files are included in published code, enhancing TypeScript support.
- 0.2.0
- Refactored codebase using TypeScript and Classes, improving code structure and maintainability.
- Simplified the process of obtaining and creating
ECUPoller
andPIDS
instances, streamlining usage. - Updated documentation and examples to reflect API changes and improvements.
This changelog provides a brief history of significant updates to the obd-parser
module, highlighting key improvements and changes over versions.