Update voice wizard (#22472)

pull/22483/head^2
Bram Kragten 2024-10-23 15:14:11 +02:00 committed by GitHub
parent ca20c2d292
commit 5d49f4007e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 305 additions and 311 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

View File

@ -39,6 +39,9 @@ export const AssistantSetupStyles = [
.footer.full-width ha-button {
width: 100%;
}
.footer.centered {
justify-content: center;
}
.footer.side-by-side {
justify-content: space-between;
}

View File

@ -14,7 +14,6 @@ import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { VoiceAssistantSetupDialogParams } from "./show-voice-assistant-setup-dialog";
import "./voice-assistant-setup-step-addons";
import "./voice-assistant-setup-step-area";
import "./voice-assistant-setup-step-change-wake-word";
import "./voice-assistant-setup-step-check";
@ -34,7 +33,6 @@ export const enum STEP {
PIPELINE,
SUCCESS,
CLOUD,
ADDONS,
CHANGE_WAKEWORD,
}
@ -210,22 +208,18 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
? html`<ha-voice-assistant-setup-step-cloud
.hass=${this.hass}
></ha-voice-assistant-setup-step-cloud>`
: this._step === STEP.ADDONS
? html`<ha-voice-assistant-setup-step-addons
: this._step === STEP.SUCCESS
? html`<ha-voice-assistant-setup-step-success
.hass=${this.hass}
></ha-voice-assistant-setup-step-addons>`
: this._step === STEP.SUCCESS
? html`<ha-voice-assistant-setup-step-success
.hass=${this.hass}
.assistConfiguration=${this
._assistConfiguration}
.assistEntityId=${this._findDomainEntityId(
this._params.deviceId,
this.hass.entities,
"assist_satellite"
)}
></ha-voice-assistant-setup-step-success>`
: nothing}
.assistConfiguration=${this
._assistConfiguration}
.assistEntityId=${this._findDomainEntityId(
this._params.deviceId,
this.hass.entities,
"assist_satellite"
)}
></ha-voice-assistant-setup-step-success>`
: nothing}
</div>
</ha-dialog>
`;

View File

@ -1,185 +0,0 @@
import { css, html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { HomeAssistant } from "../../types";
import { AssistantSetupStyles } from "./styles";
import { STEP } from "./voice-assistant-setup-dialog";
import { documentationUrl } from "../../util/documentation-url";
@customElement("ha-voice-assistant-setup-step-addons")
export class HaVoiceAssistantSetupStepAddons extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _showFirst = false;
@state() private _showSecond = false;
@state() private _showThird = false;
@state() private _showFourth = false;
protected override firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
setTimeout(() => {
this._showFirst = true;
}, 200);
setTimeout(() => {
this._showSecond = true;
}, 600);
setTimeout(() => {
this._showThird = true;
}, 3000);
setTimeout(() => {
this._showFourth = true;
}, 8000);
}
protected override render() {
return html`<div class="content">
<h1>Local</h1>
<p class="secondary">
Are you sure you want to use the local voice assistant? It requires a
powerful device to run. If you device is not powerful enough, Home
Assistant cloud might be a better option.
</p>
<h3>Raspberry Pi 4</h3>
<div class="messages-container rpi">
<div class="message user ${this._showThird ? "show" : ""}">
${!this._showThird ? "…" : "Turn on the lights in the bedroom"}
</div>
${this._showThird
? html`<div class="timing user">3 seconds</div>`
: nothing}
${this._showThird
? html`<div class="message hass ${this._showFourth ? "show" : ""}">
${!this._showFourth ? "…" : "Turned on the lights"}
</div>`
: nothing}
${this._showFourth
? html`<div class="timing hass">5 seconds</div>`
: nothing}
</div>
<h3>Home Assistant Cloud</h3>
<div class="messages-container cloud">
<div class="message user ${this._showFirst ? "show" : ""}">
${!this._showFirst ? "…" : "Turn on the lights in the bedroom"}
</div>
${this._showFirst
? html`<div class="timing user">0.2 seconds</div>`
: nothing}
${this._showFirst
? html` <div class="message hass ${this._showSecond ? "show" : ""}">
${!this._showSecond ? "…" : "Turned on the lights"}
</div>`
: nothing}
${this._showSecond
? html`<div class="timing hass">0.4 seconds</div>`
: nothing}
</div>
</div>
<div class="footer side-by-side">
<ha-button @click=${this._goToCloud}
>Try Home Assistant Cloud</ha-button
>
<a
href=${documentationUrl(
this.hass,
"/voice_control/voice_remote_local_assistant/"
)}
target="_blank"
rel="noreferrer noopenner"
>
<ha-button @click=${this._skip} unelevated>Learn more</ha-button>
</a>
</div>`;
}
private _goToCloud() {
fireEvent(this, "next-step", { step: STEP.CLOUD });
}
private _skip() {
fireEvent(this, "next-step", { step: STEP.SUCCESS });
}
static styles = [
AssistantSetupStyles,
css`
.messages-container {
padding: 24px;
box-sizing: border-box;
height: 195px;
background: var(--input-fill-color);
border-radius: 16px;
border: 1px solid var(--divider-color);
display: flex;
flex-direction: column;
}
.message {
white-space: nowrap;
font-size: 18px;
clear: both;
margin: 8px 0;
padding: 8px;
border-radius: 15px;
height: 36px;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
width: 30px;
}
.rpi .message {
transition: width 1s;
}
.cloud .message {
transition: width 0.5s;
}
.message.user {
margin-left: 24px;
margin-inline-start: 24px;
margin-inline-end: initial;
align-self: self-end;
text-align: right;
border-bottom-right-radius: 0px;
background-color: var(--primary-color);
color: var(--text-primary-color);
direction: var(--direction);
}
.timing.user {
align-self: self-end;
}
.message.user.show {
width: 295px;
}
.message.hass {
margin-right: 24px;
margin-inline-end: 24px;
margin-inline-start: initial;
align-self: self-start;
border-bottom-left-radius: 0px;
background-color: var(--secondary-background-color);
color: var(--primary-text-color);
direction: var(--direction);
}
.timing.hass {
align-self: self-start;
}
.message.hass.show {
width: 184px;
}
.footer {
margin-top: 24px;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-voice-assistant-setup-step-addons": HaVoiceAssistantSetupStepAddons;
}
}

View File

@ -16,7 +16,7 @@ export class HaVoiceAssistantSetupStepArea extends LitElement {
const device = this.hass.devices[this.deviceId];
return html`<div class="content">
<img src="/static/icons/casita/loving.png" />
<img src="/static/images/voice-assistant/area.gif" />
<h1>Select area</h1>
<p class="secondary">
When you voice assistant knows where it is, it can better control the

View File

@ -10,6 +10,7 @@ import { STEP } from "./voice-assistant-setup-dialog";
import { AssistantSetupStyles } from "./styles";
import "../../components/ha-md-list";
import "../../components/ha-md-list-item";
import { formatLanguageCode } from "../../common/language/format_language";
@customElement("ha-voice-assistant-setup-step-change-wake-word")
export class HaVoiceAssistantSetupStepChangeWakeWord extends LitElement {
@ -22,11 +23,12 @@ export class HaVoiceAssistantSetupStepChangeWakeWord extends LitElement {
protected override render() {
return html`<div class="padding content">
<img src="/static/icons/casita/smiling.png" />
<img src="/static/images/voice-assistant/change-wake-word.gif" />
<h1>Change wake word</h1>
<p class="secondary">
Some wake words are better for [your language] and voice than others.
Please try them out.
Some wake words are better for
${formatLanguageCode(this.hass.locale.language, this.hass.locale)} and
voice than others. Please try them out.
</p>
</div>
<ha-md-list>

View File

@ -1,4 +1,4 @@
import { html, LitElement, PropertyValues } from "lit";
import { html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { testAssistSatelliteConnection } from "../../data/assist_satellite";
@ -13,6 +13,8 @@ export class HaVoiceAssistantSetupStepCheck extends LitElement {
@state() private _status?: "success" | "timeout";
@state() private _showLoader = false;
protected override willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
if (!this.hasUpdated) {
@ -30,39 +32,48 @@ export class HaVoiceAssistantSetupStepCheck extends LitElement {
protected override render() {
return html`<div class="content">
${this._status === "success"
? html`<img src="/static/icons/casita/smiling.png" />
${this._status === "timeout"
? html`<img src="/static/images/voice-assistant/error.gif" />
<h1>The voice assistant is unable to connect to Home Assistant</h1>
<p class="secondary">
To play audio, the voice assistant device has to connect to Home
Assistant to fetch the files. Our test shows that the device is
unable to reach the Home Assistant server.
</p>
<div class="footer">
<a
href="https://www.home-assistant.io/docs/configuration/remote/#adding-a-remote-url-to-home-assistant"
><ha-button>Help me</ha-button></a
>
<ha-button @click=${this._testConnection}>Retry</ha-button>
</div>`
: html`<img src="/static/images/voice-assistant/hi.gif" />
<h1>Hi</h1>
<p class="secondary">
With a couple of steps we are going to setup your voice assistant.
</p>`
: this._status === "timeout"
? html`<img src="/static/icons/casita/sad.png" />
<h1>Voice assistant can not connect to Home Assistant</h1>
<p class="secondary">
A good explanation what is happening and what action you should
take.
</p>
<div class="footer">
<a href="#"><ha-button>Help me</ha-button></a>
<ha-button @click=${this._testConnection}>Retry</ha-button>
</div>`
: html`<img src="/static/icons/casita/loading.png" />
<h1>Checking...</h1>
<p class="secondary">
We are checking if the device can reach your Home Assistant
instance.
</p>
<ha-circular-progress indeterminate></ha-circular-progress>`}
Over the next couple steps we're going to personalize your voice
assistant.
</p>
${this._showLoader
? html`<ha-circular-progress
indeterminate
></ha-circular-progress>`
: nothing} `}
</div>`;
}
private async _testConnection() {
this._status = undefined;
this._showLoader = false;
const timeout = setTimeout(() => {
this._showLoader = true;
}, 3000);
const result = await testAssistSatelliteConnection(
this.hass,
this.assistEntityId!
);
clearTimeout(timeout);
this._showLoader = false;
this._status = result.status;
}

View File

@ -1,7 +1,9 @@
import { html, LitElement } from "lit";
import { mdiEarth, mdiMicrophoneMessage, mdiOpenInNew } from "@mdi/js";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { HomeAssistant } from "../../types";
import { brandsUrl } from "../../util/brands-url";
import { AssistantSetupStyles } from "./styles";
@customElement("ha-voice-assistant-setup-step-cloud")
@ -10,22 +12,92 @@ export class HaVoiceAssistantSetupStepCloud extends LitElement {
protected override render() {
return html`<div class="content">
<img src="/static/images/logo_nabu_casa.png" />
<h1>Supercharge your assistant with Home Assistant Cloud</h1>
<p class="secondary">
Speed up and take the load off your system by running your
text-to-speech and speech-to-text in our private and secure cloud.
Cloud also includes secure remote access to your system while
supporting the development of Home Assistant.
</p>
<img
src=${`/static/images/logo_nabu_casa${this.hass.themes?.darkMode ? "_dark" : ""}.png`}
alt="Nabu Casa logo"
/>
<h1>The power of Home Assistant Cloud</h1>
<div class="features">
<div class="feature speech">
<div class="logos">
<div class="round-icon">
<ha-svg-icon .path=${mdiMicrophoneMessage}></ha-svg-icon>
</div>
</div>
<h2>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.cloud.features.speech.title"
)}
<span class="no-wrap"></span>
</h2>
<p>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.cloud.features.speech.text"
)}
</p>
</div>
<div class="feature access">
<div class="logos">
<div class="round-icon">
<ha-svg-icon .path=${mdiEarth}></ha-svg-icon>
</div>
</div>
<h2>
Remote access
<span class="no-wrap"></span>
</h2>
<p>
Secure remote access to your system while supporting the
development of Home Assistant.
</p>
</div>
<div class="feature">
<div class="logos">
<img
alt="Google Assistant"
src=${brandsUrl({
domain: "google_assistant",
type: "icon",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<img
alt="Amazon Alexa"
src=${brandsUrl({
domain: "alexa",
type: "icon",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</div>
<h2>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.cloud.features.assistants.title"
)}
</h2>
<p>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.cloud.features.assistants.text"
)}
</p>
</div>
</div>
</div>
<div class="footer side-by-side">
<a
href="https://www.nabucasa.com"
target="_blank"
rel="noreferrer noopenner"
><ha-button>Learn more</ha-button></a
>
<ha-button>
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
nabucasa.com
</ha-button>
</a>
<a href="/config/cloud/register" @click=${this._close}
><ha-button unelevated>Try 1 month for free</ha-button></a
>
@ -36,7 +108,58 @@ export class HaVoiceAssistantSetupStepCloud extends LitElement {
fireEvent(this, "closed");
}
static styles = AssistantSetupStyles;
static styles = [
AssistantSetupStyles,
css`
.features {
display: flex;
flex-direction: column;
grid-gap: 16px;
padding: 16px;
}
.feature {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
margin-bottom: 16px;
}
.feature .logos {
margin-bottom: 16px;
}
.feature .logos > * {
width: 40px;
height: 40px;
margin: 0 4px;
}
.round-icon {
border-radius: 50%;
color: #6e41ab;
background-color: #e8dcf7;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
.access .round-icon {
color: #00aef8;
background-color: #cceffe;
}
.feature h2 {
font-weight: 500;
font-size: 16px;
line-height: 24px;
margin-top: 0;
margin-bottom: 8px;
}
.feature p {
font-weight: 400;
font-size: 14px;
line-height: 20px;
margin: 0;
}
`,
];
}
declare global {

View File

@ -32,6 +32,10 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
@state() private _showSecond = false;
@state() private _showThird = false;
@state() private _showFourth = false;
protected override willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
@ -44,63 +48,83 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
super.firstUpdated(changedProperties);
setTimeout(() => {
this._showFirst = true;
}, 1);
}, 200);
setTimeout(() => {
this._showSecond = true;
}, 1500);
}, 600);
setTimeout(() => {
this._showThird = true;
}, 3000);
setTimeout(() => {
this._showFourth = true;
}, 8000);
}
protected override render() {
return html`<div class="padding content">
<div class="messages-container">
return html`<div class="content">
<h1>What hardware do you want to use?</h1>
<p class="secondary">
How quickly your assistant responds depends on the power of the
hardware.
</p>
<div class="container">
<div class="messages-container cloud">
<div class="message user ${this._showFirst ? "show" : ""}">
${!this._showFirst ? "…" : "Turn on the lights in the bedroom"}
</div>
${this._showFirst
? html`<div class="timing user">0.2 seconds</div>`
: nothing}
${this._showFirst
? html` <div class="message hass ${this._showSecond ? "show" : ""}">
${!this._showSecond ? "…" : "Turned on the lights"}
</div>`
: nothing}
${this._showSecond
? html`<div class="timing hass">0.4 seconds</div>`
: nothing}
</div>
<h1>Select system</h1>
<p class="secondary">
How quickly your voice assistant responds depends on the power of your
system.
</p>
<h2>Home Assistant Cloud</h2>
<p>Ideal if you don't have a powerful system at home.</p>
<ha-button @click=${this._setupCloud}>Learn more</ha-button>
</div>
<ha-md-list>
<ha-md-list-item interactive type="button" @click=${this._setupCloud}>
Home Assistant Cloud
<span slot="supporting-text"
>Ideal if you don't have a powerful system at home</span
>
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
<ha-md-list-item interactive type="button" @click=${this._thisSystem}>
On this system
<span slot="supporting-text"
>Local setup with the Whisper and Piper add-ons</span
>
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
<ha-md-list-item
interactive
type="link"
<div class="container">
<div class="messages-container rpi">
<div class="message user ${this._showThird ? "show" : ""}">
${!this._showThird ? "…" : "Turn on the lights in the bedroom"}
</div>
${this._showThird
? html`<div class="timing user">3 seconds</div>`
: nothing}
${this._showThird
? html`<div class="message hass ${this._showFourth ? "show" : ""}">
${!this._showFourth ? "…" : "Turned on the lights"}
</div>`
: nothing}
${this._showFourth
? html`<div class="timing hass">5 seconds</div>`
: nothing}
</div>
<h2>Do-it-yourself</h2>
<p>
Install add-ons or containers to run it on your own system. Powerful
hardware is needed for fast responses.
</p>
<a
href=${documentationUrl(
this.hass,
"/voice_control/voice_remote_local_assistant/"
)}
rel="noreferrer noopenner"
target="_blank"
@click=${this._skip}
rel="noreferrer noopenner"
>
Use external system
<span slot="supporting-text"
>Learn more about how to host it on another system</span
<ha-button @click=${this._skip}>
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
Learn more</ha-button
>
<ha-svg-icon slot="end" .path=${mdiOpenInNew}></ha-svg-icon>
</ha-md-list-item>
</ha-md-list>`;
</a>
</div>
</div>`;
}
private async _checkCloud() {
@ -217,10 +241,6 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
this._nextStep(STEP.CLOUD);
}
private async _thisSystem() {
this._nextStep(STEP.ADDONS);
}
private _skip() {
this._nextStep(STEP.SUCCESS);
}
@ -232,21 +252,22 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
static styles = [
AssistantSetupStyles,
css`
:host {
padding: 0;
.container {
border-radius: 16px;
border: 1px solid var(--divider-color);
overflow: hidden;
padding-bottom: 16px;
}
.padding {
padding: 24px;
.container:last-child {
margin-top: 16px;
}
ha-md-list {
width: 100%;
text-align: initial;
}
.messages-container {
padding: 24px;
box-sizing: border-box;
height: 152px;
height: 195px;
background: var(--input-fill-color);
display: flex;
flex-direction: column;
}
.message {
white-space: nowrap;
@ -259,21 +280,29 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
transition: width 1s;
width: 30px;
}
.rpi .message {
transition: width 1s;
}
.cloud .message {
transition: width 0.5s;
}
.message.user {
margin-left: 24px;
margin-inline-start: 24px;
margin-inline-end: initial;
float: var(--float-end);
align-self: self-end;
text-align: right;
border-bottom-right-radius: 0px;
background-color: var(--primary-color);
color: var(--text-primary-color);
direction: var(--direction);
}
.timing.user {
align-self: self-end;
}
.message.user.show {
width: 295px;
@ -283,12 +312,15 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
margin-right: 24px;
margin-inline-end: 24px;
margin-inline-start: initial;
float: var(--float-start);
align-self: self-start;
border-bottom-left-radius: 0px;
background-color: var(--secondary-background-color);
color: var(--primary-text-color);
direction: var(--direction);
}
.timing.hass {
align-self: self-start;
}
.message.hass.show {
width: 184px;

View File

@ -66,11 +66,11 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
: undefined;
return html`<div class="content">
<img src="/static/icons/casita/loving.png" />
<h1>Ready to assist!</h1>
<img src="/static/images/voice-assistant/heart.gif" />
<h1>Ready to Assist!</h1>
<p class="secondary">
Your device is all ready to go! If you want to tweak some more
settings, you can change that below.
Make any final customizations here. You can always change these in the
Voice Assistants section of the settings page.
</p>
<div class="rows">
${this.assistConfiguration &&

View File

@ -2,7 +2,13 @@ import { css, html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/ha-circular-progress";
import { OFF, ON, UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { ON, UNAVAILABLE } from "../../data/entity";
import {
updateCanInstall,
UpdateEntity,
updateIsInstalling,
updateUsesProgress,
} from "../../data/update";
import { HomeAssistant } from "../../types";
import { AssistantSetupStyles } from "./styles";
@ -51,17 +57,19 @@ export class HaVoiceAssistantSetupStepUpdate extends LitElement {
return nothing;
}
const stateObj = this.hass.states[this.updateEntityId];
const stateObj = this.hass.states[this.updateEntityId] as
| UpdateEntity
| undefined;
const progressIsNumeric =
typeof stateObj?.attributes.update_percentage !== null;
const progressIsNumeric = stateObj && updateUsesProgress(stateObj);
return html`<div class="content">
<img src="/static/icons/casita/loading.png" />
<img src="/static/images/voice-assistant/update.gif" />
<h1>
${stateObj.state === OFF || stateObj.state === UNKNOWN
? "Checking for updates"
: "Updating your voice assistant"}
${stateObj &&
(stateObj.state === "unavailable" || updateIsInstalling(stateObj))
? "Updating your voice assistant"
: "Checking for updates"}
</h1>
<p class="secondary">
We are making sure you have the latest and greatest version of your
@ -69,12 +77,12 @@ export class HaVoiceAssistantSetupStepUpdate extends LitElement {
</p>
<ha-circular-progress
.value=${progressIsNumeric
? stateObj.attributes.update_percentage / 100
? (stateObj.attributes.update_percentage as number) / 100
: undefined}
.indeterminate=${!progressIsNumeric}
></ha-circular-progress>
<p>
${stateObj.state === "unavailable"
${stateObj?.state === UNAVAILABLE
? "Restarting voice assistant"
: progressIsNumeric
? `Installing ${stateObj.attributes.update_percentage}%`
@ -88,8 +96,14 @@ export class HaVoiceAssistantSetupStepUpdate extends LitElement {
if (!this.updateEntityId) {
return;
}
const updateEntity = this.hass.states[this.updateEntityId];
if (updateEntity && this.hass.states[updateEntity.entity_id].state === ON) {
const updateEntity = this.hass.states[this.updateEntityId] as
| UpdateEntity
| undefined;
if (
updateEntity &&
this.hass.states[updateEntity.entity_id].state === ON &&
updateCanInstall(updateEntity)
) {
this._updated = true;
await this.hass.callService(
"update",

View File

@ -65,14 +65,14 @@ export class HaVoiceAssistantSetupStepWakeWord extends LitElement {
return html`<div class="content">
${!this._detected
? html`
<img src="/static/icons/casita/sleeping.png" />
<img src="/static/images/voice-assistant/sleep.gif" />
<h1>
Say ${this._activeWakeWord(this.assistConfiguration)} to wake the
device up
</h1>
<p class="secondary">Setup will continue once the device is awake.</p>
</div>`
: html`<img src="/static/icons/casita/normal.png" />
: html`<img src="/static/images/voice-assistant/ok-nabu.gif" />
<h1>
Say ${this._activeWakeWord(this.assistConfiguration)} again
</h1>
@ -80,7 +80,7 @@ export class HaVoiceAssistantSetupStepWakeWord extends LitElement {
To make sure the wake word works for you.
</p>`}
</div>
<div class="footer full-width">
<div class="footer centered">
<ha-button @click=${this._changeWakeWord}>Change wake word</ha-button>
</div>`;
}