Wire the real fetch -> display -> deep-sleep cycle
frame_client_run() now does what it was always meant to: probe the tools server, GET /frame/image and stream the response straight into the panel via epd_display_stream() (esp_http_client's manual open/fetch_headers/read API pulls in exactly the shape epd_display_stream()'s read_fn expects, so the ~192KB frame never sits in RAM at once), then epd_sleep() and esp_deep_sleep_start() for an hour. Skips the WiFi/server status checklist screen on the happy path now that there's a real photo to show instead -- three full refreshes every single hour (status-pending, status-final, photo) wasn't worth it once bring-up was actually working. Still shows it (status FAILED) when the server isn't reachable, since nothing's been drawn yet that cycle and it's the cheapest useful diagnostic. A mid-fetch failure after the panel's already started refreshing just logs and retries sooner, rather than compounding with a second refresh. New Kconfig knobs: FRAME_FETCH_TIMEOUT_MS, FRAME_SLEEP_INTERVAL_S (default 3600s), FRAME_RETRY_INTERVAL_S (default 300s on failure).
This commit is contained in:
@@ -51,4 +51,29 @@ menu "ESPresso Frame Configuration"
|
||||
How long to wait for an HTTP response from the tools server
|
||||
when checking reachability on the post-connect status screen.
|
||||
|
||||
config FRAME_FETCH_TIMEOUT_MS
|
||||
int "Image fetch HTTP timeout (ms)"
|
||||
default 15000
|
||||
help
|
||||
How long to wait on the GET /frame/image request before giving
|
||||
up. The server does real work per request (Immich download +
|
||||
resize + dither), so this is longer than the reachability
|
||||
check's timeout.
|
||||
|
||||
config FRAME_SLEEP_INTERVAL_S
|
||||
int "Deep sleep interval between refreshes (seconds)"
|
||||
default 3600
|
||||
help
|
||||
How long the device deep-sleeps between successful
|
||||
fetch-and-display cycles. Lower this for bench testing so you
|
||||
don't have to wait an hour per iteration.
|
||||
|
||||
config FRAME_RETRY_INTERVAL_S
|
||||
int "Deep sleep interval after a failed cycle (seconds)"
|
||||
default 300
|
||||
help
|
||||
How long the device deep-sleeps before retrying after the
|
||||
server was unreachable or the fetch/display failed, instead of
|
||||
waiting the full FRAME_SLEEP_INTERVAL_S.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "esp_wifi_default.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "epd7in3e.h"
|
||||
@@ -134,27 +134,94 @@ static bool check_server_reachable(const char *toolsserver)
|
||||
return err == ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
esp_http_client_handle_t client;
|
||||
} http_read_ctx_t;
|
||||
|
||||
/* Pulls the next chunk straight out of the in-progress HTTP response --
|
||||
* epd_display_stream() calls this to feed the panel without ever holding
|
||||
* the full ~192KB frame in RAM. */
|
||||
static size_t http_read_fn(uint8_t *chunk, size_t chunk_size, void *ctx_)
|
||||
{
|
||||
http_read_ctx_t *ctx = (http_read_ctx_t *)ctx_;
|
||||
int n = esp_http_client_read(ctx->client, (char *)chunk, (int)chunk_size);
|
||||
return n > 0 ? (size_t)n : 0;
|
||||
}
|
||||
|
||||
/* GETs /frame/image and streams the response directly into the panel. */
|
||||
static esp_err_t fetch_and_display(const frame_config_t *cfg)
|
||||
{
|
||||
char url[160];
|
||||
snprintf(url, sizeof(url), "http://%s/frame/image", cfg->toolsserver);
|
||||
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_GET,
|
||||
.timeout_ms = CONFIG_FRAME_FETCH_TIMEOUT_MS,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
esp_err_t err = esp_http_client_open(client, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open '%s': %s", url, esp_err_to_name(err));
|
||||
esp_http_client_cleanup(client);
|
||||
return err;
|
||||
}
|
||||
|
||||
int content_length = esp_http_client_fetch_headers(client);
|
||||
int status = esp_http_client_get_status_code(client);
|
||||
if (status != 200) {
|
||||
ESP_LOGE(TAG, "'%s' returned HTTP %d", url, status);
|
||||
esp_http_client_close(client);
|
||||
esp_http_client_cleanup(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Fetching frame (%d bytes) from '%s'", content_length, url);
|
||||
|
||||
http_read_ctx_t ctx = { .client = client };
|
||||
err = epd_display_stream(http_read_fn, &ctx);
|
||||
|
||||
esp_http_client_close(client);
|
||||
esp_http_client_cleanup(client);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void frame_client_run(const frame_config_t *cfg)
|
||||
{
|
||||
esp_err_t epd_err = epd_init();
|
||||
if (epd_err != ESP_OK) {
|
||||
bool have_display = (epd_err == ESP_OK);
|
||||
if (!have_display) {
|
||||
ESP_LOGW(TAG, "EPD init failed (%s), continuing without display", esp_err_to_name(epd_err));
|
||||
} else {
|
||||
status_screen_show(cfg->sta_ssid, STATUS_OK, cfg->toolsserver, STATUS_PENDING);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
bool reachable = check_server_reachable(cfg->toolsserver);
|
||||
status_screen_show(cfg->sta_ssid, STATUS_OK, cfg->toolsserver, reachable ? STATUS_OK : STATUS_FAILED);
|
||||
}
|
||||
|
||||
/* TODO(step 6): HTTP fetch from cfg->toolsserver -> epd_write_stream ->
|
||||
* epd_refresh -> esp_deep_sleep. Idling here for now so the device
|
||||
* stays observable over serial while STA connectivity is verified. */
|
||||
ESP_LOGI(TAG, "Connected to home WiFi. toolsserver='%s' (fetch/display cycle not yet implemented)",
|
||||
cfg->toolsserver);
|
||||
uint32_t sleep_seconds = CONFIG_FRAME_SLEEP_INTERVAL_S;
|
||||
bool server_reachable = check_server_reachable(cfg->toolsserver);
|
||||
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "heartbeat: still connected");
|
||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||
if (!server_reachable) {
|
||||
/* Nothing's been drawn yet this cycle, so this is the only
|
||||
* refresh -- cheap diagnostics without compounding flashing. */
|
||||
ESP_LOGW(TAG, "Tools server not reachable, retrying sooner");
|
||||
sleep_seconds = CONFIG_FRAME_RETRY_INTERVAL_S;
|
||||
if (have_display) {
|
||||
status_screen_show(cfg->sta_ssid, STATUS_OK, cfg->toolsserver, STATUS_FAILED);
|
||||
}
|
||||
} else if (have_display) {
|
||||
esp_err_t fetch_err = fetch_and_display(cfg);
|
||||
if (fetch_err != ESP_OK) {
|
||||
/* The panel may have already partially refreshed with a
|
||||
* truncated frame by this point -- log and retry sooner
|
||||
* rather than drawing a second status screen on top of it. */
|
||||
ESP_LOGW(TAG, "Fetch/display failed (%s), retrying sooner", esp_err_to_name(fetch_err));
|
||||
sleep_seconds = CONFIG_FRAME_RETRY_INTERVAL_S;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_display) {
|
||||
epd_sleep();
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Deep sleeping for %u seconds", (unsigned)sleep_seconds);
|
||||
esp_sleep_enable_timer_wakeup((uint64_t)sleep_seconds * 1000000ULL);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user