feat: implement Wi-Fi provisioning and persistent configuration

This commit is contained in:
2026-09-03 22:58:57 +03:00
parent 8ffd6dabcf
commit b10c7f5972
29 changed files with 1713 additions and 16 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
idf_component_register(
SRCS "main.c"
REQUIRES esp_event esp_netif maze32_platform maze32_web
REQUIRES esp_event esp_netif maze32_config maze32_network maze32_platform maze32_web
)
+99 -2
View File
@@ -4,14 +4,70 @@
#include "esp_littlefs.h"
#include "esp_log.h"
#include "esp_netif.h"
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
#include "esp_system.h"
#include <string.h>
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "maze32_health.h"
#include "maze32_config_store.h"
#include "maze32_network.h"
#include "maze32_web.h"
static const char *TAG = "maze32";
static maze32_health_t health;
static httpd_handle_t web_server;
static maze32_network_t network;
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
static int device_test_has_persisted_credentials;
static esp_err_t run_device_test_before_network(void)
{
const maze32_wifi_credentials_t expected = {
.ssid = "maze32-unavailable-test",
.password = "test-only-password",
};
maze32_wifi_credentials_t loaded = {0};
esp_err_t result = maze32_config_store_load(&loaded);
if (result == ESP_ERR_NOT_FOUND) {
result = maze32_config_store_save(&expected);
if (result == ESP_OK) {
ESP_LOGI(TAG, "M003 device test: credentials saved; restarting");
esp_restart();
}
return result;
}
if (result != ESP_OK || strcmp(loaded.ssid, expected.ssid) != 0 ||
strcmp(loaded.password, expected.password) != 0) {
ESP_LOGE(TAG, "M003 device test refused to overwrite unexpected NVS credentials");
return ESP_ERR_INVALID_STATE;
}
device_test_has_persisted_credentials = 1;
ESP_LOGI(TAG, "M003 device test: credentials survived restart");
return ESP_OK;
}
static esp_err_t finish_device_test(void)
{
if (!device_test_has_persisted_credentials) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t result = maze32_config_store_clear();
if (result == ESP_OK) {
ESP_LOGI(TAG, "M003 device test: failed station returned to fallback; credentials cleared");
}
return result;
}
#endif
static int prepare_for_network_reconfiguration(void *context)
{
(void)context;
ESP_LOGW(TAG, "Runtime accepted network reconfiguration; no active match exists");
return 0;
}
static esp_err_t mount_littlefs(void)
{
@@ -57,6 +113,22 @@ void app_main(void)
maze32_health_set(&health, MAZE32_HEALTH_FILESYSTEM_READY, 0);
result = maze32_config_store_init();
if (result != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
ESP_LOGE(TAG, "Persistent configuration initialization failed: %s",
esp_err_to_name(result));
return;
}
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
result = run_device_test_before_network();
if (result != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
return;
}
#endif
result = esp_netif_init();
if (result != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
@@ -71,13 +143,38 @@ void app_main(void)
return;
}
maze32_health_set(&health, MAZE32_HEALTH_SERVING, 0);
result = maze32_web_start(&web_server, &health);
result = maze32_network_init(&network, prepare_for_network_reconfiguration, NULL);
if (result == ESP_OK) {
result = maze32_network_start(&network);
}
if (result != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
ESP_LOGE(TAG, "Network initialization failed: %s", esp_err_to_name(result));
return;
}
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
result = finish_device_test();
if (result != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
return;
}
#endif
result = maze32_web_start(&web_server, &health);
if (result == ESP_OK) {
result = maze32_provisioning_register(web_server, &network);
}
if (result != ESP_OK) {
if (web_server != NULL) {
httpd_stop(web_server);
web_server = NULL;
}
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)result);
ESP_LOGE(TAG, "HTTP server startup failed: %s", esp_err_to_name(result));
return;
}
maze32_health_set(&health, MAZE32_HEALTH_SERVING, 0);
ESP_LOGI(TAG, "Health state: %s", maze32_health_state_name(health.state));
}