From fa39595c37504d7dc6afc11088774fb45648266e Mon Sep 17 00:00:00 2001 From: Petar Petrov Date: Tue, 5 Nov 2024 16:00:05 +0200 Subject: [PATCH] Fix scanning of small QR codes with JS (#22651) * Fix scanning of small QR codes with JS * fix filename * fix qr error and add device button * fix yarn.lock --- build-scripts/gulp/gather-static.js | 9 +++++ package.json | 1 + src/components/ha-qr-scanner.ts | 16 ++++++++- .../zwave_js/dialog-zwave_js-add-node.ts | 9 ++--- .../zwave_js/show-dialog-zwave_js-add-node.ts | 2 +- .../zwave_js/zwave_js-config-dashboard.ts | 3 +- yarn.lock | 34 +++++++++++++++++++ 7 files changed, 65 insertions(+), 9 deletions(-) diff --git a/build-scripts/gulp/gather-static.js b/build-scripts/gulp/gather-static.js index 8902c33dc6..c02511abff 100644 --- a/build-scripts/gulp/gather-static.js +++ b/build-scripts/gulp/gather-static.js @@ -106,6 +106,14 @@ function copyMapPanel(staticDir) { ); } +function copyZXingWasm(staticDir) { + const staticPath = genStaticPath(staticDir); + copyFileDir( + npmPath("zxing-wasm/dist/reader/zxing_reader.wasm"), + staticPath("js") + ); +} + gulp.task("copy-locale-data", async () => { const staticDir = paths.app_output_static; copyLocaleData(staticDir); @@ -143,6 +151,7 @@ gulp.task("copy-static-app", async () => { copyMapPanel(staticDir); // Qr Scanner assets + copyZXingWasm(staticDir); copyQrScannerWorker(staticDir); }); diff --git a/package.json b/package.json index 956b2bf945..6bc912e9ae 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "@webcomponents/scoped-custom-element-registry": "0.0.9", "@webcomponents/webcomponentsjs": "2.8.0", "app-datepicker": "5.1.1", + "barcode-detector": "2.2.11", "chart.js": "4.4.6", "color-name": "2.0.0", "comlink": "4.4.1", diff --git a/src/components/ha-qr-scanner.ts b/src/components/ha-qr-scanner.ts index b38d24ff7c..2869b1986d 100644 --- a/src/components/ha-qr-scanner.ts +++ b/src/components/ha-qr-scanner.ts @@ -4,6 +4,11 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; +// The BarcodeDetector Web API is not yet supported in all browsers, +// and "qr-scanner" defaults to a suboptimal implementation if it is not available. +// The following import makes a better implementation available that is based on a +// WebAssembly port of ZXing: +import { setZXingModuleOverrides } from "barcode-detector"; import type QrScanner from "qr-scanner"; import { fireEvent } from "../common/dom/fire_event"; import { stopPropagation } from "../common/dom/stop_propagation"; @@ -16,6 +21,15 @@ import "./ha-list-item"; import "./ha-textfield"; import type { HaTextField } from "./ha-textfield"; +setZXingModuleOverrides({ + locateFile: (path: string, prefix: string) => { + if (path.endsWith(".wasm")) { + return "/static/js/zxing_reader.wasm"; + } + return prefix + path; + }, +}); + @customElement("ha-qr-scanner") class HaQrScanner extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -174,7 +188,7 @@ class HaQrScanner extends LitElement { } private _qrCodeError = (err: any) => { - if (err === "No QR code found") { + if (err.endsWith("No QR code found")) { this._qrNotFoundCount++; if (this._qrNotFoundCount === 250) { this._reportError(err); diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts index ad0d87aaf5..565478d982 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts @@ -690,9 +690,6 @@ class DialogZWaveJSAddNode extends LitElement { provisioningInfo ); this._status = "provisioned"; - if (this._params?.addedCallback) { - this._params.addedCallback(); - } } catch (err: any) { this._error = err.message; this._status = "failed"; @@ -831,9 +828,6 @@ class DialogZWaveJSAddNode extends LitElement { if (message.event === "interview completed") { this._unsubscribe(); this._status = "finished"; - if (this._params?.addedCallback) { - this._params.addedCallback(); - } } if (message.event === "interview stage completed") { @@ -874,6 +868,9 @@ class DialogZWaveJSAddNode extends LitElement { } if (this._entryId) { stopZwaveInclusion(this.hass, this._entryId); + if (this._params?.onStop) { + this._params.onStop(); + } } this._requestedGrant = undefined; this._dsk = undefined; diff --git a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node.ts index d956d79d78..6c4c3b38f8 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node.ts @@ -2,7 +2,7 @@ import { fireEvent } from "../../../../../common/dom/fire_event"; export interface ZWaveJSAddNodeDialogParams { entry_id: string; - addedCallback?: () => void; + onStop?: () => void; } export const loadAddNodeDialog = () => import("./dialog-zwave_js-add-node"); diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts index 286cbd2adb..f6232ca43c 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts @@ -564,7 +564,8 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) { private async _addNodeClicked() { showZWaveJSAddNodeDialog(this, { entry_id: this.configEntryId!, - addedCallback: () => this._fetchData(), + // refresh the data after the dialog is closed. add a small delay for the inclusion state to update + onStop: () => setTimeout(() => this._fetchData(), 100), }); } diff --git a/yarn.lock b/yarn.lock index 190ad621bb..3ac463b311 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3944,6 +3944,20 @@ __metadata: languageName: node linkType: hard +"@types/dom-webcodecs@npm:^0.1.13": + version: 0.1.13 + resolution: "@types/dom-webcodecs@npm:0.1.13" + checksum: 10/99cb227416725efd4b22175ef18988ae3fc728480fe6ed2192777d7dba52d18af540b4df49fcfa3cf73753d1dcf9d5399b089702bde215d78679284848b078f7 + languageName: node + linkType: hard + +"@types/emscripten@npm:^1.39.13": + version: 1.39.13 + resolution: "@types/emscripten@npm:1.39.13" + checksum: 10/02c0446150f9cc2c74dc3a551f86ce13df266c33d8b98d11d9f17263e2d98a6a6b4d36bdd15066c4e1547ae1ed2d52eed9420116b4935d119009e0f53ddbb041 + languageName: node + linkType: hard + "@types/eslint-scope@npm:^3.7.7": version: 3.7.7 resolution: "@types/eslint-scope@npm:3.7.7" @@ -5742,6 +5756,16 @@ __metadata: languageName: node linkType: hard +"barcode-detector@npm:2.2.11": + version: 2.2.11 + resolution: "barcode-detector@npm:2.2.11" + dependencies: + "@types/dom-webcodecs": "npm:^0.1.13" + zxing-wasm: "npm:1.2.14" + checksum: 10/91f04ac8a73a5fccf15d08c2b148e3f9584448956de9b2506f5c5c3213ba133c504cd6890926f4fde2b1294e42b9943f979820440bc8373388d5a86cb6c764c5 + languageName: node + linkType: hard + "bare-events@npm:^2.2.0": version: 2.5.0 resolution: "bare-events@npm:2.5.0" @@ -8833,6 +8857,7 @@ __metadata: app-datepicker: "npm:5.1.1" babel-loader: "npm:9.2.1" babel-plugin-template-html-minifier: "npm:4.1.0" + barcode-detector: "npm:2.2.11" browserslist-useragent-regexp: "npm:4.1.3" chai: "npm:5.1.2" chart.js: "npm:4.4.6" @@ -15465,3 +15490,12 @@ __metadata: checksum: 10/f2e05b767ed3141e6372a80af9caa4715d60969227f38b1a4370d60bffe153c9c5b33a862905609afc9b375ec57cd40999810d20e5e10229a204e8bde7ef255c languageName: node linkType: hard + +"zxing-wasm@npm:1.2.14": + version: 1.2.14 + resolution: "zxing-wasm@npm:1.2.14" + dependencies: + "@types/emscripten": "npm:^1.39.13" + checksum: 10/02ea0408553f1aebb412a97c5e11887c58da1b2adff636302232535e752b91bdb3f358411259b6cddd34b341df565336bc03f48895e362f61316018d9bbff8c3 + languageName: node + linkType: hard