Skip to content

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

Open
cheetahdotcat wants to merge 1 commit into
LizardByte:masterfrom
cheetahdotcat:esp32-bridge-pr
Open

cheetahdotcat wants to merge 1 commit into
LizardByte:masterfrom
cheetahdotcat:esp32-bridge-pr

Conversation

@cheetahdotcat

@cheetahdotcat cheetahdotcat commented Oct 22, 2026 •

Copy link
Copy Markdown

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:
home-pairing

Troubleshooting, pairing pending:
troubleshooting-pairing

Troubleshooting, connected:
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.

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

- esp32_bridge_port selects the COM port; empty auto-detects. On first
  start with a bridge attached and no driver chosen, Sunshine selects it.
- Capability probes and the driver status endpoint no longer create a
  second runtime in bridge mode (the serial port can only be opened
  once); pen and touch are not advertised because the bridge has no
  such devices.
- The bridge requires pairing: on first connection the user presses BOOT
  on the bridge. /api/esp32-bridge/status reports the connection and
  pairing state, shown on the home page while pairing is pending and on
  the troubleshooting page.
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant