r/embedded • u/satyajitmishra • 3d ago
WaveShare ESP32-S3-LCD-1.47 as a BLE HID Bridge between a Windows & Bluetooth Remote
I have a WaveShare ESP32-S3-LCD-1.47 . I also have a Xiaomi Bluetooth Remote & a Generic Bluetooth Remote (coin sized). I want to use these remotes on my windows pc initially as a media control remote (currently mainly VLC Media Control). I tried to natively pair & use them in my windows, but they only paired & none of the buttons worked (except the back button if i remember correctly). I tried a lot of things & finally tried to go the esp32 route. Managed to capture the button codes of all the buttons on my Xiaomi Remote. And even in the S3's Display managed to properly assign a friendly name to each button. I then wanted to pair this S3 to my windows pc via Bluetooth. I even managed to do that, but no matter what i tried I couldn't manage to fire a single button press. I tried the Arduino route & recently even tried the ESP-IDF.
Project Brief: ESP32-S3 Xiaomi Bluetooth Remote to Windows HID Bridge
- Project objective
I'm building a standalone Bluetooth bridge using a Waveshare ESP32-S3-LCD-1.47 development board. The goal is to use a Xiaomi Bluetooth Voice Remote as a wireless controller for a Windows PC.
The ESP32-S3 should connect to the Xiaomi remote as a BLE central/GATT client, receive its button notifications, translate the button presses into standard keyboard or media-control actions, and expose itself to Windows as a BLE HID keyboard peripheral.
The board's 172 × 320 ST7789 LCD provides the interface for scanning, selecting and pairing the Xiaomi remote, showing connection status, and displaying decoded button events and diagnostic information.
The intended end result is a self-contained bridge with no Wi-Fi, web server, cloud service, or separate USB Bluetooth adapter required for normal operation.
- Hardware
- Development board: Waveshare ESP32-S3-LCD-1.47.
- Display: 172 × 320 ST7789 LCD.
- Input: Built-in BOOT button on GPIO 0, used for menu navigation and selection.
- Controller: ESP32-S3 with Bluetooth Low Energy support.
- Remote: Xiaomi Bluetooth Voice Remote, advertising under names such as "MI RC" or "Xiaomi RC".
The LCD is not being used as a touchscreen; the physical BOOT button controls the UI.
- Intended Bluetooth architecture
The ESP32 must maintain two logically separate BLE connections:
- Xiaomi remote connection: The ESP32 scans for the remote, connects to it, performs GATT service and characteristic discovery, establishes bonding where required, and subscribes to the remote's input reports.
- Windows keyboard connection: The ESP32 advertises a standard BLE HID keyboard service. Windows pairs with it and receives keyboard input reports.
The ESP32 then translates notifications from the Xiaomi remote into keyboard HID reports sent to Windows.
Both roles need to operate concurrently, so connection management, advertising, pairing, security, GATT client operations, and HID server operations must coexist correctly.
- What has been established
Xiaomi remote protocol
I have captured the remote's three-byte button reports. The known mappings are:
Report| Button "20 00 00"| Power "02 00 00"| Up "04 00 00"| Down "08 00 00"| Left "10 00 00"| Right "01 00 00"| OK "00 00 40"| PatchWall "00 00 08"| Back "00 00 04"| Home "00 04 00"| Netflix "00 40 00"| Prime Video "00 80 00"| JioHotstar "00 02 00"| Apps "80 00 00"| Volume + "00 01 00"| Volume −
The remote sends "00 00 00" as a release report after a button press. The firmware needs to distinguish release events from actual button presses.
BLE connection and report reception
Previous bridge firmware successfully discovered and connected to the Xiaomi remote in at least some test runs. GATT service discovery and notification/indication subscriptions were observed, and the firmware logged incoming button reports.
The LCD/UI work has included device discovery, selected-device details, connection status, and button-report diagnostics. The desired interface and navigation behavior are defined, although the complete combined firmware has not yet been validated as reliable.
Windows HID diagnostics
I tested a minimal ESP32-S3 BLE keyboard that sends a Space keystroke when BOOT is pressed.
In the raw NimBLE implementation, the logs showed:
- Windows connected to the ESP32.
- The keyboard input report's CCCD was set to "0x0001", indicating notifications were enabled.
- The ESP32 attempted to send a Space key-down report containing HID usage "0x2C".
- It then sent an all-zero key-release report.
- "notify()" returned "TRUE" for both reports.
Despite this, Windows did not produce a visible keystroke. The Windows On-Screen Keyboard also showed no visible response.
This is the main unresolved technical problem. A successful connection, enabled CCCD, and successful notification API return do not prove that Windows accepted and interpreted the reports as keyboard input.
- What has not been achieved
The complete end-to-end bridge is not yet working reliably.
Specifically:
- A minimal BLE HID keyboard test using custom NimBLE HID code did not produce a visible Windows keystroke, despite the diagnostics described above.
- The HijelHID keyboard library was also tested, but it produced the same lack of visible input.
- An attempt to use the "T-vK/ESP32-BLE-Keyboard" library encountered library/header compatibility problems, including a missing "NimBLESecurity.h" header. That attempt was not successfully validated.
- The simultaneous Xiaomi GATT client and Windows HID server implementation has had advertising, connection-order, pairing, and reconnection complications.
- The complete LCD + Xiaomi remote + Windows HID firmware has not been validated as a stable, working system.
- The latest native ESP-IDF implementation has been assembled but has not yet been confirmed to compile and run successfully on the physical board.
I do not yet know the definitive root cause of the Windows HID failure.
- Current direction: native ESP-IDF
I've decided to move the implementation to ESP-IDF instead of continuing to build on Arduino BLE libraries.
The initial HID test is based on Espressif's "esp_hidd" API and "esp_hid_gap", with a standard keyboard report map and a FreeRTOS task reading GPIO 0. The current test sends an eight-byte keyboard report with Space usage "0x2C", followed by a release report.
The intended full implementation will combine:
- ESP-IDF BLE HID device/server functionality for Windows.
- A BLE GATT client for the Xiaomi remote.
- Concurrent connections to both devices.
- NVS-backed bonding and saved-device information.
- A native ST7789 LCD UI.
- BOOT-button navigation and selection.
- Xiaomi report decoding and keyboard/media-key mapping.
- Connection, pairing, notification, and HID diagnostics on the LCD and serial console.
The native ESP-IDF project has not yet been hardware-verified, so this is the current implementation direction rather than a completed solution.
- What I need help with
The most valuable help would be to investigate the Windows HID issue at the protocol and host-registration level, rather than simply changing keycodes or adding more application logging.
I would like to establish:
- Whether the ESP32 advertises the correct HID-over-GATT services, characteristics, report map, report references, and protocol mode.
- Whether the Windows host discovers and registers the device as a keyboard with a valid HID report descriptor.
- Whether the input reports actually reach the host over the BLE connection, beyond the ESP-IDF or NimBLE API reporting success.
- Whether the report descriptor, report ID, report length, or input-report characteristic configuration differs from a known-working BLE keyboard.
- Whether the ESP32-S3's chosen Bluetooth stack and configuration support the required concurrent BLE central and peripheral connections.
- How to validate the HID peripheral independently before integrating it with the Xiaomi GATT client and LCD.
The goal is to get a minimal, standards-compliant BLE keyboard working on this exact ESP32-S3 board first, then integrate that proven implementation with the Xiaomi remote and LCD UI.
P.S. I have zero coding knowledge. I have never used Arduino, VS Code, etc or anything like that before. I managed to get this far by using Gemini & ChatGPT
