diff --git a/src/data/alexa.ts b/src/data/alexa.ts index bdc079c60f..ea8710e033 100644 --- a/src/data/alexa.ts +++ b/src/data/alexa.ts @@ -9,5 +9,11 @@ export interface AlexaEntity { export const fetchCloudAlexaEntities = (hass: HomeAssistant) => hass.callWS({ type: "cloud/alexa/entities" }); +export const fetchCloudAlexaEntity = (hass: HomeAssistant, entity_id: string) => + hass.callWS({ + type: "cloud/alexa/entities/get", + entity_id, + }); + export const syncCloudAlexaEntities = (hass: HomeAssistant) => hass.callWS({ type: "cloud/alexa/sync" }); diff --git a/src/panels/config/voice-assistants/entity-voice-settings.ts b/src/panels/config/voice-assistants/entity-voice-settings.ts index eb0a71935f..bc5a3b9a8d 100644 --- a/src/panels/config/voice-assistants/entity-voice-settings.ts +++ b/src/panels/config/voice-assistants/entity-voice-settings.ts @@ -19,6 +19,7 @@ import { import "../../../components/ha-aliases-editor"; import "../../../components/ha-settings-row"; import "../../../components/ha-switch"; +import { fetchCloudAlexaEntity } from "../../../data/alexa"; import { CloudStatus, CloudStatusLoggedIn, @@ -53,16 +54,16 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) { @state() private _googleEntity?: GoogleEntity; + @state() private _unsupported: Partial< + Record<"cloud.google_assistant" | "cloud.alexa" | "conversation", boolean> + > = {}; + protected willUpdate(changedProps: PropertyValues) { if (!isComponentLoaded(this.hass, "cloud")) { return; } if (changedProps.has("entry") && this.entry) { - fetchCloudGoogleEntity(this.hass, this.entry.entity_id).then( - (googleEntity) => { - this._googleEntity = googleEntity; - } - ); + this._fetchEntities(); } if (!this.hasUpdated) { fetchCloudStatus(this.hass).then((status) => { @@ -71,6 +72,31 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) { } } + private async _fetchEntities() { + try { + const googleEntity = await fetchCloudGoogleEntity( + this.hass, + this.entry.entity_id + ); + this._googleEntity = googleEntity; + this.requestUpdate("_googleEntity"); + } catch (err: any) { + if (err.code === "not_supported") { + this._unsupported["cloud.google_assistant"] = true; + this.requestUpdate("_unsupported"); + } + } + + try { + await fetchCloudAlexaEntity(this.hass, this.entry.entity_id); + } catch (err: any) { + if (err.code === "not_supported") { + this._unsupported["cloud.alexa"] = true; + this.requestUpdate("_unsupported"); + } + } + } + private _getEntityFilterFuncs = memoizeOne( (googleFilter: EntityFilter, alexaFilter: EntityFilter) => ({ google: generateFilter( @@ -163,9 +189,28 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) { > ${anyExposed - ? showAssistants.map( - (key) => html` - + ? showAssistants.map((key) => { + const supported = !this._unsupported[key]; + + const exposed = + alexaManual && key === "cloud.alexa" + ? manExposedAlexa + : googleManual && key === "cloud.google_assistant" + ? manExposedGoogle + : this.entry.options?.[key]?.should_expose; + + const manualConfig = + (alexaManual && key === "cloud.alexa") || + (googleManual && key === "cloud.google_assistant"); + + const support2fa = + key === "cloud.google_assistant" && + !googleManual && + supported && + this._googleEntity?.might_2fa; + + return html` + ${voiceAssistants[key].name} - ${key === "cloud.google_assistant" && - !googleManual && - this._googleEntity?.might_2fa + ${!supported + ? html`
+ ${this.hass.localize( + "ui.dialogs.voice-settings.unsupported" + )} +
` + : nothing} + ${manualConfig + ? html` +
+ ${this.hass.localize( + "ui.dialogs.voice-settings.manual_config" + )} +
+ ` + : nothing} + ${support2fa ? html` ` - : (alexaManual && key === "cloud.alexa") || - (googleManual && key === "cloud.google_assistant") - ? html` - - ${this.hass.localize( - "ui.dialogs.voice-settings.manual_config" - )} - - ` : nothing}
- ` - ) + `; + }) : nothing}

@@ -283,9 +328,15 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) { } private async _toggleAll(ev) { + const expose = ev.target.checked; + + const assistants = expose + ? ev.target.assistants.filter((key) => !this._unsupported[key]) + : ev.target.assistants; + exposeEntities( this.hass, - ev.target.assistants, + assistants, [this.entry.entity_id], ev.target.checked ); @@ -305,6 +356,7 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) { margin: 32px; margin-top: 0; --settings-row-prefix-display: contents; + --settings-row-content-display: contents; } ha-settings-row { padding: 0; diff --git a/src/translations/en.json b/src/translations/en.json index e04d09888b..573ed1bcdb 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1083,7 +1083,8 @@ "aliases_header": "Aliases", "aliases_description": "Aliases are supported by Assist and Google Assistant.", "ask_pin": "Ask for PIN", - "manual_config": "Managed with filters in configuration.yaml" + "manual_config": "Managed in configuration.yaml", + "unsupported": "Unsupported" }, "restart": { "heading": "Restart Home Assistant",