Skip to content

[Feature] HID Joystick/Gamepad Support #2629

@rngtng

Description

@rngtng

As brief mentioned here, I (and Claude) managed to get BLE HID Joystick/Gamepad support running on TechnicHub. I see HID support is already discussed here although hasn't been implemented.

Is your feature request related to a problem? Please describe.

Yes. There's currently no way to connect a generic BLE HID joystick to a Pybricks hub. Users who want to remotely control LEGO motors - for example with an ExpressLRS (ELRS) radio transmitter, an ESP32-based gamepad, or any standard BLE HID device - have no supported path. The existing XboxController class only works with Xbox gamepads and relies on Xbox-specific advertisement matching and report parsing.

Describe the solution you'd like

A new HIDJoystick class in pybricks.iodevices that connects to any BLE device advertising the standard HID Service (UUID 0x1812) or Gamepad appearance (0x03C4). The API to be discussed, but it could be very similar to XBox. This should work on hubs with BLE peripheral support (Technic Hub, Prime Hub, Essential Hub, Virtual Hub).

Describe alternatives you've considered

  1. Extend XboxController to support more devices — rejected because the Xbox class hardcodes Xbox-specific advertisement UUIDs, report formats, and button layouts. A generic HID class is cleaner.
  2. Use BLEDevice low-level API — Pybricks doesn't expose raw BLE GATT operations to Python, so users can't DIY a joystick connection from Python alone.
  3. External bridge (e.g., Raspberry Pi relay) — adds hardware complexity and latency. A direct BLE connection is simpler and more responsive.

Additional context

A working implementation exists on my fork tested end-to-end with an ELRS transmitter (NimBLE/ESP32-BLE-Gamepad) driving motors on a Technic Hub.

Key implementation details

  • Follows the existing XboxController BLE peripheral pattern (advertisement matching, async connect thread, notification handler)
  • HID report format: 18 bytes — uint16 buttons + 8 × uint16 axes (ESP32-BLE-Gamepad / NimBLE standard)
  • Connect sequence: scan → connect → pair → set Protocol Mode → discover HID Report char → write CCCD (with response) → notifications flow
  • Technic Hub single-BLE-slot constraint handled via DISCONNECT_HOST option
  • Feature-flagged per hub (PYBRICKS_PY_IODEVICES_HID_JOYSTICK)

Requirements for documentation and example scripts to be discussed. Please advice on this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageIssues that have not been triaged yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions