#5973

feat(input): add ESP32-S3 USB bridge gamepad backend

Opencheetahdotcatwants to merge intofrom

Description

Adds gamepad_driver = esp32_bridge (Windows). Gamepads, keyboard, and mouse are published through libvirtualhid's ESP32-S3 bridge backend. The bridge is a board on the host's USB port that enumerates as standard USB devices.

Depends on LizardByte/libvirtualhid#201. The submodule currently points at that PR's commit. It will be bumped to the merged commit before this is ready.

  • Config:
    • gamepad_driver = esp32_bridge, plus esp32_bridge_port (empty auto-detects).
    • On first start with a bridge attached and no driver chosen, Sunshine selects the bridge and persists the choice.
    • Input tab, docs, and the tray and broker notices are updated for the bridge.
  • Runtimes: the bridge's serial port can only be opened once, so in bridge mode:
    • The pen/touch capability probe and the driver status endpoint no longer create a second runtime.
    • Pen and touch are not advertised, because the bridge has no such devices.
  • Pairing UI: the bridge requires pairing, confirmed with its BOOT button.
    • New /api/esp32-bridge/status endpoint.
    • The home page warns while pairing is pending or the bridge is disconnected.
    • The troubleshooting page shows state, port, bridge ID, firmware, and the pairing setting.

Screenshot

Home, pairing pending:

Troubleshooting, pairing pending:

Troubleshooting, connected:

Issues Fixed or Closed

None.

Roadmap Issues

None.

Testing

New tests:

  • C++:
    • test_config.cpp: bridge auto-selection only without an existing preference.
    • test_virtualhid_input.cpp: backend selection and no pen/touch advertised in bridge mode.
    • test_confighttp.cpp: authenticated /api/esp32-bridge/status, and driver status in bridge mode without a second runtime.
  • Web:
    • Home.test.js: pairing, disconnected, and missing notices, plus polling stopping on unmount.
    • Troubleshooting.test.js: bridge state rows, and no bridge query for other drivers.

Runs:

  • Locally: Vitest 222/222 passed, and clang-format 23.1.0 reports no changes.
  • Not run locally: the C++ suite, because the build dependencies were not installed.
  • CI on a fork-internal draft PR: Windows AMD64 and ARM64, macOS x86_64 and arm64, Linux AppImage, Alpine, Arch, FreeBSD, and Web UI pass.
  • Docker builds pass. Flatpak and Homebrew fail because they fetch the libvirtualhid submodule commit from LizardByte/libvirtualhid, where it does not exist until the dependency PR is merged ("not our ref"). Copr fails on missing credentials on the fork.

Manual: on Windows 11 with an ESP32-S3, Sunshine detected the bridge (COM63), connected, and created the keyboard/mouse slot. The pairing UI has not been tried on Windows hardware yet.

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Tests have been added or updated for new or modified functionality, including regression tests for bug fixes

AI Usage

See our AI usage policy.

  • AI tools were used while preparing this PR

Model: Claude Opus 5.5 (claude-opus-5-5) via Claude Code, used for implementation, tests, and drafting this description. The author reviewed the changes and tested them on hardware.