Skip to content

Commit 9cfa721

Browse files
committed
flasher page update
1 parent d4c7e2e commit 9cfa721

5 files changed

Lines changed: 212 additions & 71 deletions

File tree

.github/workflows/github-pages-flasher.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Build env azimuth_main and deploy web-flasher/ (USB install via esp-web-tools).
22
# Repo: Settings → Pages → Source: GitHub Actions.
3+
# Deploy job uses a custom environment name so Deployments / Environments UI reads "azimuth-flasher" (not the generic github-pages label).
34

45
name: Deploy web flasher (GitHub Pages)
56

@@ -63,6 +64,9 @@ jobs:
6364
f.write("\n")
6465
PY
6566
67+
- name: Sync flasher logos from logo/
68+
run: mkdir -p web-flasher/logo && cp logo/AzimuthLogo_Dark.png logo/AzimuthLogo_Light.png web-flasher/logo/
69+
6670
- uses: actions/upload-pages-artifact@v3
6771
with:
6872
path: web-flasher
@@ -71,7 +75,7 @@ jobs:
7175
needs: build
7276
runs-on: ubuntu-latest
7377
environment:
74-
name: github-pages
78+
name: azimuth-flasher
7579
url: ${{ steps.deployment.outputs.page_url }}
7680
steps:
7781
- id: deployment

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Summary SPI / control pin map (full table, battery, buttons, LED, buzzer in **[d
9191
| What | Where |
9292
|------|--------|
9393
| **GitLab pipeline** | Pushes to **`main`** run **`.gitlab-ci.yml`**: builds **`azimuth_main`** using **`include/secrets.h.example`****`include/secrets.h`** in CI. **Artifacts****`ci-artifacts/firmware/`** (`bootloader.bin`, `partitions.bin`, `boot_app0.bin`, `firmware.bin`). |
94-
| **GitHub Pages USB flasher** | Workflow **`.github/workflows/github-pages-flasher.yml`** runs on **`main`**, builds the same env, runs **`scripts/prepare_web_flasher_firmware.sh`**, and deploys **`web-flasher/`** (portal-styled page using [esp-web-tools](https://github.com/esphome/esp-web-tools)). In the repo: **Settings → Pages → Build and deployment → Source: GitHub Actions**. Users need **Chrome** or **Edge** (Web Serial) and a **USB data** cable. When the installer offers **erase flash**, use it for a **factory-clean** device (clears NVS like on-device “Erase saved settings”). The page links to **`http://azimuth.local:8080/`** for the settings portal after install. |
94+
| **GitHub Pages USB flasher** | Workflow **`.github/workflows/github-pages-flasher.yml`** runs on **`main`**, builds the same env, runs **`scripts/prepare_web_flasher_firmware.sh`**, and deploys **`web-flasher/`** (USB installer using [esp-web-tools](https://github.com/esphome/esp-web-tools)). In the repo: **Settings → Pages → Build and deployment → Source: GitHub Actions**. The deploy job uses GitHub Environment **`azimuth-flasher`** (so the Deployments UI is labeled that way, not the generic `github-pages` name). Users need **Chrome** or **Edge** (Web Serial) and a **USB data** cable. When the installer offers **erase flash**, use it for a **factory-clean** device (clears NVS like on-device “Erase saved settings”). The page links to **`http://azimuth.local:8080/`** for the settings portal after install. |
9595

9696
Local check: `pio run -e azimuth_main` then `./scripts/prepare_web_flasher_firmware.sh` copies binaries into **`web-flasher/firmware/`** for testing.
9797

web-flasher/index.html

Lines changed: 206 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,87 +2,224 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8"/>
5-
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"/>
6-
<meta name="color-scheme" content="dark"/>
7-
<title>Azimuth — Web flasher</title>
5+
<meta name="viewport" content="width=device-width,initial-scale=1"/>
6+
<meta name="color-scheme" content="dark light"/>
7+
<title>Install Azimuth firmware</title>
88
<script type="module" src="https://unpkg.com/esp-web-tools@10.0.1/dist/web/install-button.js?module"></script>
99
<style>
10-
:root{
11-
--bg:#0a0e14;--bg2:#121a24;--card:rgba(26,35,50,.92);--bd:rgba(61,158,229,.22);
12-
--tx:#eef4fa;--muted:#8b9cb3;--acc:#3d9ee5;--acc-dim:rgba(61,158,229,.15);
13-
--ok:#4ade80;--shadow:0 8px 32px rgba(0,0,0,.35);
14-
}
15-
*{box-sizing:border-box}
16-
html{-webkit-text-size-adjust:100%}
17-
body{
18-
margin:0;min-height:100dvh;
19-
font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
20-
color:var(--tx);
21-
background:var(--bg);
22-
background-image:radial-gradient(ellipse 100% 60% at 50% -15%,#1a4a6e 0%,transparent 55%),radial-gradient(ellipse 80% 50% at 100% 100%,rgba(61,158,229,.08),transparent);
23-
}
24-
.wrap{max-width:34rem;margin:0 auto;padding:clamp(1rem,4vw,2rem) clamp(1rem,3vw,1.25rem) 2.5rem}
25-
.brand{text-align:center;margin-bottom:1.1rem}
26-
.brand h1{font-size:1.35rem;font-weight:700;margin:0;letter-spacing:.02em;background:linear-gradient(165deg,#e8eef5,var(--acc));-webkit-background-clip:text;background-clip:text;color:transparent}
27-
.sub{color:var(--muted);font-size:.8125rem;margin:.5rem 0 0;line-height:1.45}
28-
.card{
29-
background:var(--card);border:1px solid var(--bd);border-radius:14px;padding:1.1rem 1.15rem;margin-bottom:1rem;
30-
box-shadow:var(--shadow)
31-
}
32-
.hd{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--acc);margin:0 0 .75rem}
33-
.hint{font-size:.75rem;color:var(--muted);margin:0 0 .85rem;line-height:1.45}
34-
.btn-row{display:flex;flex-direction:column;gap:.65rem;margin-top:.5rem;align-items:stretch}
35-
.btn-row esp-web-install-button{
36-
--esp-tools-button-color:var(--acc);
37-
--esp-tools-button-text-color:#051018;
38-
--esp-tools-button-border-radius:10px;
39-
display:block;width:100%;
40-
}
41-
.link-card a{color:var(--acc);text-decoration:none;font-weight:600}
42-
.link-card a:hover{text-decoration:underline}
43-
.callout{margin-top:.75rem;padding:.75rem .85rem;border-radius:11px;background:var(--bg2);border:1px solid var(--bd);font-size:.8125rem;color:var(--muted);line-height:1.5}
44-
.callout strong{color:var(--tx)}
45-
code{font-family:ui-monospace,SFMono-Regular,monospace;font-size:.85em;color:var(--acc)}
46-
#msg{margin-top:.75rem;font-size:.8125rem;min-height:1.25em}
47-
.err{color:#f87171}
10+
:root {
11+
--bg: #0c1118;
12+
--bg-elev: #151d28;
13+
--tx: #e8eef4;
14+
--tx-soft: #9aa8b8;
15+
--line: rgba(61, 158, 229, 0.22);
16+
--accent: #3d9ee5;
17+
--accent-soft: rgba(61, 158, 229, 0.14);
18+
--warn-bg: rgba(248, 113, 113, 0.1);
19+
--warn-bd: rgba(248, 113, 113, 0.35);
20+
--radius: 16px;
21+
--font: system-ui, -apple-system, "Segoe UI", sans-serif;
22+
}
23+
@media (prefers-color-scheme: light) {
24+
:root {
25+
--bg: #f0f4f8;
26+
--bg-elev: #fff;
27+
--tx: #0f172a;
28+
--tx-soft: #5c6b7a;
29+
--line: rgba(15, 23, 42, 0.12);
30+
--accent-soft: rgba(61, 158, 229, 0.12);
31+
--warn-bg: #fff1f2;
32+
--warn-bd: #fecdd3;
33+
}
34+
}
35+
*, *::before, *::after { box-sizing: border-box; }
36+
html { -webkit-text-size-adjust: 100%; }
37+
body {
38+
margin: 0;
39+
min-height: 100dvh;
40+
font: 17px/1.55 var(--font);
41+
color: var(--tx);
42+
background: var(--bg);
43+
}
44+
.page {
45+
max-width: 28rem;
46+
margin: 0 auto;
47+
padding: 2rem 1.25rem 3rem;
48+
}
49+
.logo {
50+
display: block;
51+
width: min(220px, 72vw);
52+
height: auto;
53+
margin: 0 auto 1.75rem;
54+
}
55+
.lede {
56+
text-align: center;
57+
font-size: 1.05rem;
58+
color: var(--tx-soft);
59+
margin: 0 0 2rem;
60+
line-height: 1.5;
61+
}
62+
.panel {
63+
background: var(--bg-elev);
64+
border: 1px solid var(--line);
65+
border-radius: var(--radius);
66+
padding: 1.35rem 1.25rem 1.5rem;
67+
margin-bottom: 1.25rem;
68+
}
69+
.panel + .panel { margin-top: 1.5rem; }
70+
h2 {
71+
font-size: 1rem;
72+
font-weight: 650;
73+
margin: 0 0 0.85rem;
74+
letter-spacing: -0.02em;
75+
color: var(--tx);
76+
}
77+
p {
78+
margin: 0 0 1rem;
79+
color: var(--tx-soft);
80+
font-size: 0.94rem;
81+
line-height: 1.55;
82+
}
83+
p:last-child { margin-bottom: 0; }
84+
.browser-problem {
85+
background: var(--warn-bg);
86+
border: 1px solid var(--warn-bd);
87+
border-radius: var(--radius);
88+
padding: 1rem 1.1rem;
89+
margin: 0 0 1.15rem;
90+
font-size: 0.92rem;
91+
color: var(--tx);
92+
line-height: 1.5;
93+
}
94+
.steps {
95+
list-style: none;
96+
padding: 0;
97+
margin: 0 0 1.25rem;
98+
counter-reset: s;
99+
}
100+
.steps li {
101+
position: relative;
102+
padding-left: 2.35rem;
103+
margin-bottom: 0.85rem;
104+
color: var(--tx-soft);
105+
font-size: 0.94rem;
106+
line-height: 1.5;
107+
}
108+
.steps li:last-child { margin-bottom: 0; }
109+
.steps li::before {
110+
counter-increment: s;
111+
content: counter(s);
112+
position: absolute;
113+
left: 0;
114+
top: 0.1rem;
115+
width: 1.65rem;
116+
height: 1.65rem;
117+
border-radius: 50%;
118+
background: var(--accent-soft);
119+
color: var(--accent);
120+
font-size: 0.8rem;
121+
font-weight: 700;
122+
display: flex;
123+
align-items: center;
124+
justify-content: center;
125+
}
126+
.flash-wrap {
127+
margin-top: 0.25rem;
128+
}
129+
.flash-wrap esp-web-install-button {
130+
--esp-tools-button-color: var(--accent);
131+
--esp-tools-button-text-color: #071018;
132+
--esp-tools-button-border-radius: 12px;
133+
display: block;
134+
width: 100%;
135+
}
136+
details {
137+
margin-top: 1rem;
138+
font-size: 0.88rem;
139+
color: var(--tx-soft);
140+
line-height: 1.5;
141+
}
142+
details summary {
143+
cursor: pointer;
144+
color: var(--accent);
145+
font-weight: 600;
146+
padding: 0.35rem 0;
147+
}
148+
.link-main {
149+
display: inline-block;
150+
font-size: 1.05rem;
151+
font-weight: 600;
152+
color: var(--accent);
153+
text-decoration: none;
154+
word-break: break-all;
155+
}
156+
.link-main:hover { text-decoration: underline; }
157+
code {
158+
font-family: ui-monospace, "SF Mono", monospace;
159+
font-size: 0.88em;
160+
color: var(--accent);
161+
}
162+
.fine-print {
163+
font-size: 0.85rem;
164+
margin-top: 0.9rem;
165+
padding-top: 0.9rem;
166+
border-top: 1px solid var(--line);
167+
}
48168
</style>
49169
</head>
50170
<body>
51-
<div class="wrap">
52-
<header class="brand">
53-
<h1>Azimuth</h1>
54-
<p class="sub">Flash <strong>Azimuth</strong> release firmware over USB — same look as the on-device portal.</p>
55-
</header>
171+
<div class="page">
172+
<picture>
173+
<source media="(prefers-color-scheme: light)" srcset="logo/AzimuthLogo_Dark.png"/>
174+
<img class="logo" src="logo/AzimuthLogo_Light.png" width="220" alt="Azimuth"/>
175+
</picture>
176+
177+
<p class="lede">Put the latest firmware on your tracker from the browser.</p>
56178

57-
<div class="card">
58-
<div class="hd">Install firmware</div>
59-
<p class="hint">Use a <strong>USB data</strong> cable. Works in <strong>Chrome</strong> or <strong>Edge</strong> on desktop (Web Serial). Connect your <strong>Seeed XIAO ESP32-C3</strong>, put it in <strong>bootloader</strong> if prompted (hold BOOT, tap RST, release BOOT).</p>
60-
<div class="btn-row">
61-
<esp-web-install-button manifest="manifest.json">
62-
<button slot="activate" type="button">Connect &amp; flash Azimuth</button>
63-
</esp-web-install-button>
179+
<section class="panel" aria-labelledby="h-flash">
180+
<h2 id="h-flash">Install</h2>
181+
<div id="browserProblem" class="browser-problem" hidden role="alert">
182+
Use <strong>Chrome</strong> or <strong>Edge</strong> on a <strong>computer</strong> (not a phone). This browser can’t use USB serial, so flashing from here won’t work.
64183
</div>
65-
<div class="callout">
66-
<strong>Factory reset / clean install:</strong> When the installer asks, choose to <strong>erase flash</strong> first. That clears saved Wi‑Fi and portal settings (like “Erase saved settings” on the device). Then the image is written fresh.
184+
<ol class="steps" id="installSteps">
185+
<li>Use a USB cable that carries data (not charge-only).</li>
186+
<li>Plug in a <strong>Seeed XIAO ESP32-C3</strong>.</li>
187+
<li>Click the button below and pick the serial port.</li>
188+
</ol>
189+
<div id="serialInstaller">
190+
<div class="flash-wrap">
191+
<esp-web-install-button manifest="manifest.json">
192+
<button slot="activate" type="button">Install firmware</button>
193+
</esp-web-install-button>
194+
</div>
195+
<details>
196+
<summary>Stuck? Bootloader mode</summary>
197+
Hold <strong>BOOT</strong>, tap <strong>RST</strong>, release <strong>BOOT</strong>, then try the button again.
198+
</details>
67199
</div>
68-
</div>
200+
</section>
69201

70-
<div class="card link-card">
71-
<div class="hd">After flashing</div>
72-
<p class="hint">On your home Wi‑Fi, open the settings portal (mDNS):</p>
73-
<p style="margin:0;font-size:1rem"><a href="http://azimuth.local:8080/" rel="noopener">http://azimuth.local:8080/</a></p>
74-
<p class="hint" style="margin-top:.65rem;margin-bottom:0">If <code>.local</code> does not resolve, use your router’s DHCP list for the board IP and port <strong>8080</strong>. First-time setup can use the <strong>Azimuth-Setup</strong> AP at <code>http://192.168.4.1/</code> (port 80).</p>
75-
</div>
202+
<section class="panel" aria-labelledby="h-erase">
203+
<h2 id="h-erase">Start fresh (optional)</h2>
204+
<p>If the installer asks whether to erase memory first, say yes if you want Wi‑Fi and saved settings cleared—the same idea as “erase saved settings” on the device.</p>
205+
</section>
76206

77-
<p id="msg" class="err" style="display:none"></p>
207+
<section class="panel" aria-labelledby="h-after">
208+
<h2 id="h-after">When it’s done</h2>
209+
<p>On your home network, open the setup page:</p>
210+
<p><a class="link-main" href="http://azimuth.local:8080/">azimuth.local:8080</a></p>
211+
<p class="fine-print">If that link doesn’t open, find the board in your router’s device list and use its IP with port <strong>8080</strong>. Brand-new devices can join Wi‑Fi through the <strong>Azimuth-Setup</strong> network, then open <code>192.168.4.1</code> in the browser (port 80).</p>
212+
</section>
78213
</div>
79214
<script>
80-
(function(){
81-
if(!("serial" in navigator)){
82-
var m=document.getElementById("msg");
83-
m.style.display="block";
84-
m.textContent="This browser does not support Web Serial. Use Chrome or Edge on a desktop to flash.";
85-
}
215+
(function () {
216+
if ("serial" in navigator) return;
217+
var bp = document.getElementById("browserProblem");
218+
if (bp) bp.hidden = false;
219+
var steps = document.getElementById("installSteps");
220+
if (steps) steps.hidden = true;
221+
var el = document.getElementById("serialInstaller");
222+
if (el) el.hidden = true;
86223
})();
87224
</script>
88225
</body>
386 KB
Loading
386 KB
Loading

0 commit comments

Comments
 (0)