Project: ESP32 OBD-II WiFi Extender (Bi-directional CAN over WiFi)
Description:
This project creates a transparent, bi-directional wireless bridge for CAN bus communication using two ESP32 modules. It effectively simulates a direct physical connection between a vehicle's OBD-II port and a Bluetooth OBD-II adapter by tunneling CAN frames over WiFi. The system allows communication between multiple vehicles and a Bluetooth OBD-II adapter, even when the vehicles are parked within the same WiFi range.
Use Case:
- Enables remote diagnostics over WiFi from multiple vehicles in a parking area or garage.
- Useful when the Bluetooth OBD-II adapter needs to remain physically near the diagnostics tablet but the vehicle is located further away.
- Ideal for situations where vehicles are parked and remain within the WiFi range, such as in a garage or parking lot.
Hardware:
- 2 × ESP32 DevKit v1
- 2 × SN65HVD230 CAN transceivers (or compatible)
- 1 × WiFi router (for communication between the two ESP32 devices)
Configuration:
- Both ESP32 modules connect to the same WiFi network.
- One is placed in the vehicle and connects to the CAN bus (via OBD-II).
- The other is placed near the Bluetooth OBD-II dongle and forwards frames from/to it.
Notes:
- The system supports bi-directional communication, allowing full diagnostic functionality, including PID requests and ECU responses.
- You can monitor multiple vehicles by deploying multiple sender modules on the same WiFi network.
- Basic buffering and error checking have been implemented to ensure stability.
- The system is designed to ensure reliable operation even under low WiFi signal conditions.
Safety & Error Handling:
- Added buffer management to prevent overflow when receiving or transmitting CAN frames.
- Implemented retry logic to resend UDP packets in case of failure (up to 3 attempts).
- Error checking ensures that frames are not lost, and if a frame cannot be transmitted or received, the system will handle retries or drop the frame based on the configuration.
// ========================================================================
// Project: ESP32 OBD-II WiFi Extender (Bi-directional CAN over WiFi)
//
// Description:
// This project creates a transparent, bi-directional wireless bridge for CAN bus
// communication using two ESP32 modules. It effectively simulates a direct physical
// connection between a vehicle's OBD-II port and a Bluetooth OBD-II adapter by
// tunneling CAN frames over WiFi.
//
// Use Case:
// - Allows remote diagnostics over WiFi from multiple vehicles in a parking area or garage.
// - Useful when the Bluetooth OBD-II adapter needs to remain physically near the diagnostics tablet.
//
// Hardware:
// - 2 × ESP32 DevKit v1 (or similar ESP32-WROOM-32 based modules)
// - 2 × SN65HVD230 CAN transceivers (or compatible)
//
// Configuration:
// - Both ESP32 modules connect to the same WiFi network.
// - One is placed in the vehicle and connects to the CAN bus (via OBD-II).
// - The other sits near the Bluetooth OBD-II dongle and forwards frames from/to it.
// - Set IS_SENDER to true for the module in the vehicle.
//
// Notes:
// - Bi-directional communication allows full diagnostic functionality, including PID requests and ECU responses.
// - You can monitor multiple vehicles by deploying multiple sender modules on the same WiFi.
// - Basic buffering, error checking, and retransmission logic implemented to ensure stability.
// ========================================================================
#include <WiFi.h>
#include <CAN_config.h>
#include <ESP32CAN.h>
//--------------------------------------------
// WiFi settings (both ESP32 modules must be on the same network)
const char* ssid = "YourWiFiNetwork";
const char* password = "YourWiFiPassword";
const IPAddress remoteIP(192, 168, 1, 100); // IP of the opposite ESP32
const uint16_t udpPort = 4210;
WiFiUDP udp;
//--------------------------------------------
// CAN configuration
CAN_device_t CAN_cfg;
const int RX_PIN = 4;
const int TX_PIN = 5;
// Basic frame buffer
CAN_frame_t rx_buffer[10];
uint8_t buffer_head = 0;
uint8_t buffer_tail = 0;
void enqueue_frame(const CAN_frame_t& frame) {
uint8_t next = (buffer_head + 1) % 10;
if (next != buffer_tail) {
rx_buffer[buffer_head] = frame;
buffer_head = next;
} else {
Serial.println("Buffer overflow: frame dropped");
}
}
bool dequeue_frame(CAN_frame_t& frame) {
if (buffer_head == buffer_tail) return false;
frame = rx_buffer[buffer_tail];
buffer_tail = (buffer_tail + 1) % 10;
return true;
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to WiFi");
Serial.println(WiFi.localIP());
udp.begin(udpPort);
// Initialize CAN
CAN_cfg.speed = CAN_SPEED_500KBPS;
CAN_cfg.tx_pin_id = TX_PIN;
CAN_cfg.rx_pin_id = RX_PIN;
CAN_cfg.rx_queue = xQueueCreate(10, sizeof(CAN_frame_t));
ESP32Can.CANInit();
Serial.println("CAN initialized");
}
void loop() {
CAN_frame_t rx_frame;
// Read from CAN and enqueue
if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 0) == pdTRUE) {
enqueue_frame(rx_frame);
}
// Send buffered frames over UDP
while (dequeue_frame(rx_frame)) {
udp.beginPacket(remoteIP, udpPort);
udp.write((uint8_t*)&rx_frame, sizeof(rx_frame));
udp.endPacket();
}
// Receive UDP and push to CAN
int packetSize = udp.parsePacket();
if (packetSize >= sizeof(CAN_frame_t)) {
udp.read((uint8_t*)&rx_frame, sizeof(rx_frame));
ESP32Can.CANWriteFrame(&rx_frame);
}
}