Files
espresso_frame/firmware/main/main.c
T
tfaour d32236d832 Add two ways back into provisioning: RST press and repeated server failure
RST/power-on trigger: checks esp_reset_reason() at the very top of boot.
ESP32-C6 can't electrically distinguish the RST/EN button from a genuine
power-on (both report ESP_RST_POWERON -- confirmed against ESP-IDF's own
docs, ESP_RST_EXT is explicitly "not applicable"), so POWERON is treated
as "user wants to reconfigure" and routes straight to provisioning. Safe
because the device's only normal restart path is ESP_RST_DEEPSLEEP (its
own scheduled wake), and crash-type resets (brownout/watchdog/panic)
report their own distinct reasons, not POWERON -- so a flaky power supply
or transient crash won't get bounced into provisioning, only an actual
power cycle or RST press will (which plausibly means the frame is being
moved/redeployed anyway).

Auto-fallback: a new NVS-persisted consecutive-failure counter
(frame_config_record_server_failure/reset_server_failures) tracks wakes
where the tools server was unreachable. After
CONFIG_FRAME_REPROVISION_AFTER_FAILURES in a row (default 12, ~1hr at the
retry interval), the device clears its stored WiFi config and
esp_restart()s rather than calling wifi_provisioning_start() directly --
doing that inline would mean initializing the display driver a second
time in the same session (frame_client_run already did once), the same
class of double-init bug hit earlier with WiFi. The next boot's
frame_config_load() naturally reports "not provisioned" and routes
through the existing, already-tested provisioning path with a single
fresh epd_init(). Solves the "I moved the server to a new address" case
without needing USB access.

Both frame_config_save() (fresh provisioning) and any successful server
contact reset the failure counter.
2026-07-18 16:10:03 -04:00

62 lines
2.4 KiB
C

#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "wifi_provisioning.h"
#include "frame_client.h"
static const char *TAG = "main";
void app_main(void)
{
/* Redirected/invalid captive-portal traffic generates a lot of noise
* at the default log level. */
esp_log_level_set("httpd_uri", ESP_LOG_ERROR);
esp_log_level_set("httpd_txrx", ESP_LOG_ERROR);
esp_log_level_set("httpd_parse", ESP_LOG_ERROR);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_err_t nvs_err = nvs_flash_init();
if (nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
nvs_err = nvs_flash_init();
}
ESP_ERROR_CHECK(nvs_err);
/* ESP32-C6 (like most ESP32 variants) can't electrically distinguish
* the RST/EN button from a genuine power-on -- both report as
* ESP_RST_POWERON, since there's no separate external-reset-pin signal
* (see ESP_RST_EXT's doc comment). The device's only *normal* restart
* path is ESP_RST_DEEPSLEEP (its own scheduled timer wake); crash-type
* resets (brownout/watchdog/panic) report their own distinct reasons,
* not POWERON. So treating POWERON as "user wants to reconfigure" is
* safe: it won't fire on a scheduled wake or a transient crash, only
* on an actual power cycle or RST press -- which for this device
* plausibly means it's being moved/redeployed anyway. */
if (esp_reset_reason() == ESP_RST_POWERON) {
ESP_LOGI(TAG, "Power-on/RST reset -- entering provisioning to allow reconfiguration");
wifi_provisioning_start();
return;
}
frame_config_t cfg;
esp_err_t cfg_err = frame_config_load(&cfg);
if (cfg_err == ESP_OK) {
ESP_LOGI(TAG, "Found stored config for '%s', connecting to home WiFi", cfg.sta_ssid);
if (frame_wifi_connect_sta(&cfg) == ESP_OK) {
frame_client_run(&cfg);
return; /* frame_client_run currently never returns */
}
ESP_LOGW(TAG, "Could not connect to stored WiFi after %d attempts, falling back to provisioning",
CONFIG_FRAME_STA_CONNECT_MAX_RETRIES);
} else {
ESP_LOGI(TAG, "No stored config found (%s), starting provisioning", esp_err_to_name(cfg_err));
}
wifi_provisioning_start();
}