Skip to content
Open
2 changes: 1 addition & 1 deletion src/components/entity/ha-statistic-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import "../ha-combo-box-item";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import "../ha-icon-button";
import "../ha-input-helper-text";
import type {
PickerComboBoxItem,
PickerComboBoxSearchFn,
Expand Down Expand Up @@ -477,6 +476,7 @@ export class HaStatisticPicker extends LitElement {
.hideClearIcon=${this.hideClearIcon}
.searchFn=${this._searchFn}
.valueRenderer=${this._valueRenderer}
.helper=${this.helper}
@value-changed=${this._valueChanged}
>
</ha-generic-picker>
Expand Down
9 changes: 9 additions & 0 deletions src/data/energy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type EnergySolarForecasts = Record<string, EnergySolarForecast>;
export interface DeviceConsumptionEnergyPreference {
// This is an ever increasing value
stat_consumption: string;
stat_power?: string;
name?: string;
included_in_stat?: string;
}
Expand Down Expand Up @@ -130,11 +131,17 @@ export interface FlowToGridSourceEnergyPreference {
number_energy_price: number | null;
}

export interface GridPowerSourceEnergyPreference {
// W meter
stat_power: string;
}

export interface GridSourceTypeEnergyPreference {
type: "grid";

flow_from: FlowFromGridSourceEnergyPreference[];
flow_to: FlowToGridSourceEnergyPreference[];
power?: GridPowerSourceEnergyPreference[];

cost_adjustment_day: number;
}
Expand All @@ -143,13 +150,15 @@ export interface SolarSourceTypeEnergyPreference {
type: "solar";

stat_energy_from: string;
stat_power?: string;
config_entry_solar_forecast: string[] | null;
}

export interface BatterySourceTypeEnergyPreference {
type: "battery";
stat_energy_from: string;
stat_energy_to: string;
stat_power?: string;
}
export interface GasSourceTypeEnergyPreference {
type: "gas";
Expand Down
148 changes: 147 additions & 1 deletion src/panels/config/energy/components/ha-energy-grid-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
EnergySource,
FlowFromGridSourceEnergyPreference,
FlowToGridSourceEnergyPreference,
GridPowerSourceEnergyPreference,
GridSourceTypeEnergyPreference,
} from "../../../../data/energy";
import {
Expand All @@ -47,6 +48,7 @@ import { documentationUrl } from "../../../../util/documentation-url";
import {
showEnergySettingsGridFlowFromDialog,
showEnergySettingsGridFlowToDialog,
showEnergySettingsGridPowerDialog,
} from "../dialogs/show-dialogs-energy";
import "./ha-energy-validation-result";
import { energyCardStyles } from "./styles";
Expand Down Expand Up @@ -226,6 +228,58 @@ export class EnergyGridSettings extends LitElement {
>
</div>

<h3>
${this.hass.localize("ui.panel.config.energy.grid.grid_power")}
</h3>
${gridSource.power?.map((power) => {
const entityState = this.hass.states[power.stat_power];
return html`
<div class="row" .source=${power}>
${entityState?.attributes.icon
? html`<ha-icon
.icon=${entityState.attributes.icon}
></ha-icon>`
: html`<ha-svg-icon
.path=${mdiTransmissionTower}
></ha-svg-icon>`}
<span class="content"
>${getStatisticLabel(
this.hass,
power.stat_power,
this.statsMetadata?.[power.stat_power]
)}</span
>
<ha-icon-button
.label=${this.hass.localize(
"ui.panel.config.energy.grid.edit_power"
)}
@click=${this._editPowerSource}
.path=${mdiPencil}
></ha-icon-button>
<ha-icon-button
.label=${this.hass.localize(
"ui.panel.config.energy.grid.delete_power"
)}
@click=${this._deletePowerSource}
.path=${mdiDelete}
></ha-icon-button>
</div>
`;
})}
<div class="row border-bottom">
<ha-svg-icon .path=${mdiTransmissionTower}></ha-svg-icon>
<ha-button
@click=${this._addPowerSource}
appearance="filled"
size="small"
>
<ha-svg-icon .path=${mdiPlus} slot="start"></ha-svg-icon
>${this.hass.localize(
"ui.panel.config.energy.grid.add_power"
)}</ha-button
>
</div>

<h3>
${this.hass.localize(
"ui.panel.config.energy.grid.grid_carbon_footprint"
Expand Down Expand Up @@ -499,6 +553,97 @@ export class EnergyGridSettings extends LitElement {
await this._savePreferences(cleanedPreferences);
}

private _addPowerSource() {
const gridSource = this.preferences.energy_sources.find(
(src) => src.type === "grid"
) as GridSourceTypeEnergyPreference | undefined;
showEnergySettingsGridPowerDialog(this, {
grid_source: gridSource,
saveCallback: async (power) => {
let preferences: EnergyPreferences;
if (!gridSource) {
preferences = {
...this.preferences,
energy_sources: [
...this.preferences.energy_sources,
{
...emptyGridSourceEnergyPreference(),
power: [power],
},
],
};
} else {
preferences = {
...this.preferences,
energy_sources: this.preferences.energy_sources.map((src) =>
src.type === "grid"
? { ...src, power: [...(gridSource.power || []), power] }
: src
),
};
}
await this._savePreferences(preferences);
},
});
}

private _editPowerSource(ev) {
const origSource: GridPowerSourceEnergyPreference =
ev.currentTarget.closest(".row").source;
const gridSource = this.preferences.energy_sources.find(
(src) => src.type === "grid"
) as GridSourceTypeEnergyPreference | undefined;
showEnergySettingsGridPowerDialog(this, {
source: { ...origSource },
grid_source: gridSource,
saveCallback: async (source) => {
const power =
energySourcesByType(this.preferences).grid![0].power || [];

const preferences: EnergyPreferences = {
...this.preferences,
energy_sources: this.preferences.energy_sources.map((src) =>
src.type === "grid"
? {
...src,
power: power.map((p) => (p === origSource ? source : p)),
}
: src
),
};
await this._savePreferences(preferences);
},
});
}

private async _deletePowerSource(ev) {
const sourceToDelete: GridPowerSourceEnergyPreference =
ev.currentTarget.closest(".row").source;

if (
!(await showConfirmationDialog(this, {
title: this.hass.localize("ui.panel.config.energy.delete_source"),
}))
) {
return;
}

const power =
energySourcesByType(this.preferences).grid![0].power?.filter(
(p) => p !== sourceToDelete
) || [];

const preferences: EnergyPreferences = {
...this.preferences,
energy_sources: this.preferences.energy_sources.map((source) =>
source.type === "grid" ? { ...source, power } : source
),
};

const cleanedPreferences = this._removeEmptySources(preferences);
await this._savePreferences(cleanedPreferences);
}

private _removeEmptySources(preferences: EnergyPreferences) {
// Check if grid sources became an empty type and remove if so
preferences.energy_sources = preferences.energy_sources.reduce<
Expand All @@ -507,7 +652,8 @@ export class EnergyGridSettings extends LitElement {
if (
source.type !== "grid" ||
source.flow_from.length > 0 ||
source.flow_to.length > 0
source.flow_to.length > 0 ||
(source.power && source.power.length > 0)
) {
acc.push(source);
}
Expand Down
52 changes: 43 additions & 9 deletions src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { HomeAssistant } from "../../../../types";
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";

const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];

@customElement("dialog-energy-battery-settings")
export class DialogEnergyBatterySettings
Expand All @@ -32,10 +33,14 @@ export class DialogEnergyBatterySettings

@state() private _energy_units?: string[];

@state() private _power_units?: string[];

@state() private _error?: string;

private _excludeList?: string[];

private _excludeListPower?: string[];

public async showDialog(
params: EnergySettingsBatteryDialogParams
): Promise<void> {
Expand All @@ -46,6 +51,9 @@ export class DialogEnergyBatterySettings
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
const allSources: string[] = [];
this._params.battery_sources.forEach((entry) => {
allSources.push(entry.stat_energy_from);
Expand All @@ -56,6 +64,9 @@ export class DialogEnergyBatterySettings
id !== this._source?.stat_energy_from &&
id !== this._source?.stat_energy_to
);
this._excludeListPower = this._params.battery_sources
.map((entry) => entry.stat_power)
.filter((id) => id && id !== this._source?.stat_power) as string[];
}

public closeDialog() {
Expand All @@ -72,8 +83,6 @@ export class DialogEnergyBatterySettings
return nothing;
}

const pickableUnit = this._energy_units?.join(", ") || "";

return html`
<ha-dialog
open
Expand All @@ -85,12 +94,6 @@ export class DialogEnergyBatterySettings
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: pickableUnit }
)}
</div>

<ha-statistic-picker
.hass=${this.hass}
Expand All @@ -105,6 +108,10 @@ export class DialogEnergyBatterySettings
this._source.stat_energy_from,
]}
@value-changed=${this._statisticToChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.energy_helper_into",
{ unit: this._energy_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>

Expand All @@ -121,6 +128,25 @@ export class DialogEnergyBatterySettings
this._source.stat_energy_to,
]}
@value-changed=${this._statisticFromChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.energy_helper_out",
{ unit: this._energy_units?.join(", ") || "" }
)}
></ha-statistic-picker>

<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_power}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_helper",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>

<ha-button
Expand Down Expand Up @@ -150,6 +176,10 @@ export class DialogEnergyBatterySettings
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
}

private _powerChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_power: ev.detail.value };
}

private async _save() {
try {
await this._params!.saveCallback(this._source!);
Expand All @@ -168,7 +198,11 @@ export class DialogEnergyBatterySettings
--mdc-dialog-max-width: 430px;
}
ha-statistic-picker {
width: 100%;
display: block;
margin-bottom: var(--ha-space-4);
}
ha-statistic-picker:last-of-type {
margin-bottom: 0;
}
`,
];
Expand Down
Loading
Loading