Skip to content

Commit d04f70e

Browse files
committed
[feat] Add esptool logs to install web dialog
1 parent 37934e7 commit d04f70e

File tree

4 files changed

+155
-5
lines changed

4 files changed

+155
-5
lines changed

src/install-web/index.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,39 @@
1+
import type { IEspLoaderTerminal } from "esptool-js";
12
import { openNoPortPickedDialog } from "../no-port-picked";
23
import { createESPLoader } from "../web-serial/create-esploader";
34
import type { ESPHomeInstallWebDialog } from "./install-web-dialog";
45

6+
export class ESPLoaderTerminalStream {
7+
public stream: ReadableStream;
8+
public terminal: IEspLoaderTerminal;
9+
private controller?: ReadableStreamDefaultController<any>;
10+
11+
constructor() {
12+
const _this = this;
13+
this.stream = new ReadableStream({
14+
start(controller) {
15+
_this.controller = controller;
16+
},
17+
});
18+
19+
this.terminal = {
20+
clean: () => {
21+
this.controller?.enqueue("\n\n\n");
22+
},
23+
writeLine: (data: string) => {
24+
console.log(data);
25+
this.controller?.enqueue(`${data}\n`);
26+
},
27+
write: (data: string) => {
28+
console.log(data);
29+
// Fix "Connecting..." line break
30+
if (data == "\n\r") this.controller?.enqueue("\n");
31+
else this.controller?.enqueue(data);
32+
},
33+
};
34+
}
35+
}
36+
537
export const preloadInstallWebDialog = () => import("./install-web-dialog");
638

739
export const openInstallWebDialog = async (
@@ -30,7 +62,10 @@ export const openInstallWebDialog = async (
3062
return;
3163
}
3264
}
33-
const esploader = createESPLoader(port);
65+
66+
const terminalStream = new ESPLoaderTerminalStream();
67+
68+
const esploader = createESPLoader(port, terminalStream.terminal);
3469

3570
if (onDialogOpen) {
3671
onDialogOpen();
@@ -39,5 +74,6 @@ export const openInstallWebDialog = async (
3974
const dialog = document.createElement("esphome-install-web-dialog");
4075
dialog.params = params;
4176
dialog.esploader = esploader;
77+
dialog.stream = terminalStream.stream;
4278
document.body.append(dialog);
4379
};

src/install-web/install-console.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { ColoredConsole, coloredConsoleStyles } from "../util/console-color";
2+
import { Logger } from "../const";
3+
4+
export class InstallConsole extends HTMLElement {
5+
public port!: SerialPort;
6+
public logger!: Logger;
7+
8+
private _console?: ColoredConsole;
9+
10+
public logs(): string {
11+
return this._console?.logs() || "";
12+
}
13+
14+
public addLine(line: string) {
15+
this._console?.addLine(line);
16+
}
17+
18+
public connectedCallback() {
19+
if (this._console) {
20+
return;
21+
}
22+
const shadowRoot = this.attachShadow({ mode: "open" });
23+
24+
shadowRoot.innerHTML = `
25+
<style>
26+
:host, input {
27+
background-color: #1c1c1c;
28+
color: #ddd;
29+
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
30+
monospace;
31+
line-height: 1.45;
32+
display: flex;
33+
flex-direction: column;
34+
}
35+
form {
36+
display: flex;
37+
align-items: center;
38+
padding: 0 8px 0 16px;
39+
}
40+
input {
41+
flex: 1;
42+
padding: 4px;
43+
margin: 0 8px;
44+
border: 0;
45+
outline: none;
46+
}
47+
${coloredConsoleStyles}
48+
</style>
49+
<div class="log"></div>
50+
`;
51+
52+
this._console = new ColoredConsole(this.shadowRoot!.querySelector("div")!);
53+
}
54+
}
55+
56+
customElements.define("install-console", InstallConsole);
57+
58+
declare global {
59+
interface HTMLElementTagNameMap {
60+
"install-console": InstallConsole;
61+
}
62+
}

src/install-web/install-web-dialog.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { LitElement, html, PropertyValues, css, TemplateResult } from "lit";
2-
import { customElement, property, state } from "lit/decorators.js";
2+
import { customElement, property, query, state } from "lit/decorators.js";
33
import "@material/mwc-dialog";
44
import "@material/mwc-circular-progress";
55
import "@material/mwc-button";
66
import type { ESPLoader } from "esptool-js";
7+
import "./install-console";
8+
import type { InstallConsole } from "./install-console";
79
import {
810
compileConfiguration,
911
Configuration,
@@ -43,6 +45,9 @@ export class ESPHomeInstallWebDialog extends LitElement {
4345
};
4446

4547
@property() public esploader!: ESPLoader;
48+
@property() public stream?: ReadableStream;
49+
50+
@query("install-console") private _console!: InstallConsole;
4651

4752
@state() private _writeProgress?: number;
4853

@@ -56,6 +61,23 @@ export class ESPHomeInstallWebDialog extends LitElement {
5661

5762
private _platform?: ValueOf<typeof chipFamilyToPlatform>;
5863

64+
@property() private _showLogs = false;
65+
66+
connectedCallback() {
67+
super.connectedCallback();
68+
69+
// this._console won't be defined until after the first paint
70+
setTimeout(() => {
71+
this.stream?.pipeTo(
72+
new WritableStream({
73+
write: (chunk) => {
74+
this._console.addLine(chunk);
75+
},
76+
}),
77+
);
78+
});
79+
}
80+
5981
protected render() {
6082
let heading;
6183
let content;
@@ -106,6 +128,8 @@ export class ESPHomeInstallWebDialog extends LitElement {
106128
}
107129
}
108130

131+
hideActions = false;
132+
109133
return html`
110134
<mwc-dialog
111135
open
@@ -115,6 +139,14 @@ export class ESPHomeInstallWebDialog extends LitElement {
115139
.hideActions=${hideActions}
116140
>
117141
${content}
142+
<install-console
143+
class="${this._showLogs ? "" : "hidden"}"
144+
></install-console>
145+
<mwc-button
146+
slot="secondaryAction"
147+
@click=${this._toggleLogs}
148+
label="${this._showLogs ? "Hide" : "Show"} Logs"
149+
></mwc-button>
118150
</mwc-dialog>
119151
`;
120152
}
@@ -148,7 +180,7 @@ export class ESPHomeInstallWebDialog extends LitElement {
148180
<div class="icon">${icon}</div>
149181
${label}
150182
</div>
151-
${showClose
183+
${showClose || true
152184
? html`
153185
<mwc-button
154186
slot="primaryAction"
@@ -303,6 +335,10 @@ export class ESPHomeInstallWebDialog extends LitElement {
303335
return await getConfigurationFiles(configuration);
304336
}
305337

338+
private _toggleLogs() {
339+
this._showLogs = !this._showLogs;
340+
}
341+
306342
private _close() {
307343
this.shadowRoot!.querySelector("mwc-dialog")!.close();
308344
}
@@ -317,6 +353,18 @@ export class ESPHomeInstallWebDialog extends LitElement {
317353
static styles = [
318354
esphomeDialogStyles,
319355
css`
356+
install-console {
357+
width: 500px;
358+
height: 300px;
359+
margin-top: 16px;
360+
overflow: hidden;
361+
transition: all 0.2s ease-in-out;
362+
}
363+
install-console.hidden {
364+
margin-top: 0;
365+
width: 230px;
366+
height: 0;
367+
}
320368
mwc-list-item {
321369
margin: 0 -20px;
322370
}

src/web-serial/create-esploader.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { Transport, ESPLoader } from "esptool-js";
1+
import { Transport, ESPLoader, IEspLoaderTerminal } from "esptool-js";
22

3-
export const createESPLoader = (port: SerialPort) => {
3+
export const createESPLoader = (
4+
port: SerialPort,
5+
terminal?: IEspLoaderTerminal,
6+
) => {
47
const transport = new Transport(port);
58
return new ESPLoader({
69
transport,
710
baudrate: 115200,
811
romBaudrate: 115200,
912
enableTracing: false,
13+
terminal,
1014
});
1115
};

0 commit comments

Comments
 (0)