Skip to content

Improve image fetch retries and error messaging - #635

Draft
schrockwell wants to merge 6 commits into
mainfrom
add-image-retries
Draft

Improve image fetch retries and error messaging#635
schrockwell wants to merge 6 commits into
mainfrom
add-image-retries

Conversation

@schrockwell

@schrockwell schrockwell commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Problems

  1. failed image fetches had no retry mechanism
  2. confusing error message for failed image fetches
  3. no retries at all on X 5 GHz
  4. when woken by tap/button, device would sleep without error message → appearance of frozen device
  5. WiFI retry failure would require button press to continue

Solution

This PR reduces bl.cpp by 253 lines.

  1. adds HttpRetryRequest class for generic HTTP requests with fast-retry
    1. follows one redirect hop
    2. only retries on transport error, or HTTP codes 408 and 5xx
    3. retries 5x with 2s delay
    4. works for WiFi and 5 GHz modem
  2. implements HttpRetryRequest for both /api/display and image fetching so they share the same retry logic
  3. adds IMAGE_DOWNLOAD_FAILED screen (cherry-picked from Create a dedicated image download error screen page. #611)
  4. adds scripts/mock_server.py for local testing of server failure modes
  5. always shows an error message immediately if device was woken by user (i.e. non-timer wake)
  6. change API retries to fixed 5 minutes
  7. change WiFi retries to 5 minutes for 1 hour, then 15 minutes; don't require button press

Validation

  • OG
  • X
  • BWRY

New fetch logic pseudocode

BOOT / WAKE
  record wake reason (timer, button, touch bar, power-on)
  if not a timer wake: show the TRMNL logo splash

  connect Wi-Fi (or the modem on TRMNL X 5 GHz)
  if Wi-Fi connect fails:
    sleep interval = 5 min
    if this is the 12th or later consecutive Wi-Fi failure:
      sleep interval = 15 min
      reset the Wi-Fi retry counter
      show "Wi-Fi retry limit" screen
    go to sleep with the timer armed (keeps retrying on its own)

  reset the Wi-Fi retry counter
  submit stored logs

DOWNLOAD AND SHOW
  fetch /api/display via HttpRetryRequest
    up to 5 attempts, 2 s apart:
      pick transport: modem if TRMNL X on 5 GHz, else Wi-Fi
      GET (follow one 307/308; auth headers only to hops on the API base URL)
      if body received and non-empty: success, stop
      if failure is transient (no response, 408, 5xx): try again
      else (4xx etc.): stop, do not retry
  if the API fetch failed: result = that error, skip to AFTER

  handle the JSON
    status 0:   apply the API's refresh_rate, note filename / update / reset flags
    status 202: result = NOT REGISTERED, fast poll
    status 500: result = RESET
  if filename is the screen wiper: wipe the panel, fetch again once
  if the image is already cached in SPIFFS:
    if it is the one already on screen: do nothing
    else: draw it from cache
    skip to AFTER
  if nothing new to download, or filename empty: skip to AFTER

  fetch the image via HttpRetryRequest (same retry rules as above)
  if it failed:
    if failure was a bad HTTP status / no response: result = IMAGE_DOWNLOAD_FAILED
    else: result = the body error (timed out, too big, wrong size, out of memory)
    skip to AFTER
  decode PNG / JPEG / BMP, write to SPIFFS, draw it, turn Wi-Fi off
  result = SUCCESS (or WRONG_IMAGE_FORMAT if decoding failed)

AFTER (bl_init)
  if result is IMAGE_FILE_TOO_BIG: show "too big" screen now

  if result is IMAGE_DOWNLOAD_FAILED:
    reset the API retry counter
    (fall through to ERROR SCREENS; sleep will use the API's refresh_rate)

  else if result is a failure (not success / unregistered / reset / no-plugin, and Wi-Fi was fine):
    if woken by button, touch bar, or power-on:
      log it; leave the retry counter and sleep interval alone
      (fall through to ERROR SCREENS)
    else (timer wake):
      sleep interval = 5 min
      retry counter += 1
      if retry number was 1, 2, or 3:
        keep the old image on screen, go to sleep now   <- no error shown
      else:
        (fall through to ERROR SCREENS)

  else:
    reset the API retry counter

  submit stored logs
  if unregistered: show the friendly-ID screen
  if reset requested: wipe stored credentials
  if a firmware update is due: download it, reboot on success, show a message on failure

ERROR SCREENS
  REQUEST_FAILED         -> "request to API failed" (or "weak Wi-Fi" if RSSI is poor)
  RESPONSE_CODE_INVALID  -> "internal error"
  UNABLE_TO_CONNECT      -> "unable to connect to API" (or "weak Wi-Fi")
  IMAGE_DOWNLOAD_FAILED  -> "failed to download the image, device will retry"
  TIMED_OUT              -> "image timeout"
  WRONG_IMAGE_SIZE       -> "size error" (or "weak Wi-Fi")
  WRONG_IMAGE_FORMAT     -> "format error"
  NO PLUGIN              -> no screen; fast poll
  anything else          -> no screen change

SLEEP
  interval = whichever was set last:
    the API's refresh_rate on a normal wake
    5 min on an API failure (timer wake)
    5 min / 15 min on a Wi-Fi failure
    5 s while unregistered or waiting for a plugin (fast poll)
    default 5 min if nothing set one
  deep sleep until the timer fires or the user wakes the device

@schrockwell schrockwell added this to the v1.8.17 milestone Sep 10, 2026
@schrockwell schrockwell added enhancement New feature or request refactor Code cleanup only labels Sep 10, 2026
@schrockwell schrockwell changed the title Improve handling of image fetch failures Improve image fetch retries and error messaging Sep 10, 2026
…r 1 hour; keep retrying WiFi without requiring button press
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request refactor Code cleanup only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant