ESP-IDF firmware for an ESP32-S3 that turns BLE controller input into USB HID keyboard/media output, managed through a built-in web UI.
Put simply, this project allows you to use a Bluetooth controller (like a gamepad or remote) as a keyboard or media controller for hardware that only supports USB input.
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#262626',
'primaryTextColor': '#dbdbdb',
'primaryBorderColor': '#00ff99',
'lineColor': '#8d81ff',
'secondaryColor': '#1f1f1f',
'tertiaryColor': '#333'
}
}}%%
flowchart LR
C[🎮 Bluetooth LE Controller<br/>Gamepad / Remote]
E[ESP32-S3<br/>BLE ➜ USB HID Bridge]
R[💻 Receiver System<br/>PC / Console / Media Center]
C -- Bluetooth LE --> E
E -- USB HID Keyboard / Media Keys --> R
Assuming ESP-IDF is installed and the ESP32-S3 is connected to your computer, simply run the following from the root of the repo:
source "~/.espressif/tools/activate_idf_v6.0.2.sh"
idf.py set-target esp32s3 && idf.py build && idf.py flash- Power on the device and connect to its broadcasted access point (SSID:
ControllerMapper-XXXX, password:mapper1234). - Open the web UI hosted at http://192.168.4.1
- Press Start Scan to find BLE devices and Pair on your desired one.
- These Paired devices are persisted across reboots and automatically reconnected to at startup.
- Press Edit Keys for your paired device and press some keys on your controller.
- The keymap is autopopulated as new buttons are discovered.
- Remap your desired keys to USB keyboard/media combos (ex. Controller A Button -> CTRL+ALT+X over USB).
- Pressing Save to Flash will persist your keymap to NVS so it is remembered across reboots.
- Controlling game consoles or media center PCs that lack Bluetooth LE support, with a cheap universal remote like the Sofabaton U1 or U2.
The web UI and API are always available during runtime and allows for test firing key combinations, viewing the serial log, and viewing other useful status/runtime information.
/api/status- Returns current status of the app, including connected devices and last key pressed./api/logs- Returns the last 180 lines of the log ring buffer./api/ble/*- Endpoints for scanning, pairing, connecting, and disconnecting BLE devices./api/keymap/*- Endpoints for viewing, adding, removing, and saving key mappings./api/hid/test- Endpoint for test firing a key combination over USB./api/last_button- Returns the last button pressed on the connected BLE device.
main/ble-to-hid-controller-mapper.c: startup orchestrationmain/wifi_ap.c: SoftAP initialization and AP event logsmain/web_ui.c: embedded single-page HTML/JS UI + REST-like JSON endpointsmain/ble_scanner.c: NimBLE host lifecycle, scanning, pairing, connection, input decoding, reconnect loopmain/hid_bridge.c: combo parser + TinyUSB HID send pipelinemain/app_state.c: mutex-protected in-memory app statemain/keymap_store.c: keymap NVS load/save/clearmain/paired_store.c: paired-address NVS load/savemain/log_sink.c: in-memory log ring buffer for/api/logsmain/include/*.h: module interfaces
- Allow for connecting to a home Wi-Fi network for easier management (currently only SoftAP mode is supported).
- Some simpler remotes may not properly "zero out" their key state on release, causing an inability to detect repeated key presses.
- Fix double keypresses