Skip to content

gaugelabsinc/obd-bridge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gauge-obd-bridge

Note

This repository is intended for development use only.

Local HTTP bridge between Gauge (web) and an ELM327 compatible OBD adapter that speaks over a serial device typically Linux Classic Bluetooth via /dev/rfcomm0 after you bind RFCOMM.

The bridge does not implement Bluetooth itself. It opens a TTY (e.g. rfcomm), sends ELM commands with a trailing \r, and returns raw text until it sees an ELM > prompt.


Warning

Security note:

The server binds to localhost only. Do not expose it to the network without authentication.

Also any local process could send arbitrary ELM commands to your vehicle bus through the adapter.


What it’s for

  • Gauge native web (Expo web in Chromium) often cannot use Classic Bluetooth SPP directly; Web Bluetooth targets BLE GATT.
  • This service runs on your PC next to the browser: the app sets EXPO_PUBLIC_OBD_BRIDGE_URL=http://127.0.0.1:8765 and uses the “Local OBD bridge” device row to send AT / OBD commands through your existing rfcomm or USB serial link.

Requirements

  • Node.js (for npm start).
  • A paired OBD adapter on Linux when using rfcomm (pair with BlueZ / your desktop Bluetooth UI first).
  • Read/write access to the serial device (often dialout or uucp group).

Install and run

cd obd-bridge
npm install
npm start

By default it listens on 127.0.0.1:8765 (not all interfaces).

From the Gauge repo you can also run:

npm run bridge

(if that script points at this folder).


Environment variables

Variable Default Purpose
OBD_BRIDGE_PORT 8765 HTTP listen port
OBD_SERIAL /dev/rfcomm0 Default serial path when opening the port
OBD_BAUD 115200 Serial baud rate
OBD_SERIAL_SETTLE_MS 2000 Delay after open before traffic (helps rfcomm/SPP)

Example:

OBD_SERIAL=/dev/ttyUSB0 OBD_BAUD=115200 npm start

HTTP API

All routes use JSON where a body is required. CORS is enabled for local frontends.

GET /health

Returns bridge status, default/preferred serial path, whether the port file exists, whether serial is open, baud, and—when the path looks like rfcomm—a best-effort parse of rfcomm show 0:

  • rfcomm.state: e.g. clean, connected, or closed
  • rfcomm.ok: false when state is closed (ELM will usually time out until you re-bind)
  • rfcomm.hint: suggested bind command when the link is bad

POST /api/open

Body (optional):

{ "path": "/dev/rfcomm0" }

Omit path to use OBD_SERIAL / /dev/rfcomm0. Opens the serial port. If rfcomm is closed, the response may still be { ok: true } but include a warn string—check /health before relying on the link.

POST /api/close

Closes the serial port (stops holding the TTY open from Node).

POST /api/elm

Body:

{ "cmd": "ATZ", "timeoutMs": 12000 }
  • cmd: ELM command (no \r needed; the bridge adds it).
  • timeoutMs: optional; default 30000.

Success:

{ "text": "...raw ELM response including > ..." }

Errors return HTTP 4xx/5xx with { "error": "..." }. Timeout messages may include an rfcomm re-bind hint when /dev/rfcomm* is used and BlueZ reports closed.

Note: Commands are queued so only one runs at a time (real adapters expect that).

The first /api/elm may auto-open the preferred serial path if nothing is open yet.


Connecting Gauge (web)

  1. In gauge-native, copy .env.example to .env and set:

    EXPO_PUBLIC_OBD_BRIDGE_URL=http://127.0.0.1:8765

    If the bridge uses another device path than the default, you can set EXPO_PUBLIC_OBD_SERIAL_PATH (the app passes it to /api/open when connecting to the bridge—see Gauge’s bluetooth web implementation).

  2. Start this bridge, then start Expo web and open the app from localhost or 127.0.0.1 (mixed content / Web Bluetooth expectations).

  3. On the Bluetooth screen, choose Local OBD bridge and proceed to live data.


RFCOMM: bind and unbind (Linux Classic Bluetooth)

The bridge does not run rfcomm bind for you (it needs root and is a system/BlueZ concern). You create /dev/rfcomm0 and the live ACL/SPP link with rfcomm or equivalent.

Find your adapter MAC

bluetoothctl devices

Example line: Device 00:04:38:8E:F3:38 OBDLink MX+

Bind (create /dev/rfcomm0 and attach to channel 1)

Channel 1 is typical for many ELM/SPP dongles (e.g. OBDLink); yours may differ.

sudo rfcomm bind 0 00:04:38:8E:F3:38 1

Check:

rfcomm show 0

You want a state other than closed (e.g. clean or connected). If you see channel 1 closed, the device node may exist but no data reaches the ELM—ATZ will time out in Gauge until you fix it.

Unbind / release (drop the rfcomm device and usually the Classic link)

sudo rfcomm release 0

0 is the rfcomm device index (rfcomm0). Use rfcomm -a to list bindings.

Typical “stuck” recovery

When rfcomm show 0 shows closed after sleep or adapter power-save:

sudo rfcomm release 0
sudo rfcomm bind 0 <your-adapter-MAC> 1
rfcomm show 0

Then POST /api/close and POST /api/open on the bridge (or restart the bridge) so it reopens the TTY cleanly.


Permissions

If /api/open says the port is not readable/writable:

sudo usermod -aG dialout $USER
# or on some systems: uucp

Refresh CTRL + R, then retry.


Troubleshooting

Symptom Things to check
ELM timeout: ATZ rfcomm show 0 — if closed, re-bind; ensure adapter is paired and awake.
Bridge OK but no adapter Pair with Bluetooth UI first; correct MAC; try channel 1.
/health open: false Normal until first /api/open or /api/elm; Gauge usually opens on connect.
Works only right after bind Adapter or BlueZ dropped the link—automate bind at boot (systemd) if you need that.

About

Local HTTP bridge connecting a web app to an ELM327 OBD adapter via a serial interface (rfcomm/USB), enabling browser vehicle diagnostics and command execution.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors