Compare commits

..

3 Commits

Author SHA1 Message Date
1b5b3cd8ca feat(check-wifi): check wifi in setup mode before reboot 2026-06-09 16:25:18 +03:00
802035d38b fix 2026-06-08 14:23:22 +03:00
8b679be22a test 2026-06-08 14:01:41 +03:00
3 changed files with 138 additions and 17 deletions

View File

@ -50,11 +50,6 @@ On **first boot**, the device creates a captive Wi-Fi access point:
That IP becomes your **pump control dashboard** That IP becomes your **pump control dashboard**
> [!WARNING]
>
> If you enter wrong credentials, the device will **not** connect.
> Youll need to [**factory reset**](#factory_reset) and try again.
--- ---

View File

@ -652,7 +652,7 @@
const payload = { ssid: ssid, password: password }; const payload = { ssid: ssid, password: password };
try { try {
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); const timeoutId = setTimeout(() => controller.abort(), 15000);
const response = await fetch('/settings', { const response = await fetch('/settings', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@ -660,6 +660,8 @@
signal: controller.signal signal: controller.signal
}); });
clearTimeout(timeoutId); clearTimeout(timeoutId);
showToast(`Wi-Fi credentials sent to device`, false);
if (!response.ok) { if (!response.ok) {
let errorText = `Error ${response.status}`; let errorText = `Error ${response.status}`;
try { try {
@ -669,12 +671,16 @@
throw new Error(errorText); throw new Error(errorText);
} }
const result = await response.json(); const result = await response.json();
console.log('Wi-Fi settings saved:', result);
showToast(`✓ Wi-Fi credentials sent to device`, false); if (!result.success) {
throw new Error(result.message);
}
showToast(result.message, false);
passwordInput.value = ""; passwordInput.value = "";
} catch (error) { } catch (error) {
let errMsg = "✗ Connection failed"; let errMsg = "✗ Connection failed";
if (error.name === 'AbortError') errMsg = "✗ Request timeout (5s)"; if (error.name === 'AbortError') errMsg = "✗ Request timeout (15s)";
else if (error.message) errMsg = `✗ ${error.message}`; else if (error.message) errMsg = `✗ ${error.message}`;
showToast(errMsg, true); showToast(errMsg, true);
} }

View File

@ -137,7 +137,7 @@ static const error_info_t error_table[] = {
{APP_ERR_ADC_CALIB_FAIL, "ADC calibration failed", false}, {APP_ERR_ADC_CALIB_FAIL, "ADC calibration failed", false},
{APP_ERR_PUMP_INIT_FAIL, "Pump GPIO initialization failed", true}, {APP_ERR_PUMP_INIT_FAIL, "Pump GPIO initialization failed", true},
{APP_ERR_WIFI_INIT_FAIL, "WiFi initialization failed", true}, {APP_ERR_WIFI_INIT_FAIL, "WiFi initialization failed", true},
{APP_ERR_WIFI_CONNECT_FAIL, "WiFi connection failed", false}, {APP_ERR_WIFI_CONNECT_FAIL, "WiFi connection failed", true},
{APP_ERR_MDNS_INIT_FAIL, "mDNS service initialization failed", false}, {APP_ERR_MDNS_INIT_FAIL, "mDNS service initialization failed", false},
{APP_ERR_HTTP_SERVER_START_FAIL, "HTTP server start failed", false}, {APP_ERR_HTTP_SERVER_START_FAIL, "HTTP server start failed", false},
{APP_ERR_TASK_CREATE_FAIL, "Task creation failed", true}, {APP_ERR_TASK_CREATE_FAIL, "Task creation failed", true},
@ -479,6 +479,10 @@ static app_error_t pump_init(void) {
// WiFi functions // WiFi functions
// ============================================================================ // ============================================================================
// Добавьте в глобальные переменные:
static bool g_wifi_test_in_progress = false;
// Дополните существующий wifi_event_handler:
static void wifi_event_handler(void* arg, esp_event_base_t event_base, static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) { int32_t event_id, void* event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
@ -486,14 +490,16 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "Attempting to connect to WiFi..."); ESP_LOGI(TAG, "Attempting to connect to WiFi...");
} }
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (retry_count < MAX_RETRY_COUNT) { if (g_wifi_test_in_progress) {
// Если идет тестирование, сразу сигнализируем об ошибке
xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
} else if (retry_count < MAX_RETRY_COUNT) {
esp_wifi_connect(); esp_wifi_connect();
retry_count++; retry_count++;
ESP_LOGI(TAG, "Retry connecting (%d/%d)...", retry_count, MAX_RETRY_COUNT); ESP_LOGI(TAG, "Retry connecting (%d/%d)...", retry_count, MAX_RETRY_COUNT);
} else { } else {
xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT); xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
ESP_LOGE(TAG, "Failed to connect after %d retries", MAX_RETRY_COUNT); ESP_LOGE(TAG, "Failed to connect after %d retries", MAX_RETRY_COUNT);
handle_error(APP_ERR_WIFI_CONNECT_FAIL);
} }
} }
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
@ -504,6 +510,75 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base,
} }
} }
bool test_wifi_credentials(const char* ssid, const char* password, int timeout_ms) {
wifi_config_t old_config;
esp_wifi_get_config(WIFI_IF_STA, &old_config);
if (wifi_event_group == NULL) {
wifi_event_group = xEventGroupCreate();
if (wifi_event_group == NULL) {
ESP_LOGE(TAG, "Failed to create event group");
return false;
}
}
// Очищаем предыдущие биты
xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT);
// Устанавливаем флаг тестирования
g_wifi_test_in_progress = true;
// Останавливаем текущее подключение если есть
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(500));
// Настраиваем STA интерфейс с новыми credentials
wifi_config_t wifi_config = {0};
strncpy((char*)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1);
strncpy((char*)wifi_config.sta.password, password, sizeof(wifi_config.sta.password) - 1);
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
esp_err_t ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set WiFi config: %s", esp_err_to_name(ret));
g_wifi_test_in_progress = false;
return false;
}
// Запускаем подключение
ret = esp_wifi_connect();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to start WiFi connection: %s", esp_err_to_name(ret));
g_wifi_test_in_progress = false;
return false;
}
ESP_LOGI(TAG, "Testing WiFi connection to SSID: %s", ssid);
// Ожидаем результат
EventBits_t bits = xEventGroupWaitBits(wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
timeout_ms / portTICK_PERIOD_MS);
bool success = (bits & WIFI_CONNECTED_BIT) != 0;
if (success) {
ESP_LOGI(TAG, "✓ Successfully connected to %s", ssid);
esp_wifi_disconnect();
esp_wifi_set_config(WIFI_IF_STA, &old_config);
vTaskDelay(pdMS_TO_TICKS(500));
} else {
ESP_LOGW(TAG, "✗ Failed to connect to %s", ssid);
}
g_wifi_test_in_progress = false;
return success;
}
static app_error_t wifi_softap_init(void) { static app_error_t wifi_softap_init(void) {
CHECK_ERROR(esp_netif_init(), APP_ERR_WIFI_INIT_FAIL); CHECK_ERROR(esp_netif_init(), APP_ERR_WIFI_INIT_FAIL);
CHECK_ERROR(esp_event_loop_create_default(), APP_ERR_WIFI_INIT_FAIL); CHECK_ERROR(esp_event_loop_create_default(), APP_ERR_WIFI_INIT_FAIL);
@ -517,6 +592,9 @@ static app_error_t wifi_softap_init(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
CHECK_ERROR(esp_wifi_init(&cfg), APP_ERR_WIFI_INIT_FAIL); CHECK_ERROR(esp_wifi_init(&cfg), APP_ERR_WIFI_INIT_FAIL);
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL);
wifi_config_t wifi_config = { wifi_config_t wifi_config = {
.ap = { .ap = {
.ssid = CONFIG_AP_WIFI_SSID, .ssid = CONFIG_AP_WIFI_SSID,
@ -826,27 +904,69 @@ static esp_err_t parse_wifi_settings_json(const char *content, char *ssid, char
static esp_err_t setup_set_settings_handler(httpd_req_t *req) { static esp_err_t setup_set_settings_handler(httpd_req_t *req) {
char *content = NULL; char *content = NULL;
if (receive_http_content(req, &content) != ESP_OK) { if (receive_http_content(req, &content) != ESP_OK) {
httpd_resp_set_type(req, "application/json");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "{\"success\":false,\"message\":\"Failed to receive content\"}");
return ESP_FAIL; return ESP_FAIL;
} }
char ssid[WIFI_SSID_MAX_LEN]; char ssid[WIFI_SSID_MAX_LEN];
char password[WIFI_PASS_MAX_LEN]; char password[WIFI_PASS_MAX_LEN];
if (parse_wifi_settings_json(content, ssid, password) != ESP_OK) { if (parse_wifi_settings_json(content, ssid, password) != ESP_OK) {
free(content); free(content);
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Missing or invalid 'ssid' or 'password' parameters"); httpd_resp_set_type(req, "application/json");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "{\"success\":false,\"message\":\"Missing or invalid 'ssid' or 'password' parameters\"}");
return ESP_FAIL; return ESP_FAIL;
} }
free(content); free(content);
send_json_response(req, "{\"success\":true}"); // Проверяем, что пароль не пустой для защищенных сетей
if (strlen(ssid) == 0) {
httpd_resp_set_type(req, "application/json");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "{\"success\":false,\"message\":\"SSID cannot be empty\"}");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Testing WiFi connection to SSID: %s", ssid);
// Сохраняем текущий режим WiFi перед тестированием
wifi_mode_t current_mode;
esp_wifi_get_mode(&current_mode);
// Убеждаемся, что STA режим активен
if (!(current_mode & WIFI_MODE_STA)) {
esp_wifi_set_mode(WIFI_MODE_APSTA);
vTaskDelay(pdMS_TO_TICKS(100));
}
bool wifi_ok = test_wifi_credentials(ssid, password, 15000); // 15 секунд таймаут
if (wifi_ok) {
save_wifi_config(ssid, password); save_wifi_config(ssid, password);
vTaskDelay(pdMS_TO_TICKS(1000));
httpd_resp_set_type(req, "application/json");
httpd_resp_set_status(req, HTTPD_200);
const char *success_response = "{\"success\":true,\"message\":\"WiFi connected successfully! Rebooting in 2 seconds...\"}";
httpd_resp_send(req, success_response, strlen(success_response));
ESP_LOGI(TAG, "WiFi test SUCCESSFUL, rebooting...");
vTaskDelay(pdMS_TO_TICKS(2000));
esp_restart(); esp_restart();
} else {
httpd_resp_set_type(req, "application/json");
const char *error_response = "{\"success\":false,\"message\":\"Failed to connect to WiFi. Please check SSID and password.\"}";
httpd_resp_send(req, error_response, strlen(error_response));
ESP_LOGW(TAG, "WiFi test FAILED for SSID: %s", ssid);
}
return ESP_OK; return ESP_OK;
} }
static esp_err_t setup_get_wifi_list_handler(httpd_req_t *req) { static esp_err_t setup_get_wifi_list_handler(httpd_req_t *req) {
esp_err_t ret; esp_err_t ret;
uint16_t ap_count = 0; uint16_t ap_count = 0;