Refactor, state manager
This commit is contained in:
@ -9,13 +9,13 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
// Project modules
|
||||
#include "config.h"
|
||||
#include "motor_control.h"
|
||||
#include "state_manager.h"
|
||||
|
||||
// WiFi event group
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
@ -84,11 +84,6 @@ static const char* html_page =
|
||||
"function startUpdates(){if(updateInterval)clearInterval(updateInterval);updateInterval=setInterval(getStatus,1000)}"
|
||||
"document.addEventListener('DOMContentLoaded',function(){getStatus();startUpdates()})</script></body></html>";
|
||||
|
||||
// Forward declarations
|
||||
static esp_err_t save_motor_state_to_nvs(void);
|
||||
static esp_err_t load_motor_state_from_nvs(void);
|
||||
static bool is_watchdog_reset(void);
|
||||
|
||||
// Initialize watchdog timer
|
||||
void init_watchdog(void) {
|
||||
ESP_LOGI(SYSTEM_TAG, "Setting up watchdog monitoring...");
|
||||
@ -117,165 +112,6 @@ void feed_watchdog(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this was a watchdog reset
|
||||
static bool is_watchdog_reset(void) {
|
||||
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||
|
||||
// Only consider TASK_WDT and INT_WDT as true watchdog resets
|
||||
// ESP_RST_WDT can be triggered by power disconnection, so we exclude it
|
||||
return (reset_reason == ESP_RST_TASK_WDT ||
|
||||
reset_reason == ESP_RST_INT_WDT);
|
||||
}
|
||||
|
||||
// Save motor state to NVS
|
||||
static esp_err_t save_motor_state_to_nvs(void) {
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err;
|
||||
|
||||
err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(SYSTEM_TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
// Get current motor state
|
||||
const motor_state_t* state = motor_get_state();
|
||||
motor_mode_t last_on_mode;
|
||||
int last_on_speed;
|
||||
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
||||
bool user_turned_off = motor_get_user_turned_off();
|
||||
|
||||
ESP_LOGI(SYSTEM_TAG, "=== SAVING STATE TO NVS ===");
|
||||
ESP_LOGI(SYSTEM_TAG, "Mode: %d, Speed: %d%%, Last ON: %d@%d%%, User OFF: %s",
|
||||
state->mode, state->target_speed,
|
||||
last_on_mode, last_on_speed,
|
||||
user_turned_off ? "YES" : "NO");
|
||||
|
||||
// Save current motor state
|
||||
err = nvs_set_u8(nvs_handle, NVS_KEY_MODE, (uint8_t)state->mode);
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_set_u8(nvs_handle, NVS_KEY_SPEED, (uint8_t)state->target_speed);
|
||||
}
|
||||
|
||||
// Save last ON state
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, (uint8_t)last_on_mode);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, (uint8_t)last_on_speed);
|
||||
}
|
||||
|
||||
// Save power state (whether user turned off manually)
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_set_u8(nvs_handle, NVS_KEY_POWER_STATE, user_turned_off ? 1 : 0);
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_commit(nvs_handle);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(SYSTEM_TAG, "✓ Motor state successfully saved to NVS");
|
||||
} else {
|
||||
ESP_LOGE(SYSTEM_TAG, "✗ NVS commit failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(SYSTEM_TAG, "✗ Error saving to NVS: %s", esp_err_to_name(err));
|
||||
}
|
||||
ESP_LOGI(SYSTEM_TAG, "===========================");
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Load motor state from NVS
|
||||
static esp_err_t load_motor_state_from_nvs(void) {
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err;
|
||||
|
||||
err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGI(SYSTEM_TAG, "NVS not found, using default state");
|
||||
return ESP_ERR_NVS_NOT_FOUND;
|
||||
}
|
||||
|
||||
uint8_t stored_mode = 0;
|
||||
uint8_t stored_speed = 0;
|
||||
uint8_t stored_last_mode = 1; // Default to MOTOR_EXHAUST
|
||||
uint8_t stored_last_speed = 50;
|
||||
uint8_t stored_power_state = 0;
|
||||
|
||||
// Load current motor state
|
||||
err = nvs_get_u8(nvs_handle, NVS_KEY_MODE, &stored_mode);
|
||||
if (err == ESP_OK) {
|
||||
nvs_get_u8(nvs_handle, NVS_KEY_SPEED, &stored_speed);
|
||||
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, &stored_last_mode);
|
||||
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, &stored_last_speed);
|
||||
nvs_get_u8(nvs_handle, NVS_KEY_POWER_STATE, &stored_power_state);
|
||||
|
||||
// Validate ranges using config macros
|
||||
if (stored_mode > MOTOR_INTAKE) stored_mode = MOTOR_OFF;
|
||||
if (!IS_VALID_SPEED(stored_speed)) stored_speed = 0;
|
||||
if (stored_last_mode < MOTOR_EXHAUST || stored_last_mode > MOTOR_INTAKE) stored_last_mode = MOTOR_EXHAUST;
|
||||
if (!IS_VALID_SPEED(stored_last_speed)) stored_last_speed = 50;
|
||||
|
||||
// Set the last ON state in motor control module
|
||||
motor_set_last_on_state((motor_mode_t)stored_last_mode, stored_last_speed);
|
||||
motor_set_user_turned_off(stored_power_state == 1);
|
||||
|
||||
ESP_LOGI(SYSTEM_TAG, "Loaded state from NVS - Mode: %d, Speed: %d%%, Last ON: %d@%d%%, User OFF: %s",
|
||||
stored_mode, stored_speed, stored_last_mode, stored_last_speed,
|
||||
stored_power_state ? "YES" : "NO");
|
||||
|
||||
// Check reset reason to decide whether to restore state
|
||||
bool was_watchdog_reset = is_watchdog_reset();
|
||||
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||
|
||||
ESP_LOGI(SYSTEM_TAG, "=== RESET ANALYSIS ===");
|
||||
ESP_LOGI(SYSTEM_TAG, "Reset reason: %d", reset_reason);
|
||||
ESP_LOGI(SYSTEM_TAG, "Reset reason name: %s",
|
||||
reset_reason == ESP_RST_POWERON ? "POWERON" :
|
||||
reset_reason == ESP_RST_EXT ? "EXTERNAL" :
|
||||
reset_reason == ESP_RST_SW ? "SOFTWARE" :
|
||||
reset_reason == ESP_RST_PANIC ? "PANIC" :
|
||||
reset_reason == ESP_RST_INT_WDT ? "INT_WDT" :
|
||||
reset_reason == ESP_RST_TASK_WDT ? "TASK_WDT" :
|
||||
reset_reason == ESP_RST_WDT ? "WDT" :
|
||||
reset_reason == ESP_RST_DEEPSLEEP ? "DEEPSLEEP" :
|
||||
reset_reason == ESP_RST_BROWNOUT ? "BROWNOUT" :
|
||||
reset_reason == ESP_RST_SDIO ? "SDIO" : "UNKNOWN");
|
||||
ESP_LOGI(SYSTEM_TAG, "Watchdog reset: %s", was_watchdog_reset ? "YES" : "NO");
|
||||
ESP_LOGI(SYSTEM_TAG, "Stored mode: %d, speed: %d", stored_mode, stored_speed);
|
||||
ESP_LOGI(SYSTEM_TAG, "User turned off: %s", stored_power_state ? "YES" : "NO");
|
||||
ESP_LOGI(SYSTEM_TAG, "====================");
|
||||
|
||||
// Store the restored state for potential motor restoration
|
||||
if (was_watchdog_reset) {
|
||||
// True watchdog reset (TASK_WDT or INT_WDT) - don't restore state, start fresh
|
||||
ESP_LOGI(SYSTEM_TAG, "⚠️ TRUE watchdog reset detected - starting in OFF state for safety");
|
||||
// Motor module is already initialized in OFF state, no action needed
|
||||
} else if (stored_power_state) {
|
||||
// User manually turned off - stay off
|
||||
ESP_LOGI(SYSTEM_TAG, "🔒 User had turned off manually - staying OFF");
|
||||
// Motor module is already initialized in OFF state, no action needed
|
||||
} else if (stored_mode != MOTOR_OFF && stored_speed > 0) {
|
||||
// Normal power loss or general WDT (which can be power-related) - restore previous state
|
||||
ESP_LOGI(SYSTEM_TAG, "🔋 Power restored - will resume previous state: %s @ %d%%",
|
||||
stored_mode == MOTOR_EXHAUST ? "EXHAUST" : "INTAKE", stored_speed);
|
||||
|
||||
// Set the motor to the restored state (will be applied after initialization)
|
||||
motor_set_speed((motor_mode_t)stored_mode, stored_speed);
|
||||
} else {
|
||||
ESP_LOGI(SYSTEM_TAG, "❌ No valid state to restore (mode=%d, speed=%d)", stored_mode, stored_speed);
|
||||
// Motor module is already initialized in OFF state, no action needed
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(SYSTEM_TAG, "No saved state found, using defaults");
|
||||
err = ESP_ERR_NVS_NOT_FOUND;
|
||||
}
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
// WiFi event handler
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
@ -444,8 +280,11 @@ static esp_err_t fan_post_handler(httpd_req_t *req)
|
||||
ESP_LOGI(SYSTEM_TAG, "ON button pressed - resuming last state");
|
||||
motor_resume_last_state();
|
||||
|
||||
// Save state after ON button
|
||||
save_motor_state_to_nvs();
|
||||
// Save state after ON button using state manager
|
||||
esp_err_t save_result = state_manager_save();
|
||||
if (save_result != ESP_OK) {
|
||||
ESP_LOGW(SYSTEM_TAG, "Failed to save state after ON button: %s", esp_err_to_name(save_result));
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
return status_get_handler(req);
|
||||
@ -458,8 +297,11 @@ static esp_err_t fan_post_handler(httpd_req_t *req)
|
||||
ESP_LOGI(SYSTEM_TAG, "HTTP Request: mode=%s, speed=%d", mode_str, speed);
|
||||
motor_set_speed(mode, speed);
|
||||
|
||||
// Save state after any motor command
|
||||
save_motor_state_to_nvs();
|
||||
// Save state after any motor command using state manager
|
||||
esp_err_t save_result = state_manager_save();
|
||||
if (save_result != ESP_OK) {
|
||||
ESP_LOGW(SYSTEM_TAG, "Failed to save state after motor command: %s", esp_err_to_name(save_result));
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
|
||||
@ -600,13 +442,13 @@ void app_main(void)
|
||||
{
|
||||
ESP_LOGI(SYSTEM_TAG, "Starting Maxxfan HTTP Controller with State Preservation!");
|
||||
|
||||
// Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
// Initialize state manager (includes NVS initialization)
|
||||
ESP_LOGI(SYSTEM_TAG, "Initializing state manager...");
|
||||
esp_err_t ret = state_manager_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(SYSTEM_TAG, "Failed to initialize state manager: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
// Initialize watchdog timer
|
||||
init_watchdog();
|
||||
@ -619,9 +461,16 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// Load saved state from NVS and potentially restore motor state
|
||||
ESP_LOGI(SYSTEM_TAG, "Loading saved state...");
|
||||
load_motor_state_from_nvs();
|
||||
// Load saved state and restore motor if appropriate
|
||||
ESP_LOGI(SYSTEM_TAG, "Loading saved state and applying restoration logic...");
|
||||
esp_err_t load_result = state_manager_load_and_restore();
|
||||
if (load_result == ESP_OK) {
|
||||
ESP_LOGI(SYSTEM_TAG, "✓ State loaded and restoration logic applied");
|
||||
} else if (load_result == ESP_ERR_NVS_NOT_FOUND) {
|
||||
ESP_LOGI(SYSTEM_TAG, "ℹ️ No saved state found, using defaults");
|
||||
} else {
|
||||
ESP_LOGW(SYSTEM_TAG, "⚠️ Failed to load state: %s", esp_err_to_name(load_result));
|
||||
}
|
||||
|
||||
ESP_LOGI(SYSTEM_TAG, "Connecting to WiFi network: %s", WIFI_SSID);
|
||||
wifi_init_sta();
|
||||
@ -629,25 +478,36 @@ void app_main(void)
|
||||
// Start HTTP server
|
||||
start_webserver();
|
||||
|
||||
// Report final motor state after initialization
|
||||
// Report final system state after initialization
|
||||
const motor_state_t* final_state = motor_get_state();
|
||||
ESP_LOGI(SYSTEM_TAG, "=== MOTOR STATE AFTER INITIALIZATION ===");
|
||||
ESP_LOGI(SYSTEM_TAG, "=== SYSTEM INITIALIZATION COMPLETE ===");
|
||||
ESP_LOGI(SYSTEM_TAG, "Reset Reason: %s", state_manager_get_reset_reason_string());
|
||||
ESP_LOGI(SYSTEM_TAG, "Watchdog Reset: %s", state_manager_was_watchdog_reset() ? "YES" : "NO");
|
||||
ESP_LOGI(SYSTEM_TAG, "Final motor state: mode=%s, target=%d%%, current=%d%%, state=%s",
|
||||
motor_mode_to_string(final_state->mode), final_state->target_speed,
|
||||
final_state->current_speed, motor_state_to_string(final_state->state));
|
||||
|
||||
if (final_state->mode != MOTOR_OFF && final_state->target_speed > 0) {
|
||||
ESP_LOGI(SYSTEM_TAG, "Motor restored to: %s @ %d%%",
|
||||
ESP_LOGI(SYSTEM_TAG, "🔄 Motor restored to: %s @ %d%%",
|
||||
motor_mode_to_string(final_state->mode), final_state->target_speed);
|
||||
} else {
|
||||
ESP_LOGI(SYSTEM_TAG, "Motor remains OFF");
|
||||
ESP_LOGI(SYSTEM_TAG, "⏸️ Motor remains OFF");
|
||||
}
|
||||
ESP_LOGI(SYSTEM_TAG, "=======================================");
|
||||
|
||||
motor_mode_t last_on_mode;
|
||||
int last_on_speed;
|
||||
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
||||
ESP_LOGI(SYSTEM_TAG, "Last ON state: %s @ %d%%",
|
||||
motor_mode_to_string(last_on_mode), last_on_speed);
|
||||
ESP_LOGI(SYSTEM_TAG, "User turned off: %s", motor_get_user_turned_off() ? "YES" : "NO");
|
||||
ESP_LOGI(SYSTEM_TAG, "Saved state exists: %s", state_manager_has_saved_state() ? "YES" : "NO");
|
||||
ESP_LOGI(SYSTEM_TAG, "=====================================");
|
||||
|
||||
ESP_LOGI(SYSTEM_TAG, "=== Enhanced Maxxfan Controller Ready! ===");
|
||||
ESP_LOGI(SYSTEM_TAG, "Features: State Preservation, Direction Safety, Motor Ramping, ON Button");
|
||||
ESP_LOGI(SYSTEM_TAG, "Safety: %d-second cooldown for direction changes", DIRECTION_CHANGE_COOLDOWN_MS / 1000);
|
||||
ESP_LOGI(SYSTEM_TAG, "Memory: Remembers settings after power loss (except watchdog resets)");
|
||||
ESP_LOGI(SYSTEM_TAG, "State Manager: Enhanced NVS operations with validation and recovery");
|
||||
ESP_LOGI(SYSTEM_TAG, "Open your browser and go to: http://[ESP32_IP_ADDRESS]");
|
||||
ESP_LOGI(SYSTEM_TAG, "Check the monitor output above for your IP address");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user