diff --git a/src/panels/energy/constants.ts b/src/panels/energy/constants.ts new file mode 100644 index 0000000000..e682c7314f --- /dev/null +++ b/src/panels/energy/constants.ts @@ -0,0 +1,2 @@ +export const DEFAULT_ENERGY_COLLECTION_KEY = "energy_dashboard"; +export const DEFAULT_POWER_COLLECTION_KEY = "energy_dashboard_now"; diff --git a/src/panels/energy/ha-panel-energy.ts b/src/panels/energy/ha-panel-energy.ts index eca00a476d..e5616547f7 100644 --- a/src/panels/energy/ha-panel-energy.ts +++ b/src/panels/energy/ha-panel-energy.ts @@ -1,78 +1,20 @@ import type { CSSResultGroup, PropertyValues } from "lit"; -import { LitElement, css, html, nothing } from "lit"; +import { LitElement, css, html } from "lit"; import { customElement, property, state } from "lit/decorators"; import { navigate } from "../../common/navigate"; -import type { LocalizeKeys } from "../../common/translations/localize"; import "../../components/ha-alert"; import "../../components/ha-icon-button-arrow-prev"; import "../../components/ha-menu-button"; import "../../components/ha-top-app-bar-fixed"; -import type { EnergyPreferences } from "../../data/energy"; -import { getEnergyDataCollection } from "../../data/energy"; import type { LovelaceConfig } from "../../data/lovelace/config/types"; -import type { LovelaceViewConfig } from "../../data/lovelace/config/view"; import { haStyle } from "../../resources/styles"; import type { HomeAssistant, PanelInfo } from "../../types"; +import { generateLovelaceDashboardStrategy } from "../lovelace/strategies/get-strategy"; import "../lovelace/hui-root"; import type { Lovelace } from "../lovelace/types"; import "../lovelace/views/hui-view"; import "../lovelace/views/hui-view-container"; -export const DEFAULT_ENERGY_COLLECTION_KEY = "energy_dashboard"; -export const DEFAULT_POWER_COLLECTION_KEY = "energy_dashboard_now"; - -const EMPTY_PREFERENCES: EnergyPreferences = { - energy_sources: [], - device_consumption: [], - device_consumption_water: [], -}; - -const OVERVIEW_VIEW = { - path: "overview", - strategy: { - type: "energy-overview", - collection_key: DEFAULT_ENERGY_COLLECTION_KEY, - }, -} as LovelaceViewConfig; - -const ENERGY_VIEW = { - path: "electricity", - strategy: { - type: "energy", - collection_key: DEFAULT_ENERGY_COLLECTION_KEY, - }, -} as LovelaceViewConfig; - -const WATER_VIEW = { - path: "water", - strategy: { - type: "water", - collection_key: DEFAULT_ENERGY_COLLECTION_KEY, - }, -} as LovelaceViewConfig; - -const GAS_VIEW = { - path: "gas", - strategy: { - type: "gas", - collection_key: DEFAULT_ENERGY_COLLECTION_KEY, - }, -} as LovelaceViewConfig; - -const POWER_VIEW = { - path: "now", - strategy: { - type: "power", - collection_key: DEFAULT_POWER_COLLECTION_KEY, - }, -} as LovelaceViewConfig; - -const WIZARD_VIEW = { - type: "panel", - path: "setup", - cards: [{ type: "custom:energy-setup-wizard-card" }], -}; - @customElement("ha-panel-energy") class PanelEnergy extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -88,9 +30,6 @@ class PanelEnergy extends LitElement { prefix: string; }; - @state() - private _prefs?: EnergyPreferences; - @state() private _searchParms = new URLSearchParams(window.location.search); @state() @@ -115,35 +54,16 @@ class PanelEnergy extends LitElement { } } - private _fetchEnergyPrefs = async (): Promise< - EnergyPreferences | undefined - > => { - const collection = getEnergyDataCollection(this.hass, { - key: DEFAULT_ENERGY_COLLECTION_KEY, - }); - try { - await collection.refresh(); - } catch (err: any) { - if (err.code === "not_found") { - return undefined; - } - throw err; - } - return collection.prefs; - }; - private async _loadConfig() { try { this._error = undefined; - const prefs = await this._fetchEnergyPrefs(); - this._prefs = prefs || EMPTY_PREFERENCES; + await this._setLovelace(); } catch (err) { // eslint-disable-next-line no-console - console.error("Failed to load prefs:", err); - this._prefs = EMPTY_PREFERENCES; + console.error("Failed to load energy config:", err); this._error = (err as Error).message || "Unknown error"; + return; } - await this._setLovelace(); // Check if current path is valid, navigate to first view if not const views = this._lovelace!.config?.views || []; @@ -158,7 +78,10 @@ class PanelEnergy extends LitElement { } private async _setLovelace() { - const config = await this._generateLovelaceConfig(); + const config: LovelaceConfig = await generateLovelaceDashboardStrategy( + { strategy: { type: "energy" } }, + this.hass + ); this._lovelace = { config: config, @@ -188,8 +111,7 @@ class PanelEnergy extends LitElement { `; } - if (!this._prefs) { - // Still loading + if (!this._lovelace) { return html`
@@ -197,10 +119,6 @@ class PanelEnergy extends LitElement { `; } - if (!this._lovelace) { - return nothing; - } - return html` { - if ( - !this._prefs || - (this._prefs.device_consumption.length === 0 && - this._prefs.energy_sources.length === 0) - ) { - await import("./cards/energy-setup-wizard-card"); - return { - views: [WIZARD_VIEW], - }; - } - - const hasEnergy = this._prefs.energy_sources.some((source) => - ["grid", "solar", "battery"].includes(source.type) - ); - - const hasPowerSource = this._prefs.energy_sources.some((source) => { - if (source.type === "solar" && source.stat_rate) return true; - if (source.type === "battery" && source.stat_rate) return true; - if (source.type === "grid") { - return !!source.stat_rate || !!source.power_config; - } - return false; - }); - - const hasDevicePower = this._prefs.device_consumption.some( - (device) => device.stat_rate - ); - - const hasPower = hasPowerSource || hasDevicePower; - - const hasWater = - this._prefs.energy_sources.some((source) => source.type === "water") || - this._prefs.device_consumption_water?.length > 0; - - const hasGas = this._prefs.energy_sources.some( - (source) => source.type === "gas" - ); - - const hasDeviceConsumption = this._prefs.device_consumption.length > 0; - - const views: LovelaceViewConfig[] = []; - if (hasEnergy || hasDeviceConsumption) { - views.push(ENERGY_VIEW); - } - if (hasGas) { - views.push(GAS_VIEW); - } - if (hasWater) { - views.push(WATER_VIEW); - } - if (hasPower) { - views.push(POWER_VIEW); - } - if ( - hasPowerSource || - [hasEnergy, hasGas, hasWater].filter(Boolean).length > 1 - ) { - views.unshift(OVERVIEW_VIEW); - } - return { - views: views.map((view) => ({ - ...view, - title: - view.title || - this.hass.localize( - `ui.panel.energy.title.${view.path}` as LocalizeKeys - ), - })), - }; - } - private _navigateConfig(ev?: Event) { ev?.stopPropagation(); const viewPath = this.route?.path?.split("/")[1] || ""; diff --git a/src/panels/energy/strategies/energy-dashboard-strategy.ts b/src/panels/energy/strategies/energy-dashboard-strategy.ts new file mode 100644 index 0000000000..a5bd9bef7e --- /dev/null +++ b/src/panels/energy/strategies/energy-dashboard-strategy.ts @@ -0,0 +1,170 @@ +import { ReactiveElement } from "lit"; +import { customElement } from "lit/decorators"; +import { getEnergyDataCollection } from "../../../data/energy"; +import type { EnergyPreferences } from "../../../data/energy"; +import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; +import type { LovelaceConfig } from "../../../data/lovelace/config/types"; +import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; +import type { LocalizeKeys } from "../../../common/translations/localize"; +import type { HomeAssistant } from "../../../types"; +import { + DEFAULT_ENERGY_COLLECTION_KEY, + DEFAULT_POWER_COLLECTION_KEY, +} from "../constants"; + +const OVERVIEW_VIEW = { + path: "overview", + strategy: { + type: "energy-overview", + collection_key: DEFAULT_ENERGY_COLLECTION_KEY, + }, +} as LovelaceViewConfig; + +const ENERGY_VIEW = { + path: "electricity", + strategy: { + type: "energy", + collection_key: DEFAULT_ENERGY_COLLECTION_KEY, + }, +} as LovelaceViewConfig; + +const WATER_VIEW = { + path: "water", + strategy: { + type: "water", + collection_key: DEFAULT_ENERGY_COLLECTION_KEY, + }, +} as LovelaceViewConfig; + +const GAS_VIEW = { + path: "gas", + strategy: { + type: "gas", + collection_key: DEFAULT_ENERGY_COLLECTION_KEY, + }, +} as LovelaceViewConfig; + +const POWER_VIEW = { + path: "now", + strategy: { + type: "power", + collection_key: DEFAULT_POWER_COLLECTION_KEY, + }, +} as LovelaceViewConfig; + +const WIZARD_VIEW = { + type: "panel", + path: "setup", + cards: [{ type: "custom:energy-setup-wizard-card" }], +}; + +const EMPTY_PREFERENCES: EnergyPreferences = { + energy_sources: [], + device_consumption: [], + device_consumption_water: [], +}; + +export interface EnergyDashboardStrategyConfig extends LovelaceStrategyConfig { + type: "energy"; +} + +@customElement("energy-dashboard-strategy") +export class EnergyDashboardStrategy extends ReactiveElement { + static async generate( + _config: EnergyDashboardStrategyConfig, + hass: HomeAssistant + ): Promise { + const prefs = await fetchEnergyPrefs(hass); + + if ( + !prefs || + (prefs.device_consumption.length === 0 && + prefs.energy_sources.length === 0) + ) { + await import("../cards/energy-setup-wizard-card"); + return { + views: [WIZARD_VIEW], + }; + } + + const hasEnergy = prefs.energy_sources.some((source) => + ["grid", "solar", "battery"].includes(source.type) + ); + + const hasPowerSource = prefs.energy_sources.some((source) => { + if (source.type === "solar" && source.stat_rate) return true; + if (source.type === "battery" && source.stat_rate) return true; + if (source.type === "grid") { + return !!source.stat_rate || !!source.power_config; + } + return false; + }); + + const hasDevicePower = prefs.device_consumption.some( + (device) => device.stat_rate + ); + + const hasPower = hasPowerSource || hasDevicePower; + + const hasWater = + prefs.energy_sources.some((source) => source.type === "water") || + prefs.device_consumption_water?.length > 0; + + const hasGas = prefs.energy_sources.some((source) => source.type === "gas"); + + const hasDeviceConsumption = prefs.device_consumption.length > 0; + + const views: LovelaceViewConfig[] = []; + if (hasEnergy || hasDeviceConsumption) { + views.push(ENERGY_VIEW); + } + if (hasGas) { + views.push(GAS_VIEW); + } + if (hasWater) { + views.push(WATER_VIEW); + } + if (hasPower) { + views.push(POWER_VIEW); + } + if ( + hasPowerSource || + [hasEnergy, hasGas, hasWater].filter(Boolean).length > 1 + ) { + views.unshift(OVERVIEW_VIEW); + } + return { + views: views.map((view) => ({ + ...view, + title: + view.title || + hass.localize(`ui.panel.energy.title.${view.path}` as LocalizeKeys), + })), + }; + } + + static noEditor = true; +} + +async function fetchEnergyPrefs( + hass: HomeAssistant +): Promise { + const collection = getEnergyDataCollection(hass, { + key: DEFAULT_ENERGY_COLLECTION_KEY, + }); + try { + await collection.refresh(); + } catch (err: any) { + if (err.code === "not_found") { + return EMPTY_PREFERENCES; + } + throw err; + } + return collection.prefs || EMPTY_PREFERENCES; +} + +declare global { + interface HTMLElementTagNameMap { + "energy-dashboard-strategy": EnergyDashboardStrategy; + } +} diff --git a/src/panels/energy/strategies/energy-overview-view-strategy.ts b/src/panels/energy/strategies/energy-overview-view-strategy.ts index 2905ce0cfe..8a8523f893 100644 --- a/src/panels/energy/strategies/energy-overview-view-strategy.ts +++ b/src/panels/energy/strategies/energy-overview-view-strategy.ts @@ -5,7 +5,7 @@ import { getEnergyDataCollection } from "../../../data/energy"; import type { HomeAssistant } from "../../../types"; import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; -import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy"; +import { DEFAULT_ENERGY_COLLECTION_KEY } from "../constants"; @customElement("energy-overview-view-strategy") export class EnergyOverviewViewStrategy extends ReactiveElement { diff --git a/src/panels/energy/strategies/energy-view-strategy.ts b/src/panels/energy/strategies/energy-view-strategy.ts index dea22e7a3f..5f620f8ad7 100644 --- a/src/panels/energy/strategies/energy-view-strategy.ts +++ b/src/panels/energy/strategies/energy-view-strategy.ts @@ -6,7 +6,7 @@ import type { LovelaceCardConfig } from "../../../data/lovelace/config/card"; import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; import type { HomeAssistant } from "../../../types"; -import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy"; +import { DEFAULT_ENERGY_COLLECTION_KEY } from "../constants"; import { shouldShowFloorsAndAreas } from "./show-floors-and-areas"; import { LARGE_SCREEN_CONDITION, diff --git a/src/panels/energy/strategies/gas-view-strategy.ts b/src/panels/energy/strategies/gas-view-strategy.ts index 59a754daa7..15e9d74800 100644 --- a/src/panels/energy/strategies/gas-view-strategy.ts +++ b/src/panels/energy/strategies/gas-view-strategy.ts @@ -4,7 +4,7 @@ import { getEnergyDataCollection } from "../../../data/energy"; import type { HomeAssistant } from "../../../types"; import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; -import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy"; +import { DEFAULT_ENERGY_COLLECTION_KEY } from "../constants"; import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section"; @customElement("gas-view-strategy") diff --git a/src/panels/energy/strategies/power-view-strategy.ts b/src/panels/energy/strategies/power-view-strategy.ts index f223fa8e16..1c3e9110c7 100644 --- a/src/panels/energy/strategies/power-view-strategy.ts +++ b/src/panels/energy/strategies/power-view-strategy.ts @@ -4,7 +4,7 @@ import { getEnergyDataCollection } from "../../../data/energy"; import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; import type { HomeAssistant } from "../../../types"; -import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy"; +import { DEFAULT_ENERGY_COLLECTION_KEY } from "../constants"; import { shouldShowFloorsAndAreas } from "./show-floors-and-areas"; import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section"; import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge"; diff --git a/src/panels/energy/strategies/water-view-strategy.ts b/src/panels/energy/strategies/water-view-strategy.ts index 64209107b3..258aeaa794 100644 --- a/src/panels/energy/strategies/water-view-strategy.ts +++ b/src/panels/energy/strategies/water-view-strategy.ts @@ -5,7 +5,7 @@ import type { LovelaceSectionConfig } from "../../../data/lovelace/config/sectio import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; import type { LovelaceViewConfig } from "../../../data/lovelace/config/view"; import type { HomeAssistant } from "../../../types"; -import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy"; +import { DEFAULT_ENERGY_COLLECTION_KEY } from "../constants"; import { shouldShowFloorsAndAreas } from "./show-floors-and-areas"; @customElement("water-view-strategy") diff --git a/src/panels/lovelace/strategies/get-strategy.ts b/src/panels/lovelace/strategies/get-strategy.ts index 5295902508..139a64a8c5 100644 --- a/src/panels/lovelace/strategies/get-strategy.ts +++ b/src/panels/lovelace/strategies/get-strategy.ts @@ -34,6 +34,7 @@ const STRATEGIES: Record> = { iframe: () => import("./iframe/iframe-dashboard-strategy"), areas: () => import("./areas/areas-dashboard-strategy"), home: () => import("./home/home-dashboard-strategy"), + energy: () => import("../../energy/strategies/energy-dashboard-strategy"), }, view: { "original-states": () =>