Fix BLE notification and heartbeat state races - #112
Open
ODevStudio wants to merge 9 commits into
Open
Conversation
ODevStudio
marked this pull request as ready for review
July 27, 2026 15:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
bleCanNotifyCurrent()loop()Root causes
After rapid reconnects, the callback-maintained
deviceConnectedflag can disagree with NimBLE's connection table. Incoming writes may still work while outbound notifications are suppressed.A physical connection can also remain live while FFF4 is not ready to notify. Physical connection state and current FFF4 subscription readiness therefore need separate gates.
During cold boot, BLE advertising previously started before
b_requireHeartBeatwas restored from NVS. A client could change heartbeat enforcement and then have that command overwritten by the continuing setup path.Recovery behavior
A small critical-section-protected mailbox serializes the current connection, FFF4 subscription, pending status reply, request timestamp, connection generation, and one-shot notification-failure state. No lock is held across
notify()ordisconnect().If a status command arrives before FFF4 subscription, the reply remains pending. Subscription delivers it; a two-second timeout retires it and disconnects only if the same connection generation is still current. Revalidation prevents a late subscription, newer request, reused connection handle, or stale disconnect callback from affecting the current client.
Scope
No BLE UUID, packet, command, NVS, client API, or Arduino-ESP32 framework changes. PR #113 remains independent.
Validation
python tools/test_ble_subscription_contract.pypython tools/test_ai_docs_contract.pygit diff --check.pio-core:pio run -e esp32s3(RAM 18.4%, flash 49.7%)Only the existing
wifi_setup.cppvolatile-increment warnings remain. Hardware checks for normal subscription, deferred status delivery, timeout reconnect, rapid reconnects, 10 Hz weight traffic, and one-shot notification-failure logging remain required.