Skip to content

Commit

Permalink
20241127.2 (#23104)
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten authored Dec 2, 2024
2 parents 6e00390 + 04beef5 commit 1ebd130
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 51 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "home-assistant-frontend"
version = "20241127.1"
version = "20241127.2"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
Expand Down
19 changes: 19 additions & 0 deletions src/data/hassio/supervisor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,25 @@ export const fetchHassioLogsFollow = async (
signal
);

export const fetchHassioLogsFollowSkip = async (
hass: HomeAssistant,
provider: string,
signal: AbortSignal,
cursor: string,
skipLines: number,
lines = 100,
boot = 0
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs${boot !== 0 ? `/boots/${boot}` : ""}/follow`,
undefined,
{
Range: `entries=${cursor}:${skipLines}:${lines}`,
},
signal
);

export const getHassioLogDownloadUrl = (provider: string) =>
`/api/hassio/${
provider.includes("_") ? `addons/${provider}` : provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {

@state() private _detailState?: string;

@state() private _error?: string;

@state() private _localTts?: EntityRegistryDisplayEntry[];

@state() private _localStt?: EntityRegistryDisplayEntry[];
Expand All @@ -62,6 +64,7 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
alt="Casita Home Assistant error logo"
/>
<h1>Failed to install add-ons</h1>
<p>${this._error}</p>
<p>
We could not automatically install a local TTS and STT provider
for you. Read the documentation to learn how to install them.
Expand Down Expand Up @@ -179,8 +182,9 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
}
this._detailState = "Creating assistant";
await this._findEntitiesAndCreatePipeline();
} catch (e) {
} catch (e: any) {
this._state = "ERROR";
this._error = e.message;
}
}

Expand All @@ -199,11 +203,13 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
private async _setupConfigEntry(addon: string) {
const configFlow = await createConfigFlow(this.hass, "wyoming");
const step = await handleConfigFlowStep(this.hass, configFlow.flow_id, {
host: `core_${addon}`,
host: `core-${addon}`,
port: addon === "piper" ? 10200 : 10300,
});
if (step.type !== "create_entry") {
throw new Error("Failed to create entry");
throw new Error(
`Failed to create entry for ${addon}${"errors" in step ? `: ${step.errors.base}` : ""}`
);
}
}

Expand Down Expand Up @@ -321,7 +327,7 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
this._findLocalEntities();
if (!this._localTts?.length || !this._localStt?.length) {
if (tryNo > 3) {
throw new Error("Timeout searching for local TTS and STT entities");
throw new Error("Could not find local TTS and STT entities");
}
await new Promise<void>((resolve) => {
setTimeout(resolve, 2000);
Expand Down
13 changes: 7 additions & 6 deletions src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ export class HaVoiceCommandDialog extends LitElement {

const controlHA = !this._pipeline
? false
: this.hass.states[this._pipeline?.conversation_engine]
? supportsFeature(
this.hass.states[this._pipeline?.conversation_engine],
ConversationEntityFeature.CONTROL
)
: true;
: this._pipeline.prefer_local_intents ||
(this.hass.states[this._pipeline.conversation_engine]
? supportsFeature(
this.hass.states[this._pipeline.conversation_engine],
ConversationEntityFeature.CONTROL
)
: true);
const supportsMicrophone = AudioRecorder.isSupported;
const supportsSTT = this._pipeline?.stt_engine;

Expand Down
90 changes: 61 additions & 29 deletions src/panels/config/logs/error-log-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
fetchHassioBoots,
fetchHassioLogs,
fetchHassioLogsFollow,
fetchHassioLogsFollowSkip,
fetchHassioLogsLegacy,
getHassioLogDownloadLinesUrl,
getHassioLogDownloadUrl,
Expand Down Expand Up @@ -428,46 +429,66 @@ class ErrorLogCard extends LitElement {
}
}

private async _loadLogs(): Promise<void> {
private async _loadLogs(retry = false): Promise<void> {
this._error = undefined;
this._loadingState = "loading";
this._loadingPrevState = undefined;
this._firstCursor = undefined;
this._numberOfLines = 0;
this._ansiToHtmlElement?.clear();
this._numberOfLines = retry ? (this._numberOfLines ?? 0) : 0;

if (!retry) {
this._loadingPrevState = undefined;
this._firstCursor = undefined;
this._ansiToHtmlElement?.clear();
}

const streamLogs =
this._streamSupported &&
isComponentLoaded(this.hass, "hassio") &&
this.provider;

try {
if (this._logStreamAborter) {
this._logStreamAborter.abort();
this._logStreamAborter = undefined;
}

if (
this._streamSupported &&
isComponentLoaded(this.hass, "hassio") &&
this.provider
) {
if (streamLogs) {
this._logStreamAborter = new AbortController();

// check if there are any logs at all
const testResponse = await fetchHassioLogs(
this.hass,
this.provider,
`entries=:-1:`,
this._boot
);
const testLogs = await testResponse.text();
if (!testLogs.trim()) {
this._loadingState = "empty";
if (!retry) {
// check if there are any logs at all
const testResponse = await fetchHassioLogs(
this.hass,
this.provider!,
`entries=:-1:`,
this._boot
);
const testLogs = await testResponse.text();
if (!testLogs.trim()) {
this._loadingState = "empty";
}
}

const response = await fetchHassioLogsFollow(
this.hass,
this.provider,
this._logStreamAborter.signal,
NUMBER_OF_LINES,
this._boot
);
let response: Response;

if (retry && this._firstCursor) {
response = await fetchHassioLogsFollowSkip(
this.hass,
this.provider!,
this._logStreamAborter.signal,
this._firstCursor,
this._numberOfLines,
NUMBER_OF_LINES,
this._boot
);
} else {
response = await fetchHassioLogsFollow(
this.hass,
this.provider!,
this._logStreamAborter.signal,
NUMBER_OF_LINES,
this._boot
);
}

if (response.headers.has("X-First-Cursor")) {
this._firstCursor = response.headers.get("X-First-Cursor")!;
Expand Down Expand Up @@ -524,14 +545,17 @@ class ErrorLogCard extends LitElement {

if (!this._downloadSupported) {
const downloadUrl = getHassioLogDownloadLinesUrl(
this.provider,
this.provider!,
this._numberOfLines,
this._boot
);
getSignedPath(this.hass, downloadUrl).then((signedUrl) => {
this._logsFileLink = signedUrl.path;
});
}

// first chunk loads successfully, reset retry param
retry = false;
}
}
} else {
Expand All @@ -554,6 +578,13 @@ class ErrorLogCard extends LitElement {
if (err.name === "AbortError") {
return;
}

// The stream can fail if the connection is lost or firefox service worker intercept the connection
if (!retry && streamLogs) {
this._loadLogs(true);
return;
}

this._error = (this.localizeFunc || this.hass.localize)(
"ui.panel.config.logs.failed_get_logs",
{
Expand Down Expand Up @@ -590,9 +621,10 @@ class ErrorLogCard extends LitElement {
private _handleConnectionStatus = (ev: HASSDomEvent<ConnectionStatus>) => {
if (ev.detail === "disconnected" && this._logStreamAborter) {
this._logStreamAborter.abort();
this._loadingState = "loading";
}
if (ev.detail === "connected") {
this._loadLogs();
this._loadLogs(true);
}
};

Expand Down
33 changes: 28 additions & 5 deletions src/panels/config/scene/ha-scene-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
mdiContentSave,
mdiDelete,
mdiDotsVertical,
mdiEye,
mdiInformationOutline,
mdiMotionPlayOutline,
mdiPlay,
mdiTag,
} from "@mdi/js";
Expand Down Expand Up @@ -204,6 +206,14 @@ export class HaSceneEditor extends SubscribeMixin(
}
);

public connectedCallback() {
super.connectedCallback();
if (!this.sceneId) {
this._mode = "live";
this._subscribeEvents();
}
}

public disconnectedCallback() {
super.disconnectedCallback();
if (this._unsubscribeEvents) {
Expand Down Expand Up @@ -387,15 +397,22 @@ export class HaSceneEditor extends SubscribeMixin(
alert-type="info"
.narrow=${this.narrow}
.title=${this.hass.localize(
`ui.panel.config.scene.editor.${this._mode === "live" ? "live_preview" : "review_mode"}`
`ui.panel.config.scene.editor.${this._mode === "live" ? "live_edit" : "review_mode"}`
)}
>
${this.hass.localize(
`ui.panel.config.scene.editor.${this._mode === "live" ? "live_preview_detail" : "review_mode_detail"}`
`ui.panel.config.scene.editor.${this._mode === "live" ? "live_edit_detail" : "review_mode_detail"}`
)}
<span slot="icon">
<ha-svg-icon
.path=${this._mode === "live"
? mdiMotionPlayOutline
: mdiEye}
></ha-svg-icon>
</span>
<ha-button slot="action" @click=${this._toggleLiveMode}>
${this.hass.localize(
`ui.panel.config.scene.editor.${this._mode === "live" ? "back_to_review_mode" : "live_preview"}`
`ui.panel.config.scene.editor.${this._mode === "live" ? "switch_to_review_mode" : "live_edit"}`
)}
</ha-button>
</ha-alert>
Expand Down Expand Up @@ -542,6 +559,7 @@ export class HaSceneEditor extends SubscribeMixin(
}
return html`
<ha-list-item
class="entity"
hasMeta
.graphic=${this._mode === "live"
? "icon"
Expand Down Expand Up @@ -759,13 +777,15 @@ export class HaSceneEditor extends SubscribeMixin(
text: this.hass.localize(
"ui.panel.config.scene.editor.enter_live_mode_unsaved"
),
confirmText: this.hass!.localize("ui.common.continue"),
destructive: true,
confirmText: this.hass!.localize(
"ui.panel.config.scene.editor.save_before_live"
),
dismissText: this.hass!.localize("ui.common.cancel"),
});
if (!result) {
return;
}
await this._saveScene();
}

this._entities.forEach((entity) => this._storeState(entity));
Expand Down Expand Up @@ -1309,6 +1329,9 @@ export class HaSceneEditor extends SubscribeMixin(
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
ha-list-item.entity {
padding-right: 28px;
}
`,
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class HuiHistoryGraphCardEditor
{
name: "hours_to_show",
default: DEFAULT_HOURS_TO_SHOW,
selector: { number: { min: 1, mode: "box" } },
selector: { number: { min: 0, step: "any", mode: "box" } },
},
],
},
Expand Down
11 changes: 6 additions & 5 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3878,11 +3878,12 @@
},
"editor": {
"review_mode": "Review Mode",
"review_mode_detail": "You can adjust the scene's details and remove devices or entities. To fully edit, switch to Live Preview, which will apply the scene.",
"live_preview": "Live Preview",
"live_preview_detail": "In Live Preview, all changes to this scene are applied in real-time to your devices and entities.",
"enter_live_mode_unsaved": "You have unsaved changes to this scene. Continuing to live preview will apply the saved scene, which may overwrite your unsaved changes. Consider if you would like to save the scene first before activating it.",
"back_to_review_mode": "Back to review mode",
"review_mode_detail": "You can adjust the scene's details and remove devices or entities. To fully edit, switch to Live Edit, which will apply the scene.",
"live_edit": "Live Edit",
"live_edit_detail": "In Live Edit, all changes to this scene are applied in real-time to your devices and entities.",
"enter_live_mode_unsaved": "Before proceeding to Live Edit, please save your current changes.",
"save_before_live": "Save and Live Edit",
"switch_to_review_mode": "Switch to review mode",
"default_name": "New scene",
"load_error_not_editable": "Only scenes in scenes.yaml are editable.",
"load_error_unknown": "Error loading scene ({err_no}).",
Expand Down

0 comments on commit 1ebd130

Please sign in to comment.