feat(operation): poll every 15s until first image lands

A freshly-claimed device on a noon-daily schedule would otherwise sit
dark for up to 24 h after WiFi setup waiting for its first image. The
schedule kicks in only AFTER an image has actually been displayed.

Mechanism: at the bottom of normal_operation_impl, re-read NVS_KEY_IMG_ID
to see whether any successful 200-with-integrity-OK persisted an image
id this cycle (or any prior). If still -1, override sleepMs to
FIRST_IMAGE_POLL_INTERVAL_MS (15 s) — bypassing the schedule and the
clamp range, since SLEEP_CLAMP_MIN_MS is about runaway protection in
steady state and the bootstrap window is naturally bounded by "first
image arrives."

Tests:
  - FW-FIRST-IMG-A: 204 with no img_id in NVS → 15s override fires
    even when server says 6 hours.
  - FW-FIRST-IMG-B: img_id pre-set, 200 cycle → server interval honored
    (override doesn't trap the device in 15s forever).
  - FW-FIRST-IMG-C: first 200 ever (img_id was -1, now persisted) →
    server interval applies starting THIS cycle, no extra 15s nap.

Also patched FW-03 (304 sleep timing) to pre-set img_id so the test
exercises what it claims; 304 in production only happens when the
device already holds the image, so the override would never fire there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 16:13:53 -04:00
parent a0dc4e0115
commit 2df2a14df6
4 changed files with 71 additions and 0 deletions
+12
View File
@@ -303,6 +303,18 @@ void normal_operation_impl(const String& mac, HTTP& http, const String& url, Pre
// entire poll interval on every 304 response.
if (displayInitialized) epd_sleep();
// Bootstrap-fast polling: until we've ever displayed an image, ignore
// the schedule and poll every 15 s. Without this, a freshly-claimed
// device whose owner has wakeTimes set to e.g. noon would sit dark for
// up to 24 h before the first photo lands. We re-read img_id from NVS
// because the 200 path persists it AFTER the local var was captured.
prefs.begin(NVS_NAMESPACE, true);
int32_t imgIdAfter = prefs.getInt(NVS_KEY_IMG_ID, -1);
prefs.end();
if (imgIdAfter < 0) {
sleepMs = FIRST_IMAGE_POLL_INTERVAL_MS;
}
esp_sleep_enable_timer_wakeup(sleepMs * 1000ULL);
esp_deep_sleep_start();
}