Skip to content

Add AT commands to switch between BLE, Classic BT/A2DP, and Bluetooth off - #1

Closed
gagarinlg with Copilot wants to merge 2 commits into
mainfrom
copilot/implement-bluetooth-control-commands
Closed

gagarinlg with Copilot wants to merge 2 commits into
mainfrom
copilot/implement-bluetooth-control-commands

Conversation

Copilot AI commented Oct 15, 2026 •

Copy link
Copy Markdown

The firmware was BLE-only. This PR adds runtime commands to turn BLE and Bluetooth Classic/A2DP on and off, so audio streaming can replace the FrSky/BLE behaviour without a reflash. BLE and A2DP are mutually exclusive, so the module switches between them rather than running both at once.

I couldn't compile or run this: there was no ESP-IDF or PlatformIO toolchain available. Please build and test it on a board.

Commands (existing AT-style parser)

AT+BLEON / AT+BLEOFF
AT+A2DPON / AT+A2DPOFF
AT+A2DPCON<12-hex-addr>   (only valid while A2DP is active)
AT+BTOFF
AT+BTBOTH                 -> ERROR (unsupported, logged)

Mode switching (terminal.c)

  • Each mode is a role_t handled by the existing setRole().
  • setRole() tears down the current stack first: A2DP deinit, then Bluedroid and controller disable.
  • A partial AT command is dropped on every switch.
  • FrSky byte parsing now runs only in BLE modes.
  • AT+BLEON returns to the last BLE role (central by default).
  • The active mode is logged and sent over UART as Mode:<name> when BLE is off.

Persistence

  • ROLE_BTEDR_AUDIO_SOURCE and ROLE_BT_OFF are appended to role_t, so saved values keep their meaning. The mode is stored in the existing NVS settings blob.
  • At boot, a saved A2DP mode on a build without A2DP falls back to BLE central.
  • If A2DP fails to start, the module ends up in Bluetooth off.

BT stack (bt.c, new bt_a2dp.c/bt_a2dp.h)

  • bt_init() is now a thin wrapper over a shared start path, and bt_classic_init() is new.
  • Classic controller memory is released only on builds that can't use A2DP, because the release is permanent until reboot.
  • The A2DP source has a minimal init and deinit path with a stubbed data callback that sends silence.
  • Everything A2DP is compiled behind CONFIG_BT_CLASSIC_ENABLED and CONFIG_BT_A2DP_ENABLE, and bt_a2dp_supported() reports whether it's available.

Review notes

  • A2DP is not enabled in any sdkconfig in this PR. Those sdkconfigs have CONFIG_BT_CLASSIC_ENABLED unset, so until a classic-ESP32 sdkconfig enables both options, AT+A2DPON returns ERROR and BLE behaves as before.
  • UART audio ingestion, ring buffer and resampling are out of scope here.
  • esp_bt_gap_set_scan_mode() and esp_a2d_source_register_data_cb() use the IDF 4.4/5.x signatures. Please check them against the IDF version PlatformIO resolves.

Co-authored-by: gagarinlg <54738901+gagarinlg@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for switching Bluetooth subsystems via commands Add AT commands to switch between BLE, Classic BT/A2DP, and Bluetooth off Oct 15, 2026
Copilot AI requested a review from gagarinlg October 15, 2026 07:11
@Amigache

Copy link
Copy Markdown
Collaborator

Thanks for the PR. Some notes after reviewing it against the current development branch (develop), which has diverged significantly from main:

Base and conflicts

  • This PR is based on main (pre-refactor): it uses btaddrtostr, btSetName, src/defines.h and an strncmp-based AT parser. On develop those were renamed/restructured (bt_addr_to_str, bt_set_name, role_t moved into board.h, and the AT parser now lives in at_command.c/h). Merging as-is would conflict heavily, so this would need to be ported, not merged.
  • If you want to make changes, please do so on the develop branch, not main.

Hardware scope

  • Bluetooth Classic / A2DP is not available on the ESP32-C3 (our primary target): the C3 is BLE-only. On C3SuperMini / C3Mini, AT+A2DPON can only ever return ERROR. The feature only makes sense on ESP32-classic boards (pico32, Node32s, and the Seeit ESP32-DEV-38P).
  • Please expose A2DP only on ESP32-classic targets and keep returning ERROR on C3 (which bt_a2dp_supported() already handles).

Functionality

  • The A2DP data callback currently sends silence, so audio streaming is not implemented yet — it is a stub. Could you clarify the intended scope (streaming the radio's audio?) and whether it belongs in this project at all?

Process

  • The PR is a draft and has not been compiled or tested. Before it can be considered it must build cleanly and be validated on hardware (see doc/BENCH.md and tools/at_bench.py).
  • New AT commands are a project extension (like AT+HTRESET); they should be added to the AT parser and documented.

Happy to help port it onto develop if there is interest.

@gagarinlg

Copy link
Copy Markdown
Member

It was just a test run of Copilot, nothing too serious. In the end it would be great to be able to use bletooth audio, when the HW supports it.

@gagarinlg gagarinlg closed this Oct 15, 2026
@gagarinlg
gagarinlg deleted the copilot/implement-bluetooth-control-commands branch October 15, 2026 18:53
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.

3 participants