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:
@@ -112,6 +112,11 @@ void test_fw03_304_no_redraw() {
|
||||
g_http_get_code = 304;
|
||||
// 30 s — at SLEEP_CLAMP_MIN_MS, well under MAX, so honored as-is
|
||||
g_http_response_headers["X-Interval-Ms"] = "30000";
|
||||
// 304 only ever happens when the device already holds the image, so
|
||||
// pre-set img_id to match what the server would have served. Without
|
||||
// this the FIRST_IMAGE_POLL bootstrap override would (correctly)
|
||||
// shorten sleep to 15 s — and that's not what this test exercises.
|
||||
prefs.ints[NVS_KEY_IMG_ID] = 1;
|
||||
|
||||
normal_operation_impl(String("mac"), http, String("url"), prefs);
|
||||
|
||||
@@ -347,6 +352,48 @@ void test_fw_X_Claimed_response_clears_flag() {
|
||||
TEST_ASSERT_EQUAL(0, prefs.getInt(NVS_KEY_JUST_PROVISIONED, -1));
|
||||
}
|
||||
|
||||
// FW-FIRST-IMG-A: device has never received an image (img_id = -1) AND the
|
||||
// poll didn't deliver one (e.g. 204 because no images approved yet). Sleep
|
||||
// must be the 15s bootstrap interval, NOT whatever the server's schedule
|
||||
// says. Without this, a fresh device on a noon-daily schedule sits dark
|
||||
// for up to 24 h before the first photo lands.
|
||||
void test_fw_first_image_bootstrap_polls_at_15s_when_no_image_yet() {
|
||||
g_http_get_code = 204;
|
||||
// Server tries to set a 6-hour interval for the user's noon-daily schedule.
|
||||
g_http_response_headers["X-Interval-Ms"] = String((unsigned long)(6ULL * 60 * 60 * 1000)).c_str();
|
||||
// No img_id in NVS → device has never seen an image.
|
||||
normal_operation_impl(String("mac"), http, String("url"), prefs);
|
||||
TEST_ASSERT_EQUAL_UINT64(FIRST_IMAGE_POLL_INTERVAL_MS * 1000ULL, g_sleep_us);
|
||||
}
|
||||
|
||||
// FW-FIRST-IMG-B: once we've persisted an image (200 path wrote img_id), the
|
||||
// server's schedule wins again. Without this assertion the override would
|
||||
// trap the device in 15s polling forever and burn the battery.
|
||||
void test_fw_first_image_bootstrap_clears_after_200() {
|
||||
// Pre-set NVS as if we'd received an image previously.
|
||||
prefs.ints[NVS_KEY_IMG_ID] = 42;
|
||||
g_http_get_code = 200;
|
||||
g_http_response_headers["X-Image-Id"] = "42";
|
||||
g_http_response_headers["X-Interval-Ms"] = "300000"; // 5 min (well above 15s)
|
||||
g_http_body = "BINDATA";
|
||||
normal_operation_impl(String("mac"), http, String("url"), prefs);
|
||||
TEST_ASSERT_EQUAL_UINT64(300000ULL * 1000ULL, g_sleep_us);
|
||||
}
|
||||
|
||||
// FW-FIRST-IMG-C: receiving the FIRST image (200 with previously -1 img_id)
|
||||
// must let the server's schedule take over starting from this very poll —
|
||||
// no extra "one more 15s sleep" cycle.
|
||||
void test_fw_first_image_just_arrived_uses_server_interval() {
|
||||
// img_id starts at -1 (default, no prior image).
|
||||
g_http_get_code = 200;
|
||||
g_http_response_headers["X-Image-Id"] = "1";
|
||||
g_http_response_headers["X-Interval-Ms"] = "300000";
|
||||
g_http_body = "BINDATA";
|
||||
normal_operation_impl(String("mac"), http, String("url"), prefs);
|
||||
// The 200 path persists img_id=1 BEFORE sleep is computed.
|
||||
TEST_ASSERT_EQUAL_UINT64(300000ULL * 1000ULL, g_sleep_us);
|
||||
}
|
||||
|
||||
// FW-PROV-D: server omits X-Claimed (e.g. stale-binding 204) → flag stays
|
||||
// set so the device keeps signaling "I'm freshly provisioned" until a
|
||||
// later poll lands on a fresh-binding response.
|
||||
@@ -476,6 +523,9 @@ int main(int argc, char** argv) {
|
||||
RUN_TEST(test_fw_no_flag_means_no_header);
|
||||
RUN_TEST(test_fw_X_Claimed_response_clears_flag);
|
||||
RUN_TEST(test_fw_no_X_Claimed_response_keeps_flag);
|
||||
RUN_TEST(test_fw_first_image_bootstrap_polls_at_15s_when_no_image_yet);
|
||||
RUN_TEST(test_fw_first_image_bootstrap_clears_after_200);
|
||||
RUN_TEST(test_fw_first_image_just_arrived_uses_server_interval);
|
||||
RUN_TEST(test_fw12_ap_ssid_from_mac_aabbcc);
|
||||
RUN_TEST(test_fw13_ap_ssid_from_real_mac);
|
||||
RUN_TEST(test_fw14_304_skips_epd_sleep);
|
||||
|
||||
Reference in New Issue
Block a user