fix(provisioning): stop redrawing the QR on every poll, add WiFi-fail retry screen
Two related fixes that together let the post-WiFi-setup window be quiet: 1. operation.h 204/404: skip the panel redraw entirely. The panel already holds the right thing — setup QR if no image has ever been painted (img_id == -1), or a real photo if img_id >= 0. Redrawing the QR every 15s during the bootstrap claim window put the e-ink into a perpetual ~20s mid-refresh loop and risked ghosting. Tests updated to assert no redraw on either sub-case. 2. main.cpp WiFi-fail path: drop the epd_fill(RED) + 3s delay + AP re-redraw sequence (~43s of e-ink work that destroyed the QR mid-flow) and replace with a single repaint of a new "Connection Failed — try again" Step 1/2 screen with red accents. gen_screens.py grows a gen_ap_retry() variant that recolors yellow → red and swaps the header/QR labels; the result is shipped as ap_bg_retry.bin alongside ap_bg.bin in LittleFS. epd.h exposes epd_draw_ap_screen_retry().
This commit is contained in:
@@ -20,4 +20,7 @@ void epd_draw_qr(QRCode* qr, uint8_t cellPx, uint8_t bg, uint8_t fg);
|
||||
|
||||
// Draw the setup screen: pre-rendered background from LittleFS with QR overlaid.
|
||||
void epd_draw_ap_screen(QRCode* qr);
|
||||
// Same layout as ap_screen but with red accents and a "Connection Failed —
|
||||
// try again" label, served after a failed WiFi join attempt.
|
||||
void epd_draw_ap_screen_retry(QRCode* qr);
|
||||
void epd_draw_setup_screen(QRCode* qr);
|
||||
|
||||
+18
-13
@@ -25,13 +25,17 @@ static String g_req_pass;
|
||||
|
||||
// ── QR helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
static void show_ap_qr(const String& apSsid) {
|
||||
static void show_ap_qr(const String& apSsid, bool retry = false) {
|
||||
String content = "WIFI:S:" + apSsid + ";T:nopass;;";
|
||||
|
||||
QRCode qr;
|
||||
uint8_t buf[qrcode_getBufferSize(5)];
|
||||
qrcode_initText(&qr, buf, 5, ECC_LOW, content.c_str());
|
||||
epd_draw_ap_screen(&qr);
|
||||
if (retry) {
|
||||
epd_draw_ap_screen_retry(&qr);
|
||||
} else {
|
||||
epd_draw_ap_screen(&qr);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_setup_qr(const String& mac) {
|
||||
@@ -116,7 +120,7 @@ static void handle_captive() {
|
||||
|
||||
// ── WiFi provisioning ─────────────────────────────────────────────────────────
|
||||
|
||||
static void enter_provisioning(const String& mac) {
|
||||
static void enter_provisioning(const String& mac, bool retry = false) {
|
||||
// Derive AP name from last 4 hex chars of MAC (no colons)
|
||||
String suffix = mac;
|
||||
suffix.replace(":", "");
|
||||
@@ -124,7 +128,7 @@ static void enter_provisioning(const String& mac) {
|
||||
suffix.toUpperCase();
|
||||
String apSsid = "PictureFrame-" + suffix;
|
||||
|
||||
Serial.println("AP: " + apSsid);
|
||||
Serial.println(retry ? "AP (retry): " + apSsid : "AP: " + apSsid);
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_AP);
|
||||
@@ -143,8 +147,11 @@ static void enter_provisioning(const String& mac) {
|
||||
server.onNotFound(handle_root);
|
||||
server.begin();
|
||||
|
||||
// On retry, repaint with red accents + "Connection Failed — try again"
|
||||
// label so the user has a clear visual signal that their last credential
|
||||
// entry didn't work. On first entry, paint the standard yellow Step 1/2.
|
||||
epd_init();
|
||||
show_ap_qr(apSsid);
|
||||
show_ap_qr(apSsid, retry);
|
||||
epd_sleep();
|
||||
|
||||
g_provisioning = true;
|
||||
@@ -267,13 +274,11 @@ void loop() {
|
||||
// serves an image — no need for an artificial display delay here.
|
||||
normal_operation(mac);
|
||||
} else {
|
||||
// Connection failed — fill red, restart AP
|
||||
epd_init();
|
||||
epd_fill(COLOR_RED);
|
||||
epd_sleep();
|
||||
delay(3000);
|
||||
|
||||
// Re-enter provisioning to retry
|
||||
enter_provisioning(mac);
|
||||
// Connection failed — go back into AP mode with the red retry screen
|
||||
// so the user sees "Connection Failed — try again" and can rescan.
|
||||
// No epd_fill(COLOR_RED) detour: that would obliterate the QR for
|
||||
// ~20 s and force a second redraw to put it back. One repaint into
|
||||
// the retry screen is faster and clearer.
|
||||
enter_provisioning(mac, /*retry=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -263,16 +263,21 @@ void normal_operation_impl(const String& mac, HTTP& http, const String& url, Pre
|
||||
Serial.println("[op] recovery aborted: /img.bin not in LittleFS");
|
||||
}
|
||||
}
|
||||
} else if (code == 204) {
|
||||
} else if (code == 204 || code == 404) {
|
||||
// No image to serve. Don't touch the panel — whatever's already
|
||||
// displayed is the right thing:
|
||||
// • currentImgId == -1 → the setup QR is up (painted by
|
||||
// enter_provisioning after WiFi save). The 15s bootstrap poll
|
||||
// hits this branch every cycle until the user claims via
|
||||
// /setup/{mac}; redrawing the QR each time would put the panel
|
||||
// in a perpetual ~20s e-ink redraw loop and risk ghosting.
|
||||
// • currentImgId >= 0 → a real photo is up (server hiccup, asset
|
||||
// missing, image deleted). Don't paint the setup QR over the
|
||||
// user's photo; leave the last-good image alone.
|
||||
// displayInitialized stays false → epd_sleep() at the bottom is
|
||||
// also skipped, since the display was already in sleep from the
|
||||
// previous cycle.
|
||||
http.end();
|
||||
displayInitialized = true;
|
||||
epd_init();
|
||||
show_setup_qr(mac);
|
||||
} else if (code == 404) {
|
||||
http.end();
|
||||
displayInitialized = true;
|
||||
epd_init();
|
||||
show_setup_qr(mac);
|
||||
} else {
|
||||
// Sync failed (5xx, timeout, malformed). Per FR38, the last-good image
|
||||
// must persist; only the border indicates the error. epd_draw_image_with_border
|
||||
|
||||
@@ -179,6 +179,12 @@ void epd_draw_ap_screen(QRCode* qr) {
|
||||
draw_from_lfs("/ap_bg.bin", COLOR_YELLOW, qr, 563, 185, 5);
|
||||
}
|
||||
|
||||
void epd_draw_ap_screen_retry(QRCode* qr) {
|
||||
// Same QR coordinates — only the bg .bin differs (red accents,
|
||||
// "Connection Failed — try again" label).
|
||||
draw_from_lfs("/ap_bg_retry.bin", COLOR_RED, qr, 563, 185, 5);
|
||||
}
|
||||
|
||||
void epd_draw_setup_screen(QRCode* qr) {
|
||||
// SETUP_QR_X=553, SETUP_QR_Y=175, SETUP_QR_CELL=5 (must match gen_screens.py)
|
||||
draw_from_lfs("/setup_bg.bin", COLOR_GREEN, qr, 553, 175, 5);
|
||||
|
||||
Reference in New Issue
Block a user