Add ESP8266, ESP32-C6, ESP32-C2, ESP32-H2 to chip selector with optgroup layout. Generalize UI text from ESP32-S3-specific to board-agnostic. Add esptool merge_bin examples for ESP32, ESP32-S3, and ESP8266. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
382 lines
17 KiB
HTML
382 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ko">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>ESP32 Web Flasher</title>
|
||
<link rel="stylesheet" href="css/style.css" />
|
||
|
||
<!--
|
||
esp-web-tools (Espressif 공식)
|
||
Web Serial API를 통해 ESP32 시리얼 플래시 수행
|
||
Chrome 89+ / Edge 89+ 필요
|
||
-->
|
||
<script
|
||
type="module"
|
||
src="https://unpkg.com/esp-web-tools@10/dist/web/install-button.js">
|
||
</script>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════════
|
||
HEADER
|
||
══════════════════════════════════════════════════════════════════ -->
|
||
<header>
|
||
<a class="logo" href="#">
|
||
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<rect width="32" height="32" rx="6" fill="#00c896" fill-opacity=".15"/>
|
||
<rect x="6" y="6" width="20" height="20" rx="3" stroke="#00c896" stroke-width="2"/>
|
||
<rect x="10" y="10" width="5" height="5" fill="#00c896"/>
|
||
<rect x="17" y="10" width="5" height="5" fill="#00c896" fill-opacity=".5"/>
|
||
<rect x="10" y="17" width="5" height="5" fill="#00c896" fill-opacity=".5"/>
|
||
<rect x="17" y="17" width="5" height="5" fill="#00c896"/>
|
||
<line x1="2" y1="12" x2="6" y2="12" stroke="#00c896" stroke-width="1.5"/>
|
||
<line x1="2" y1="20" x2="6" y2="20" stroke="#00c896" stroke-width="1.5"/>
|
||
<line x1="26" y1="12" x2="30" y2="12" stroke="#00c896" stroke-width="1.5"/>
|
||
<line x1="26" y1="20" x2="30" y2="20" stroke="#00c896" stroke-width="1.5"/>
|
||
</svg>
|
||
ESP32 Web Flasher
|
||
</a>
|
||
<span class="header-badge">ESP / ESP32</span>
|
||
</header>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════════
|
||
MAIN
|
||
══════════════════════════════════════════════════════════════════ -->
|
||
<main>
|
||
|
||
<!-- 브라우저 경고 배너 -->
|
||
<div id="browser-warning" class="alert alert-warn" style="display:none;">
|
||
<span style="font-size:18px;">⚠</span>
|
||
<div>
|
||
<strong>지원되지 않는 브라우저</strong><br>
|
||
Web Serial API는 <strong>Chrome 89+</strong> 또는 <strong>Edge 89+</strong>에서만 동작합니다.
|
||
현재 브라우저에서는 시리얼 연결 및 플래시 기능을 사용할 수 없습니다.
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ─────────────────────────────────────────────────────────────
|
||
STEP 1: 시리얼 연결 확인
|
||
──────────────────────────────────────────────────────────────── -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="step-badge" id="step1-badge">1</div>
|
||
<h2>시리얼 연결 확인</h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="alert alert-info" style="margin-bottom:16px;">
|
||
<span>ℹ</span>
|
||
<div>
|
||
ESP 보드를 USB 케이블로 PC에 연결한 후 아래 버튼을 눌러 연결 상태를 확인하세요.
|
||
<br><small style="color:var(--text-muted);">내장 USB 포트 또는 USB-UART 변환기(CP2102, CH340, FTDI) 모두 지원</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="status-row">
|
||
<div class="dot dot-idle" id="conn-dot"></div>
|
||
<span id="conn-text">연결 안 됨</span>
|
||
<span id="device-info" style="margin-left:auto;font-size:12px;color:var(--text-muted);"></span>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:10px;margin-top:14px;">
|
||
<button id="btn-connect" class="btn btn-primary needs-serial">
|
||
🔌 포트 연결
|
||
</button>
|
||
<button id="btn-disconnect" class="btn btn-secondary" style="display:none;">
|
||
⏏ 연결 해제
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ─────────────────────────────────────────────────────────────
|
||
STEP 2 & 3: 펌웨어 업로드 / 플래시 (탭)
|
||
──────────────────────────────────────────────────────────────── -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="step-badge" id="step2-badge">2</div>
|
||
<h2>펌웨어 관리 및 플래시</h2>
|
||
</div>
|
||
|
||
<!-- 탭 바 -->
|
||
<div class="tab-bar">
|
||
<button class="tab-btn active" data-tab="tab-upload">📤 펌웨어 업로드</button>
|
||
<button class="tab-btn" data-tab="tab-flash">⚡ 플래시</button>
|
||
</div>
|
||
|
||
<!-- ── 탭: 펌웨어 업로드 ──────────────────────────────── -->
|
||
<div class="tab-panel active" id="tab-upload">
|
||
|
||
<div class="alert alert-info" style="margin-bottom:16px;">
|
||
<span>ℹ</span>
|
||
<div>
|
||
Arduino IDE <strong>Sketch → Export Compiled Binary</strong> 로 생성한 .bin 파일을 업로드하세요.
|
||
<br>병합 바이너리(merged.bin)는 '펌웨어' 하나만 업로드해도 됩니다.
|
||
<br><small style="color:var(--text-muted);">
|
||
분리 파일 사용 시: bootloader(0x0000) + partition-table(0x8000) + app(0x10000)
|
||
</small>
|
||
</div>
|
||
</div>
|
||
|
||
<form id="upload-form">
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>펌웨어 이름</label>
|
||
<input id="fw-name" type="text" placeholder="예: MyProduct v1.0" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>버전</label>
|
||
<input id="fw-version" type="text" placeholder="예: 1.0.0" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>설명 (선택)</label>
|
||
<input id="fw-desc" type="text" placeholder="간단한 설명" />
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>칩 패밀리</label>
|
||
<select id="fw-chip">
|
||
<optgroup label="ESP32 시리즈">
|
||
<option value="ESP32-S3" selected>ESP32-S3</option>
|
||
<option value="ESP32-S2">ESP32-S2</option>
|
||
<option value="ESP32-S3-BOX">ESP32-S3-BOX</option>
|
||
</optgroup>
|
||
<optgroup label="ESP32-C 시리즈 (RISC-V)">
|
||
<option value="ESP32-C3">ESP32-C3</option>
|
||
<option value="ESP32-C6">ESP32-C6</option>
|
||
<option value="ESP32-C2">ESP32-C2 (ESP8684)</option>
|
||
</optgroup>
|
||
<optgroup label="ESP32-H 시리즈 (RISC-V)">
|
||
<option value="ESP32-H2">ESP32-H2</option>
|
||
</optgroup>
|
||
<optgroup label="ESP32 오리지널">
|
||
<option value="ESP32">ESP32</option>
|
||
</optgroup>
|
||
<optgroup label="ESP8266 시리즈">
|
||
<option value="ESP8266">ESP8266</option>
|
||
</optgroup>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 드롭존: 펌웨어 (필수) -->
|
||
<div class="form-group">
|
||
<label>펌웨어 바이너리 <span style="color:var(--danger);">*</span></label>
|
||
<div class="drop-zone" id="drop-firmware">
|
||
<input type="file" id="file-firmware" accept=".bin" />
|
||
<div class="icon">📦</div>
|
||
<div class="drop-label">
|
||
펌웨어 .bin 파일을 드래그하거나 클릭하세요
|
||
<div style="font-size:11px;margin-top:4px;color:var(--text-muted);">(최대 8 MB)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 분리 파일 섹션 (선택) -->
|
||
<details style="margin-bottom:14px;">
|
||
<summary style="cursor:pointer;font-size:13px;color:var(--text-muted);margin-bottom:8px;">
|
||
▸ 분리 바이너리 파일 추가 (선택)
|
||
</summary>
|
||
<div style="padding-top:10px;display:flex;flex-direction:column;gap:12px;">
|
||
<div class="form-group" style="margin:0;">
|
||
<label>부트로더 (bootloader.bin) — offset 0x0000</label>
|
||
<div class="drop-zone" id="drop-bootloader" style="padding:16px;">
|
||
<input type="file" id="file-bootloader" accept=".bin" />
|
||
<div class="drop-label">부트로더 .bin (선택사항)</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group" style="margin:0;">
|
||
<label>파티션 테이블 (partition-table.bin) — offset 0x8000</label>
|
||
<div class="drop-zone" id="drop-partitions" style="padding:16px;">
|
||
<input type="file" id="file-partitions" accept=".bin" />
|
||
<div class="drop-label">파티션 테이블 .bin (선택사항)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<div id="upload-progress" style="display:none;margin-bottom:14px;">
|
||
<div class="progress-wrap"><div class="progress-bar" id="upload-bar"></div></div>
|
||
<div class="progress-label">
|
||
<span id="upload-pct">0%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-primary">
|
||
📤 서버에 업로드
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- ── 탭: 플래시 ─────────────────────────────────────── -->
|
||
<div class="tab-panel" id="tab-flash">
|
||
|
||
<div class="alert alert-info" style="margin-bottom:16px;">
|
||
<span>⚡</span>
|
||
<div>
|
||
업로드된 펌웨어를 선택 후 <strong>플래시 실행</strong> 버튼을 누르세요.
|
||
<br><small style="color:var(--text-muted);">
|
||
esp-web-tools가 시리얼 포트 선택 대화상자를 표시하고 자동으로 플래싱합니다.
|
||
</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 업로드된 펌웨어 목록 -->
|
||
<div style="margin-bottom:16px;">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
|
||
<span style="font-size:14px;font-weight:600;">업로드된 펌웨어</span>
|
||
<button class="btn btn-secondary btn-sm" onclick="loadFirmwareList()">🔄 새로고침</button>
|
||
</div>
|
||
<div id="fw-list" class="fw-list"></div>
|
||
</div>
|
||
|
||
<!-- 선택 상태 & 플래시 버튼 -->
|
||
<div style="border-top:1px solid var(--border);padding-top:16px;margin-top:4px;">
|
||
<div class="status-row" style="margin-bottom:12px;">
|
||
<span>💾</span>
|
||
<span id="selected-fw-info" style="font-size:14px;">선택된 펌웨어 없음 — 위 목록에서 선택하세요</span>
|
||
</div>
|
||
|
||
<!--
|
||
esp-web-install-button 웹 컴포넌트
|
||
manifest 속성에 백엔드 manifest URL을 동적으로 설정
|
||
펌웨어 선택 시 selectFirmware() 함수가 manifest를 업데이트
|
||
-->
|
||
<esp-web-install-button id="esp-install-btn">
|
||
<button
|
||
slot="activate"
|
||
class="btn btn-primary needs-serial"
|
||
style="width:100%;justify-content:center;padding:12px;"
|
||
>
|
||
⚡ 플래시 실행
|
||
</button>
|
||
<span slot="unsupported" style="color:var(--danger);font-size:13px;">
|
||
⚠ 이 브라우저는 Web Serial을 지원하지 않습니다 (Chrome/Edge 필요)
|
||
</span>
|
||
</esp-web-install-button>
|
||
|
||
<div class="alert alert-warn" style="margin-top:14px;">
|
||
<span>⚠</span>
|
||
<div style="font-size:12px;">
|
||
<strong>플래시 전 확인 사항:</strong>
|
||
<ul style="margin:4px 0 0 16px;line-height:1.8;">
|
||
<li>ESP 보드가 USB로 연결되어 있어야 합니다</li>
|
||
<li>다른 프로그램(Arduino IDE, esptool)이 해당 포트를 사용 중이면 안 됩니다</li>
|
||
<li>플래시 중 USB 케이블을 분리하지 마세요</li>
|
||
<li>일부 보드는 BOOT 버튼을 누른 상태로 연결해야 합니다</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ─────────────────────────────────────────────────────────────
|
||
시리얼 모니터 / 로그
|
||
──────────────────────────────────────────────────────────────── -->
|
||
<div class="card">
|
||
<div class="card-header" style="justify-content:space-between;">
|
||
<div style="display:flex;align-items:center;gap:10px;">
|
||
<span>🖥</span>
|
||
<h2>로그 / 상태</h2>
|
||
</div>
|
||
<button id="btn-clear-log" class="btn btn-secondary btn-sm">지우기</button>
|
||
</div>
|
||
<div class="card-body" style="padding:12px;">
|
||
<pre id="monitor"></pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ─────────────────────────────────────────────────────────────
|
||
도움말
|
||
──────────────────────────────────────────────────────────────── -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span>📖</span>
|
||
<h2>사용 방법 & 플래시 파일 준비</h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;">
|
||
|
||
<div>
|
||
<h3 style="font-size:14px;margin-bottom:10px;color:var(--accent);">Arduino IDE에서 .bin 내보내기</h3>
|
||
<ol style="font-size:13px;line-height:2;color:var(--text-muted);padding-left:18px;">
|
||
<li>Arduino IDE 2.x 실행</li>
|
||
<li>사용할 ESP 보드 선택 후 코드 작성</li>
|
||
<li><strong>Sketch → Export Compiled Binary</strong></li>
|
||
<li>스케치 폴더에 <code>.bin</code> 파일 생성됨</li>
|
||
<li>위 업로드 탭에서 해당 파일 업로드</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 style="font-size:14px;margin-bottom:10px;color:var(--accent);">병합 바이너리(merged.bin) 생성</h3>
|
||
<pre style="font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:10px;overflow:auto;color:var(--text-muted);"># ESP32-S3 / S2 / C3 / C6 / H2
|
||
esptool.py --chip esp32s3 merge_bin \
|
||
-o merged.bin \
|
||
0x0 bootloader.bin \
|
||
0x8000 partitions.bin \
|
||
0x10000 app.bin
|
||
|
||
# ESP32 (오리지널)
|
||
esptool.py --chip esp32 merge_bin \
|
||
-o merged.bin \
|
||
0x1000 bootloader.bin \
|
||
0x8000 partitions.bin \
|
||
0x10000 app.bin
|
||
|
||
# ESP8266
|
||
esptool.py --chip esp8266 \
|
||
-o merged.bin 0x0 app.bin</pre>
|
||
<p style="font-size:12px;color:var(--text-muted);margin-top:8px;">
|
||
병합 후 merged.bin 하나만 업로드하면 됩니다.
|
||
</p>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 style="font-size:14px;margin-bottom:10px;color:var(--accent);">Flash 암호화 (보안 강화)</h3>
|
||
<pre style="font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:10px;overflow:auto;color:var(--text-muted);"># Flash Encryption 활성화
|
||
espefuse.py --chip esp32s3 \
|
||
burn_efuse DIS_DOWNLOAD_PLAIN_DECRYPT</pre>
|
||
<p style="font-size:12px;color:var(--text-muted);margin-top:8px;">
|
||
활성화 후 덤프 시 암호화된 데이터만 읽힙니다.
|
||
</p>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 style="font-size:14px;margin-bottom:10px;color:var(--accent);">지원 환경</h3>
|
||
<table style="font-size:12px;width:100%;border-collapse:collapse;color:var(--text-muted);">
|
||
<tr>
|
||
<td style="padding:4px 0;">Chrome 89+</td>
|
||
<td style="color:var(--accent);">✓ 지원</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:4px 0;">Edge 89+</td>
|
||
<td style="color:var(--accent);">✓ 지원</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:4px 0;">Firefox</td>
|
||
<td style="color:var(--danger);">✗ 미지원</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:4px 0;">Safari</td>
|
||
<td style="color:var(--danger);">✗ 미지원</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:4px 0;">HTTP (non-localhost)</td>
|
||
<td style="color:var(--danger);">✗ HTTPS 필요</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<script src="js/app.js"></script>
|
||
</body>
|
||
</html>
|