Skip to content

Commit

Permalink
Preload energy prefs and recorder info
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bdraco committed Oct 25, 2023
1 parent e16a101 commit 3ec7431
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 32 deletions.
12 changes: 8 additions & 4 deletions src/data/energy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -208,8 +212,8 @@ export const getEnergyPreferenceValidation = async (hass: HomeAssistant) => {
});
};

export const getEnergyPreferences = (hass: HomeAssistant) =>
hass.callWS<EnergyPreferences>({
export const getEnergyPreferences = (conn: Connection) =>
conn.sendMessagePromise<EnergyPreferences>({
type: "energy/get_prefs",
});

Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 0 additions & 5 deletions src/data/lovelace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,6 @@ export const getLegacyLovelaceCollection = (conn: Connection) =>
)
);

export interface WindowWithLovelaceProm extends Window {
llConfProm?: Promise<LovelaceConfig>;
llResProm?: Promise<LovelaceResource[]>;
}

export interface ActionHandlerOptions {
hasHold?: boolean;
hasDoubleClick?: boolean;
Expand Down
10 changes: 10 additions & 0 deletions src/data/preloads.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LovelaceConfig, LovelaceResource } from "./lovelace";
import { RecorderInfo } from "./recorder";
import { EnergyPreferences } from "./energy";

export interface WindowWithPreloads extends Window {
llConfProm?: Promise<LovelaceConfig>;
llResProm?: Promise<LovelaceResource[]>;
recorderInfoProm?: Promise<RecorderInfo>;
energyPreferencesProm?: Promise<EnergyPreferences>;
}
5 changes: 3 additions & 2 deletions src/data/recorder.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -115,8 +116,8 @@ export interface StatisticsValidationResults {
[statisticId: string]: StatisticsValidationResult[];
}

export const getRecorderInfo = (hass: HomeAssistant) =>
hass.callWS<RecorderInfo>({
export const getRecorderInfo = (conn: Connection) =>
conn.sendMessagePromise<RecorderInfo>({
type: "recorder/info",
});

Expand Down
20 changes: 11 additions & 9 deletions src/entrypoints/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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__;
Expand Down Expand Up @@ -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);
}
});
13 changes: 11 additions & 2 deletions src/layouts/home-assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<RecorderInfo> | 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) {
Expand Down
2 changes: 1 addition & 1 deletion src/panels/config/energy/ha-config-energy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/panels/energy/strategies/energy-view-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 6 additions & 6 deletions src/panels/lovelace/ha-panel-lovelace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -220,16 +220,16 @@ export class LovelacePanel extends LitElement {
let rawConf: LovelaceConfig | undefined;
let confMode: Lovelace["mode"] = this.panel!.config.mode;
let confProm: Promise<LovelaceConfig> | 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!);
}
Expand Down
15 changes: 13 additions & 2 deletions src/panels/lovelace/strategies/original-states-view-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -28,11 +29,21 @@ export class OriginalStatesViewStrategy extends ReactiveElement {
};
}

let energyPreferencesProm: Promise<EnergyPreferences> | 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,
]);

Expand Down

0 comments on commit 3ec7431

Please sign in to comment.