FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: add online firmware flasher · txp666/electronBot-docs@2dcfcb2 · GitHub

Commit 2dcfcb2

Browse files
committed
feat: add online firmware flasher
1 parent 6f218ce commit 2dcfcb2

6 files changed

Lines changed: 365 additions & 0 deletions

File tree

‎docs/downloads.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ sidebar_position: 5
55
---
66

77
import useBaseUrl from '@docusaurus/useBaseUrl';
8+
import FirmwareFlasher from '@site/src/components/FirmwareFlasher';
89

910
export const ImgWithBaseUrl = ({src, alt, width}) => (
1011
<img src={useBaseUrl(src)} alt={alt} width={width ? width : undefined} />
@@ -14,6 +15,8 @@ export const ImgWithBaseUrl = ({src, alt, width}) => (
1415

1516
在这里,您可以找到 electronBot 相关的所有程序文件和源代码链接。
1617

18+
<FirmwareFlasher defaultVersion="v2.0.4" />
19+
1720
## 源代码仓库
1821

1922
### ESP32+AI 版本源代码
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import React, {useEffect, useMemo, useState} from 'react';
2+
import useBaseUrl from '@docusaurus/useBaseUrl';
3+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
4+
import styles from './styles.module.css';
5+
6+
const ESP_WEB_TOOLS_SCRIPT =
7+
'https://unpkg.com/esp-web-tools@10/dist/web/install-button.js?module';
8+
9+
const scriptId = 'esp-web-tools-install-button';
10+
let espWebToolsPromise;
11+
12+
const firmwareOptions = [
13+
{
14+
version: 'v2.0.4',
15+
date: '2025-11-3',
16+
bin: '/files/electronBot2.0.4.bin',
17+
manifest: '/files/electronBot2.0.4-web-flash-manifest.json',
18+
},
19+
{
20+
version: 'v1.1.3',
21+
date: '2025-6-13',
22+
bin: '/files/electronBot1.1.3.bin',
23+
manifest: '/files/electronBot1.1.3-web-flash-manifest.json',
24+
},
25+
];
26+
27+
function loadEspWebTools() {
28+
if (typeof document === 'undefined') {
29+
return Promise.resolve();
30+
}
31+
32+
if (window.customElements?.get('esp-web-install-button')) {
33+
return Promise.resolve();
34+
}
35+
36+
if (!espWebToolsPromise) {
37+
espWebToolsPromise = new Promise((resolve, reject) => {
38+
let script = document.getElementById(scriptId);
39+
40+
if (!script) {
41+
script = document.createElement('script');
42+
script.id = scriptId;
43+
script.type = 'module';
44+
script.src = ESP_WEB_TOOLS_SCRIPT;
45+
document.head.appendChild(script);
46+
}
47+
48+
script.addEventListener('load', () => {
49+
window.customElements.whenDefined('esp-web-install-button').then(resolve);
50+
});
51+
script.addEventListener('error', reject);
52+
});
53+
}
54+
55+
return espWebToolsPromise;
56+
}
57+
58+
export default function FirmwareFlasher({defaultVersion = 'v2.0.4'}) {
59+
const {
60+
i18n: {currentLocale},
61+
} = useDocusaurusContext();
62+
const locale = currentLocale === 'en' ? 'en' : 'zh';
63+
const [selectedVersion, setSelectedVersion] = useState(defaultVersion);
64+
const [supportState, setSupportState] = useState('checking');
65+
const [installerState, setInstallerState] = useState('loading');
66+
const selectedFirmware =
67+
firmwareOptions.find((firmware) => firmware.version === selectedVersion) ||
68+
firmwareOptions[0];
69+
const manifestUrl = useBaseUrl(selectedFirmware.manifest);
70+
const downloadUrl = useBaseUrl(selectedFirmware.bin);
71+
72+
const copy = useMemo(() => {
73+
if (locale === 'en') {
74+
return {
75+
eyebrow: 'Online flashing',
76+
title: `One-click flash ${selectedFirmware.version}`,
77+
description:
78+
'Connect electronBot to this computer with USB, click the flash button, then choose the local serial port in the browser prompt.',
79+
firmwareLabel: 'Firmware version',
80+
download: 'Download selected firmware',
81+
flashButton: 'Start online flashing',
82+
installerLoading: 'Loading online flashing tool...',
83+
installerUnavailable:
84+
'The online flashing tool could not be loaded. Check the network connection or use the firmware download link.',
85+
requirements:
86+
'Use Chrome or Edge on HTTPS or localhost. Hold BOOT while powering on if this is the first flash.',
87+
supported: 'Ready. The browser will ask you to select a serial port.',
88+
insecure:
89+
'Online flashing requires HTTPS or localhost. Open this page from the published site or a local dev server.',
90+
unsupported:
91+
'This browser does not support Web Serial. Please use Chrome or Edge on desktop, or use ESPTool manually.',
92+
notAllowed:
93+
'Serial access is blocked by this page or browser policy. Try Chrome/Edge on the published HTTPS site.',
94+
loading: 'Checking browser support...',
95+
};
96+
}
97+
98+
return {
99+
eyebrow: '在线烧录',
100+
title: `一键烧录 ${selectedFirmware.version}`,
101+
description:
102+
'用 USB 把 electronBot 连接到这台电脑,点击烧录按钮后,在浏览器弹窗里选择本机串口即可写入固件。',
103+
firmwareLabel: '固件版本',
104+
download: '下载所选固件',
105+
flashButton: '开始在线烧录',
106+
installerLoading: '正在加载在线烧录工具...',
107+
installerUnavailable: '在线烧录工具加载失败。请检查网络连接,或先下载固件后手动烧录。',
108+
requirements:
109+
'请使用 Chrome 或 Edge,并通过 HTTPS 或 localhost 打开本页。首次烧录时,请按住 BOOT 再打开电源。',
110+
supported: '已就绪。浏览器会请求选择本地串口。',
111+
insecure: '在线烧录需要 HTTPS 或 localhost。请从正式网站或本地开发服务器打开本页。',
112+
unsupported: '当前浏览器不支持 Web Serial。请在电脑端使用 Chrome/Edge,或改用 ESPTool 手动烧录。',
113+
notAllowed: '当前页面或浏览器策略禁止串口访问。请使用电脑端 Chrome/Edge 打开 HTTPS 正式网站。',
114+
loading: '正在检查浏览器支持...',
115+
};
116+
}, [locale, selectedFirmware.version]);
117+
118+
useEffect(() => {
119+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
120+
return;
121+
}
122+
123+
if (!window.isSecureContext) {
124+
setSupportState('insecure');
125+
setInstallerState('blocked');
126+
return;
127+
}
128+
129+
const hasSerial = 'serial' in navigator;
130+
setSupportState(hasSerial ? 'supported' : 'unsupported');
131+
132+
if (!hasSerial) {
133+
setInstallerState('blocked');
134+
return;
135+
}
136+
137+
loadEspWebTools()
138+
.then(() => setInstallerState('ready'))
139+
.catch(() => setInstallerState('error'));
140+
}, []);
141+
142+
const statusText =
143+
installerState === 'error'
144+
? copy.installerUnavailable
145+
: installerState === 'loading' && supportState === 'supported'
146+
? copy.installerLoading
147+
: supportState === 'checking'
148+
? copy.loading
149+
: supportState === 'supported'
150+
? copy.supported
151+
: supportState === 'insecure'
152+
? copy.insecure
153+
: copy.unsupported;
154+
155+
return (
156+
<section className={styles.wrapper} aria-labelledby="online-flasher-title">
157+
<div className={styles.header}>
158+
<span className={styles.eyebrow}>{copy.eyebrow}</span>
159+
<h2 id="online-flasher-title" className={styles.title}>
160+
{copy.title}
161+
</h2>
162+
<p className={styles.description}>{copy.description}</p>
163+
</div>
164+
165+
<div className={styles.selectorRow}>
166+
<label className={styles.field}>
167+
<span className={styles.fieldLabel}>{copy.firmwareLabel}</span>
168+
<select
169+
className={styles.select}
170+
value={selectedFirmware.version}
171+
onChange={(event) => setSelectedVersion(event.target.value)}>
172+
{firmwareOptions.map((firmware) => (
173+
<option key={firmware.version} value={firmware.version}>
174+
{firmware.version} · {firmware.date}
175+
</option>
176+
))}
177+
</select>
178+
</label>
179+
<a className={styles.downloadLink} href={downloadUrl}>
180+
{copy.download}
181+
</a>
182+
</div>
183+
184+
<div className={styles.actions}>
185+
{installerState === 'ready' ? (
186+
<esp-web-install-button
187+
key={selectedFirmware.version}
188+
manifest={manifestUrl}>
189+
<button slot="activate" className="button button--primary">
190+
{copy.flashButton}
191+
</button>
192+
<span slot="unsupported">{copy.unsupported}</span>
193+
<span slot="not-allowed">{copy.notAllowed}</span>
194+
</esp-web-install-button>
195+
) : (
196+
<button className="button button--primary" type="button" disabled>
197+
{copy.flashButton}
198+
</button>
199+
)}
200+
<p className={styles.status}>{statusText}</p>
201+
</div>
202+
203+
<p className={styles.requirements}>{copy.requirements}</p>
204+
</section>
205+
);
206+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
.wrapper {
2+
border: 1px solid var(--ifm-color-emphasis-300);
3+
border-radius: 8px;
4+
padding: 1.25rem;
5+
margin: 1.5rem 0 2rem;
6+
background: var(--ifm-background-surface-color);
7+
}
8+
9+
.header {
10+
max-width: 760px;
11+
}
12+
13+
.eyebrow {
14+
display: inline-flex;
15+
align-items: center;
16+
min-height: 1.5rem;
17+
margin-bottom: 0.35rem;
18+
color: var(--ifm-color-primary-dark);
19+
font-size: 0.875rem;
20+
font-weight: 700;
21+
}
22+
23+
.title {
24+
margin-bottom: 0.5rem;
25+
}
26+
27+
.description {
28+
margin-bottom: 0;
29+
color: var(--ifm-color-emphasis-800);
30+
}
31+
32+
.selectorRow {
33+
display: flex;
34+
flex-wrap: wrap;
35+
align-items: flex-end;
36+
gap: 0.85rem 1rem;
37+
margin-top: 1rem;
38+
}
39+
40+
.field {
41+
display: flex;
42+
flex-direction: column;
43+
gap: 0.35rem;
44+
min-width: min(100%, 280px);
45+
}
46+
47+
.fieldLabel {
48+
color: var(--ifm-color-emphasis-700);
49+
font-size: 0.9rem;
50+
font-weight: 700;
51+
}
52+
53+
.select {
54+
min-height: 2.5rem;
55+
border: 1px solid var(--ifm-color-emphasis-300);
56+
border-radius: 6px;
57+
padding: 0 2rem 0 0.75rem;
58+
background: var(--ifm-background-color);
59+
color: var(--ifm-font-color-base);
60+
font: inherit;
61+
}
62+
63+
.downloadLink {
64+
min-height: 2.5rem;
65+
display: inline-flex;
66+
align-items: center;
67+
font-weight: 700;
68+
}
69+
70+
.actions {
71+
display: flex;
72+
flex-wrap: wrap;
73+
align-items: center;
74+
gap: 0.85rem 1rem;
75+
margin-top: 1rem;
76+
}
77+
78+
.status {
79+
margin: 0;
80+
color: var(--ifm-color-emphasis-700);
81+
font-size: 0.95rem;
82+
}
83+
84+
.requirements {
85+
margin: 1rem 0 0;
86+
color: var(--ifm-color-emphasis-700);
87+
font-size: 0.95rem;
88+
}
89+
90+
[data-theme='dark'] .eyebrow {
91+
color: var(--ifm-color-primary-light);
92+
}
93+
94+
@media (max-width: 480px) {
95+
.wrapper {
96+
padding: 1rem;
97+
}
98+
99+
.actions,
100+
.selectorRow {
101+
align-items: flex-start;
102+
flex-direction: column;
103+
}
104+
105+
.downloadLink {
106+
min-height: auto;
107+
}
108+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "electronBot ESP32+AI v2.0.4",
3+
"version": "2.0.4",
4+
"new_install_prompt_erase": true,
5+
"builds": [
6+
{
7+
"chipFamily": "ESP32-S3",
8+
"parts": [
9+
{
10+
"path": "electronBot2.0.4.bin",
11+
"offset": 0
12+
}
13+
]
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "electronBot ESP32+AI v1.1.3",
3+
"version": "1.1.3",
4+
"new_install_prompt_erase": true,
5+
"builds": [
6+
{
7+
"chipFamily": "ESP32-S3",
8+
"parts": [
9+
{
10+
"path": "electronBot1.1.3.bin",
11+
"offset": 0
12+
}
13+
]
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "electronBot ESP32+AI v2.0.4",
3+
"version": "2.0.4",
4+
"new_install_prompt_erase": true,
5+
"builds": [
6+
{
7+
"chipFamily": "ESP32-S3",
8+
"parts": [
9+
{
10+
"path": "electronBot2.0.4.bin",
11+
"offset": 0
12+
}
13+
]
14+
}
15+
]
16+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL