From ba85feb548db894654a5f76ba300c1ec3e5ce2ec Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen <balloob@gmail.com> Date: Tue, 3 Jan 2023 15:58:37 -0500 Subject: [PATCH] Configure wifi improvements (#304) * Add timeout to improv provisioning * Add refresh SSIDs button * Hide password if insecured wifi * Bump serial sdk 2.4.0 --- package-lock.json | 16 +++--- package.json | 2 +- src/components/svg.ts | 9 +++ src/install-dialog.ts | 124 ++++++++++++++++++++++++++++-------------- 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index e54ec2cb..211ad7ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@material/mwc-icon-button": "^0.27.0", "@material/mwc-textfield": "^0.27.0", "esptool-js": "github:espressif/esptool-js#076af269f44daa5b7823031221f39bf22124c129", - "improv-wifi-serial-sdk": "^2.3.0", + "improv-wifi-serial-sdk": "^2.4.0", "lit": "^2.5.0", "pako": "^2.1.0", "tslib": "^2.4.1" @@ -2050,13 +2050,14 @@ } }, "node_modules/improv-wifi-serial-sdk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/improv-wifi-serial-sdk/-/improv-wifi-serial-sdk-2.3.0.tgz", - "integrity": "sha512-z5wiuM0uAiLL/Ifc2ZwdEBpGqpjJsUv0MS12kRqMgI01C8mn58ZSEVwoxExpOPUfX8dZL5kdrpYygqM+VfhCJQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/improv-wifi-serial-sdk/-/improv-wifi-serial-sdk-2.4.0.tgz", + "integrity": "sha512-QiWbGMZdXN4LsyiS0hml0NY9D5hpmje1092SrKcFzGTuAiHpOJOfNTalD/Zl3hAd1LuN4XJLS3JCfa6ntoV8KQ==", "dependencies": { "@material/mwc-button": "^0.27.0", "@material/mwc-circular-progress": "^0.27.0", "@material/mwc-dialog": "^0.27.0", + "@material/mwc-icon-button": "^0.27.0", "@material/mwc-list": "^0.27.0", "@material/mwc-select": "^0.27.0", "@material/mwc-textfield": "^0.27.0", @@ -4525,13 +4526,14 @@ "dev": true }, "improv-wifi-serial-sdk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/improv-wifi-serial-sdk/-/improv-wifi-serial-sdk-2.3.0.tgz", - "integrity": "sha512-z5wiuM0uAiLL/Ifc2ZwdEBpGqpjJsUv0MS12kRqMgI01C8mn58ZSEVwoxExpOPUfX8dZL5kdrpYygqM+VfhCJQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/improv-wifi-serial-sdk/-/improv-wifi-serial-sdk-2.4.0.tgz", + "integrity": "sha512-QiWbGMZdXN4LsyiS0hml0NY9D5hpmje1092SrKcFzGTuAiHpOJOfNTalD/Zl3hAd1LuN4XJLS3JCfa6ntoV8KQ==", "requires": { "@material/mwc-button": "^0.27.0", "@material/mwc-circular-progress": "^0.27.0", "@material/mwc-dialog": "^0.27.0", + "@material/mwc-icon-button": "^0.27.0", "@material/mwc-list": "^0.27.0", "@material/mwc-select": "^0.27.0", "@material/mwc-textfield": "^0.27.0", diff --git a/package.json b/package.json index b818ca9f..46bae73a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@material/mwc-icon-button": "^0.27.0", "@material/mwc-textfield": "^0.27.0", "esptool-js": "github:espressif/esptool-js#076af269f44daa5b7823031221f39bf22124c129", - "improv-wifi-serial-sdk": "^2.3.0", + "improv-wifi-serial-sdk": "^2.4.0", "lit": "^2.5.0", "pako": "^2.1.0", "tslib": "^2.4.1" diff --git a/src/components/svg.ts b/src/components/svg.ts index a9cb1451..e7f23674 100644 --- a/src/components/svg.ts +++ b/src/components/svg.ts @@ -25,3 +25,12 @@ export const chipIcon = svg` /> </svg> `; + +export const refreshIcon = svg` + <svg viewBox="0 0 24 24"> + <path + fill="currentColor" + d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" + /> + </svg> +`; diff --git a/src/install-dialog.ts b/src/install-dialog.ts index 36485a09..6e2c3d63 100644 --- a/src/install-dialog.ts +++ b/src/install-dialog.ts @@ -12,7 +12,12 @@ import "./components/ewt-select"; import "./components/ewt-list-item"; import "./pages/ewt-page-progress"; import "./pages/ewt-page-message"; -import { chipIcon, closeIcon, firmwareIcon } from "./components/svg"; +import { + chipIcon, + closeIcon, + firmwareIcon, + refreshIcon, +} from "./components/svg"; import { Logger, Manifest, FlashStateType, FlashState } from "./const.js"; import { ImprovSerial, Ssid } from "improv-wifi-serial-sdk/dist/serial"; import { @@ -74,8 +79,8 @@ export class EwtInstallDialog extends LitElement { // null = not available @state() private _ssids?: Ssid[] | null; - // -1 = custom - @state() private _selectedSsid = -1; + // Name of Ssid. Null = other + @state() private _selectedSsid: string | null = null; protected render() { if (!this.port) { @@ -416,6 +421,10 @@ export class EwtInstallDialog extends LitElement { error = "Unable to connect"; break; + case ImprovSerialErrorState.TIMEOUT: + error = "Timeout"; + break; + case ImprovSerialErrorState.NO_ERROR: // Happens when list SSIDs not supported. case ImprovSerialErrorState.UNKNOWN_RPC_COMMAND: @@ -424,6 +433,9 @@ export class EwtInstallDialog extends LitElement { default: error = `Unknown error (${this._client!.error})`; } + const selectedSsid = this._ssids?.find( + (info) => info.name === this._selectedSsid + ); content = html` <div> Enter the credentials of the Wi-Fi network that you want your device @@ -439,42 +451,48 @@ export class EwtInstallDialog extends LitElement { const index = ev.detail.index; // The "Join Other" item is always the last item. this._selectedSsid = - index === this._ssids!.length ? -1 : index; + index === this._ssids!.length + ? null + : this._ssids![index].name; }} @closed=${(ev: Event) => ev.stopPropagation()} > ${this._ssids!.map( - (info, idx) => html` + (info) => html` <ewt-list-item - .selected=${this._selectedSsid === idx} - value=${idx} + .selected=${selectedSsid === info} + .value=${info.name} > ${info.name} </ewt-list-item> ` )} - <ewt-list-item - .selected=${this._selectedSsid === -1} - value="-1" - > + <ewt-list-item .selected=${!selectedSsid} value="-1"> Join other… </ewt-list-item> </ewt-select> + <ewt-icon-button @click=${this._updateSsids}> + ${refreshIcon} + </ewt-icon-button> ` : ""} ${ // Show input box if command not supported or "Join Other" selected - this._selectedSsid === -1 + !selectedSsid ? html` <ewt-textfield label="Network Name" name="ssid"></ewt-textfield> ` : "" } - <ewt-textfield - label="Password" - name="password" - type="password" - ></ewt-textfield> + ${!selectedSsid || selectedSsid.secured + ? html` + <ewt-textfield + label="Password" + name="password" + type="password" + ></ewt-textfield> + ` + : ""} <ewt-button slot="primaryAction" label="Connect" @@ -701,20 +719,7 @@ export class EwtInstallDialog extends LitElement { } // Scan for SSIDs on provision if (this._state === "PROVISION") { - this._ssids = undefined; - this._busy = true; - this._client!.scan().then( - (ssids) => { - this._busy = false; - this._ssids = ssids; - this._selectedSsid = ssids.length ? 0 : -1; - }, - () => { - this._busy = false; - this._ssids = null; - this._selectedSsid = -1; - } - ); + this._updateSsids(); } else { // Reset this value if we leave provisioning. this._provisionForce = false; @@ -726,6 +731,41 @@ export class EwtInstallDialog extends LitElement { } } + private async _updateSsids() { + const oldSsids = this._ssids; + this._ssids = undefined; + this._busy = true; + + let ssids: Ssid[]; + + try { + ssids = await this._client!.scan(); + } catch (err) { + // When we fail on first load, pick "Join other" + if (this._ssids === undefined) { + this._ssids = null; + this._selectedSsid = null; + } + this._busy = false; + return; + } + + if (oldSsids) { + // If we had a previous list, ensure the selection is still valid + if ( + this._selectedSsid && + !ssids.find((s) => s.name === this._selectedSsid) + ) { + this._selectedSsid = ssids[0].name; + } + } else { + this._selectedSsid = ssids.length ? ssids[0].name : null; + } + + this._ssids = ssids; + this._busy = false; + } + protected override firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); this._initialize(); @@ -742,7 +782,7 @@ export class EwtInstallDialog extends LitElement { return; } - if (changedProps.has("_selectedSsid") && this._selectedSsid === -1) { + if (changedProps.has("_selectedSsid") && this._selectedSsid === null) { // If we pick "Join other", select SSID input. this._focusFormElement("ewt-textfield[name=ssid]"); } else if (changedProps.has("_ssids")) { @@ -855,20 +895,21 @@ export class EwtInstallDialog extends LitElement { this._wasProvisioned = this._client!.state === ImprovSerialCurrentState.PROVISIONED; const ssid = - this._selectedSsid === -1 + this._selectedSsid === null ? ( this.shadowRoot!.querySelector( "ewt-textfield[name=ssid]" ) as EwtTextfield ).value - : this._ssids![this._selectedSsid].name; - const password = ( - this.shadowRoot!.querySelector( - "ewt-textfield[name=password]" - ) as EwtTextfield - ).value; + : this._selectedSsid; + const password = + ( + this.shadowRoot!.querySelector( + "ewt-textfield[name=password]" + ) as EwtTextfield | null + )?.value || ""; try { - await this._client!.provision(ssid, password); + await this._client!.provision(ssid, password, 30000); } catch (err: any) { return; } finally { @@ -975,6 +1016,9 @@ export class EwtInstallDialog extends LitElement { width: calc(80vw - 48px); height: 80vh; } + ewt-list-item[value="-1"] { + border-top: 1px solid #ccc; + } `, ]; }