fix(bluetooth): auto-reconnect to paired devices after reboot

- Auto-set enableOnBoot=true when BT is enabled or device is paired,
  so board restarts with BT on and can reconnect
- Make RADIO_STATE_ON handler non-exclusive: scan for HID Host,
  start HID Device, SPP and MIDI all independently (was else-if)
- Improve HID Host auto-connect for RPA: direct addr match, name-match
  fallback, and direct connect to stored identity using resolving list
- Persist addrType in PairedDevice file for more reliable reconnection
- Add verbose logging for loadAll/save to debug missing files

Fixes issue where board restart did not reconnect to previously
connected BT devices. Also preserves f94cc160 fullscreen flag feature.
This commit is contained in:
Adolfo Reyna
2026-07-19 19:31:57 -04:00
parent f94cc160cf
commit 80bd1c9f20
4 changed files with 149 additions and 34 deletions
+47 -12
View File
@@ -115,6 +115,15 @@ static void bt_event_bridge(Device*, void* /*context*/, BtEvent event) {
case BT_RADIO_STATE_ON:
getMainDispatcher().dispatch([] {
auto peers = settings::loadAll();
LOG_I(TAG, "RADIO ON: loaded %d paired peers", (int)peers.size());
for (const auto& p : peers) {
LOG_I(TAG, " - peer %s name='%s' profile=%d auto=%d type=%d",
settings::addrToHex(p.addr).c_str(),
p.name.c_str(),
p.profileId,
(int)p.autoConnect,
(int)p.addrType);
}
bool has_hid_host_auto = false;
bool has_hid_device_auto = false;
for (const auto& p : peers) {
@@ -122,28 +131,36 @@ static void bt_event_bridge(Device*, void* /*context*/, BtEvent event) {
if (p.profileId == BT_PROFILE_HID_HOST) has_hid_host_auto = true;
if (p.profileId == BT_PROFILE_HID_DEVICE) has_hid_device_auto = true;
}
LOG_I(TAG, "RADIO ON: has_hid_host_auto=%d has_hid_device_auto=%d spp=%d midi=%d",
(int)has_hid_host_auto, (int)has_hid_device_auto,
(int)settings::shouldSppAutoStart(), (int)settings::shouldMidiAutoStart());
// Start all auto-connect/auto-start roles that are configured.
// Scanning (central) and advertising (peripheral) can run concurrently
// on ESP32 NimBLE, so we no longer use exclusive else-if.
if (has_hid_host_auto) {
LOG_I(TAG, "HID host auto-connect peer found — starting scan");
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
bluetooth_scan_start(dev);
}
} else if (has_hid_device_auto) {
}
if (has_hid_device_auto) {
LOG_I(TAG, "HID device auto-start (bonded peer found)");
if (Device* dev = bluetooth_hid_device_get_device()) {
bluetooth_hid_device_start(dev, BT_HID_DEVICE_MODE_KEYBOARD);
}
} else {
if (settings::shouldSppAutoStart()) {
LOG_I(TAG, "Auto-starting SPP server");
if (Device* dev = bluetooth_serial_get_device()) {
bluetooth_serial_start(dev);
}
}
// SPP and MIDI are peripheral servers; start them if their global
// auto-start flags are set, regardless of HID roles.
if (settings::shouldSppAutoStart()) {
LOG_I(TAG, "Auto-starting SPP server");
if (Device* dev = bluetooth_serial_get_device()) {
bluetooth_serial_start(dev);
}
if (settings::shouldMidiAutoStart()) {
LOG_I(TAG, "Auto-starting MIDI server");
if (Device* dev = bluetooth_midi_get_device()) {
bluetooth_midi_start(dev);
}
}
if (settings::shouldMidiAutoStart()) {
LOG_I(TAG, "Auto-starting MIDI server");
if (Device* dev = bluetooth_midi_get_device()) {
bluetooth_midi_start(dev);
}
}
});
@@ -176,6 +193,9 @@ static void bt_event_bridge(Device*, void* /*context*/, BtEvent event) {
int profile_copy = event.pair_result.profile;
memcpy(addr_buf, event.pair_result.addr, 6);
getMainDispatcher().dispatch([addr_buf, profile_copy]() mutable {
// Ensure Bluetooth auto-enables on boot after successful pairing,
// so previously connected devices reconnect after a restart.
settings::setEnableOnBoot(true);
std::array<uint8_t, 6> peer_addr;
memcpy(peer_addr.data(), addr_buf, 6);
const auto hex = settings::addrToHex(peer_addr);
@@ -185,6 +205,13 @@ static void bt_event_bridge(Device*, void* /*context*/, BtEvent event) {
dev.name = "";
dev.autoConnect = true;
dev.profileId = profile_copy;
// Try to preserve addrType from scan cache if available
uint8_t cached_type = 0;
if (getCachedScanAddrType(peer_addr.data(), &cached_type)) {
dev.addrType = cached_type;
} else {
dev.addrType = 0;
}
if (settings::save(dev)) {
LOG_I(TAG, "Saved paired peer %s (profile=%d)", hex.c_str(), profile_copy);
}
@@ -290,6 +317,11 @@ bool start(Device* dev) {
return false;
}
// Persist enable-on-boot so that paired devices auto-reconnect after a restart.
// The settings file is written from the main task to avoid blocking the NimBLE host
// task, but the dispatcher may run immediately, so we also set it here.
settings::setEnableOnBoot(true);
LOG_I(TAG, "BT enabled");
return true;
}
@@ -414,6 +446,9 @@ void unpair(const std::array<uint8_t, 6>& addr) {
void connect(const std::array<uint8_t, 6>& addr, int profileId) {
LOG_I(TAG, "connect(profile=%d)", profileId);
// Ensure BT restarts in the same mode after reboot, so previously connected
// devices can be re-found (scan) or reconnected to (advertising).
settings::setEnableOnBoot(true);
if (profileId == BT_PROFILE_HID_HOST) {
hidHostConnect(addr);
} else if (profileId == BT_PROFILE_HID_DEVICE) {