diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 38d348be22..958e14e0e3 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -23,7 +23,6 @@ import { mockTranslations } from "./stubs/translations"; import { mockEnergy } from "./stubs/energy"; import { mockConfig } from "./stubs/config"; import { energyEntities } from "./stubs/entities"; -import { mockForecastSolar } from "./stubs/forecast_solar"; class HaDemo extends HomeAssistantAppEl { protected async _initializeHass() { @@ -52,7 +51,6 @@ class HaDemo extends HomeAssistantAppEl { mockMediaPlayer(hass); mockFrontend(hass); mockEnergy(hass); - mockForecastSolar(hass); mockConfig(hass); mockPersistentNotification(hass); diff --git a/demo/src/stubs/energy.ts b/demo/src/stubs/energy.ts index 4e921fc9b5..42e3fd5a20 100644 --- a/demo/src/stubs/energy.ts +++ b/demo/src/stubs/energy.ts @@ -1,3 +1,5 @@ +import { format, startOfToday, startOfTomorrow } from "date-fns"; +import { EnergySolarForecasts } from "../../../src/data/energy"; import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; export const mockEnergy = (hass: MockHomeAssistant) => { @@ -80,4 +82,53 @@ export const mockEnergy = (hass: MockHomeAssistant) => { ], })); hass.mockWS("energy/info", () => ({ cost_sensors: [] })); + const todayString = format(startOfToday(), "yyyy-MM-dd"); + const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd"); + hass.mockWS( + "energy/solar_forecast", + (): EnergySolarForecasts => ({ + solar_forecast: { + wh_hours: { + [`${todayString}T06:00:00`]: 0, + [`${todayString}T06:23:00`]: 6, + [`${todayString}T06:45:00`]: 39, + [`${todayString}T07:00:00`]: 28, + [`${todayString}T08:00:00`]: 208, + [`${todayString}T09:00:00`]: 352, + [`${todayString}T10:00:00`]: 544, + [`${todayString}T11:00:00`]: 748, + [`${todayString}T12:00:00`]: 1259, + [`${todayString}T13:00:00`]: 1361, + [`${todayString}T14:00:00`]: 1373, + [`${todayString}T15:00:00`]: 1370, + [`${todayString}T16:00:00`]: 1186, + [`${todayString}T17:00:00`]: 937, + [`${todayString}T18:00:00`]: 652, + [`${todayString}T19:00:00`]: 370, + [`${todayString}T20:00:00`]: 155, + [`${todayString}T21:48:00`]: 24, + [`${todayString}T22:36:00`]: 0, + [`${tomorrowString}T06:01:00`]: 0, + [`${tomorrowString}T06:23:00`]: 9, + [`${tomorrowString}T06:45:00`]: 47, + [`${tomorrowString}T07:00:00`]: 48, + [`${tomorrowString}T08:00:00`]: 473, + [`${tomorrowString}T09:00:00`]: 827, + [`${tomorrowString}T10:00:00`]: 1153, + [`${tomorrowString}T11:00:00`]: 1413, + [`${tomorrowString}T12:00:00`]: 1590, + [`${tomorrowString}T13:00:00`]: 1652, + [`${tomorrowString}T14:00:00`]: 1612, + [`${tomorrowString}T15:00:00`]: 1438, + [`${tomorrowString}T16:00:00`]: 1149, + [`${tomorrowString}T17:00:00`]: 830, + [`${tomorrowString}T18:00:00`]: 542, + [`${tomorrowString}T19:00:00`]: 311, + [`${tomorrowString}T20:00:00`]: 140, + [`${tomorrowString}T21:47:00`]: 22, + [`${tomorrowString}T22:34:00`]: 0, + }, + }, + }) + ); }; diff --git a/demo/src/stubs/forecast_solar.ts b/demo/src/stubs/forecast_solar.ts deleted file mode 100644 index 19bb61083a..0000000000 --- a/demo/src/stubs/forecast_solar.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { format, startOfToday, startOfTomorrow } from "date-fns"; -import { ForecastSolarForecast } from "../../../src/data/forecast_solar"; -import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; - -export const mockForecastSolar = (hass: MockHomeAssistant) => { - const todayString = format(startOfToday(), "yyyy-MM-dd"); - const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd"); - hass.mockWS( - "forecast_solar/forecasts", - (): Record => ({ - solar_forecast: { - wh_hours: { - [`${todayString}T06:00:00`]: 0, - [`${todayString}T06:23:00`]: 6, - [`${todayString}T06:45:00`]: 39, - [`${todayString}T07:00:00`]: 28, - [`${todayString}T08:00:00`]: 208, - [`${todayString}T09:00:00`]: 352, - [`${todayString}T10:00:00`]: 544, - [`${todayString}T11:00:00`]: 748, - [`${todayString}T12:00:00`]: 1259, - [`${todayString}T13:00:00`]: 1361, - [`${todayString}T14:00:00`]: 1373, - [`${todayString}T15:00:00`]: 1370, - [`${todayString}T16:00:00`]: 1186, - [`${todayString}T17:00:00`]: 937, - [`${todayString}T18:00:00`]: 652, - [`${todayString}T19:00:00`]: 370, - [`${todayString}T20:00:00`]: 155, - [`${todayString}T21:48:00`]: 24, - [`${todayString}T22:36:00`]: 0, - [`${tomorrowString}T06:01:00`]: 0, - [`${tomorrowString}T06:23:00`]: 9, - [`${tomorrowString}T06:45:00`]: 47, - [`${tomorrowString}T07:00:00`]: 48, - [`${tomorrowString}T08:00:00`]: 473, - [`${tomorrowString}T09:00:00`]: 827, - [`${tomorrowString}T10:00:00`]: 1153, - [`${tomorrowString}T11:00:00`]: 1413, - [`${tomorrowString}T12:00:00`]: 1590, - [`${tomorrowString}T13:00:00`]: 1652, - [`${tomorrowString}T14:00:00`]: 1612, - [`${tomorrowString}T15:00:00`]: 1438, - [`${tomorrowString}T16:00:00`]: 1149, - [`${tomorrowString}T17:00:00`]: 830, - [`${tomorrowString}T18:00:00`]: 542, - [`${tomorrowString}T19:00:00`]: 311, - [`${tomorrowString}T20:00:00`]: 140, - [`${tomorrowString}T21:47:00`]: 22, - [`${tomorrowString}T22:34:00`]: 0, - }, - }, - }) - ); -}; diff --git a/src/data/energy.ts b/src/data/energy.ts index 799bb284f7..6e1cb28796 100644 --- a/src/data/energy.ts +++ b/src/data/energy.ts @@ -63,6 +63,13 @@ export const emptyGasEnergyPreference = (): GasSourceTypeEnergyPreference => ({ number_energy_price: null, }); +interface EnergySolarForecast { + wh_hours: Record; +} +export type EnergySolarForecasts = { + [config_entry_id: string]: EnergySolarForecast; +}; + export interface DeviceConsumptionEnergyPreference { // This is an ever increasing value stat_consumption: string; @@ -143,6 +150,7 @@ export interface EnergyPreferences { export interface EnergyInfo { cost_sensors: Record; + solar_forecast_domains: string[]; } export interface EnergyValidationIssue { @@ -440,3 +448,8 @@ export const getEnergyDataCollection = ( }; return collection; }; + +export const getEnergySolarForecasts = (hass: HomeAssistant) => + hass.callWS({ + type: "energy/solar_forecast", + }); diff --git a/src/data/forecast_solar.ts b/src/data/forecast_solar.ts deleted file mode 100644 index 91b9620216..0000000000 --- a/src/data/forecast_solar.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { HomeAssistant } from "../types"; - -export interface ForecastSolarForecast { - wh_hours: Record; -} - -export const getForecastSolarForecasts = (hass: HomeAssistant) => - hass.callWS>({ - type: "forecast_solar/forecasts", - }); diff --git a/src/panels/config/energy/components/ha-energy-solar-settings.ts b/src/panels/config/energy/components/ha-energy-solar-settings.ts index d58550e8d8..5dc093e9d2 100644 --- a/src/panels/config/energy/components/ha-energy-solar-settings.ts +++ b/src/panels/config/energy/components/ha-energy-solar-settings.ts @@ -6,6 +6,7 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { computeStateName } from "../../../../common/entity/compute_state_name"; import "../../../../components/ha-card"; import { + EnergyInfo, EnergyPreferences, EnergyPreferencesValidation, EnergyValidationIssue, @@ -33,6 +34,9 @@ export class EnergySolarSettings extends LitElement { @property({ attribute: false }) public validationResult?: EnergyPreferencesValidation; + @property({ attribute: false }) + public info?: EnergyInfo; + protected render(): TemplateResult { const solarSources: SolarSourceTypeEnergyPreference[] = []; const solarValidation: EnergyValidationIssue[][] = []; @@ -95,21 +99,29 @@ export class EnergySolarSettings extends LitElement { ? computeStateName(entityState) : source.stat_energy_from} - - - + ${this.info + ? html` + + + + ` + : ""} `; })} -
- - Add solar production -
+ ${this.info + ? html` +
+ + + Add solar production + +
+ ` + : ""} `; @@ -117,6 +129,7 @@ export class EnergySolarSettings extends LitElement { private _addSource() { showEnergySettingsSolarDialog(this, { + info: this.info!, saveCallback: async (source) => { await this._savePreferences({ ...this.preferences, @@ -130,6 +143,7 @@ export class EnergySolarSettings extends LitElement { const origSource: SolarSourceTypeEnergyPreference = ev.currentTarget.closest(".row").source; showEnergySettingsSolarDialog(this, { + info: this.info!, source: { ...origSource }, saveCallback: async (newSource) => { await this._savePreferences({ diff --git a/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts index 3cb983a857..c875641c33 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts @@ -44,8 +44,8 @@ export class DialogEnergySolarSettings public async showDialog( params: EnergySettingsSolarDialogParams ): Promise { - this._fetchForecastSolarConfigEntries(); this._params = params; + this._fetchSolarForecastConfigEntries(); this._source = params.source ? { ...params.source } : (this._source = emptySolarEnergyPreference()); @@ -118,7 +118,7 @@ export class DialogEnergySolarSettings referrerpolicy="no-referrer" style="height: 24px; margin-right: 16px;" src=${brandsUrl({ - domain: "forecast_solar", + domain: entry.domain, type: "icon", darkOptimized: this.hass.selectedTheme?.dark, })} @@ -155,9 +155,10 @@ export class DialogEnergySolarSettings `; } - private async _fetchForecastSolarConfigEntries() { - this._configEntries = (await getConfigEntries(this.hass)).filter( - (entry) => entry.domain === "forecast_solar" + private async _fetchSolarForecastConfigEntries() { + const domains = this._params!.info.solar_forecast_domains; + this._configEntries = (await getConfigEntries(this.hass)).filter((entry) => + domains.includes(entry.domain) ); } @@ -192,7 +193,7 @@ export class DialogEnergySolarSettings this._source!.config_entry_solar_forecast = []; } this._source!.config_entry_solar_forecast.push(params.entryId); - this._fetchForecastSolarConfigEntries(); + this._fetchSolarForecastConfigEntries(); } }, }); diff --git a/src/panels/config/energy/dialogs/show-dialogs-energy.ts b/src/panels/config/energy/dialogs/show-dialogs-energy.ts index 296533da8c..28d6d79c62 100644 --- a/src/panels/config/energy/dialogs/show-dialogs-energy.ts +++ b/src/panels/config/energy/dialogs/show-dialogs-energy.ts @@ -2,6 +2,7 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { BatterySourceTypeEnergyPreference, DeviceConsumptionEnergyPreference, + EnergyInfo, FlowFromGridSourceEnergyPreference, FlowToGridSourceEnergyPreference, GasSourceTypeEnergyPreference, @@ -31,6 +32,7 @@ export interface EnergySettingsGridFlowToDialogParams { } export interface EnergySettingsSolarDialogParams { + info: EnergyInfo; source?: SolarSourceTypeEnergyPreference; saveCallback: (source: SolarSourceTypeEnergyPreference) => Promise; } diff --git a/src/panels/config/energy/ha-config-energy.ts b/src/panels/config/energy/ha-config-energy.ts index bd1efaa2ab..c1b6a28c3a 100644 --- a/src/panels/config/energy/ha-config-energy.ts +++ b/src/panels/config/energy/ha-config-energy.ts @@ -2,10 +2,12 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import "../../../components/ha-svg-icon"; import { - EnergyPreferences, EnergyPreferencesValidation, - getEnergyPreferences, getEnergyPreferenceValidation, + EnergyInfo, + EnergyPreferences, + getEnergyInfo, + getEnergyPreferences, } from "../../../data/energy"; import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage"; @@ -37,6 +39,8 @@ class HaConfigEnergy extends LitElement { @state() private _searchParms = new URLSearchParams(window.location.search); + @state() private _info?: EnergyInfo; + @state() private _preferences?: EnergyPreferences; @state() private _validationResult?: EnergyPreferencesValidation; @@ -90,6 +94,7 @@ class HaConfigEnergy extends LitElement { .hass=${this.hass} .preferences=${this._preferences!} .validationResult=${this._validationResult!} + .info=${this._info} @value-changed=${this._prefsChanged} > source.type === "solar" ) as SolarSourceTypeEnergyPreference[]; - let forecasts: Record; + let forecasts: EnergySolarForecasts | undefined; if ( - isComponentLoaded(this.hass, "forecast_solar") && - solarSources.some((source) => source.config_entry_solar_forecast) + solarSources.some((source) => source.config_entry_solar_forecast?.length) ) { try { - forecasts = await getForecastSolarForecasts(this.hass); + forecasts = await getEnergySolarForecasts(this.hass); } catch (_e) { // ignore }