NimBLE params overhaul and try-fix for incompatible bond cleanup - #10741
Conversation
⚡ Try this PR in the Web FlasherWarning This is an automated, unreviewed CI test build. Back up your device configuration Supported boards built by this PR (24)
Build artifacts expire on 2026-07-19. Updated for |
There was a problem hiding this comment.
Pull request overview
This PR targets ESP32 NimBLE stability and Android pairing reliability by cleaning up incompatible bond data after upgrades, avoiding unsafe advertising restarts during NimBLE host resets, and reducing ESP32 BLE RAM usage for the firmware’s single-phone-peripheral model.
Changes:
- Add ESP32-only boot-time detection and one-shot purge of incompatible on-disk NimBLE bond records, with an automatic reboot after cleanup.
- Defer advertising restarts out of the NimBLE disconnect callback into the main thread (gated on
ble_hs_synced()), avoiding crashes during host resets; tighten auth callback handling to avoid marking connections “connected” on failed encryption. - Tune ESP32 NimBLE/controller sdkconfig defaults to reduce RAM usage (single connection, fewer CCCDs/buffers, smaller host task stack).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| variants/esp32/esp32-common.ini | Adjusts ESP32 NimBLE/controller sdkconfig defaults to reduce RAM usage for a single BLE connection scenario. |
| src/nimble/NimbleBluetooth.cpp | Adds incompatible bond purge on ESP32, defers advertising restart to main thread, and improves security/auth state handling; extends bond-clearing to include OUR_SEC records. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Firmware Size Report22 targets | vs
Show 17 more target(s)
Updated for 95a003a |
cpatulea
left a comment
There was a problem hiding this comment.
Code looks reasonable.
Did not compile or test on device.
… init - Delete unused clearNVS() (no callers; should have been removed in #10264). - Move purgeIncompatibleBleBonds() after the "Init the NimBLE" log so bond-cleanup output doesn't appear to precede module init; it still runs before BLEDevice::init() reads the store.
…htastic#10741) * NimBLE params overhaul and try-fix for incompatible bond cleanup * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Address PR review: remove dead clearNVS(), defer bond-purge log below init - Delete unused clearNVS() (no callers; should have been removed in meshtastic#10264). - Move purgeIncompatibleBleBonds() after the "Init the NimBLE" log so bond-cleanup output doesn't appear to precede module init; it still runs before BLEDevice::init() reads the store. * Update MAX_SATELLITE_NODES and WARM_NODE_COUNT definitions for ESP32-S3 PSRAM support --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
sendLog() notified once per firmware log line with no backpressure. With debug_log_api_enabled and a subscribed client, a logging burst drains the msys_1 mbuf pool that every GATT notification and ATT response allocates from, so ble_gatts_notify_custom starts returning BLE_HS_ENOMEM (rc=6) -- for the fromNum doorbell too, not just the log line that exhausted it. Each failure then prints an error over serial at ~12ms apiece, which is itself enough to throttle the main loop during a burst. Register a callback on the log characteristic so the host's own ERROR_GATT verdict pauses log notifies for 250ms and lets the pool refill. Keying off the failure rather than a free-block count keeps this correct however the pools are sized. Also restore CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT to the IDF default of 12. Pool selection is by block size and a notify request always resolves to the smallest pool, so msys_1 is the only pool GATT draws from; 8 was thin once anything chains or fragments. msys_2 and the ACL/EVT transport pools are left trimmed -- neither is on the notify path, and restoring the full defaults would re-spend the contiguous allocation that #10741 was fixing on heap-tight boards. sendLog() also lacked the null check onNowHasData() already has, so a log line arriving during BLE teardown dereferenced a freed characteristic. Fixes #11245
sendLog() notified once per firmware log line with no backpressure. With debug_log_api_enabled and a subscribed client, a logging burst drains the msys_1 mbuf pool that every GATT notification and ATT response allocates from, so ble_gatts_notify_custom starts returning BLE_HS_ENOMEM (rc=6) -- for the fromNum doorbell too, not just the log line that exhausted it. Each failure then prints an error over serial at ~12ms apiece, which is itself enough to throttle the main loop during a burst. Register a callback on the log characteristic so the host's own ERROR_GATT verdict pauses log notifies for 250ms and lets the pool refill. Keying off the failure rather than a free-block count keeps this correct however the pools are sized. Also restore CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT to the IDF default of 12. Pool selection is by block size and a notify request always resolves to the smallest pool, so msys_1 is the only pool GATT draws from; 8 was thin once anything chains or fragments. msys_2 and the ACL/EVT transport pools are left trimmed -- neither is on the notify path, and restoring the full defaults would re-spend the contiguous allocation that #10741 was fixing on heap-tight boards. sendLog() also lacked the null check onNowHasData() already has, so a log line arriving during BLE teardown dereferenced a freed characteristic. Fixes #11245
…htastic#10741) * NimBLE params overhaul and try-fix for incompatible bond cleanup * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Address PR review: remove dead clearNVS(), defer bond-purge log below init - Delete unused clearNVS() (no callers; should have been removed in meshtastic#10264). - Move purgeIncompatibleBleBonds() after the "Init the NimBLE" log so bond-cleanup output doesn't appear to precede module init; it still runs before BLEDevice::init() reads the store. * Update MAX_SATELLITE_NODES and WARM_NODE_COUNT definitions for ESP32-S3 PSRAM support --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Fixes Android BLE pairing for my Heltec V3.
This pull request introduces several important improvements to BLE bond management, connection handling, and memory optimization for ESP32 devices using NimBLE. The most significant changes involve automatically purging incompatible BLE bonds after a NimBLE upgrade, deferring advertising restarts to prevent crashes during host resets, and right-sizing BLE RAM usage for single-connection scenarios. These changes enhance robustness during upgrades and improve memory efficiency.
BLE bond management and upgrade robustness:
purgeIncompatibleBleBonds) to automatically detect and wipe incompatible BLE bond records left after a NimBLE upgrade, preventing persistent pairing failures without requiring a factory reset. This is called during setup on ESP32 devices. [1] [2]clearBonds()andclearNVS()to also deleteBLE_STORE_OBJ_TYPE_OUR_SECentries, ensuring all relevant bond data is removed. [1] [2]Connection and advertising handling improvements:
pendingStartAdvertisingto defer advertising restarts after disconnects, avoiding crashes caused by attempting to restart advertising while the NimBLE host is resetting. The main thread now safely handles advertising restarts. [1] [2] [3]BLE RAM and configuration optimization (ESP32):
esp32-common.inito reduce RAM usage for single-connection scenarios: lowered stack size, reduced buffer counts, and limited maximum connections, freeing heap space and preventing out-of-memory errors during BLE initialization.Dependency and platform-specific adjustments: