Fall back to BLE Wi-Fi provisioning on sustained post-boot link loss
Once StaClient::connect() had already succeeded once, a later link loss (router rebooted, password changed, device moved) just retried esp_wifi_connect() forever with no bound and no fallback -- the only recovery path was a power cycle, since BLE provisioning only ever started from startSetupMode() (no stored credentials, or the initial boot-time connect attempt exhausting its own bounded retry count). connect() now optionally takes the secure store and device identity; when set, a link lost for longer than ~1 minute starts BLE provisioning (net::ble_provisioning::start(), same GATT flow as first- time setup) alongside the still-ongoing STA reconnect attempts -- it doesn't stop trying Wi-Fi on its own, it just also gives the app a way in over Bluetooth if Wi-Fi doesn't come back. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "net/StaClient.hpp"
|
||||
|
||||
#include "net/BleProvisioning.hpp"
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
@@ -39,10 +41,20 @@ constexpr int kFailedBit = BIT1;
|
||||
constexpr int kMaxConnectRetries = 10;
|
||||
constexpr TickType_t kConnectTimeout = pdMS_TO_TICKS(45000);
|
||||
constexpr TickType_t kRetryDelay = pdMS_TO_TICKS(800);
|
||||
/** How long a post-boot link loss must persist before BLE fallback starts. */
|
||||
constexpr TickType_t kBleFallbackThreshold = pdMS_TO_TICKS(60000);
|
||||
|
||||
EventGroupHandle_t s_wifiEventGroup = nullptr;
|
||||
int s_connectRetries = 0;
|
||||
|
||||
// Set once by connect() on success when the caller opted in; used only by
|
||||
// the post-boot branch of wifiEventHandler() below (s_wifiEventGroup is
|
||||
// null there, since the bounded connect() call has already returned).
|
||||
core::ISecureStore* s_bleFallbackStore = nullptr;
|
||||
const core::DeviceIdentity* s_bleFallbackIdentity = nullptr;
|
||||
TickType_t s_disconnectedSinceTick = 0;
|
||||
bool s_bleFallbackActive = false;
|
||||
|
||||
/**
|
||||
* @brief disconnectReasonString — map ESP-IDF Wi-Fi disconnect reason codes.
|
||||
*
|
||||
@@ -136,6 +148,32 @@ void wifiEventHandler(void* arg,
|
||||
return;
|
||||
}
|
||||
|
||||
// Post-boot link loss (the bounded connect() call above already
|
||||
// succeeded once): esp_wifi_connect() below retries forever on its
|
||||
// own, which used to be the whole story -- if the AP never comes
|
||||
// back (moved, replaced, password changed), the device retried
|
||||
// silently forever with no way for the app to reach it and no way
|
||||
// for the user to reconfigure Wi-Fi short of a power cycle. After
|
||||
// a sustained ~1 minute outage, start BLE provisioning alongside
|
||||
// the ongoing reconnect attempts (does not stop them) so the app
|
||||
// can push new credentials over Bluetooth.
|
||||
if (s_disconnectedSinceTick == 0) {
|
||||
s_disconnectedSinceTick = xTaskGetTickCount();
|
||||
} else if (!s_bleFallbackActive && s_bleFallbackStore != nullptr
|
||||
&& s_bleFallbackIdentity != nullptr
|
||||
&& (xTaskGetTickCount() - s_disconnectedSinceTick)
|
||||
>= kBleFallbackThreshold) {
|
||||
ESP_LOGW(kTag, "STA link lost for over a minute — starting BLE "
|
||||
"provisioning fallback");
|
||||
if (auto bleResult = ble_provisioning::start(
|
||||
*s_bleFallbackStore, *s_bleFallbackIdentity);
|
||||
!bleResult) {
|
||||
ESP_LOGW(kTag, "BLE fallback provisioning failed to start");
|
||||
} else {
|
||||
s_bleFallbackActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGW(kTag, "STA link lost — reconnecting");
|
||||
esp_wifi_connect();
|
||||
} else if (eventBase == IP_EVENT && eventId == IP_EVENT_STA_GOT_IP) {
|
||||
@@ -145,6 +183,7 @@ void wifiEventHandler(void* arg,
|
||||
ESP_LOGI(kTag, "STA IP " IPSTR, IP2STR(&event->ip_info.ip));
|
||||
}
|
||||
applyStaLinkTuning();
|
||||
s_disconnectedSinceTick = 0;
|
||||
if (s_wifiEventGroup != nullptr) {
|
||||
xEventGroupSetBits(s_wifiEventGroup, kConnectedBit);
|
||||
}
|
||||
@@ -212,12 +251,20 @@ StaClient& StaClient::operator=(StaClient&& other) noexcept
|
||||
}
|
||||
|
||||
std::expected<void, NetError>
|
||||
StaClient::connect(const core::WifiCredentials& creds, std::string_view hostname)
|
||||
StaClient::connect(const core::WifiCredentials& creds,
|
||||
std::string_view hostname,
|
||||
core::ISecureStore* bleFallbackStore,
|
||||
const core::DeviceIdentity* bleFallbackIdentity)
|
||||
{
|
||||
if (connected_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
s_bleFallbackStore = bleFallbackStore;
|
||||
s_bleFallbackIdentity = bleFallbackIdentity;
|
||||
s_disconnectedSinceTick = 0;
|
||||
s_bleFallbackActive = false;
|
||||
|
||||
std::string hostLabel;
|
||||
if (!hostname.empty()) {
|
||||
hostLabel.assign(hostname.begin(), hostname.end());
|
||||
|
||||
Reference in New Issue
Block a user