OBD-II Driver

jumpstarter-driver-obd wraps python-obd to query On-Board Diagnostics (OBD-II) PIDs from a vehicle ECU via an ELM327 adapter.

Installation

$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple jumpstarter-driver-obd

Hardware Requirements

  • An ELM327 USB adapter (e.g. PremiumCord ELM327 USB)

  • A vehicle with an OBD-II port (petrol cars from 2001+, diesel from 2004+, all US cars from 1996+)

  • macOS only: ELM327 USB cables use a CH340 or CP2102 USB-serial chip that may need a kernel extension — install the appropriate driver if the port does not appear after plugging in

Configuration

Explicit port

Specify the serial port directly when you have multiple adapters or want a deterministic setup:

export:
  obd:
    type: jumpstarter_driver_obd.driver.OBD
    config:
      port: /dev/ttyUSB0       # Linux
      # port: /dev/cu.usbserial-XXXX   # macOS
      baudrate: 38400

Config parameters

Parameter

Description

Type

Required

Default

port

Serial port path; null to auto-detect an ELM327 adapter

str | null

no

null

baudrate

ELM327 baud rate

int

no

38400

fast

Enable ELM327 fast mode (~100–400 ms faster per query); unreliable on cheap clone adapters, so it is opt-in

bool

no

false

Usage

from jumpstarter_driver_obd import OBDConnectionStatus

# Check connection state
status = obd.status()                              # returns OBDConnectionStatus
print(status == OBDConnectionStatus.CAR_CONNECTED) # True
print(obd.is_connected())                          # True

# Discover what the ECU supports
cmds = obd.supported_commands()   # ["RPM", "SPEED", "COOLANT_TEMP", ...]

# Query individual PIDs by name
rpm   = obd.query("RPM")          # "3000.0 revolutions_per_minute"
speed = obd.query("SPEED")        # "60.0 kph"
temp  = obd.query("COOLANT_TEMP") # "90.0 degC"

# Clearing trouble codes is a separate, explicit call (see note below)
obd.clear_dtc()

query() returns None when the ECU does not answer the command (unsupported PID or no vehicle on the bus). It is read-only: it refuses destructive commands such as CLEAR_DTC (OBD-II mode 04, which erases stored trouble codes and resets emissions readiness monitors). To clear codes deliberately, call clear_dtc() instead.

Troubleshooting

Port not found on macOS Run ls /dev/cu.* before and after plugging in the cable to spot the new device. Install a CH340 or CP2102 USB-serial kernel extension if no new port appears.

Permission denied on Linux Add your user to the dialout group and log out/in:

sudo usermod -aG dialout $USER

Alternatively, create a udev rule for the adapter’s USB vendor/product ID.

“No OBD-II adapters found” Make sure the cable is seated in the OBD-II port (typically under the dashboard on the driver’s side) and that the vehicle ignition is in the ON or ACC position.

API Reference

class jumpstarter_driver_obd.driver.OBD

OBD-II vehicle diagnostics via an ELM327 adapter, wrapping python-obd.

port=None (the default) auto-detects the adapter; otherwise pass the serial path, e.g. /dev/ttyUSB0.

clear_dtc() None

Clear stored DTCs and freeze-frame data (mode 04).

Destructive: also resets readiness monitors, which then need drive cycles to re-complete. Use only as a deliberate reset.

classmethod client() str

Return full import path of the corresponding driver client class

is_connected() bool

True when a vehicle ECU is on the bus, not just the adapter.

query(command_name: str) str | None

Query a PID by name (e.g. ‘RPM’, ‘SPEED’, ‘COOLANT_TEMP’).

Returns None if the ECU doesn’t answer. Destructive commands such as CLEAR_DTC are rejected here; use clear_dtc() instead.

status() OBDConnectionStatus

Connection state.

supported_commands() list[str]

Sorted PID names the connected ECU advertises.

class jumpstarter_driver_obd.client.OBDClient

Client for the OBD-II driver.

clear_dtc() None

Clear stored DTCs and freeze-frame data (mode 04).

Destructive: also resets readiness monitors.

is_connected() bool

True when a vehicle ECU is on the bus, not just the adapter.

query(command_name: str) str | None

Query a PID by name (e.g. ‘RPM’); returns None if the ECU doesn’t answer.

status() OBDConnectionStatus

Connection state.

supported_commands() list[str]

Sorted PID names the connected ECU advertises.

class jumpstarter_driver_obd.driver.OBDConnectionStatus