From 3ec7431e02fbb4dd0246ebec0e5d802806b6362e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 25 Oct 2023 12:48:25 -0500 Subject: [PATCH] Preload energy prefs and recorder info These are always called late when loading the UI which means another round trip to fetch them. Since we know we are going to fetch them anyways, add them as preloads. The recorder prefetch makes quite a difference outside the local network since the whole UI blocks to wait for it to come back. follow up to #18384 and #18332 --- src/data/energy.ts | 12 +++++++---- src/data/lovelace.ts | 5 ----- src/data/preloads.ts | 10 ++++++++++ src/data/recorder.ts | 5 +++-- src/entrypoints/core.ts | 20 ++++++++++--------- src/layouts/home-assistant.ts | 13 ++++++++++-- src/panels/config/energy/ha-config-energy.ts | 2 +- .../energy/strategies/energy-view-strategy.ts | 2 +- src/panels/lovelace/ha-panel-lovelace.ts | 12 +++++------ .../original-states-view-strategy.ts | 15 ++++++++++++-- 10 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 src/data/preloads.ts diff --git a/src/data/energy.ts b/src/data/energy.ts index fbc89045a96e..e4190814ca9e 100644 --- a/src/data/energy.ts +++ b/src/data/energy.ts @@ -10,7 +10,11 @@ import { isFirstDayOfMonth, isLastDayOfMonth, } from "date-fns/esm"; -import { Collection, getCollection } from "home-assistant-js-websocket"; +import { + Collection, + Connection, + getCollection, +} from "home-assistant-js-websocket"; import { calcDate, calcDateProperty } from "../common/datetime/calc_date"; import { formatTime24h } from "../common/datetime/format_time"; import { groupBy } from "../common/util/group-by"; @@ -208,8 +212,8 @@ export const getEnergyPreferenceValidation = async (hass: HomeAssistant) => { }); }; -export const getEnergyPreferences = (hass: HomeAssistant) => - hass.callWS({ +export const getEnergyPreferences = (conn: Connection) => + conn.sendMessagePromise({ type: "energy/get_prefs", }); @@ -606,7 +610,7 @@ export const getEnergyDataCollection = ( if (!collection.prefs) { // This will raise if not found. // Detect by checking `e.code === "not_found" - collection.prefs = await getEnergyPreferences(hass); + collection.prefs = await getEnergyPreferences(hass.connection); } if (collection._refreshTimeout) { diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index b8d13b2004dd..87279bc2b0ff 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -348,11 +348,6 @@ export const getLegacyLovelaceCollection = (conn: Connection) => ) ); -export interface WindowWithLovelaceProm extends Window { - llConfProm?: Promise; - llResProm?: Promise; -} - export interface ActionHandlerOptions { hasHold?: boolean; hasDoubleClick?: boolean; diff --git a/src/data/preloads.ts b/src/data/preloads.ts new file mode 100644 index 000000000000..3dbdde995269 --- /dev/null +++ b/src/data/preloads.ts @@ -0,0 +1,10 @@ +import { LovelaceConfig, LovelaceResource } from "./lovelace"; +import { RecorderInfo } from "./recorder"; +import { EnergyPreferences } from "./energy"; + +export interface WindowWithPreloads extends Window { + llConfProm?: Promise; + llResProm?: Promise; + recorderInfoProm?: Promise; + energyPreferencesProm?: Promise; +} diff --git a/src/data/recorder.ts b/src/data/recorder.ts index 32b471f4a75d..23b63a6d1cb4 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -1,3 +1,4 @@ +import { Connection } from "home-assistant-js-websocket"; import { computeStateName } from "../common/entity/compute_state_name"; import { HaDurationData } from "../components/ha-duration-input"; import { HomeAssistant } from "../types"; @@ -115,8 +116,8 @@ export interface StatisticsValidationResults { [statisticId: string]: StatisticsValidationResult[]; } -export const getRecorderInfo = (hass: HomeAssistant) => - hass.callWS({ +export const getRecorderInfo = (conn: Connection) => + conn.sendMessagePromise({ type: "recorder/info", }); diff --git a/src/entrypoints/core.ts b/src/entrypoints/core.ts index 5353a142435c..a7aa01eb342a 100644 --- a/src/entrypoints/core.ts +++ b/src/entrypoints/core.ts @@ -13,12 +13,10 @@ import { import { loadTokens, saveTokens } from "../common/auth/token_storage"; import { hassUrl } from "../data/auth"; import { isExternal } from "../data/external"; +import { getRecorderInfo } from "../data/recorder"; +import { getEnergyPreferences } from "../data/energy"; import { subscribeFrontendUserData } from "../data/frontend"; -import { - fetchConfig, - fetchResources, - WindowWithLovelaceProm, -} from "../data/lovelace"; +import { fetchConfig, fetchResources } from "../data/lovelace"; import { subscribePanels } from "../data/ws-panels"; import { subscribeThemes } from "../data/ws-themes"; import { subscribeRepairsIssueRegistry } from "../data/repairs"; @@ -27,6 +25,7 @@ import type { ExternalAuth } from "../external_app/external_auth"; import "../resources/array.flat.polyfill"; import "../resources/safari-14-attachshadow-patch"; import { MAIN_WINDOW_NAME } from "../data/main_window"; +import { WindowWithPreloads } from "../data/preloads"; window.name = MAIN_WINDOW_NAME; (window as any).frontendVersion = __VERSION__; @@ -124,12 +123,15 @@ window.hassConnection.then(({ conn }) => { subscribeFrontendUserData(conn, "core", noop); subscribeRepairsIssueRegistry(conn, noop); + const preloadWindow = window as WindowWithPreloads; + preloadWindow.recorderInfoProm = getRecorderInfo(conn); + if (location.pathname === "/" || location.pathname.startsWith("/lovelace/")) { - const llWindow = window as WindowWithLovelaceProm; - llWindow.llConfProm = fetchConfig(conn, null, false); - llWindow.llConfProm.catch(() => { + preloadWindow.llConfProm = fetchConfig(conn, null, false); + preloadWindow.llConfProm.catch(() => { // Ignore it, it is handled by Lovelace panel. }); - llWindow.llResProm = fetchResources(conn); + preloadWindow.llResProm = fetchResources(conn); + preloadWindow.energyPreferencesProm = getEnergyPreferences(conn); } }); diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index ba9f321c7976..f9781eef5db5 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -3,11 +3,12 @@ import { customElement, state } from "lit/decorators"; import { isNavigationClick } from "../common/dom/is-navigation-click"; import { navigate } from "../common/navigate"; import { getStorageDefaultPanelUrlPath } from "../data/panel"; -import { getRecorderInfo } from "../data/recorder"; +import { getRecorderInfo, RecorderInfo } from "../data/recorder"; import "../resources/custom-card-support"; import { HassElement } from "../state/hass-element"; import QuickBarMixin from "../state/quick-bar-mixin"; import { HomeAssistant, Route } from "../types"; +import { WindowWithPreloads } from "../data/preloads"; import { storeState } from "../util/ha-pref-storage"; import { renderLaunchScreenInfoBox, @@ -204,7 +205,15 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { protected async checkDataBaseMigration() { if (this.hass?.config?.components.includes("recorder")) { - const info = await getRecorderInfo(this.hass); + let recorderInfoProm: Promise | undefined; + const preloadWindow = window as WindowWithPreloads; + // On first load, we speed up loading page by having recorderInfoProm ready + if (preloadWindow.recorderInfoProm) { + recorderInfoProm = preloadWindow.recorderInfoProm; + preloadWindow.recorderInfoProm = undefined; + } + const info = await (recorderInfoProm || + getRecorderInfo(this.hass.connection)); this._databaseMigration = info.migration_in_progress && !info.migration_is_live; if (this._databaseMigration) { diff --git a/src/panels/config/energy/ha-config-energy.ts b/src/panels/config/energy/ha-config-energy.ts index c31cbd135171..15d77e7e3c60 100644 --- a/src/panels/config/energy/ha-config-energy.ts +++ b/src/panels/config/energy/ha-config-energy.ts @@ -142,7 +142,7 @@ class HaConfigEnergy extends LitElement { const validationPromise = getEnergyPreferenceValidation(this.hass); const energyInfoPromise = await getEnergyInfo(this.hass); try { - this._preferences = await getEnergyPreferences(this.hass); + this._preferences = await getEnergyPreferences(this.hass.connection); } catch (err: any) { if (err.code === "not_found") { this._preferences = INITIAL_CONFIG; diff --git a/src/panels/energy/strategies/energy-view-strategy.ts b/src/panels/energy/strategies/energy-view-strategy.ts index 4c263ea438f7..2922f2125098 100644 --- a/src/panels/energy/strategies/energy-view-strategy.ts +++ b/src/panels/energy/strategies/energy-view-strategy.ts @@ -34,7 +34,7 @@ export class EnergyViewStrategy extends ReactiveElement { let prefs: EnergyPreferences; try { - prefs = await getEnergyPreferences(hass); + prefs = await getEnergyPreferences(hass.connection); } catch (err: any) { if (err.code === "not_found") { return setupWizard(); diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index 9fd8da1d9db8..ae6bc209ed09 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -15,8 +15,8 @@ import { LovelaceConfig, saveConfig, subscribeLovelaceUpdates, - WindowWithLovelaceProm, } from "../../data/lovelace"; +import { WindowWithPreloads } from "../../data/preloads"; import "../../layouts/hass-error-screen"; import "../../layouts/hass-loading-screen"; import { HomeAssistant, PanelInfo, Route } from "../../types"; @@ -220,16 +220,16 @@ export class LovelacePanel extends LitElement { let rawConf: LovelaceConfig | undefined; let confMode: Lovelace["mode"] = this.panel!.config.mode; let confProm: Promise | undefined; - const llWindow = window as WindowWithLovelaceProm; + const preloadWindow = window as WindowWithPreloads; // On first load, we speed up loading page by having LL promise ready - if (llWindow.llConfProm) { - confProm = llWindow.llConfProm; - llWindow.llConfProm = undefined; + if (preloadWindow.llConfProm) { + confProm = preloadWindow.llConfProm; + preloadWindow.llConfProm = undefined; } if (!resourcesLoaded) { resourcesLoaded = true; - const resources = await (llWindow.llResProm || + const resources = await (preloadWindow.llResProm || fetchResources(this.hass!.connection)); loadLovelaceResources(resources, this.hass!); } diff --git a/src/panels/lovelace/strategies/original-states-view-strategy.ts b/src/panels/lovelace/strategies/original-states-view-strategy.ts index c1708cc04788..c9748f3908e1 100644 --- a/src/panels/lovelace/strategies/original-states-view-strategy.ts +++ b/src/panels/lovelace/strategies/original-states-view-strategy.ts @@ -2,7 +2,8 @@ import { STATE_NOT_RUNNING } from "home-assistant-js-websocket"; import { ReactiveElement } from "lit"; import { customElement } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; -import { getEnergyPreferences } from "../../../data/energy"; +import { getEnergyPreferences, EnergyPreferences } from "../../../data/energy"; +import { WindowWithPreloads } from "../../../data/preloads"; import { LovelaceStrategyConfig, LovelaceViewConfig, @@ -28,11 +29,21 @@ export class OriginalStatesViewStrategy extends ReactiveElement { }; } + let energyPreferencesProm: Promise | undefined; + const preloadWindow = window as WindowWithPreloads; + // On first load, we speed up loading page by having energyPreferencesProm ready + if (preloadWindow.energyPreferencesProm) { + energyPreferencesProm = preloadWindow.energyPreferencesProm; + preloadWindow.energyPreferencesProm = undefined; + } + const [localize, energyPrefs] = await Promise.all([ hass.loadBackendTranslation("title"), isComponentLoaded(hass, "energy") ? // It raises if not configured, just swallow that. - getEnergyPreferences(hass).catch(() => undefined) + ( + energyPreferencesProm || getEnergyPreferences(hass.connection) + ).catch(() => undefined) : undefined, ]);