mirror of
https://github.com/esphome/esp-web-tools.git
synced 2025-07-24 12:16:37 +00:00
Compare commits
No commits in common. "main" and "10.0.0" have entirely different histories.
@ -66,5 +66,3 @@ Example manifest:
|
|||||||
## Development
|
## Development
|
||||||
|
|
||||||
Run `script/develop`. This starts a server. Open it on http://localhost:5001.
|
Run `script/develop`. This starts a server. Open it on http://localhost:5001.
|
||||||
|
|
||||||
[](https://www.openhomefoundation.org/)
|
|
||||||
|
57
index.html
57
index.html
@ -281,30 +281,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="name">OpenEpaperLink</div>
|
<div class="name">OpenEpaperLink</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://openspool.io" target="_blank" class="project">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="static/logos/openspool.png" alt="OpenSpool logo" />
|
|
||||||
</div>
|
|
||||||
<div class="name">OpenSpool</div>
|
|
||||||
</a>
|
|
||||||
<a href="https://usetrmnl.com/flash" target="_blank" class="project">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="static/logos/trmnl.png" alt="TRMNL logo" />
|
|
||||||
</div>
|
|
||||||
<div class="name">TRMNL</div>
|
|
||||||
</a>
|
|
||||||
<a href="https://nspanelmanager.com" target="_blank" class="project">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="static/logos/nspanelmanager.svg" alt="NSPanelManager logo" />
|
|
||||||
</div>
|
|
||||||
<div class="name">NSPanel Manager</div>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/blak3r/treadspan" target="_blank" class="project">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="static/logos/treadspan.png" alt="Treadspan logo" />
|
|
||||||
</div>
|
|
||||||
<div class="name">TreadSpan</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>How it works</h2>
|
<h2>How it works</h2>
|
||||||
@ -552,35 +528,6 @@ button.overrides = {
|
|||||||
};</pre
|
};</pre
|
||||||
>
|
>
|
||||||
|
|
||||||
<h4>Generating a manifest dynamically & version management</h4>
|
|
||||||
<p>
|
|
||||||
Alternatively to a static manifest JSON file, you can generate a Blob URL of a JSON object using <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static"><code>URL.createObjectURL</code></a> to use as the manifest url. This can be useful in situations where you have many firmware bin files, e.g. previous software versions, where you don't want to have a different static manifest json file for each bin. If you are hosting on github.io, this can be paired nicely with <a href="https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-contents">github's REST API</a> to view all the bin files inside a folder.
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
const manifest = {
|
|
||||||
"name": name,
|
|
||||||
"version": version,
|
|
||||||
"funding_url": funding_url,
|
|
||||||
"new_install_prompt_erase": true,
|
|
||||||
"builds": [
|
|
||||||
{
|
|
||||||
"chipFamily": "ESP32",
|
|
||||||
"improv": false,
|
|
||||||
"parts": [
|
|
||||||
{ "path": dependenciesDir+"bootloader.bin", "offset": 4096 },
|
|
||||||
{ "path": dependenciesDir+"partitions.bin", "offset": 32768 },
|
|
||||||
{ "path": dependenciesDir+"boot_app0.bin", "offset": 57344 },
|
|
||||||
{ "path": firmwareFile, "offset": 65536 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = JSON.stringify(manifest);
|
|
||||||
const blob = new Blob([json], {type: "application/json"});
|
|
||||||
document.querySelector("esp-web-install-button").manifest = URL.createObjectURL(blob);
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3 id="customize">Customizing the look and feel</h3>
|
<h3 id="customize">Customizing the look and feel</h3>
|
||||||
<p>
|
<p>
|
||||||
You can change the colors of the default UI elements with CSS custom
|
You can change the colors of the default UI elements with CSS custom
|
||||||
@ -634,9 +581,7 @@ document.querySelector("esp-web-install-button").manifest = URL.createObjectURL(
|
|||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="initiative">
|
<div class="initiative">
|
||||||
ESP Web Tools is a project by
|
ESP Web Tools is a project by
|
||||||
<a href="https://esphome.io">ESPHome</a>,
|
<a href="https://esphome.io">ESPHome</a>.<br />
|
||||||
<a href="https://www.openhomefoundation.org">Open Home Foundation</a
|
|
||||||
>.<br />
|
|
||||||
Development is funded by
|
Development is funded by
|
||||||
<a href="https://www.nabucasa.com">Nabu Casa</a>.
|
<a href="https://www.nabucasa.com">Nabu Casa</a>.
|
||||||
</div>
|
</div>
|
||||||
|
4157
package-lock.json
generated
4157
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "esp-web-tools",
|
"name": "esp-web-tools",
|
||||||
"version": "10.1.1",
|
"version": "10.0.1",
|
||||||
"description": "Web tools for ESP devices",
|
"description": "Web tools for ESP devices",
|
||||||
"main": "dist/install-button.js",
|
"main": "dist/install-button.js",
|
||||||
"repository": "https://github.com/esphome/esp-web-tools",
|
"repository": "https://github.com/esphome/esp-web-tools",
|
||||||
@ -10,25 +10,26 @@
|
|||||||
"prepublishOnly": "script/build"
|
"prepublishOnly": "script/build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||||
|
"@babel/plugin-transform-logical-assignment-operators": "^7.23.4",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
"@rollup/plugin-commonjs": "^28.0.2",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.1.2",
|
"@rollup/plugin-typescript": "^11.1.6",
|
||||||
"@types/w3c-web-serial": "^1.0.7",
|
"@types/w3c-web-serial": "^1.0.6",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.2.5",
|
||||||
"rollup": "^4.29.1",
|
"rollup": "^4.10.0",
|
||||||
"serve": "^14.2.4",
|
"serve": "^14.2.1",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.3.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material/web": "^2.2.0",
|
"@material/web": "^1.2.0",
|
||||||
"esptool-js": "^0.5.3",
|
"esptool-js": "^0.4.1",
|
||||||
"improv-wifi-serial-sdk": "^2.5.0",
|
"improv-wifi-serial-sdk": "^2.5.0",
|
||||||
"lit": "^3.2.1",
|
"lit": "^3.1.2",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,9 @@ const config = {
|
|||||||
}),
|
}),
|
||||||
babel({
|
babel({
|
||||||
babelHelpers: "bundled",
|
babelHelpers: "bundled",
|
||||||
presets: [
|
plugins: [
|
||||||
[
|
"@babel/plugin-proposal-class-properties",
|
||||||
"@babel/preset-env",
|
"@babel/plugin-transform-logical-assignment-operators",
|
||||||
{
|
|
||||||
targets: {
|
|
||||||
// We use unpkg as CDN and it doesn't bundle modern syntax
|
|
||||||
chrome: "84",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
json(),
|
json(),
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
# Stop on errors
|
# Stop on errors
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ -z "$PORT" ]; then
|
|
||||||
PORT=5001
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
@ -13,8 +9,8 @@ rm -rf dist
|
|||||||
trap "kill 0" EXIT
|
trap "kill 0" EXIT
|
||||||
|
|
||||||
# Run tsc once as rollup expects those files
|
# Run tsc once as rollup expects those files
|
||||||
npm exec -- tsc || true
|
tsc || true
|
||||||
|
|
||||||
npm exec -- serve -p "$PORT" &
|
npm exec -- serve -p 5001 &
|
||||||
npm exec -- tsc --watch &
|
npm exec -- tsc --watch &
|
||||||
npm exec -- rollup -c --watch
|
npm exec -- rollup -c --watch
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Checkbox } from "@material/web/checkbox/internal/checkbox.js";
|
import { Checkbox } from "@material/web/checkbox/internal/checkbox.js";
|
||||||
import { styles } from "@material/web/checkbox/internal/checkbox-styles.js";
|
import { styles } from "@material/web/checkbox/internal/checkbox-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { CircularProgress } from "@material/web/progress/internal/circular-progress.js";
|
import { CircularProgress } from "@material/web/progress/internal/circular-progress.js";
|
||||||
import { styles } from "@material/web/progress/internal/circular-progress-styles.js";
|
import { styles } from "@material/web/progress/internal/circular-progress-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Dialog } from "@material/web/dialog/internal/dialog.js";
|
import { Dialog } from "@material/web/dialog/internal/dialog.js";
|
||||||
import { styles } from "@material/web/dialog/internal/dialog-styles.js";
|
import { styles } from "@material/web/dialog/internal/dialog-styles.css";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Divider } from "@material/web/divider/internal/divider.js";
|
import { Divider } from "@material/web/divider/internal/divider.js";
|
||||||
import { styles } from "@material/web/divider/internal/divider-styles.js";
|
import { styles } from "@material/web/divider/internal/divider-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FilledSelect } from "@material/web/select/internal/filled-select.js";
|
import { FilledSelect } from "@material/web/select/internal/filled-select.js";
|
||||||
import { styles } from "@material/web/select/internal/filled-select-styles.js";
|
import { styles } from "@material/web/select/internal/filled-select-styles.css.js";
|
||||||
import { styles as sharedStyles } from "@material/web/select/internal/shared-styles.js";
|
import { styles as sharedStyles } from "@material/web/select/internal/shared-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { styles as filledStyles } from "@material/web/textfield/internal/filled-styles.js";
|
import { styles as filledStyles } from "@material/web/textfield/internal/filled-styles.css.js";
|
||||||
import { FilledTextField } from "@material/web/textfield/internal/filled-text-field.js";
|
import { FilledTextField } from "@material/web/textfield/internal/filled-text-field.js";
|
||||||
import { styles as sharedStyles } from "@material/web/textfield/internal/shared-styles.js";
|
import { styles as sharedStyles } from "@material/web/textfield/internal/shared-styles.css.js";
|
||||||
import { literal } from "lit/static-html.js";
|
import { literal } from "lit/static-html.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IconButton } from "@material/web/iconbutton/internal/icon-button.js";
|
import { IconButton } from "@material/web/iconbutton/internal/icon-button.js";
|
||||||
import { styles as sharedStyles } from "@material/web/iconbutton/internal/shared-styles.js";
|
import { styles as sharedStyles } from "@material/web/iconbutton/internal/shared-styles.css.js";
|
||||||
import { styles } from "@material/web/iconbutton/internal/standard-styles.js";
|
import { styles } from "@material/web/iconbutton/internal/standard-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ListItemEl as ListItem } from "@material/web/list/internal/listitem/list-item.js";
|
import { ListItemEl as ListItem } from "@material/web/list/internal/listitem/list-item.js";
|
||||||
import { styles } from "@material/web/list/internal/listitem/list-item-styles.js";
|
import { styles } from "@material/web/list/internal/listitem/list-item-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { List } from "@material/web/list/internal/list.js";
|
import { List } from "@material/web/list/internal/list.js";
|
||||||
import { styles } from "@material/web/list/internal/list-styles.js";
|
import { styles } from "@material/web/list/internal/list-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { styles } from "@material/web/menu/internal/menuitem/menu-item-styles.js";
|
import { styles } from "@material/web/menu/internal/menuitem/menu-item-styles.css.js";
|
||||||
import { SelectOptionEl } from "@material/web/select/internal/selectoption/select-option.js";
|
import { SelectOptionEl } from "@material/web/select/internal/selectoption/select-option.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { styles as sharedStyles } from "@material/web/button/internal/shared-styles.js";
|
import { styles as sharedStyles } from "@material/web/button/internal/shared-styles.css.js";
|
||||||
import { TextButton } from "@material/web/button/internal/text-button.js";
|
import { TextButton } from "@material/web/button/internal/text-button.js";
|
||||||
import { styles as textStyles } from "@material/web/button/internal/text-styles.js";
|
import { styles as textStyles } from "@material/web/button/internal/text-styles.css.js";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { ColoredConsole, coloredConsoleStyles } from "../util/console-color";
|
import { ColoredConsole, coloredConsoleStyles } from "../util/console-color";
|
||||||
import { sleep } from "../util/sleep";
|
import { sleep } from "../util/sleep";
|
||||||
import { LineBreakTransformer } from "../util/line-break-transformer";
|
import { LineBreakTransformer } from "../util/line-break-transformer";
|
||||||
import { TimestampTransformer } from "../util/timestamp-transformer";
|
|
||||||
import { Logger } from "../const";
|
import { Logger } from "../const";
|
||||||
|
|
||||||
export class EwtConsole extends HTMLElement {
|
export class EwtConsole extends HTMLElement {
|
||||||
@ -96,7 +95,6 @@ export class EwtConsole extends HTMLElement {
|
|||||||
signal: abortSignal,
|
signal: abortSignal,
|
||||||
})
|
})
|
||||||
.pipeThrough(new TransformStream(new LineBreakTransformer()))
|
.pipeThrough(new TransformStream(new LineBreakTransformer()))
|
||||||
.pipeThrough(new TransformStream(new TimestampTransformer()))
|
|
||||||
.pipeTo(
|
.pipeTo(
|
||||||
new WritableStream({
|
new WritableStream({
|
||||||
write: (chunk) => {
|
write: (chunk) => {
|
||||||
|
@ -21,7 +21,7 @@ export const connect = async (button: InstallButton) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await port.open({ baudRate: 115200, bufferSize: 8192 });
|
await port.open({ baudRate: 115200 });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
alert(err.message);
|
alert(err.message);
|
||||||
return;
|
return;
|
||||||
|
43
src/flash.ts
43
src/flash.ts
@ -6,7 +6,20 @@ import {
|
|||||||
Manifest,
|
Manifest,
|
||||||
FlashStateType,
|
FlashStateType,
|
||||||
} from "./const";
|
} from "./const";
|
||||||
import { hardReset } from "./util/reset";
|
import { sleep } from "./util/sleep";
|
||||||
|
|
||||||
|
const resetTransport = async (transport: Transport) => {
|
||||||
|
await transport.device.setSignals({
|
||||||
|
dataTerminalReady: false,
|
||||||
|
requestToSend: true,
|
||||||
|
});
|
||||||
|
await sleep(250);
|
||||||
|
await transport.device.setSignals({
|
||||||
|
dataTerminalReady: false,
|
||||||
|
requestToSend: false,
|
||||||
|
});
|
||||||
|
await sleep(250);
|
||||||
|
};
|
||||||
|
|
||||||
export const flash = async (
|
export const flash = async (
|
||||||
onEvent: (state: FlashState) => void,
|
onEvent: (state: FlashState) => void,
|
||||||
@ -54,14 +67,27 @@ export const flash = async (
|
|||||||
"Failed to initialize. Try resetting your device or holding the BOOT button while clicking INSTALL.",
|
"Failed to initialize. Try resetting your device or holding the BOOT button while clicking INSTALL.",
|
||||||
details: { error: FlashError.FAILED_INITIALIZING, details: err },
|
details: { error: FlashError.FAILED_INITIALIZING, details: err },
|
||||||
});
|
});
|
||||||
|
await resetTransport(transport);
|
||||||
await hardReset(transport);
|
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chipFamily = esploader.chip.CHIP_NAME as any;
|
chipFamily = esploader.chip.CHIP_NAME as any;
|
||||||
|
|
||||||
|
if (!esploader.chip.ROM_TEXT) {
|
||||||
|
fireStateEvent({
|
||||||
|
state: FlashStateType.ERROR,
|
||||||
|
message: `Chip ${chipFamily} is not supported`,
|
||||||
|
details: {
|
||||||
|
error: FlashError.NOT_SUPPORTED,
|
||||||
|
details: `Chip ${chipFamily} is not supported`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await resetTransport(transport);
|
||||||
|
await transport.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fireStateEvent({
|
fireStateEvent({
|
||||||
state: FlashStateType.INITIALIZING,
|
state: FlashStateType.INITIALIZING,
|
||||||
message: `Initialized. Found ${chipFamily}`,
|
message: `Initialized. Found ${chipFamily}`,
|
||||||
@ -76,7 +102,7 @@ export const flash = async (
|
|||||||
message: `Your ${chipFamily} board is not supported.`,
|
message: `Your ${chipFamily} board is not supported.`,
|
||||||
details: { error: FlashError.NOT_SUPPORTED, details: chipFamily },
|
details: { error: FlashError.NOT_SUPPORTED, details: chipFamily },
|
||||||
});
|
});
|
||||||
await hardReset(transport);
|
await resetTransport(transport);
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -123,7 +149,7 @@ export const flash = async (
|
|||||||
details: err.message,
|
details: err.message,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await hardReset(transport);
|
await resetTransport(transport);
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -201,7 +227,7 @@ export const flash = async (
|
|||||||
message: err.message,
|
message: err.message,
|
||||||
details: { error: FlashError.WRITE_FAILED, details: err },
|
details: { error: FlashError.WRITE_FAILED, details: err },
|
||||||
});
|
});
|
||||||
await hardReset(transport);
|
await resetTransport(transport);
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -216,8 +242,9 @@ export const flash = async (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await hardReset(transport);
|
await sleep(100);
|
||||||
|
console.log("HARD RESET");
|
||||||
|
await resetTransport(transport);
|
||||||
console.log("DISCONNECT");
|
console.log("DISCONNECT");
|
||||||
await transport.disconnect();
|
await transport.disconnect();
|
||||||
|
|
||||||
|
@ -17,8 +17,6 @@ import "./pages/ewt-page-message";
|
|||||||
import {
|
import {
|
||||||
closeIcon,
|
closeIcon,
|
||||||
listItemConsole,
|
listItemConsole,
|
||||||
listItemEraseUserData,
|
|
||||||
listItemFundDevelopment,
|
|
||||||
listItemHomeAssistant,
|
listItemHomeAssistant,
|
||||||
listItemInstallIcon,
|
listItemInstallIcon,
|
||||||
listItemVisitDevice,
|
listItemVisitDevice,
|
||||||
@ -42,7 +40,7 @@ import { version } from "./version";
|
|||||||
import type { EwFilledSelect } from "./components/ew-filled-select";
|
import type { EwFilledSelect } from "./components/ew-filled-select";
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`ESP Web Tools ${version} by Open Home Foundation; https://esphome.github.io/esp-web-tools/`,
|
`ESP Web Tools ${version} by Nabu Casa; https://esphome.github.io/esp-web-tools/`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ERROR_ICON = "⚠️";
|
const ERROR_ICON = "⚠️";
|
||||||
@ -281,7 +279,6 @@ export class EwtInstallDialog extends LitElement {
|
|||||||
href=${this._manifest.funding_url}
|
href=${this._manifest.funding_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
${listItemFundDevelopment}
|
|
||||||
<div slot="headline">Fund Development</div>
|
<div slot="headline">Fund Development</div>
|
||||||
</ew-list-item>
|
</ew-list-item>
|
||||||
`
|
`
|
||||||
@ -293,7 +290,6 @@ export class EwtInstallDialog extends LitElement {
|
|||||||
class="danger"
|
class="danger"
|
||||||
@click=${() => this._startInstall(true)}
|
@click=${() => this._startInstall(true)}
|
||||||
>
|
>
|
||||||
${listItemEraseUserData}
|
|
||||||
<div slot="headline">Erase User Data</div>
|
<div slot="headline">Erase User Data</div>
|
||||||
</ew-list-item>
|
</ew-list-item>
|
||||||
`
|
`
|
||||||
@ -923,13 +919,13 @@ export class EwtInstallDialog extends LitElement {
|
|||||||
if (state.state === FlashStateType.FINISHED) {
|
if (state.state === FlashStateType.FINISHED) {
|
||||||
sleep(100)
|
sleep(100)
|
||||||
// Flashing closes the port
|
// Flashing closes the port
|
||||||
.then(() => this.port.open({ baudRate: 115200, bufferSize: 8192 }))
|
.then(() => this.port.open({ baudRate: 115200 }))
|
||||||
.then(() => this._initialize(true))
|
.then(() => this._initialize(true))
|
||||||
.then(() => this.requestUpdate());
|
.then(() => this.requestUpdate());
|
||||||
} else if (state.state === FlashStateType.ERROR) {
|
} else if (state.state === FlashStateType.ERROR) {
|
||||||
sleep(100)
|
sleep(100)
|
||||||
// Flashing closes the port
|
// Flashing closes the port
|
||||||
.then(() => this.port.open({ baudRate: 115200, bufferSize: 8192 }));
|
.then(() => this.port.open({ baudRate: 115200 }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
this.port,
|
this.port,
|
||||||
|
@ -6,7 +6,6 @@ interface ConsoleState {
|
|||||||
foregroundColor: string | null;
|
foregroundColor: string | null;
|
||||||
backgroundColor: string | null;
|
backgroundColor: string | null;
|
||||||
carriageReturn: boolean;
|
carriageReturn: boolean;
|
||||||
lines: string[];
|
|
||||||
secret: boolean;
|
secret: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +18,6 @@ export class ColoredConsole {
|
|||||||
foregroundColor: null,
|
foregroundColor: null,
|
||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
carriageReturn: false,
|
carriageReturn: false,
|
||||||
lines: [],
|
|
||||||
secret: false,
|
secret: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,13 +27,25 @@ export class ColoredConsole {
|
|||||||
return this.targetElement.innerText;
|
return this.targetElement.innerText;
|
||||||
}
|
}
|
||||||
|
|
||||||
processLine(line: string): Element {
|
addLine(line: string) {
|
||||||
// @ts-expect-error
|
|
||||||
const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
|
const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
|
if (this.state.carriageReturn) {
|
||||||
|
if (line !== "\n") {
|
||||||
|
// don't remove if \r\n
|
||||||
|
this.targetElement.removeChild(this.targetElement.lastChild!);
|
||||||
|
}
|
||||||
|
this.state.carriageReturn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.includes("\r")) {
|
||||||
|
this.state.carriageReturn = true;
|
||||||
|
}
|
||||||
|
|
||||||
const lineSpan = document.createElement("span");
|
const lineSpan = document.createElement("span");
|
||||||
lineSpan.classList.add("line");
|
lineSpan.classList.add("line");
|
||||||
|
this.targetElement.appendChild(lineSpan);
|
||||||
|
|
||||||
const addSpan = (content: string) => {
|
const addSpan = (content: string) => {
|
||||||
if (content === "") return;
|
if (content === "") return;
|
||||||
@ -168,52 +178,17 @@ export class ColoredConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addSpan(line.substring(i));
|
|
||||||
return lineSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
processLines() {
|
|
||||||
const atBottom =
|
const atBottom =
|
||||||
this.targetElement.scrollTop >
|
this.targetElement.scrollTop >
|
||||||
this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50;
|
this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50;
|
||||||
const prevCarriageReturn = this.state.carriageReturn;
|
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
|
|
||||||
if (this.state.lines.length == 0) {
|
addSpan(line.substring(i));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const line of this.state.lines) {
|
|
||||||
if (this.state.carriageReturn && line !== "\n") {
|
|
||||||
if (fragment.childElementCount) {
|
|
||||||
fragment.removeChild(fragment.lastChild!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment.appendChild(this.processLine(line));
|
|
||||||
this.state.carriageReturn = line.includes("\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevCarriageReturn && this.state.lines[0] !== "\n") {
|
|
||||||
this.targetElement.replaceChild(fragment, this.targetElement.lastChild!);
|
|
||||||
} else {
|
|
||||||
this.targetElement.appendChild(fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.lines = [];
|
|
||||||
|
|
||||||
// Keep scroll at bottom
|
// Keep scroll at bottom
|
||||||
if (atBottom) {
|
if (atBottom) {
|
||||||
this.targetElement.scrollTop = this.targetElement.scrollHeight;
|
this.targetElement.scrollTop = this.targetElement.scrollHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addLine(line: string) {
|
|
||||||
// Processing of lines is deferred for performance reasons
|
|
||||||
if (this.state.lines.length == 0) {
|
|
||||||
setTimeout(() => this.processLines(), 0);
|
|
||||||
}
|
|
||||||
this.state.lines.push(line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const coloredConsoleStyles = `
|
export const coloredConsoleStyles = `
|
||||||
|
@ -8,7 +8,7 @@ export class LineBreakTransformer implements Transformer<string, string> {
|
|||||||
// Append new chunks to existing chunks.
|
// Append new chunks to existing chunks.
|
||||||
this.chunks += chunk;
|
this.chunks += chunk;
|
||||||
// For each line breaks in chunks, send the parsed lines out.
|
// For each line breaks in chunks, send the parsed lines out.
|
||||||
const lines = this.chunks.split(/\r?\n/);
|
const lines = this.chunks.split("\r\n");
|
||||||
this.chunks = lines.pop()!;
|
this.chunks = lines.pop()!;
|
||||||
lines.forEach((line) => controller.enqueue(line + "\r\n"));
|
lines.forEach((line) => controller.enqueue(line + "\r\n"));
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import { Transport } from "esptool-js";
|
|
||||||
import { sleep } from "./sleep";
|
|
||||||
|
|
||||||
export const hardReset = async (transport: Transport) => {
|
|
||||||
console.log("Triggering reset");
|
|
||||||
await transport.device.setSignals({
|
|
||||||
dataTerminalReady: false,
|
|
||||||
requestToSend: true,
|
|
||||||
});
|
|
||||||
await sleep(250);
|
|
||||||
await transport.device.setSignals({
|
|
||||||
dataTerminalReady: false,
|
|
||||||
requestToSend: false,
|
|
||||||
});
|
|
||||||
await sleep(250);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
export class TimestampTransformer implements Transformer<string, string> {
|
|
||||||
transform(
|
|
||||||
chunk: string,
|
|
||||||
controller: TransformStreamDefaultController<string>,
|
|
||||||
) {
|
|
||||||
const date = new Date();
|
|
||||||
const h = date.getHours().toString().padStart(2, "0");
|
|
||||||
const m = date.getMinutes().toString().padStart(2, "0");
|
|
||||||
const s = date.getSeconds().toString().padStart(2, "0");
|
|
||||||
controller.enqueue(`[${h}:${m}:${s}]${chunk}`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,156 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="95.541344mm"
|
|
||||||
height="29.999447mm"
|
|
||||||
viewBox="0 0 95.54134 29.999447"
|
|
||||||
version="1.1"
|
|
||||||
id="svg5"
|
|
||||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
|
||||||
sodipodi:docname="logo.svg"
|
|
||||||
inkscape:export-filename="/home/erik/Documents/Projekt/NSPanel Manager/Logos/logo250.png"
|
|
||||||
inkscape:export-xdpi="76.010269"
|
|
||||||
inkscape:export-ydpi="76.010269"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview7"
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pagecheckerboard="false"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="1.3404872"
|
|
||||||
inkscape:cx="174.5634"
|
|
||||||
inkscape:cy="71.988753"
|
|
||||||
inkscape:window-width="1366"
|
|
||||||
inkscape:window-height="704"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="layer2"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:guide-bbox="true"
|
|
||||||
fit-margin-top="5"
|
|
||||||
fit-margin-left="7"
|
|
||||||
fit-margin-right="7"
|
|
||||||
fit-margin-bottom="5" />
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
style="display:inline"
|
|
||||||
transform="translate(-23.806324,-37.155967)">
|
|
||||||
<rect
|
|
||||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583"
|
|
||||||
id="rect91625"
|
|
||||||
width="16.863066"
|
|
||||||
height="1.0996726"
|
|
||||||
x="30.938616"
|
|
||||||
y="59.758064" />
|
|
||||||
<rect
|
|
||||||
style="fill:#000000;stroke:#000000;stroke-width:0.473039"
|
|
||||||
id="rect91761"
|
|
||||||
width="66.510048"
|
|
||||||
height="0.89121634"
|
|
||||||
x="31.042845"
|
|
||||||
y="42.392487" />
|
|
||||||
<rect
|
|
||||||
style="fill:#000000;stroke:#000000;stroke-width:0.34752"
|
|
||||||
id="rect91763"
|
|
||||||
width="31.46484"
|
|
||||||
height="1.0167363"
|
|
||||||
x="80.709068"
|
|
||||||
y="59.79953" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer2"
|
|
||||||
inkscape:label="Layer 2"
|
|
||||||
style="display:inline"
|
|
||||||
transform="translate(-23.806324,-37.155967)">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:0;font-family:sans-serif;letter-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
|
||||||
x="64.189873"
|
|
||||||
y="56.76144"
|
|
||||||
id="text39249"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.4056px;line-height:0.55;font-family:Hamlin;-inkscape-font-specification:'Hamlin, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
|
|
||||||
x="64.189873"
|
|
||||||
y="56.76144"
|
|
||||||
id="tspan62001">NSPANEL</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93889px;line-height:1.55;font-family:Hamlin;-inkscape-font-specification:'Hamlin Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
|
|
||||||
x="64.189873"
|
|
||||||
y="62.091209"
|
|
||||||
id="tspan73527">MANAGER</tspan></text>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer3"
|
|
||||||
inkscape:label="Layer 3"
|
|
||||||
transform="translate(-23.806324,-37.155967)">
|
|
||||||
<g
|
|
||||||
id="g91894"
|
|
||||||
transform="matrix(0.15910033,0,0,0.15910033,102.25849,44.830316)">
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
id="layer1-1"
|
|
||||||
transform="translate(-30.269979,-9.7200098)"
|
|
||||||
style="display:inline;fill:#ffc101;fill-opacity:1">
|
|
||||||
<path
|
|
||||||
style="fill:#ffc101;fill-opacity:1;stroke-width:0.103892"
|
|
||||||
d="m 55.789326,41.355207 -7.50621,-0.0036 c -8.143469,-0.0039 -15.508914,-0.135689 -16.902471,-0.302478 -0.482408,-0.05774 -0.940146,-0.168019 -1.017198,-0.245069 -0.115522,-0.115523 -0.121188,-0.512246 -0.03231,-2.261925 0.23677,-4.661121 1.011239,-7.815267 2.954845,-12.034057 2.163281,-4.695621 5.19604,-8.340625 9.101253,-10.938592 2.710535,-1.8032 6.982591,-3.536303 9.582241,-3.887359 0.270422,-0.03652 0.543941,-0.129371 0.60782,-0.20634 0.06388,-0.07697 0.286764,-0.168201 0.495299,-0.202735 0.208537,-0.03453 0.449284,-0.09017 0.534995,-0.123628 0.168484,-0.06577 0.381034,-0.08553 1.215776,-0.112981 l 0.540477,-0.01778 0.03093,-0.649326 0.03093,-0.6493272 h 1.610329 1.610329 l 0.03093,0.6493272 0.03093,0.649326 0.540477,0.01778 c 0.834742,0.02745 1.047292,0.04721 1.215776,0.112981 0.08571,0.03346 0.326458,0.08909 0.534995,0.123628 0.208535,0.03453 0.43142,0.125765 0.495299,0.202735 0.06388,0.07697 0.337398,0.169823 0.60782,0.20634 1.199505,0.161981 3.423686,0.820696 4.997483,1.480058 3.507719,1.469604 6.221358,3.303143 8.667596,5.856479 2.140092,2.233788 3.602852,4.416791 5.018415,7.489412 1.943606,4.21879 2.718075,7.372936 2.954845,12.034057 0.08888,1.749679 0.08321,2.146402 -0.03231,2.261925 -0.07705,0.07705 -0.53479,0.187332 -1.017198,0.245069 -1.393557,0.166789 -8.759002,0.298597 -16.902471,0.302478 l -7.50621,0.0036 z"
|
|
||||||
id="path1465"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:export-xdpi="15.183412"
|
|
||||||
inkscape:export-ydpi="15.183412"
|
|
||||||
sodipodi:nodetypes="csssssssssscccccccccscssssssssccc" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1 copy"
|
|
||||||
id="g2878"
|
|
||||||
transform="translate(-30.269979,-9.7200098)"
|
|
||||||
style="display:inline">
|
|
||||||
<path
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke-width:0.103892"
|
|
||||||
d="m 54.334834,101.13608 c -3.956539,-0.21732 -5.98252,-0.58093 -6.463066,-1.159955 -0.09761,-0.11762 -0.123549,-0.57148 -0.09916,-1.73541 0.02799,-1.33577 0.008,-1.59689 -0.130816,-1.71212 -0.09011,-0.0748 -0.16384,-0.29294 -0.16384,-0.48477 0,-0.30436 0.05486,-0.37678 0.430667,-0.5685 0.694102,-0.3541 2.301256,-0.71174 4.060659,-0.9036 l 1.638312,-0.17866 V 70.783119 c 0,-15.670705 -0.03494,-23.609951 -0.103892,-23.609951 -0.05714,0 -0.103892,-0.0935 -0.103892,-0.207784 0,-0.194592 0.06926,-0.207784 1.090868,-0.207784 0.900399,0 1.090868,-0.02721 1.090868,-0.155839 0,-0.08571 0.04675,-0.155838 0.103892,-0.155838 0.06644,0 0.103892,-3.463072 0.103892,-5.090716 l 2.493412,-2e-6 c 0,1.627644 0.03746,5.090716 0.103892,5.090716 0.05714,0 0.103892,0.07013 0.103892,0.155838 0,0.128629 0.190469,0.155839 1.090868,0.155839 1.021606,0 1.090868,0.01319 1.090868,0.207784 0,0.114281 -0.04675,0.207784 -0.103892,0.207784 -0.06896,0 -0.103892,7.939246 -0.103892,23.609951 v 23.609948 l 1.638312,0.17866 c 1.759403,0.19186 3.366557,0.54949 4.060659,0.9036 0.375812,0.19172 0.430667,0.26413 0.430667,0.5685 0,0.19183 -0.07373,0.40998 -0.16384,0.48476 -0.138668,0.11509 -0.158971,0.37643 -0.132144,1.70097 0.01743,0.86075 -0.0055,1.62411 -0.05099,1.69635 -0.27864,0.442605 -1.632284,0.804945 -3.803075,1.017985 -1.460176,0.14331 -6.726732,0.26812 -8.109225,0.19219 z"
|
|
||||||
id="path2876"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:export-xdpi="15.183412"
|
|
||||||
inkscape:export-ydpi="15.183412"
|
|
||||||
sodipodi:nodetypes="ssssssscssssssccsssssscssssscsss" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="layer3-5"
|
|
||||||
inkscape:label="Layer 3">
|
|
||||||
<circle
|
|
||||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:17.1351;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
|
|
||||||
id="path1510"
|
|
||||||
cx="34.837666"
|
|
||||||
cy="55.072739"
|
|
||||||
r="1.2872558" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="layer2-9"
|
|
||||||
inkscape:label="Layer 2">
|
|
||||||
<rect
|
|
||||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:12.8043;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
|
|
||||||
id="rect1508"
|
|
||||||
width="1.3904994"
|
|
||||||
height="22.681686"
|
|
||||||
x="34.147842"
|
|
||||||
y="31.601988" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
Before Width: | Height: | Size: 213 KiB |
Binary file not shown.
Before Width: | Height: | Size: 106 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.5 KiB |
Loading…
x
Reference in New Issue
Block a user