From 7d431f4a8b78b00f1bd1ea917e3209a617ea52f8 Mon Sep 17 00:00:00 2001 From: jedarden Date: Wed, 15 Apr 2026 13:35:52 -0400 Subject: [PATCH] Make flash step resilient: bootloader-mode detection and guided retry On flash-error, show BOOT+RST instructions with board diagram and a "Try Again" button instead of a dead-end error message. Escalates to USB cable/hub advice after 2 failures. Adds a proactive collapsible tips section before flashing starts for users who read ahead. Co-Authored-By: Claude Sonnet 4.6 --- dashboard/js/onboard.js | 123 ++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 36 deletions(-) diff --git a/dashboard/js/onboard.js b/dashboard/js/onboard.js index d83c2cb..dbc3fee 100644 --- a/dashboard/js/onboard.js +++ b/dashboard/js/onboard.js @@ -362,17 +362,60 @@ return html; } + var BOOTLOADER_SVG = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + 'BOOT' + + '' + + '' + + '' + + 'RST' + + '' + + 'ESP32' + + buildPins(30, 18, 15) + buildPins(30, 97, 15) + + ''; + + function renderBootloaderHelp(retryCount) { + var escalated = retryCount >= 2; + return '
' + + '

' + (escalated ? '⚠ Still not working?' : 'Device not in download mode') + '

' + + (escalated + ? '

Try a different USB cable (data cables only, not charge-only). If using a USB hub, connect directly to your computer.

' + : '

Hold BOOT, press & release RST, then release BOOT.

') + + BOOTLOADER_SVG + + '
'; + } + function renderFlashFirmware(contentEl) { + var flashRetryCount = 0; + contentEl.innerHTML = '
' + '

Flash Firmware

' + - '

The wizard will now flash the Spaxel firmware onto your ESP32-S3. This takes about 45-90 seconds.

' + + '

The wizard will flash the Spaxel firmware onto your ESP32-S3. This takes about 45–90 seconds.

' + + '
' + + 'Having trouble connecting?' + + '
' + + '

Before clicking Start Flashing, put the board in download mode:

' + + '
    ' + + '
  1. Hold BOOT
  2. ' + + '
  3. Press & release RST
  4. ' + + '
  5. Release BOOT
  6. ' + + '
' + + BOOTLOADER_SVG + + '
' + '
' + '' + - '' + + '' + '
'; hideNav(); @@ -387,45 +430,53 @@ return { cleanup: function () { } }; } - var container = document.getElementById('flash-container'); - var installBtn = document.createElement('esp-web-install-button'); - installBtn.setAttribute('manifest', '/api/firmware/manifest'); - installBtn.innerHTML = ''; - container.appendChild(installBtn); + function mountInstallButton() { + var container = document.getElementById('flash-container'); + if (!container) { return; } + container.innerHTML = ''; + var installBtn = document.createElement('esp-web-install-button'); + installBtn.setAttribute('manifest', '/api/firmware/manifest'); + installBtn.innerHTML = ''; + container.appendChild(installBtn); - installBtn.addEventListener('flash-start', function () { - document.getElementById('flash-progress').style.display = 'block'; - document.getElementById('flash-status').textContent = 'Flashing...'; - document.getElementById('flash-container').style.display = 'none'; - }); + installBtn.addEventListener('flash-start', function () { + document.getElementById('flash-progress').style.display = 'block'; + document.getElementById('flash-status').textContent = 'Flashing...'; + document.getElementById('flash-progress-fill').style.width = '0%'; + container.style.display = 'none'; + document.getElementById('flash-recovery').style.display = 'none'; + }); - installBtn.addEventListener('flash-progress', function (e) { - var detail = e.detail || {}; - var pct = 0; - if (detail.bytesTotal > 0) { - pct = Math.round((detail.bytesWritten / detail.bytesTotal) * 100); - } - document.getElementById('flash-progress-fill').style.width = pct + '%'; - document.getElementById('flash-status').textContent = 'Flashing... ' + pct + '%'; - }); + installBtn.addEventListener('flash-progress', function (e) { + var detail = e.detail || {}; + var pct = detail.bytesTotal > 0 + ? Math.round((detail.bytesWritten / detail.bytesTotal) * 100) : 0; + document.getElementById('flash-progress-fill').style.width = pct + '%'; + document.getElementById('flash-status').textContent = 'Flashing... ' + pct + '%'; + }); - installBtn.addEventListener('flash-success', function () { - document.getElementById('flash-progress').style.display = 'none'; - document.getElementById('flash-container').innerHTML = - '

✓ Firmware flashed successfully!

'; - saveState(); - setTimeout(function () { goToStep(state.currentStepIndex + 1); }, 1500); - }); + installBtn.addEventListener('flash-success', function () { + document.getElementById('flash-progress').style.display = 'none'; + container.innerHTML = '

✓ Firmware flashed successfully!

'; + container.style.display = 'block'; + saveState(); + setTimeout(function () { goToStep(state.currentStepIndex + 1); }, 1500); + }); - installBtn.addEventListener('flash-error', function () { - document.getElementById('flash-progress').style.display = 'none'; - var errEl = document.getElementById('flash-error'); - errEl.style.display = 'block'; - errEl.textContent = - 'The connection was interrupted. Check the USB cable is not loose and try again.'; - document.getElementById('flash-container').style.display = 'block'; - }); + installBtn.addEventListener('flash-error', function () { + flashRetryCount++; + document.getElementById('flash-progress').style.display = 'none'; + container.style.display = 'block'; + var recovery = document.getElementById('flash-recovery'); + recovery.style.display = 'block'; + recovery.innerHTML = renderBootloaderHelp(flashRetryCount); + // Rebuild the button so it can be clicked again + mountInstallButton(); + }); + } + mountInstallButton(); return { cleanup: function () { } }; }