Skip to content

fix: free TFT sprite before OTA to fix SSL memory failure (#59)#61

Merged
sjordan0228 merged 4 commits into
devfrom
fix/tft-ota-progress
Mar 31, 2026
Merged

fix: free TFT sprite before OTA to fix SSL memory failure (#59)#61
sjordan0228 merged 4 commits into
devfrom
fix/tft-ota-progress

Conversation

@sjordan0228
Copy link
Copy Markdown
Contributor

@sjordan0228 sjordan0228 commented Mar 31, 2026

Summary

  • Free the 57.6KB TFT sprite buffer before OTA download, reclaiming enough heap for SSL/TLS handshake
  • Show OTA progress bar directly on TFT panel via LovyanGFX direct writes (no sprite needed)
  • Display error screen on TFT if OTA fails
  • Adds freeForOTA(), updateOTAProgress(), showOTAError() to DisplayI with default no-ops so LCDManager is unaffected

Closes #59

Test Plan

  • Clean compile on esp32s3zero and esp32dev (verified)
  • Flash TFT-enabled build to ESP32 WROOM
  • Trigger OTA from /update page — verify TFT shows "Updating..." with progress bar
  • Verify web UI also shows download/flash progress
  • Verify device reboots on success
  • Simulate failure (bad URL) — verify TFT shows error screen

Summary by CodeRabbit

  • New Features

    • OTA update UI on device: initial "Updating..." screen, live progress bar and percentage.
    • Visible OTA error messages with a clear "Update Failed" indicator.
  • Reliability

    • Display is released during OTA to free memory for secure download, reducing update failures.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ef9645bf-7523-4112-880a-c8c2c7d02b57

📥 Commits

Reviewing files that changed from the base of the PR and between 877f5cb and f93ae20.

📒 Files selected for processing (1)
  • src/TFTManager.cpp

📝 Walkthrough

Walkthrough

Adds OTA UI hooks to the display interface, implements TFT-specific OTA rendering and resource release, and wires the active display into the web server's OTA task so the display is freed before SSL download, progress is shown, and errors are reported.

Changes

Cohort / File(s) Summary
Display interface
src/DisplayI.h
Added three virtual no-op OTA methods: freeForOTA(), updateOTAProgress(uint8_t), and showOTAError(const char*).
TFT implementation
src/TFTManager.h, src/TFTManager.cpp
Implemented freeForOTA() to stop TFT task, delete sprite buffer, set brightness, and draw static "Updating..." UI; updateOTAProgress(uint8_t) fills progress bar and updates percent text; showOTAError(const char*) renders an error UI with red X and message.
Web server integration
src/WebServerManager.h, src/WebServerManager.cpp
Added DisplayI* _display member and setDisplay(DisplayI*); OTA background task calls freeForOTA() before TLS, updateOTAProgress() on percent changes, and showOTAError() on failures.
Application wiring
src/main.cpp
Passes the selected active display to WebServerManager::setDisplay() during setup so OTA task can control the display.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Client as Web Client
    participant WSM as WebServerManager (OTA task)
    participant Display as TFTManager / DisplayI
    participant Network as HTTPS / SSL
    participant Updater as Update subsystem

    User->>Client: Start OTA (POST /update)
    Client->>WSM: Trigger OTA task
    WSM->>Display: freeForOTA()
    activate Display
    Display->>Display: Stop TFT task\nDelete sprite\nDraw "Updating..."
    deactivate Display
    WSM->>Network: Establish TLS and download firmware
    loop while downloading
        Network-->>WSM: data chunk
        WSM->>WSM: compute newPct
        alt percent changed
            WSM->>Display: updateOTAProgress(newPct)
            activate Display
            Display->>Display: Fill progress bar\nUpdate percent text
            deactivate Display
        end
    end
    alt success
        WSM->>Updater: apply update
        Updater-->>WSM: success (reboot)
    else failure
        WSM->>Display: showOTAError(errorMsg)
        activate Display
        Display->>Display: Draw error UI (red X + text)
        deactivate Display
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers summary, test plan, and issue closure but lacks explicit sections for 'Changes' and 'How to Test' per the template, and the checklist items are unchecked. Add a bullet-point list under 'Changes' detailing modified files and their changes. Complete or clarify the test plan section with numbered steps and mark checklist items as done if testing was completed.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: free TFT sprite before OTA to fix SSL memory failure (#59)' clearly and specifically describes the main change—freeing TFT sprite memory to resolve OTA SSL failures—which is the core objective of the PR.
Linked Issues check ✅ Passed The PR fully implements the required functionality from issue #59: frees the TFT sprite before OTA [WebServerManager.cpp, TFTManager.cpp], displays OTA progress on TFT [TFTManager.cpp], and shows error screens on failure [TFTManager.cpp, WebServerManager.cpp].
Out of Scope Changes check ✅ Passed All code changes are directly scoped to OTA memory/display handling. DisplayI interface additions are minimal (three no-op methods for backward compatibility), and all implementations target OTA objectives. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tft-ota-progress

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/TFTManager.cpp`:
- Around line 745-768: TFT task is never restarted after OTA failure so queued
messages on _messageQueue have no consumer; update TFTManager::showOTAError (or
the OTA failure handling path after freeForOTA()) to either restart the TFT task
(the same routine that creates the TFT task, e.g., the start/create task method
used elsewhere) or explicitly document that a manual reboot is required—ensure
the fix reinitializes whatever freeForOTA() torn down so subsequent calls like
showReady() and showSpool() are served, and reference _messageQueue so the
consumer is restored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3c7af056-07eb-4cd3-aade-d548d64bd903

📥 Commits

Reviewing files that changed from the base of the PR and between 48dec0e and 877f5cb.

📒 Files selected for processing (6)
  • src/DisplayI.h
  • src/TFTManager.cpp
  • src/TFTManager.h
  • src/WebServerManager.cpp
  • src/WebServerManager.h
  • src/main.cpp

Comment thread src/TFTManager.cpp
Comment on lines +745 to +768
void TFTManager::showOTAError(const char* error) {
int cx = _tft.width() / 2;

// Clear progress area
_tft.fillRect(0, 60, _tft.width(), _tft.height() - 60, COLOR_BG);

// Error icon
_tft.fillCircle(cx, 100, 22, 0xFF4444);
_tft.setTextColor(COLOR_BG);
_tft.setTextSize(3);
_tft.setTextDatum(MC_DATUM);
_tft.drawString("X", cx, 100);

// "Update Failed" text
_tft.setTextColor(COLOR_TEXT);
_tft.setTextSize(1);
_tft.drawString("Update Failed", cx, 135);

// Error detail
if (error && error[0]) {
_tft.setTextColor(COLOR_SUBTEXT);
_tft.drawString(error, cx, 155);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

TFT task is not restarted after OTA failure—is this intentional?

After freeForOTA() deletes the TFT task, if OTA fails the task is never restarted. This means subsequent display calls (e.g., showReady(), showSpool()) will queue messages to _messageQueue with no consumer, leaving the TFT stuck on the error screen.

This is likely acceptable since OTA failure typically requires user intervention (power cycle or retry), but consider documenting this behavior or adding a note that manual reboot is expected after OTA failure.

🧰 Tools
🪛 Clang (14.0.6)

[warning] 746-746: variable 'cx' is not initialized

(cppcoreguidelines-init-variables)


[warning] 746-746: variable name 'cx' is too short, expected at least 3 characters

(readability-identifier-length)


[warning] 764-764: implicit conversion 'const char *' -> bool

(readability-implicit-bool-conversion)


[warning] 764-764: implicit conversion 'char' -> bool

(readability-implicit-bool-conversion)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/TFTManager.cpp` around lines 745 - 768, TFT task is never restarted after
OTA failure so queued messages on _messageQueue have no consumer; update
TFTManager::showOTAError (or the OTA failure handling path after freeForOTA())
to either restart the TFT task (the same routine that creates the TFT task,
e.g., the start/create task method used elsewhere) or explicitly document that a
manual reboot is required—ensure the fix reinitializes whatever freeForOTA()
torn down so subsequent calls like showReady() and showSpool() are served, and
reference _messageQueue so the consumer is restored.

@sjordan0228 sjordan0228 merged commit ca26f94 into dev Mar 31, 2026
1 check was pending
@sjordan0228 sjordan0228 deleted the fix/tft-ota-progress branch April 2, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant