Skip to content

Connection & Adapters

The ObdConnection class is the main entry point for communicating with a vehicle. It handles adapter detection, initialization, command execution, and ELM327 response parsing.

When no adapter profile is specified, Connect sends an ATI command to identify the adapter and selects the appropriate initialization profile.

var connection = new ObdConnection(transport);
await connection.Connect();
// Check what was detected
Console.WriteLine(connection.DetectedAdapter?.RawIdentifier); // "ELM327 v1.5"
Console.WriteLine(connection.DetectedAdapter?.Type); // Elm327
ATI Response ContainsDetected AsProfile Used
"ELM327"ObdAdapterType.Elm327Elm327AdapterProfile
"STN"ObdAdapterType.ObdLinkObdLinkAdapterProfile
Anything elseObdAdapterType.UnknownElm327AdapterProfile

Skip detection by providing a profile to the constructor:

var connection = new ObdConnection(transport, new ObdLinkAdapterProfile());
await connection.Connect(); // uses OBDLink init sequence, no ATI probe
// Typed command execution
var speed = await connection.Execute(StandardCommands.VehicleSpeed);
// Raw AT/OBD commands
var version = await connection.SendRaw("ATI"); // "ELM327 v1.5"
var protocol = await connection.SendRaw("ATDPN"); // current protocol number
var voltage = await connection.SendRaw("ATRV"); // battery voltage
var pids = await connection.SendRaw("0100"); // supported PIDs [01-20]

Elm327AdapterProfile — Standard ELM327 initialization:

CommandDescription
ATZReset adapter
ATE0Echo off
ATL0Linefeed off
ATS1Spaces on
ATH0Headers off
ATSP0Auto protocol selection

ObdLinkAdapterProfile — Extends ELM327 with STN optimizations:

CommandDescription
(all ELM327 commands)Standard initialization
STFACReset to STN factory defaults
ATCAF1CAN auto formatting on

Implement IObdAdapterProfile for adapters with special initialization needs:

public class MyAdapterProfile : IObdAdapterProfile
{
public string Name => "MyAdapter";
public async Task Initialize(IObdConnection connection, CancellationToken ct = default)
{
await connection.SendRaw("ATZ", ct);
await Task.Delay(500, ct);
await connection.SendRaw("ATE0", ct);
await connection.SendRaw("ATSP6", ct); // force CAN 11-bit 500kbaud
}
}
var connection = new ObdConnection(transport, new MyAdapterProfile());

ObdException is thrown for adapter-level and protocol errors:

try
{
var speed = await connection.Execute(StandardCommands.VehicleSpeed);
}
catch (ObdException ex) when (ex.Message.Contains("No data"))
{
// Vehicle not responding (engine off, unsupported PID, etc.)
}
catch (ObdException ex) when (ex.Message.Contains("Unable to connect"))
{
// Adapter can't reach the vehicle ECU
}

The connection automatically handles these ELM327 error responses:

ResponseException Message
NO DATANo data received from vehicle
UNABLE TO CONNECTUnable to connect to vehicle
BUS INIT: ...ERRORBus initialization error
?Unknown command
(empty)Empty response received

Informational prefixes like SEARCHING... and BUS INIT: ...OK are stripped automatically before parsing.

public interface IObdConnection : IAsyncDisposable
{
bool IsConnected { get; }
Task Connect(CancellationToken ct = default);
Task Disconnect();
Task<T> Execute<T>(IObdCommand<T> command, CancellationToken ct = default);
Task<string> SendRaw(string command, CancellationToken ct = default);
}