feat: enhance NVS and WiFi handlers for improved credential management and error handling
This commit is contained in:
@@ -20,6 +20,7 @@ NVSStorageHandler::~NVSStorageHandler() {
|
|||||||
void NVSStorageHandler::init(const EventGroupHandle_t& system_event_group) {
|
void NVSStorageHandler::init(const EventGroupHandle_t& system_event_group) {
|
||||||
esp_err_t err = nvs_flash_init();
|
esp_err_t err = nvs_flash_init();
|
||||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_LOGW(TAG, "NVS Flash init failed with %s, erasing and retrying...", esp_err_to_name(err));
|
||||||
nvs_flash_erase();
|
nvs_flash_erase();
|
||||||
err = nvs_flash_init();
|
err = nvs_flash_init();
|
||||||
}
|
}
|
||||||
@@ -43,11 +44,26 @@ void NVSStorageHandler::put(const std::string& key, const std::string& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = nvs_set_str(this->nvsHandle, key.c_str(), value.c_str());
|
esp_err_t err = nvs_set_str(this->nvsHandle, key.c_str(), value.c_str());
|
||||||
if (err != ESP_OK) {
|
if (err == ESP_ERR_NVS_NOT_ENOUGH_SPACE) {
|
||||||
ESP_LOGE(TAG, "Error (%s) setting key-value pair in NVS!", esp_err_to_name(err));
|
ESP_LOGE(TAG, "NVS storage full! Cannot store key '%s'. Consider clearing old data.", key.c_str());
|
||||||
} else {
|
ESP_LOGI(TAG, "Attempting to erase and retry...");
|
||||||
|
// Try to commit pending changes first
|
||||||
nvs_commit(this->nvsHandle);
|
nvs_commit(this->nvsHandle);
|
||||||
// ESP_LOGI(TAG, "Key-value pair (%s, %s) stored in NVS.", key.c_str(), value.c_str());
|
// Retry once
|
||||||
|
err = nvs_set_str(this->nvsHandle, key.c_str(), value.c_str());
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Retry failed: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Error (%s) setting key-value pair in NVS!", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit successful write
|
||||||
|
err = nvs_commit(this->nvsHandle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Error (%s) committing to NVS!", esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ esp_err_t WifiHandler::connect(const std::string& ssid, const std::string& passw
|
|||||||
this->current_ssid.clear();
|
this->current_ssid.clear();
|
||||||
}
|
}
|
||||||
this->current_ssid = ssid;
|
this->current_ssid = ssid;
|
||||||
|
this->current_password = password;
|
||||||
|
|
||||||
//
|
//
|
||||||
wifi_config_t wifi_config = {};
|
wifi_config_t wifi_config = {};
|
||||||
@@ -182,8 +183,8 @@ esp_err_t WifiHandler::connect(const std::string& ssid, const std::string& passw
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// store credentials after successful connection attempt
|
// Note: Credentials will be stored in the event handler after successful connection
|
||||||
this->store_wifi_credentials(this->current_ssid, password);
|
// to avoid storing credentials for failed connection attempts
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -305,6 +306,10 @@ void WifiHandler::wifi_event_handler(void* arg, esp_event_base_t event_base, int
|
|||||||
self->s_wifi_event_group,
|
self->s_wifi_event_group,
|
||||||
WIFI_CONNECTED_BIT
|
WIFI_CONNECTED_BIT
|
||||||
);
|
);
|
||||||
|
// Store credentials only after successful connection
|
||||||
|
if (!self->current_ssid.empty() && !self->current_password.empty()) {
|
||||||
|
self->store_wifi_credentials(self->current_ssid, self->current_password);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -328,7 +333,11 @@ void WifiHandler::store_wifi_credentials(const std::string& ssid, const std::str
|
|||||||
ESP_LOGE(TAG, "Failed to take credential mutex");
|
ESP_LOGE(TAG, "Failed to take credential mutex");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// store the password according to the JSON structure
|
|
||||||
|
// Store current SSID
|
||||||
|
kvs->put(WIFI_SSID_KEY, ssid);
|
||||||
|
|
||||||
|
// Store the password according to the JSON structure
|
||||||
std::string password_key_store = kvs->get(WIFI_PASSWORD_STORE_KEY);
|
std::string password_key_store = kvs->get(WIFI_PASSWORD_STORE_KEY);
|
||||||
cJSON* json = nullptr;
|
cJSON* json = nullptr;
|
||||||
if (password_key_store.empty()) {
|
if (password_key_store.empty()) {
|
||||||
@@ -348,17 +357,37 @@ void WifiHandler::store_wifi_credentials(const std::string& ssid, const std::str
|
|||||||
credentials = cJSON_CreateObject();
|
credentials = cJSON_CreateObject();
|
||||||
cJSON_AddItemToObject(json, "credentials", credentials);
|
cJSON_AddItemToObject(json, "credentials", credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Limit stored credentials to prevent NVS overflow (keep max 10 SSIDs)
|
||||||
|
int credential_count = cJSON_GetArraySize(credentials);
|
||||||
|
if (credential_count >= 10) {
|
||||||
|
ESP_LOGW(TAG, "Too many stored credentials (%d), clearing old ones", credential_count);
|
||||||
|
// Keep only the current SSID's credentials, clear others
|
||||||
|
cJSON_DeleteItemFromObject(credentials, ssid.c_str()); // Remove if exists
|
||||||
|
cJSON* new_credentials = cJSON_CreateObject();
|
||||||
|
cJSON_ReplaceItemInObject(json, "credentials", new_credentials);
|
||||||
|
credentials = new_credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove existing entry for this SSID to update it
|
||||||
|
cJSON_DeleteItemFromObject(credentials, ssid.c_str());
|
||||||
|
|
||||||
// create SSID object
|
// create SSID object
|
||||||
cJSON* ssid_item = cJSON_CreateObject();
|
cJSON* ssid_item = cJSON_CreateObject();
|
||||||
// add password field
|
// add password field
|
||||||
cJSON_AddStringToObject(ssid_item, "password", password.c_str());
|
cJSON_AddStringToObject(ssid_item, "password", password.c_str());
|
||||||
// add SSID object to credentials
|
// add SSID object to credentials
|
||||||
cJSON_AddItemToObject(credentials, ssid.c_str(), ssid_item);
|
cJSON_AddItemToObject(credentials, ssid.c_str(), ssid_item);
|
||||||
|
|
||||||
// store updated JSON string
|
// store updated JSON string
|
||||||
char* updated_json_str = cJSON_PrintUnformatted(json);
|
char* updated_json_str = cJSON_PrintUnformatted(json);
|
||||||
if (updated_json_str) {
|
if (updated_json_str) {
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
kvs->put(WIFI_PASSWORD_STORE_KEY, std::string(updated_json_str));
|
kvs->put(WIFI_PASSWORD_STORE_KEY, std::string(updated_json_str));
|
||||||
|
// Note: Error handling is done in nvs_handler.cpp put() method
|
||||||
cJSON_free(updated_json_str);
|
cJSON_free(updated_json_str);
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Failed to serialize WiFi credentials JSON");
|
||||||
}
|
}
|
||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ private:
|
|||||||
SemaphoreHandle_t credential_mutex = nullptr;
|
SemaphoreHandle_t credential_mutex = nullptr;
|
||||||
// current connected / preferred SSID
|
// current connected / preferred SSID
|
||||||
std::string current_ssid;
|
std::string current_ssid;
|
||||||
|
// current password (temporarily stored for successful connection event)
|
||||||
|
std::string current_password;
|
||||||
// prevent auto-reconnect on expected disconnection, e.g. when user calls disconnect()
|
// prevent auto-reconnect on expected disconnection, e.g. when user calls disconnect()
|
||||||
// should be reset to false after connect()
|
// should be reset to false after connect()
|
||||||
bool expect_disconnected = false;
|
bool expect_disconnected = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user