mirror of
https://github.com/esphome/esp-web-tools.git
synced 2025-07-24 20:26:35 +00:00
Rewrite log element
This commit is contained in:
parent
3387152181
commit
357b5f9303
27
README.md
27
README.md
@ -1,8 +1,14 @@
|
|||||||
# JavaScript SDK for ESPHome
|
# JavaScript SDK for ESPHome
|
||||||
|
|
||||||
Allow flashing ESPHome or other ESP-based firmwares via the browser.
|
Allow flashing ESPHome or other ESP-based firmwares via the browser. Will automatically detect the board type and select a supported firmware.
|
||||||
|
|
||||||
Defined using a manifest.
|
```html
|
||||||
|
<esphome-web-install-button
|
||||||
|
manifest="firmware_esphome/manifest.json"
|
||||||
|
></esphome-web-install-button>
|
||||||
|
```
|
||||||
|
|
||||||
|
Manifest definition:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -17,11 +23,28 @@ Defined using a manifest.
|
|||||||
{ "filename": "ota.bin", "offset": 57344 },
|
{ "filename": "ota.bin", "offset": 57344 },
|
||||||
{ "filename": "firmware.bin", "offset": 65536 }
|
{ "filename": "firmware.bin", "offset": 65536 }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chipFamily": "ESP8266",
|
||||||
|
"parts": [
|
||||||
|
{ "filename": "esp8266.bin", "offset": 0 },
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Allows for optionally passing an attribute to trigger an erase before installation.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<esphome-web-install-button
|
||||||
|
manifest="firmware_esphome/manifest.json"
|
||||||
|
erase-first
|
||||||
|
></esphome-web-install-button>
|
||||||
|
```
|
||||||
|
|
||||||
|
All attributes can also be set via properties (`manifest`, `eraseFirst`)
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
Run `script/develop`. This starts a server. Open it on http://localhost:5000.
|
Run `script/develop`. This starts a server. Open it on http://localhost:5000.
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
<body>
|
<body>
|
||||||
<p>ESPHome Web is a set of tools to allow working with ESP devices in the browser.</p>
|
<p>ESPHome Web is a set of tools to allow working with ESP devices in the browser.</p>
|
||||||
<p>To flash the XX firmware, connect an ESP to your computer and hit the button:</p>
|
<p>To flash the XX firmware, connect an ESP to your computer and hit the button:</p>
|
||||||
<esphome-web-flash-button
|
<esphome-web-install-button
|
||||||
manifest="firmware_build/manifest.json"
|
manifest="firmware_build/manifest.json"
|
||||||
></esphome-web-flash-button>
|
></esphome-web-install-button>
|
||||||
<p><i>Note, this only works in desktop Chrome and Edge. Android support has not been implemented yet.</i></div>
|
<p><i>Note, this only works in desktop Chrome and Edge. Android support has not been implemented yet.</i></div>
|
||||||
<p>
|
<p>
|
||||||
This works by combining Web Serial with a <a href="firmware_build/manifest.json">manifest</a> which describes the firmware. It will automatically detect the type of the connected ESP device and find the right firmware files in the manifest.
|
This works by combining Web Serial with a <a href="firmware_build/manifest.json">manifest</a> which describes the firmware. It will automatically detect the type of the connected ESP device and find the right firmware files in the manifest.
|
||||||
</p>
|
</p>
|
||||||
<script src="./dist/web/flash-button.js" type="module"></script>
|
<script src="./dist/web/install-button.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -3,11 +3,12 @@ import json from "@rollup/plugin-json";
|
|||||||
import { terser } from "rollup-plugin-terser";
|
import { terser } from "rollup-plugin-terser";
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
input: "dist/flash-button.js",
|
input: "dist/install-button.js",
|
||||||
output: {
|
output: {
|
||||||
dir: "dist/web",
|
dir: "dist/web",
|
||||||
format: "module",
|
format: "module",
|
||||||
},
|
},
|
||||||
|
external: ["https://www.improv-wifi.com/sdk-js/launch-button.js"],
|
||||||
preserveEntrySignatures: false,
|
preserveEntrySignatures: false,
|
||||||
plugins: [nodeResolve(), json()],
|
plugins: [nodeResolve(), json()],
|
||||||
};
|
};
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import "./vendor/esptool";
|
|
||||||
|
|
||||||
class FlashButton extends HTMLElement {
|
|
||||||
public static isSupported = "serial" in navigator;
|
|
||||||
|
|
||||||
private renderRoot?: ShadowRoot;
|
|
||||||
|
|
||||||
public connectedCallback() {
|
|
||||||
if (this.renderRoot) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderRoot = this.attachShadow({ mode: "open" });
|
|
||||||
|
|
||||||
if (FlashButton.isSupported) {
|
|
||||||
this.addEventListener("mouseover", () => {
|
|
||||||
// Preload
|
|
||||||
import("./start-flash");
|
|
||||||
});
|
|
||||||
this.addEventListener("click", async (ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
const manifest = this.getAttribute("manifest");
|
|
||||||
if (!manifest) {
|
|
||||||
alert("No manifest defined!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mod = await import("./start-flash");
|
|
||||||
|
|
||||||
const progress = document.createElement("div");
|
|
||||||
document.body.append(progress);
|
|
||||||
|
|
||||||
await mod.startFlash(console, manifest, progress);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderRoot.innerHTML = FlashButton.isSupported
|
|
||||||
? "<slot name='activate'><button>Flash device</button></slot>"
|
|
||||||
: "<slot name='unsupported'>Your browser does not support flashing ESP devices. Use Google Chrome or Microsoft Edge.</slot>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("esphome-web-flash-button", FlashButton);
|
|
163
src/flash-log.ts
163
src/flash-log.ts
@ -1,121 +1,64 @@
|
|||||||
import { css, html, HTMLTemplateResult, LitElement, PropertyValues } from "lit";
|
import { css, html, HTMLTemplateResult, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, state } from "lit/decorators.js";
|
||||||
import { Manifest } from "./const";
|
import { classMap } from "lit/directives/class-map.js";
|
||||||
import { getChipFamilyName } from "./util";
|
|
||||||
import { ESPLoader } from "./vendor/esptool/esp_loader";
|
interface Row {
|
||||||
|
id?: string;
|
||||||
|
content: HTMLTemplateResult | string;
|
||||||
|
error?: boolean;
|
||||||
|
action?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("esphome-web-flash-log")
|
@customElement("esphome-web-flash-log")
|
||||||
class FlashLog extends LitElement {
|
class FlashLog extends LitElement {
|
||||||
@property() public offerImprov = false;
|
@state() _rows: Row[] = [];
|
||||||
|
|
||||||
@property() public esploader?: ESPLoader;
|
protected render() {
|
||||||
|
return html`${this._rows.map(
|
||||||
@property() public manifest?: Manifest;
|
(row) =>
|
||||||
|
html`<div
|
||||||
@property() public totalBytes?: number;
|
class=${classMap({
|
||||||
|
error: row.error === true,
|
||||||
@property() public bytesWritten?: number;
|
action: row.action === true,
|
||||||
|
})}
|
||||||
@property() public extraMsg: string = "";
|
|
||||||
|
|
||||||
@property() public errorMsg: string = "";
|
|
||||||
|
|
||||||
@property() public allowClose = false;
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.esploader) {
|
|
||||||
return this._renderBody(["Establishing connection..."]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const lines: Array<HTMLTemplateResult | string> = [
|
|
||||||
html`Connection established<br />`,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!this.esploader.chipFamily) {
|
|
||||||
lines.push("Initializing...");
|
|
||||||
return this._renderBody(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push(
|
|
||||||
html`Initialized. Found ${getChipFamilyName(this.esploader)}<br />`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.manifest === undefined) {
|
|
||||||
lines.push(html`Fetching manifest...<br />`);
|
|
||||||
return this._renderBody(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push(html`Found manifest for ${this.manifest.name}<br />`);
|
|
||||||
|
|
||||||
if (!this.totalBytes) {
|
|
||||||
return this._renderBody(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push(html`Bytes to be written: ${this.totalBytes}<br />`);
|
|
||||||
|
|
||||||
if (!this.bytesWritten) {
|
|
||||||
return this._renderBody(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.bytesWritten !== this.totalBytes) {
|
|
||||||
lines.push(
|
|
||||||
html`Writing progress:
|
|
||||||
${Math.floor((this.bytesWritten / this.totalBytes) * 100)}%<br />`
|
|
||||||
);
|
|
||||||
return this._renderBody(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
const doImprov =
|
|
||||||
this.offerImprov &&
|
|
||||||
customElements.get("improv-wifi-launch-button")?.isSupported;
|
|
||||||
|
|
||||||
lines.push(html`Writing complete${doImprov ? "" : ", all done!"}<br />`);
|
|
||||||
|
|
||||||
if (doImprov) {
|
|
||||||
lines.push(html`
|
|
||||||
<br />
|
|
||||||
<improv-wifi-launch-button
|
|
||||||
><button slot="activate">
|
|
||||||
Click here to finish setting up your device.
|
|
||||||
</button></improv-wifi-launch-button
|
|
||||||
>
|
>
|
||||||
`);
|
${row.content}
|
||||||
}
|
</div>`
|
||||||
|
)}`;
|
||||||
return this._renderBody(lines, !doImprov);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderBody(
|
/**
|
||||||
lines: Array<HTMLTemplateResult | string>,
|
* Add or replace a row.
|
||||||
allowClose = false
|
*/
|
||||||
) {
|
public addRow(row: Row) {
|
||||||
// allow closing if esploader not connected
|
// If last entry has same ID, replace it.
|
||||||
// or we are at the end.
|
if (
|
||||||
// TODO force allow close if not connected
|
row.id &&
|
||||||
return html`
|
this._rows.length > 0 &&
|
||||||
${lines} ${this.extraMsg}
|
this._rows[this._rows.length - 1].id === row.id
|
||||||
${allowClose
|
) {
|
||||||
? html` <br /><button @click=${this._close}>Close this dialog</button> `
|
const newRows = this._rows.slice(0, -1);
|
||||||
: ""}
|
newRows.push(row);
|
||||||
${this.errorMsg
|
this._rows = newRows;
|
||||||
? html`<div class="error">Error: ${this.errorMsg}</div>`
|
} else {
|
||||||
: ""}
|
this._rows = [...this._rows, row];
|
||||||
${this.esploader && !this.esploader.connected
|
|
||||||
? html`<div class="error">Connection lost</div>`
|
|
||||||
: ""}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(props: PropertyValues) {
|
|
||||||
super.updated(props);
|
|
||||||
|
|
||||||
if (props.has("esploader") && this.esploader) {
|
|
||||||
this.esploader.addEventListener("disconnect", () => this.requestUpdate());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _close() {
|
/**
|
||||||
this.parentElement?.removeChild(this);
|
* Add an error row
|
||||||
|
*/
|
||||||
|
public addError(content: Row["content"]) {
|
||||||
|
this.addRow({ content, error: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove last row if ID matches
|
||||||
|
*/
|
||||||
|
public removeRow(id: string) {
|
||||||
|
if (this._rows.length > 0 && this._rows[this._rows.length - 1].id === id) {
|
||||||
|
this._rows = this._rows.slice(0, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
@ -141,8 +84,12 @@ class FlashLog extends LitElement {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action,
|
||||||
.error {
|
.error {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
52
src/install-button.ts
Normal file
52
src/install-button.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
class InstallButton extends HTMLElement {
|
||||||
|
public static isSupported = "serial" in navigator;
|
||||||
|
|
||||||
|
public eraseFirst?: boolean;
|
||||||
|
|
||||||
|
private renderRoot?: ShadowRoot;
|
||||||
|
|
||||||
|
public connectedCallback() {
|
||||||
|
if (this.renderRoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderRoot = this.attachShadow({ mode: "open" });
|
||||||
|
|
||||||
|
if (!InstallButton.isSupported) {
|
||||||
|
this.renderRoot.innerHTML =
|
||||||
|
"<slot name='unsupported'>Your browser does not support installing things on ESP devices. Use Google Chrome or Microsoft Edge.</slot>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addEventListener("mouseover", () => {
|
||||||
|
// Preload
|
||||||
|
import("./start-flash");
|
||||||
|
});
|
||||||
|
this.addEventListener("click", async (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
const manifest = this.getAttribute("manifest");
|
||||||
|
if (!manifest) {
|
||||||
|
alert("No manifest defined!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = await import("./start-flash");
|
||||||
|
|
||||||
|
const progress = document.createElement("div");
|
||||||
|
document.body.append(progress);
|
||||||
|
|
||||||
|
await mod.startFlash(
|
||||||
|
console,
|
||||||
|
manifest,
|
||||||
|
progress,
|
||||||
|
this.eraseFirst !== undefined
|
||||||
|
? this.eraseFirst
|
||||||
|
: this.hasAttribute("erase-first")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.renderRoot.innerHTML = `<slot name='activate'><button>Install</button></slot>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("esphome-web-install-button", InstallButton);
|
@ -1,25 +1,23 @@
|
|||||||
import { Build, Manifest } from "./const";
|
import { html } from "lit";
|
||||||
import { connect } from "./vendor/esptool";
|
import { connect } from "./vendor/esptool";
|
||||||
import { Logger } from "./vendor/esptool/const";
|
import type { Logger } from "./vendor/esptool/const";
|
||||||
import { ESPLoader } from "./vendor/esptool/esp_loader";
|
import type { ESPLoader } from "./vendor/esptool/esp_loader";
|
||||||
|
import { Build, Manifest } from "./const";
|
||||||
import "./flash-log";
|
import "./flash-log";
|
||||||
import { getChipFamilyName } from "./util";
|
import { getChipFamilyName } from "./util";
|
||||||
|
|
||||||
export const startFlash = async (
|
export const startFlash = async (
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
manifestPath: string,
|
manifestPath: string,
|
||||||
logParent: HTMLElement
|
logParent: HTMLElement,
|
||||||
|
eraseFirst: boolean
|
||||||
) => {
|
) => {
|
||||||
const manifestURL = new URL(manifestPath, location.toString()).toString();
|
const manifestURL = new URL(manifestPath, location.toString()).toString();
|
||||||
const manifestProm = fetch(manifestURL).then(
|
const manifestProm = fetch(manifestURL).then(
|
||||||
(resp): Promise<Manifest> => resp.json()
|
(resp): Promise<Manifest> => resp.json()
|
||||||
);
|
);
|
||||||
|
|
||||||
let bytesWritten = 0;
|
|
||||||
let totalSize = 0;
|
|
||||||
|
|
||||||
let esploader: ESPLoader | undefined;
|
let esploader: ESPLoader | undefined;
|
||||||
let manifest: Manifest | undefined;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
esploader = await connect(logger);
|
esploader = await connect(logger);
|
||||||
@ -28,8 +26,12 @@ export const startFlash = async (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For debugging
|
||||||
|
(window as any).esploader = esploader;
|
||||||
|
|
||||||
const logEl = document.createElement("esphome-web-flash-log");
|
const logEl = document.createElement("esphome-web-flash-log");
|
||||||
logEl.esploader = esploader;
|
// logEl.esploader = esploader;
|
||||||
|
logEl.addRow({ id: "initializing", content: "Initializing..." });
|
||||||
logParent.append(logEl);
|
logParent.append(logEl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -37,25 +39,33 @@ export const startFlash = async (
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
if (esploader.connected) {
|
if (esploader.connected) {
|
||||||
logEl.errorMsg =
|
logEl.addError(
|
||||||
"Failed to initialize. Try resetting your device or holding the BOOT button before clicking connect.";
|
"Failed to initialize. Try resetting your device or holding the BOOT button before clicking connect."
|
||||||
|
);
|
||||||
await esploader.disconnect();
|
await esploader.disconnect();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To reflect initialized status
|
logEl.addRow({
|
||||||
logEl.requestUpdate();
|
id: "initializing",
|
||||||
|
content: html`Initialized. Found ${getChipFamilyName(esploader)}`,
|
||||||
|
});
|
||||||
|
logEl.addRow({ id: "manifest", content: "Fetching manifest..." });
|
||||||
|
|
||||||
|
let manifest: Manifest | undefined;
|
||||||
try {
|
try {
|
||||||
manifest = await manifestProm;
|
manifest = await manifestProm;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logEl.errorMsg = `Unable to fetch manifest: ${err}`;
|
logEl.addError(`Unable to fetch manifest: ${err}`);
|
||||||
await esploader.disconnect();
|
await esploader.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logEl.manifest = manifest;
|
logEl.addRow({
|
||||||
|
id: "manifest",
|
||||||
|
content: html`Found manifest for ${manifest.name}`,
|
||||||
|
});
|
||||||
|
|
||||||
const chipFamily = getChipFamilyName(esploader);
|
const chipFamily = getChipFamilyName(esploader);
|
||||||
|
|
||||||
@ -68,21 +78,15 @@ export const startFlash = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!build) {
|
if (!build) {
|
||||||
logEl.errorMsg = `Your ${chipFamily} board is not supported.`;
|
logEl.addError(`Your ${chipFamily} board is not supported.`);
|
||||||
await esploader.disconnect();
|
await esploader.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logEl.offerImprov = build.improv;
|
logEl.addRow({
|
||||||
logEl.extraMsg = "Preparing installation...";
|
id: "preparing",
|
||||||
|
content: "Preparing installation...",
|
||||||
// Pre-load improv for later
|
});
|
||||||
if (build.improv) {
|
|
||||||
// @ts-ignore
|
|
||||||
import("https://www.improv-wifi.com/sdk-js/launch-button.js");
|
|
||||||
}
|
|
||||||
|
|
||||||
(window as any).esploader = esploader;
|
|
||||||
|
|
||||||
const filePromises = build.parts.map(async (part) => {
|
const filePromises = build.parts.map(async (part) => {
|
||||||
const url = new URL(part.filename, manifestURL).toString();
|
const url = new URL(part.filename, manifestURL).toString();
|
||||||
@ -95,10 +99,17 @@ export const startFlash = async (
|
|||||||
return resp.arrayBuffer();
|
return resp.arrayBuffer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pre-load improv for later
|
||||||
|
if (build.improv) {
|
||||||
|
// @ts-ignore
|
||||||
|
import("https://www.improv-wifi.com/sdk-js/launch-button.js");
|
||||||
|
}
|
||||||
|
|
||||||
// Run the stub while we wait for files to download
|
// Run the stub while we wait for files to download
|
||||||
const espStub = await esploader.runStub();
|
const espStub = await esploader.runStub();
|
||||||
|
|
||||||
const files: ArrayBuffer[] = [];
|
const files: ArrayBuffer[] = [];
|
||||||
|
let totalSize = 0;
|
||||||
|
|
||||||
for (const prom of filePromises) {
|
for (const prom of filePromises) {
|
||||||
try {
|
try {
|
||||||
@ -106,14 +117,21 @@ export const startFlash = async (
|
|||||||
files.push(data);
|
files.push(data);
|
||||||
totalSize += data.byteLength;
|
totalSize += data.byteLength;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logEl.errorMsg = err.message;
|
logEl.addError(err.message);
|
||||||
await esploader.disconnect();
|
await esploader.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logEl.totalBytes = totalSize;
|
logEl.removeRow("preparing");
|
||||||
logEl.extraMsg = "";
|
|
||||||
|
if (eraseFirst) {
|
||||||
|
logEl.addRow({
|
||||||
|
id: "erase",
|
||||||
|
content: html`Erasing device`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let lastPct = -1;
|
let lastPct = -1;
|
||||||
|
|
||||||
for (const part of build.parts) {
|
for (const part of build.parts) {
|
||||||
@ -125,8 +143,10 @@ export const startFlash = async (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastPct = newPct;
|
lastPct = newPct;
|
||||||
bytesWritten = newBytesWritten;
|
logEl.addRow({
|
||||||
logEl.bytesWritten = bytesWritten;
|
id: "write",
|
||||||
|
content: html`Writing progress: ${newPct}%`,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
part.offset
|
part.offset
|
||||||
);
|
);
|
||||||
@ -134,7 +154,38 @@ export const startFlash = async (
|
|||||||
|
|
||||||
await esploader.softReset();
|
await esploader.softReset();
|
||||||
|
|
||||||
logEl.bytesWritten = totalSize;
|
const doImprov =
|
||||||
|
build.improv &&
|
||||||
|
customElements.get("improv-wifi-launch-button")?.isSupported;
|
||||||
|
|
||||||
|
logEl.addRow({
|
||||||
|
id: "write",
|
||||||
|
content: html`Writing
|
||||||
|
complete${doImprov
|
||||||
|
? ""
|
||||||
|
: html`, all done!<br /><br /><button
|
||||||
|
@click=${() => logParent.removeChild(logEl)}
|
||||||
|
>
|
||||||
|
Close this dialog
|
||||||
|
</button>`}`,
|
||||||
|
});
|
||||||
|
|
||||||
await esploader.disconnect();
|
await esploader.disconnect();
|
||||||
|
|
||||||
|
if (!doImprov) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: listen for improv events to know when to close dialog
|
||||||
|
logEl.addRow({
|
||||||
|
id: "improv",
|
||||||
|
action: true,
|
||||||
|
content: html`
|
||||||
|
<improv-wifi-launch-button
|
||||||
|
><button slot="activate">
|
||||||
|
Click here to finish setting up your device.
|
||||||
|
</button></improv-wifi-launch-button
|
||||||
|
>
|
||||||
|
`,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user