From c885d08a32ca6b4050f367597284058d4b42177a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 3 Apr 2023 16:43:59 -0400 Subject: [PATCH 01/13] Merge runPipeline code and allow picking language (#16018) * Merge runPipeline code and allow picking language * Add download button * Allow to continue audio conversations once stopped --- src/data/voice_assistant.ts | 45 +++- .../assist/assist-pipeline-debug.ts | 234 +++++++++++------- .../assist/assist-render-pipeline-run.ts | 17 +- 3 files changed, 189 insertions(+), 107 deletions(-) diff --git a/src/data/voice_assistant.ts b/src/data/voice_assistant.ts index c332e19267..9b5ae8f65d 100644 --- a/src/data/voice_assistant.ts +++ b/src/data/voice_assistant.ts @@ -84,7 +84,7 @@ type PipelineRunEvent = | PipelineTTSStartEvent | PipelineTTSEndEvent; -interface PipelineRunOptions { +export interface PipelineRunOptions { start_stage: "stt" | "intent" | "tts"; end_stage: "stt" | "intent" | "tts"; language?: string; @@ -99,13 +99,15 @@ export interface PipelineRun { stage: "ready" | "stt" | "intent" | "tts" | "done" | "error"; run: PipelineRunStartEvent["data"]; error?: PipelineErrorEvent["data"]; - stt?: PipelineSTTStartEvent["data"] & Partial; + stt?: PipelineSTTStartEvent["data"] & + Partial & { done: boolean }; intent?: PipelineIntentStartEvent["data"] & - Partial; - tts?: PipelineTTSStartEvent["data"] & Partial; + Partial & { done: boolean }; + tts?: PipelineTTSStartEvent["data"] & + Partial & { done: boolean }; } -export const runPipelineFromText = ( +export const runVoiceAssistantPipeline = ( hass: HomeAssistant, callback: (event: PipelineRun) => void, options: PipelineRunOptions @@ -139,17 +141,38 @@ export const runPipelineFromText = ( } if (updateEvent.type === "stt-start") { - run = { ...run, stage: "stt", stt: updateEvent.data }; + run = { + ...run, + stage: "stt", + stt: { ...updateEvent.data, done: false }, + }; } else if (updateEvent.type === "stt-end") { - run = { ...run, stt: { ...run.stt!, ...updateEvent.data } }; + run = { + ...run, + stt: { ...run.stt!, ...updateEvent.data, done: true }, + }; } else if (updateEvent.type === "intent-start") { - run = { ...run, stage: "intent", intent: updateEvent.data }; + run = { + ...run, + stage: "intent", + intent: { ...updateEvent.data, done: false }, + }; } else if (updateEvent.type === "intent-end") { - run = { ...run, intent: { ...run.intent!, ...updateEvent.data } }; + run = { + ...run, + intent: { ...run.intent!, ...updateEvent.data, done: true }, + }; } else if (updateEvent.type === "tts-start") { - run = { ...run, stage: "tts", tts: updateEvent.data }; + run = { + ...run, + stage: "tts", + tts: { ...updateEvent.data, done: false }, + }; } else if (updateEvent.type === "tts-end") { - run = { ...run, tts: { ...run.tts!, ...updateEvent.data } }; + run = { + ...run, + tts: { ...run.tts!, ...updateEvent.data, done: true }, + }; } else if (updateEvent.type === "run-end") { run = { ...run, stage: "done" }; unsubProm.then((unsub) => unsub()); diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts index c0dcd3d5af..49906ad2a9 100644 --- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts +++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug.ts @@ -1,20 +1,25 @@ -import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import "../../../../../../components/ha-button"; import { PipelineRun, - runPipelineFromText, + PipelineRunOptions, + runVoiceAssistantPipeline, } from "../../../../../../data/voice_assistant"; import "../../../../../../layouts/hass-subpage"; import "../../../../../../components/ha-formfield"; import "../../../../../../components/ha-checkbox"; import { haStyle } from "../../../../../../resources/styles"; import type { HomeAssistant } from "../../../../../../types"; -import { showPromptDialog } from "../../../../../../dialogs/generic/show-dialog-box"; +import { + showAlertDialog, + showPromptDialog, +} from "../../../../../../dialogs/generic/show-dialog-box"; import "./assist-render-pipeline-run"; import type { HaCheckbox } from "../../../../../../components/ha-checkbox"; import type { HaTextField } from "../../../../../../components/ha-textfield"; import "../../../../../../components/ha-textfield"; +import { fileDownload } from "../../../../../../util/file_download"; @customElement("assist-pipeline-debug") export class AssistPipelineDebug extends LitElement { @@ -24,8 +29,6 @@ export class AssistPipelineDebug extends LitElement { @state() private _pipelineRuns: PipelineRun[] = []; - @state() private _stopRecording?: () => void; - @query("#continue-conversation") private _continueConversationCheckbox!: HaCheckbox; @@ -36,6 +39,8 @@ export class AssistPipelineDebug extends LitElement { @state() private _finished = false; + @state() private _languageOverride?: string; + protected render(): TemplateResult { return html` Clear + + Download + ` - : ""} + : html` + + Set Language + + `}
@@ -81,6 +96,12 @@ export class AssistPipelineDebug extends LitElement { Send ` + : this._finished + ? html` + + Continue talking + + ` : html` { - if (this._continueConversationCheckbox.checked) { - this._runAudioPipeline(); - } else { - this._finished = true; - } - }); - audio.play(); - } else if (currentRun.stage === "error") { - this._finished = true; - } - } - private get conversationId(): string | null { return this._pipelineRuns.length === 0 ? null @@ -177,26 +151,19 @@ export class AssistPipelineDebug extends LitElement { return; } - let added = false; - runPipelineFromText( - this.hass, + await this._doRunPipeline( (run) => { - if (textfield && ["done", "error"].includes(run.stage)) { - textfield.value = ""; - } - - if (added) { - this._pipelineRuns = [run, ...this._pipelineRuns.slice(1)]; - } else { - this._pipelineRuns = [run, ...this._pipelineRuns]; - added = true; + if (["done", "error"].includes(run.stage)) { + this._finished = true; + if (textfield) { + textfield.value = ""; + } } }, { start_stage: "intent", end_stage: "intent", input: { text }, - conversation_id: this.conversationId, } ); } @@ -204,7 +171,13 @@ export class AssistPipelineDebug extends LitElement { private async _runAudioPipeline() { // @ts-ignore-next-line const context = new (window.AudioContext || window.webkitAudioContext)(); - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + let stream: MediaStream; + try { + stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + } catch (err) { + return; + } + await context.audioWorklet.addModule( new URL("./recorder.worklet.js", import.meta.url) ); @@ -213,47 +186,111 @@ export class AssistPipelineDebug extends LitElement { const recorder = new AudioWorkletNode(context, "recorder.worklet"); this.hass.connection.socket!.binaryType = "arraybuffer"; - this._stopRecording = () => { + + let run: PipelineRun | undefined; + + let stopRecording: (() => void) | undefined = () => { + stopRecording = undefined; + // We're currently STTing, so finish audio + if (run?.stage === "stt" && run.stt!.done === false) { + if (this._audioBuffer) { + for (const chunk of this._audioBuffer) { + this._sendAudioChunk(chunk); + } + } + // Send empty message to indicate we're done streaming. + this._sendAudioChunk(new Int16Array()); + } + this._audioBuffer = undefined; stream.getTracks()[0].stop(); context.close(); - this._stopRecording = undefined; - this._audioBuffer = undefined; - // Send empty message to indicate we're done streaming. - this._sendAudioChunk(new Int16Array()); }; this._audioBuffer = []; source.connect(recorder).connect(context.destination); recorder.port.onmessage = (e) => { + if (!stopRecording) { + return; + } if (this._audioBuffer) { this._audioBuffer.push(e.data); - return; + } else { + this._sendAudioChunk(e.data); } - if (this._pipelineRuns[0].stage !== "stt") { - return; - } - this._sendAudioChunk(e.data); }; - this._finished = false; - let added = false; - runPipelineFromText( - this.hass, - (run) => { - if (added) { - this._pipelineRuns = [run, ...this._pipelineRuns.slice(1)]; - } else { - this._pipelineRuns = [run, ...this._pipelineRuns]; - added = true; + await this._doRunPipeline( + (updatedRun) => { + run = updatedRun; + + // When we start STT stage, the WS has a binary handler + if (updatedRun.stage === "stt" && this._audioBuffer) { + // Send the buffer over the WS to the STT engine. + for (const buffer of this._audioBuffer) { + this._sendAudioChunk(buffer); + } + this._audioBuffer = undefined; + } + + // Stop recording if the server is done with STT stage + if (!["ready", "stt"].includes(updatedRun.stage) && stopRecording) { + stopRecording(); + } + + // Play audio when we're done. + if (updatedRun.stage === "done") { + const url = updatedRun.tts!.tts_output!.url; + const audio = new Audio(url); + audio.addEventListener("ended", () => { + if (this._continueConversationCheckbox.checked) { + this._runAudioPipeline(); + } else { + this._finished = true; + } + }); + audio.play(); + } else if (updatedRun.stage === "error") { + this._finished = true; } }, { start_stage: "stt", end_stage: "tts", - conversation_id: this.conversationId, } ); } + private async _doRunPipeline( + callback: (event: PipelineRun) => void, + options: PipelineRunOptions + ) { + this._finished = false; + let added = false; + try { + await runVoiceAssistantPipeline( + this.hass, + (updatedRun) => { + if (added) { + this._pipelineRuns = [updatedRun, ...this._pipelineRuns.slice(1)]; + } else { + this._pipelineRuns = [updatedRun, ...this._pipelineRuns]; + added = true; + } + callback(updatedRun); + }, + { + ...options, + language: this._languageOverride, + conversation_id: this.conversationId, + } + ); + } catch (err: any) { + await showAlertDialog(this, { + title: "Error starting pipeline", + text: err.message || err, + }); + } + } + private _sendAudioChunk(chunk: Int16Array) { // Turn into 8 bit so we can prefix our handler ID. const data = new Uint8Array(1 + chunk.length * 2); @@ -273,6 +310,27 @@ export class AssistPipelineDebug extends LitElement { this._pipelineRuns = []; } + private _downloadConversation() { + fileDownload( + `data:text/plain;charset=utf-8,${encodeURIComponent( + JSON.stringify(this._pipelineRuns, null, 2) + )}`, + `conversation.json` + ); + } + + private async _setLanguage() { + const language = await showPromptDialog(this, { + title: "Language override", + inputLabel: "Language", + inputType: "text", + confirmText: "Set", + }); + if (language) { + this._languageOverride = language; + } + } + static styles = [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts index f9940e0cb2..596b7f7560 100644 --- a/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts +++ b/src/panels/config/integrations/integration-panels/voice_assistant/assist/assist-render-pipeline-run.ts @@ -50,9 +50,11 @@ const maybeRenderError = ( return ""; } - return html` - ${run.error!.message} (${run.error!.code}) - `; + return html` + + ${run.error!.message} (${run.error!.code}) + + `; }; const renderProgress = ( @@ -76,10 +78,9 @@ const renderProgress = ( } if (!finishEvent) { - return html``; + return html` + + `; } const duration = @@ -109,7 +110,7 @@ const dataMinusKeysRender = ( const result = {}; let render = false; for (const key in data) { - if (key in keys) { + if (key in keys || key === "done") { continue; } render = true; From 61a7652ae1e9591d7b6f230bdc26ab995f9c50b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 23:29:49 -0400 Subject: [PATCH 02/13] Update dependency @webcomponents/scoped-custom-element-registry to v0.0.9 (#16025) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b8e655dc0f..510548c912 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@vibrant/core": "3.2.1-alpha.1", "@vibrant/quantizer-mmcq": "3.2.1-alpha.1", "@vue/web-component-wrapper": "1.3.0", - "@webcomponents/scoped-custom-element-registry": "0.0.8", + "@webcomponents/scoped-custom-element-registry": "0.0.9", "@webcomponents/webcomponentsjs": "2.7.0", "app-datepicker": "5.1.1", "chart.js": "3.3.2", diff --git a/yarn.lock b/yarn.lock index 38cd20991c..be31c25744 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5179,10 +5179,10 @@ __metadata: languageName: node linkType: hard -"@webcomponents/scoped-custom-element-registry@npm:0.0.8": - version: 0.0.8 - resolution: "@webcomponents/scoped-custom-element-registry@npm:0.0.8" - checksum: b758bd34723834eedeabe53decadeaa3a655a0fb6b264f1ad55d9fb617f1cff44c72f7722e78cfb953a82c06f85c1e640929d65e775df85202c34419091d2cdf +"@webcomponents/scoped-custom-element-registry@npm:0.0.9": + version: 0.0.9 + resolution: "@webcomponents/scoped-custom-element-registry@npm:0.0.9" + checksum: 02595d7b184a04fab16b12599f80a3e405ed9cee347e42079423bf4b7d4c794201d1553d818c0663d83c8b047a77eec7b32318267927673bd4218eb0f75a1b5e languageName: node linkType: hard @@ -9535,7 +9535,7 @@ __metadata: "@vue/web-component-wrapper": 1.3.0 "@web/dev-server": 0.1.37 "@web/dev-server-rollup": 0.4.0 - "@webcomponents/scoped-custom-element-registry": 0.0.8 + "@webcomponents/scoped-custom-element-registry": 0.0.9 "@webcomponents/webcomponentsjs": 2.7.0 app-datepicker: 5.1.1 babel-loader: 9.1.2 From 12918580acea03d93be25cb09fd330fa41728006 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 03:48:54 +0000 Subject: [PATCH 03/13] Update dependency webpack-dev-server to v4.13.2 (#16049) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 510548c912..dff68a7454 100644 --- a/package.json +++ b/package.json @@ -245,7 +245,7 @@ "vinyl-source-stream": "2.0.0", "webpack": "=5.72.1", "webpack-cli": "5.0.1", - "webpack-dev-server": "4.13.1", + "webpack-dev-server": "4.13.2", "webpack-manifest-plugin": "5.0.0", "webpackbar": "5.0.2", "workbox-build": "6.5.4" diff --git a/yarn.lock b/yarn.lock index be31c25744..6f2f140b90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9633,7 +9633,7 @@ __metadata: vue2-daterange-picker: 0.6.8 webpack: =5.72.1 webpack-cli: 5.0.1 - webpack-dev-server: 4.13.1 + webpack-dev-server: 4.13.2 webpack-manifest-plugin: 5.0.0 webpackbar: 5.0.2 weekstart: 2.0.0 @@ -15863,9 +15863,9 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:4.13.1": - version: 4.13.1 - resolution: "webpack-dev-server@npm:4.13.1" +"webpack-dev-server@npm:4.13.2": + version: 4.13.2 + resolution: "webpack-dev-server@npm:4.13.2" dependencies: "@types/bonjour": ^3.5.9 "@types/connect-history-api-fallback": ^1.3.5 @@ -15906,7 +15906,7 @@ __metadata: optional: true bin: webpack-dev-server: bin/webpack-dev-server.js - checksum: f70611544b7d964a31eb3d934d7c2b376b97e6927a89e03b2e21cfa5812bb639625cd18fd350de1604ba6c455b324135523a894032f28c69d90d90682e4f3b7d + checksum: 9bf573abf05b0e0f1e8219820f6264e25a0f8ee6aebed3c0d0449c24a37f88b575972e0a2bec426112ee37d48c8f5090e7754aa1873206d3c9b6344a54718232 languageName: node linkType: hard From 9764a0f23fcb4fe0952d94dbb60edfb6f482a65d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 00:35:27 -0400 Subject: [PATCH 04/13] Update dependency @webcomponents/webcomponentsjs to v2.8.0 (#16026) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index dff68a7454..e2680fd09d 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "@vibrant/quantizer-mmcq": "3.2.1-alpha.1", "@vue/web-component-wrapper": "1.3.0", "@webcomponents/scoped-custom-element-registry": "0.0.9", - "@webcomponents/webcomponentsjs": "2.7.0", + "@webcomponents/webcomponentsjs": "2.8.0", "app-datepicker": "5.1.1", "chart.js": "3.3.2", "comlink": "4.4.1", diff --git a/yarn.lock b/yarn.lock index 6f2f140b90..9804be8337 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5193,10 +5193,10 @@ __metadata: languageName: node linkType: hard -"@webcomponents/webcomponentsjs@npm:2.7.0": - version: 2.7.0 - resolution: "@webcomponents/webcomponentsjs@npm:2.7.0" - checksum: df60a5faf79d85eba334a42f7bffb101f0e01a8ee8cc3705f17c67c70247415c4440ad6e8fdd3c74dc5be097a436c4e4831824bef039a12b69f05e84a07187b7 +"@webcomponents/webcomponentsjs@npm:2.8.0": + version: 2.8.0 + resolution: "@webcomponents/webcomponentsjs@npm:2.8.0" + checksum: 186373c0308a35abf4e97228b1cc5a5dc5c694701ccef2046baa1598636b08be5ec16baff2770584fef1aa241837fc36316f0b415396202eb444b36aa1a01117 languageName: node linkType: hard @@ -9536,7 +9536,7 @@ __metadata: "@web/dev-server": 0.1.37 "@web/dev-server-rollup": 0.4.0 "@webcomponents/scoped-custom-element-registry": 0.0.9 - "@webcomponents/webcomponentsjs": 2.7.0 + "@webcomponents/webcomponentsjs": 2.8.0 app-datepicker: 5.1.1 babel-loader: 9.1.2 babel-plugin-template-html-minifier: 4.1.0 From 99e6547807772a67744a11a28dac2772d8831dce Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 4 Apr 2023 13:36:33 +0200 Subject: [PATCH 05/13] Fix fan speed for new more info and tile feature (#16050) --- src/data/cover.ts | 11 +++++--- src/data/fan.ts | 10 ++++--- .../components/fan/ha-more-info-fan-speed.ts | 27 ++++++++++--------- .../more-info/controls/more-info-fan.ts | 5 ++-- src/panels/lovelace/cards/hui-tile-card.ts | 5 ++-- .../hui-fan-speed-tile-feature.ts | 20 +++++++------- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/data/cover.ts b/src/data/cover.ts index 8a47b1528c..af372dd5a9 100644 --- a/src/data/cover.ts +++ b/src/data/cover.ts @@ -2,6 +2,7 @@ import { HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; +import { stateActive } from "../common/entity/state_active"; import { supportsFeature } from "../common/entity/supports-feature"; import { blankBeforePercent } from "../common/translations/blank_before_percent"; import { UNAVAILABLE } from "./entity"; @@ -114,10 +115,12 @@ export function computeCoverPositionStateDisplay( locale: FrontendLocaleData, position?: number ) { - const currentPosition = - position ?? - stateObj.attributes.current_position ?? - stateObj.attributes.current_tilt_position; + const statePosition = stateActive(stateObj) + ? stateObj.attributes.current_position ?? + stateObj.attributes.current_tilt_position + : undefined; + + const currentPosition = position ?? statePosition; return currentPosition && currentPosition !== 100 ? `${Math.round(currentPosition)}${blankBeforePercent(locale)}%` diff --git a/src/data/fan.ts b/src/data/fan.ts index 9dbef3fbb4..c5c11d8e00 100644 --- a/src/data/fan.ts +++ b/src/data/fan.ts @@ -9,6 +9,7 @@ import { HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; +import { stateActive } from "../common/entity/state_active"; import { blankBeforePercent } from "../common/translations/blank_before_percent"; import { FrontendLocaleData } from "./translation"; @@ -69,7 +70,7 @@ export function fanSpeedToPercentage( if (speedValue === -1) { return 0; } - return Math.round(speedValue * step); + return Math.floor(speedValue * step); } export function computeFanSpeedCount(stateObj: FanEntity): number { @@ -99,9 +100,12 @@ export function computeFanSpeedStateDisplay( locale: FrontendLocaleData, speed?: number ) { - const currentSpeed = speed ?? stateObj.attributes.percentage; + const percentage = stateActive(stateObj) + ? stateObj.attributes.percentage + : undefined; + const currentSpeed = speed ?? percentage; return currentSpeed - ? `${Math.round(currentSpeed)}${blankBeforePercent(locale)}%` + ? `${Math.floor(currentSpeed)}${blankBeforePercent(locale)}%` : ""; } diff --git a/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts b/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts index 4762796e1b..41fead80cf 100644 --- a/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts +++ b/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts @@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators"; import { styleMap } from "lit/directives/style-map"; import { computeAttributeNameDisplay } from "../../../../common/entity/compute_attribute_display"; import { computeStateDisplay } from "../../../../common/entity/compute_state_display"; +import { stateActive } from "../../../../common/entity/state_active"; import { stateColorCss } from "../../../../common/entity/state_color"; import "../../../../components/ha-control-select"; import type { ControlSelectOption } from "../../../../components/ha-control-select"; @@ -26,20 +27,25 @@ export class HaMoreInfoFanSpeed extends LitElement { @property({ attribute: false }) public stateObj!: FanEntity; - @state() value?: number; + @state() sliderValue?: number; + + @state() speedValue?: FanSpeed; protected updated(changedProp: Map): void { if (changedProp.has("stateObj")) { - this.value = - this.stateObj.attributes.percentage != null - ? Math.max(Math.round(this.stateObj.attributes.percentage), 1) - : undefined; + const percentage = stateActive(this.stateObj) + ? this.stateObj.attributes.percentage ?? 0 + : 0; + this.sliderValue = Math.max(Math.round(percentage), 0); + this.speedValue = fanPercentageToSpeed(this.stateObj, percentage); } } private _speedValueChanged(ev: CustomEvent) { const speed = (ev.detail as any).value as FanSpeed; + this.speedValue = speed; + const percentage = fanSpeedToPercentage(this.stateObj, speed); this.hass.callService("fan", "set_percentage", { @@ -52,6 +58,8 @@ export class HaMoreInfoFanSpeed extends LitElement { const value = (ev.detail as any).value; if (isNaN(value)) return; + this.sliderValue = value; + this.hass.callService("fan", "set_percentage", { entity_id: this.stateObj!.entity_id, percentage: value, @@ -88,16 +96,11 @@ export class HaMoreInfoFanSpeed extends LitElement { }) ).reverse(); - const speed = fanPercentageToSpeed( - this.stateObj, - this.stateObj.attributes.percentage ?? 0 - ); - return html` { class HuiFanSpeedTileFeature extends LitElement implements LovelaceTileFeature { @property({ attribute: false }) public hass?: HomeAssistant; - @property({ attribute: false }) public stateObj?: HassEntity; + @property({ attribute: false }) public stateObj?: FanEntity; @state() private _config?: FanSpeedTileFeatureConfig; @@ -79,6 +81,10 @@ class HuiFanSpeedTileFeature extends LitElement implements LovelaceTileFeature { const speedCount = computeFanSpeedCount(this.stateObj); + const percentage = stateActive(this.stateObj) + ? this.stateObj.attributes.percentage ?? 0 + : 0; + if (speedCount <= FAN_SPEED_COUNT_MAX_FOR_BUTTONS) { const options = FAN_SPEEDS[speedCount]!.map( (speed) => ({ @@ -88,10 +94,7 @@ class HuiFanSpeedTileFeature extends LitElement implements LovelaceTileFeature { }) ); - const speed = fanPercentageToSpeed( - this.stateObj, - this.stateObj.attributes.percentage ?? 0 - ); + const speed = fanPercentageToSpeed(this.stateObj, percentage); return html`
@@ -113,15 +116,12 @@ class HuiFanSpeedTileFeature extends LitElement implements LovelaceTileFeature { `; } - const percentage = - this.stateObj.attributes.percentage != null - ? Math.max(Math.round(this.stateObj.attributes.percentage), 0) - : undefined; + const value = Math.max(Math.round(percentage), 0); return html`
Date: Tue, 4 Apr 2023 13:36:45 +0200 Subject: [PATCH 06/13] Fix more info vacuum status (#16051) --- .../more-info/controls/more-info-vacuum.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/dialogs/more-info/controls/more-info-vacuum.ts b/src/dialogs/more-info/controls/more-info-vacuum.ts index 541a13d865..45938a4932 100644 --- a/src/dialogs/more-info/controls/more-info-vacuum.ts +++ b/src/dialogs/more-info/controls/more-info-vacuum.ts @@ -12,6 +12,8 @@ import { import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import { stopPropagation } from "../../../common/dom/stop_propagation"; +import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display"; +import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; import "../../../components/ha-icon"; @@ -113,11 +115,19 @@ class MoreInfoVacuum extends LitElement { - ${stateObj.attributes.status || - this.hass.localize( - `component.vacuum.entity_component._.state.${stateObj.state}` + ${computeAttributeValueDisplay( + this.hass.localize, + stateObj, + this.hass.locale, + this.hass.entities, + "status" ) || - stateObj.state} + computeStateDisplay( + this.hass.localize, + stateObj, + this.hass.locale, + this.hass.entities + )}
From 32bbc9421b4135a86c27b849b8d4d388484de724 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 4 Apr 2023 14:04:05 +0200 Subject: [PATCH 07/13] Translate theme settings (#16053) --- .../editor/view-editor/hui-view-editor.ts | 1 - src/panels/profile/ha-pick-dashboard-row.ts | 1 + .../profile/ha-pick-first-weekday-row.ts | 1 + src/panels/profile/ha-pick-language-row.ts | 1 + .../profile/ha-pick-number-format-row.ts | 1 + src/panels/profile/ha-pick-theme-row.ts | 27 ++++++++++++------- src/panels/profile/ha-pick-time-format-row.ts | 1 + src/translations/en.json | 4 ++- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts index 6e6d8c9d98..35850f8bc8 100644 --- a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts +++ b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts @@ -93,7 +93,6 @@ export class HuiViewEditor extends LitElement { const schema = this._schema(this.hass.localize); const data = { - theme: "Backend-selected", ...this._config, type: this._type, }; diff --git a/src/panels/profile/ha-pick-dashboard-row.ts b/src/panels/profile/ha-pick-dashboard-row.ts index 39354f25bc..7b88eb9dfa 100644 --- a/src/panels/profile/ha-pick-dashboard-row.ts +++ b/src/panels/profile/ha-pick-dashboard-row.ts @@ -37,6 +37,7 @@ class HaPickDashboardRow extends LitElement { .disabled=${!this._dashboards?.length} .value=${this.hass.defaultPanel} @selected=${this._dashboardChanged} + naturalMenuWidth > ${this.hass.localize( diff --git a/src/panels/profile/ha-pick-first-weekday-row.ts b/src/panels/profile/ha-pick-first-weekday-row.ts index c9142efb57..6a615cc433 100644 --- a/src/panels/profile/ha-pick-first-weekday-row.ts +++ b/src/panels/profile/ha-pick-first-weekday-row.ts @@ -30,6 +30,7 @@ class FirstWeekdayRow extends LitElement { .disabled=${this.hass.locale === undefined} .value=${this.hass.locale.first_weekday} @selected=${this._handleFormatSelection} + naturalMenuWidth > ${[ FirstWeekday.language, diff --git a/src/panels/profile/ha-pick-language-row.ts b/src/panels/profile/ha-pick-language-row.ts index c2e7ba86f6..7bab38abdc 100644 --- a/src/panels/profile/ha-pick-language-row.ts +++ b/src/panels/profile/ha-pick-language-row.ts @@ -39,6 +39,7 @@ export class HaPickLanguageRow extends LitElement { )} .value=${this.hass.locale.language} @selected=${this._languageSelectionChanged} + naturalMenuWidth > ${this._languages.map( (language) => html` ${Object.values(NumberFormat).map((format) => { const formattedNumber = formatNumber(1234567.89, { diff --git a/src/panels/profile/ha-pick-theme-row.ts b/src/panels/profile/ha-pick-theme-row.ts index 0dcdaca9dd..1677ff7e15 100644 --- a/src/panels/profile/ha-pick-theme-row.ts +++ b/src/panels/profile/ha-pick-theme-row.ts @@ -23,6 +23,9 @@ import { import { HomeAssistant } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; +const BACKEND_SELECTED_THEME = "Backend-selected"; +const DEFAULT_THEME = "default"; + @customElement("ha-pick-theme-row") export class HaPickThemeRow extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -65,16 +68,24 @@ export class HaPickThemeRow extends LitElement { + + ${this.hass.localize("ui.panel.profile.themes.backend-selected")} + + + ${this.hass.localize("ui.panel.profile.themes.default")} + ${this._themeNames.map( - (theme) => - html`${theme}` + (theme) => html` + ${theme} + ` )} - ${curTheme === "default" || this._supportsModeSelection(curTheme) + ${curTheme === DEFAULT_THEME || this._supportsModeSelection(curTheme) ? html`
- ${curTheme === "default" + ${curTheme === DEFAULT_THEME ? html`
${Object.values(TimeFormat).map((format) => { const formattedTime = formatTime(date, { diff --git a/src/translations/en.json b/src/translations/en.json index 1255298cec..8b8e01ef28 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -4711,7 +4711,9 @@ }, "primary_color": "Primary color", "accent_color": "Accent color", - "reset": "Reset" + "reset": "Reset", + "backend-selected": "Use backend preferred theme", + "default": "Default" }, "dashboard": { "header": "Dashboard", From 28304bb1dcebfddf3ab991e2f9e38f44427fe0f8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 4 Apr 2023 15:01:33 +0200 Subject: [PATCH 08/13] Make deprecation warning instead of error (#16055) --- src/util/legacy-support.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/legacy-support.js b/src/util/legacy-support.js index c94ffffdb0..869ecbb4f7 100644 --- a/src/util/legacy-support.js +++ b/src/util/legacy-support.js @@ -16,7 +16,9 @@ const handler = { console.warn(message); document .querySelector("home-assistant") - .dispatchEvent(new CustomEvent("write_log", { detail: { message } })); + .dispatchEvent( + new CustomEvent("write_log", { detail: { message, level: "warning" } }) + ); return Reflect.get(target, prop, receiver); }, apply: function (target, thisArg, argumentsList) { @@ -24,7 +26,9 @@ const handler = { console.warn(message); document .querySelector("home-assistant") - .dispatchEvent(new CustomEvent("write_log", { detail: { message } })); + .dispatchEvent( + new CustomEvent("write_log", { detail: { message, level: "warning" } }) + ); return Reflect.apply(target, thisArg, argumentsList); }, }; From 1596578f961c9190e3aa9cdf4fa19457b157a410 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 5 Apr 2023 10:20:21 +0200 Subject: [PATCH 09/13] Fix automation editor (#16057) --- hassio/src/addon-store/hassio-addon-store.ts | 6 +----- hassio/src/addon-view/config/hassio-addon-config.ts | 2 +- hassio/src/backups/hassio-backups.ts | 6 +----- hassio/src/system/hassio-host-info.ts | 2 +- src/components/ha-button-menu.ts | 2 +- src/components/ha-button-related-filter-menu.ts | 2 +- src/components/ha-form/ha-form-multi_select.ts | 1 - src/components/ha-icon-overflow-menu.ts | 1 - src/components/ha-qr-scanner.ts | 6 +----- src/components/ha-target-picker.ts | 1 - src/dialogs/more-info/controls/more-info-fan.ts | 1 - src/dialogs/more-info/controls/more-info-light.ts | 1 - src/layouts/hass-subpage.ts | 4 +++- .../config/automation/action/ha-automation-action-row.ts | 2 -- .../config/automation/action/ha-automation-action.ts | 6 +----- .../automation/condition/ha-automation-condition-row.ts | 2 -- .../config/automation/condition/ha-automation-condition.ts | 6 +----- src/panels/config/automation/ha-automation-editor.ts | 2 +- src/panels/config/automation/ha-automation-picker.ts | 1 - src/panels/config/automation/ha-automation-trace.ts | 2 +- .../config/automation/trigger/ha-automation-trigger-row.ts | 2 -- src/panels/config/cloud/alexa/cloud-alexa.ts | 3 +-- .../cloud/google-assistant/cloud-google-assistant.ts | 3 +-- src/panels/config/core/ha-config-section-updates.ts | 2 +- src/panels/config/dashboard/ha-config-dashboard.ts | 6 +----- src/panels/config/devices/ha-config-device-page.ts | 2 +- src/panels/config/devices/ha-config-devices-dashboard.ts | 2 +- src/panels/config/entities/ha-config-entities.ts | 2 +- src/panels/config/integrations/ha-config-flow-card.ts | 2 +- src/panels/config/integrations/ha-config-integrations.ts | 1 - src/panels/config/integrations/ha-integration-card.ts | 2 +- .../config/integrations/ha-integration-overflow-menu.ts | 2 +- .../integration-panels/thread/thread-config-panel.ts | 3 +-- src/panels/config/logs/ha-config-logs.ts | 2 +- .../lovelace/dashboards/ha-config-lovelace-dashboards.ts | 6 +----- src/panels/config/network/supervisor-network.ts | 2 +- src/panels/config/repairs/ha-config-repairs-dashboard.ts | 2 +- src/panels/config/scene/ha-scene-dashboard.ts | 1 - src/panels/config/scene/ha-scene-editor.ts | 1 - src/panels/config/script/ha-script-editor.ts | 2 +- src/panels/config/script/ha-script-picker.ts | 1 - src/panels/config/script/ha-script-trace.ts | 2 +- src/panels/config/storage/ha-config-section-storage.ts | 2 +- src/panels/lovelace/components/hui-card-options.ts | 2 +- src/panels/lovelace/hui-root.ts | 7 ++----- src/panels/media-browser/ha-bar-media-player.ts | 4 ++-- 46 files changed, 37 insertions(+), 85 deletions(-) diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts index 024d803be2..ab434eb8ca 100644 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ b/hassio/src/addon-store/hassio-addon-store.ts @@ -92,11 +92,7 @@ export class HassioAddonStore extends LitElement { .route=${this.route} .header=${this.supervisor.localize("panel.store")} > - +
- + - + +
${this._cameras && this._cameras.length > 1 - ? html` + ? html` diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index 7ff8100b76..98b10bbffa 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -128,11 +128,7 @@ export default class HaAutomationAction extends LitElement { ` )}
- + diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index 942fe074ae..12b4fd3bbb 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -180,11 +180,7 @@ export default class HaAutomationCondition extends LitElement { ` )}
- + ` : ""} - + ` : ""} - + diff --git a/src/panels/config/cloud/alexa/cloud-alexa.ts b/src/panels/config/cloud/alexa/cloud-alexa.ts index 8c666890dc..6c8dbda913 100644 --- a/src/panels/config/cloud/alexa/cloud-alexa.ts +++ b/src/panels/config/cloud/alexa/cloud-alexa.ts @@ -168,7 +168,6 @@ class CloudAlexa extends LitElement { ${!emptyFilter ? html`${iconButton}` : html` @@ -225,7 +224,7 @@ class CloudAlexa extends LitElement { .narrow=${this.narrow} .header=${this.hass!.localize("ui.panel.config.cloud.alexa.title")} > - + @@ -302,7 +301,7 @@ class CloudGoogleAssistant extends LitElement { .hass=${this.hass} .header=${this.hass!.localize("ui.panel.config.cloud.google.title")} .narrow=${this.narrow}> - + - + - + + - + ` : html` - + - + ${disabledCount}` : ""} - + + - + ${router.server} ${router.extended_address === this._otbrInfo?.extended_address ? html` diff --git a/src/panels/config/logs/ha-config-logs.ts b/src/panels/config/logs/ha-config-logs.ts index a220344260..6788c9b639 100644 --- a/src/panels/config/logs/ha-config-logs.ts +++ b/src/panels/config/logs/ha-config-logs.ts @@ -115,7 +115,7 @@ export class HaConfigLogs extends LitElement { ${isComponentLoaded(this.hass, "hassio") && this.hass.userData?.showAdvanced ? html` - + ${this.hass.userData?.showAdvanced ? html` - + ` : this.hass.localize("ui.common.save")} - +
- + ` : ""} - + + ${this._hostInfo ? html` - + - + - + + + + ${ this.narrow ? html` From e784205e1e02981a87ad7d3bd19d286919af7888 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 5 Apr 2023 11:35:06 +0200 Subject: [PATCH 10/13] fix panel card height (#16059) --- src/panels/lovelace/hui-root.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 11609b3bdf..5571bd0316 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -1057,6 +1057,7 @@ class HUIRoot extends LitElement { ); overflow: auto; transform: translateZ(0); + display: flex; } /** * In edit mode we have the tab bar on a new line * @@ -1079,6 +1080,7 @@ class HUIRoot extends LitElement { * https://github.com/home-assistant/home-assistant-polymer/pull/3806 */ flex: 1 1 100%; + height: 100%; max-width: 100%; padding-bottom: env(safe-area-inset-bottom); display: block; From 6d29b1cfb868a4d859987ae0152c5f79fc0f32ff Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 5 Apr 2023 11:35:14 +0200 Subject: [PATCH 11/13] Fix chart mouse over in more info dialog (#16060) --- src/components/chart/ha-chart-base.ts | 2 +- src/dialogs/more-info/ha-more-info-dialog.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 3ffe16f64c..b4ecf7e063 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -302,7 +302,7 @@ export default class HaChartBase extends LitElement { return css` :host { display: block; - position: relative; + position: var(--chart-base-position, relative); } .chartContainer { overflow: hidden; diff --git a/src/dialogs/more-info/ha-more-info-dialog.ts b/src/dialogs/more-info/ha-more-info-dialog.ts index 8512a382e1..3bcc18b883 100644 --- a/src/dialogs/more-info/ha-more-info-dialog.ts +++ b/src/dialogs/more-info/ha-more-info-dialog.ts @@ -451,6 +451,7 @@ export class MoreInfoDialog extends LitElement { --dialog-surface-position: static; --dialog-content-position: static; --dialog-content-padding: 0; + --chart-base-position: static; } ha-header-bar { From c640d9edf2d22ae5ae010559ad12cbb06631725c Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 5 Apr 2023 12:29:13 +0200 Subject: [PATCH 12/13] update url of pipline-debug (#16066) --- src/panels/config/ha-panel-config.ts | 9 ++-- .../ha-config-voice-assistants.ts | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 src/panels/config/voice-assistants/ha-config-voice-assistants.ts diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 7920302c71..c00faf3711 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -353,12 +353,9 @@ class HaPanelConfig extends HassRouterPage { tag: "ha-config-areas", load: () => import("./areas/ha-config-areas"), }, - voice_assistant: { - tag: "assist-pipeline-debug", - load: () => - import( - "./integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug" - ), + "voice-assistants": { + tag: "ha-config-voice-assistants", + load: () => import("./voice-assistants/ha-config-voice-assistants"), }, automation: { tag: "ha-config-automation", diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts new file mode 100644 index 0000000000..9ebea3faad --- /dev/null +++ b/src/panels/config/voice-assistants/ha-config-voice-assistants.ts @@ -0,0 +1,41 @@ +import { customElement, property } from "lit/decorators"; +import { + HassRouterPage, + RouterOptions, +} from "../../../layouts/hass-router-page"; +import { HomeAssistant } from "../../../types"; + +@customElement("ha-config-voice-assistants") +class HaConfigVoiceAssistants extends HassRouterPage { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public narrow!: boolean; + + @property() public isWide!: boolean; + + protected routerOptions: RouterOptions = { + defaultPage: "debug", + routes: { + debug: { + tag: "assist-pipeline-debug", + load: () => + import( + "../integrations/integration-panels/voice_assistant/assist/assist-pipeline-debug" + ), + }, + }, + }; + + protected updatePageEl(pageEl) { + pageEl.hass = this.hass; + pageEl.narrow = this.narrow; + pageEl.isWide = this.isWide; + pageEl.route = this.routeTail; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-config-voice-assistants": HaConfigVoiceAssistants; + } +} From 81ebdf1448ab25689736ad59e5c9012e971280d1 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 5 Apr 2023 12:29:59 +0200 Subject: [PATCH 13/13] Bumped version to 20230405.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 97f2c429bd..33e2a52faa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20230403.0" +version = "20230405.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md"