Bridges a BLE HID gamepad to a Classic Bluetooth host such as a car head unit, PC, or gaming console. — GitHub
[ BLE HID gamepad ] <--BLE--> [ ESP32 ] <--Classic BT--> [ Host ]
Connect an LED with a series resistor between the LED GPIO pin and GND. The default firmware uses GPIO 13 (WROOM/WROVER); the D1 mini build uses the built-in blue LED on GPIO 2.
| Pattern | Meaning |
|---|---|
| Fast blink (100 ms) | Waiting for BLE controller |
| Slow blink (500 ms) | BLE connected, paging cached Classic BT host |
| Short-long blink (100 ms / 500 ms) | BLE connected, discoverable — waiting for Classic BT host to pair |
| Steady on | Both connected, battery > 75% |
| 3 blinks every 5 s | Both connected, battery 51–75% |
| 2 blinks every 5 s | Both connected, battery 26–50% |
| 1 blink every 5 s | Both connected, battery 0–25% |
Both connections are cached in flash — on subsequent boots the ESP32 reconnects to the known controller and host without re-pairing.
Reset the ESP32 with the old host off or out of range. After 3 unanswered page attempts the bridge becomes discoverable automatically. Removing the bridge from the old host’s device list causes an immediate refusal and reaches discoverable mode faster.
Measured with a Stadia controller using controllertest.io:
| Setup | Average latency |
|---|---|
| Stadia controller → Mac (direct BLE) | ~10 ms |
| Stadia controller → Bridge → Mac (Classic BT) | ~25 ms |
The bridge forces the BLE connection interval to 15 ms (min = max = 12 × 1.25 ms) and forwards reports via a 5 ms periodic poll. Additional latency may come from Classic BT sniff mode negotiated by the host, which the bridge cannot control.
Before flashing, put the ESP32 into boot mode: hold BOOT, press and release RESET, then release BOOT.
Select your board, then click Install:
Requires Chrome or Edge on desktop. Does not work on Firefox or mobile browsers.
Full documentation and source code on
GitHub.