Improve energy settings dialog (#15205)

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
This commit is contained in:
Erik Montnemery 2023-01-30 21:55:26 +01:00 committed by GitHub
parent cb00535683
commit 8212a5a48c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 272 additions and 104 deletions

View File

@ -366,6 +366,7 @@ export class EnergyGridSettings extends LitElement {
ev.currentTarget.closest(".row").source; ev.currentTarget.closest(".row").source;
showEnergySettingsGridFlowFromDialog(this, { showEnergySettingsGridFlowFromDialog(this, {
source: { ...origSource }, source: { ...origSource },
metadata: this.statsMetadata?.[origSource.stat_energy_from],
saveCallback: async (source) => { saveCallback: async (source) => {
const flowFrom = energySourcesByType(this.preferences).grid![0] const flowFrom = energySourcesByType(this.preferences).grid![0]
.flow_from; .flow_from;
@ -393,6 +394,7 @@ export class EnergyGridSettings extends LitElement {
ev.currentTarget.closest(".row").source; ev.currentTarget.closest(".row").source;
showEnergySettingsGridFlowToDialog(this, { showEnergySettingsGridFlowToDialog(this, {
source: { ...origSource }, source: { ...origSource },
metadata: this.statsMetadata?.[origSource.stat_energy_to],
saveCallback: async (source) => { saveCallback: async (source) => {
const flowTo = energySourcesByType(this.preferences).grid![0].flow_to; const flowTo = energySourcesByType(this.preferences).grid![0].flow_to;

View File

@ -13,6 +13,7 @@ import { HomeAssistant } from "../../../../types";
import { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy"; import { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
import "@material/mwc-button/mwc-button"; import "@material/mwc-button/mwc-button";
import "../../../../components/entity/ha-statistic-picker"; import "../../../../components/entity/ha-statistic-picker";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
const energyUnitClasses = ["energy"]; const energyUnitClasses = ["energy"];
@ -27,6 +28,8 @@ export class DialogEnergyBatterySettings
@state() private _source?: BatterySourceTypeEnergyPreference; @state() private _source?: BatterySourceTypeEnergyPreference;
@state() private _energy_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
@ -36,6 +39,9 @@ export class DialogEnergyBatterySettings
this._source = params.source this._source = params.source
? { ...params.source } ? { ...params.source }
: emptyBatteryEnergyPreference(); : emptyBatteryEnergyPreference();
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
@ -50,6 +56,8 @@ export class DialogEnergyBatterySettings
return html``; return html``;
} }
const pickableUnit = this._energy_units?.join(", ") || "";
return html` return html`
<ha-dialog <ha-dialog
open open
@ -63,6 +71,12 @@ export class DialogEnergyBatterySettings
@closed=${this.closeDialog} @closed=${this.closeDialog}
> >
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${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 <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}

View File

@ -13,6 +13,7 @@ import "../../../../components/entity/ha-statistic-picker";
import "../../../../components/ha-radio"; import "../../../../components/ha-radio";
import "../../../../components/ha-formfield"; import "../../../../components/ha-formfield";
import "../../../../components/entity/ha-entity-picker"; import "../../../../components/entity/ha-entity-picker";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
const energyUnitClasses = ["energy"]; const energyUnitClasses = ["energy"];
@ -27,12 +28,17 @@ export class DialogEnergyDeviceSettings
@state() private _device?: DeviceConsumptionEnergyPreference; @state() private _device?: DeviceConsumptionEnergyPreference;
@state() private _energy_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
params: EnergySettingsDeviceDialogParams params: EnergySettingsDeviceDialogParams
): Promise<void> { ): Promise<void> {
this._params = params; this._params = params;
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
@ -47,6 +53,8 @@ export class DialogEnergyDeviceSettings
return html``; return html``;
} }
const pickableUnit = this._energy_units?.join(", ") || "";
return html` return html`
<ha-dialog <ha-dialog
open open
@ -62,7 +70,8 @@ export class DialogEnergyDeviceSettings
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div> <div>
${this.hass.localize( ${this.hass.localize(
`ui.panel.config.energy.device_consumption.dialog.selected_stat_intro` "ui.panel.config.energy.device_consumption.dialog.selected_stat_intro",
{ unit: pickableUnit }
)} )}
</div> </div>

View File

@ -23,6 +23,7 @@ import {
getDisplayUnit, getDisplayUnit,
isExternalStatistic, isExternalStatistic,
} from "../../../../data/recorder"; } from "../../../../data/recorder";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
const gasDeviceClasses = ["gas", "energy"]; const gasDeviceClasses = ["gas", "energy"];
const gasUnitClasses = ["volume", "energy"]; const gasUnitClasses = ["volume", "energy"];
@ -40,10 +41,12 @@ export class DialogEnergyGasSettings
@state() private _costs?: "no-costs" | "number" | "entity" | "statistic"; @state() private _costs?: "no-costs" | "number" | "entity" | "statistic";
@state() private _pickableUnit?: string;
@state() private _pickedDisplayUnit?: string | null; @state() private _pickedDisplayUnit?: string | null;
@state() private _energy_units?: string[];
@state() private _gas_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
@ -65,12 +68,17 @@ export class DialogEnergyGasSettings
: this._source.stat_cost : this._source.stat_cost
? "statistic" ? "statistic"
: "no-costs"; : "no-costs";
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._gas_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "gas")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
this._params = undefined; this._params = undefined;
this._source = undefined; this._source = undefined;
this._pickableUnit = undefined;
this._pickedDisplayUnit = undefined; this._pickedDisplayUnit = undefined;
this._error = undefined; this._error = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName }); fireEvent(this, "dialog-closed", { dialog: this.localName });
@ -82,15 +90,19 @@ export class DialogEnergyGasSettings
} }
const pickableUnit = const pickableUnit =
this._pickableUnit || this._params.allowedGasUnitClass === undefined
(this._params.allowedGasUnitClass === undefined ? [...(this._gas_units || []), ...(this._energy_units || [])].join(", ")
? "ft³, m³, Wh, kWh, MWh or GJ"
: this._params.allowedGasUnitClass === "energy" : this._params.allowedGasUnitClass === "energy"
? "Wh, kWh, MWh or GJ" ? this._energy_units?.join(", ") || ""
: "ft³ or m³"); : this._gas_units?.join(", ") || "";
const unitPrice = this._pickedDisplayUnit
? `${this.hass.config.currency}/${this._pickedDisplayUnit}`
: undefined;
const externalSource = const externalSource =
this._source.stat_cost && isExternalStatistic(this._source.stat_cost); this._source.stat_energy_from &&
isExternalStatistic(this._source.stat_energy_from);
return html` return html`
<ha-dialog <ha-dialog
@ -103,6 +115,20 @@ export class DialogEnergyGasSettings
@closed=${this.closeDialog} @closed=${this.closeDialog}
> >
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
<p>
${this.hass.localize("ui.panel.config.energy.gas.dialog.paragraph")}
</p>
<p>
${this.hass.localize(
"ui.panel.config.energy.gas.dialog.entity_para",
{ unit: pickableUnit }
)}
</p>
<p>
${this.hass.localize("ui.panel.config.energy.gas.dialog.note_para")}
</p>
</div>
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
@ -110,26 +136,20 @@ export class DialogEnergyGasSettings
gasUnitClasses} gasUnitClasses}
.includeDeviceClass=${gasDeviceClasses} .includeDeviceClass=${gasDeviceClasses}
.value=${this._source.stat_energy_from} .value=${this._source.stat_energy_from}
.label=${`${this.hass.localize( .label=${this.hass.localize(
"ui.panel.config.energy.gas.dialog.gas_usage" "ui.panel.config.energy.gas.dialog.gas_usage"
)} (${ )}
this._params.allowedGasUnitClass === undefined
? this.hass.localize(
"ui.panel.config.energy.gas.dialog.m3_or_kWh"
)
: pickableUnit
})`}
@value-changed=${this._statisticChanged} @value-changed=${this._statisticChanged}
dialogInitialFocus dialogInitialFocus
></ha-statistic-picker> ></ha-statistic-picker>
<p> <p>
${this.hass.localize(`ui.panel.config.energy.gas.dialog.cost_para`)} ${this.hass.localize("ui.panel.config.energy.gas.dialog.cost_para")}
</p> </p>
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.gas.dialog.no_cost` "ui.panel.config.energy.gas.dialog.no_cost"
)} )}
> >
<ha-radio <ha-radio
@ -141,14 +161,13 @@ export class DialogEnergyGasSettings
</ha-formfield> </ha-formfield>
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_stat` "ui.panel.config.energy.gas.dialog.cost_stat"
)} )}
> >
<ha-radio <ha-radio
value="statistic" value="statistic"
name="costs" name="costs"
.checked=${this._costs === "statistic"} .checked=${this._costs === "statistic"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
@ -158,15 +177,15 @@ export class DialogEnergyGasSettings
.hass=${this.hass} .hass=${this.hass}
statistic-types="sum" statistic-types="sum"
.value=${this._source.stat_cost} .value=${this._source.stat_cost}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_stat_input` "ui.panel.config.energy.gas.dialog.cost_stat_input"
)} )} (${this.hass.config.currency})`}
@value-changed=${this._priceStatChanged} @value-changed=${this._priceStatChanged}
></ha-statistic-picker>` ></ha-statistic-picker>`
: ""} : ""}
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_entity` "ui.panel.config.energy.gas.dialog.cost_entity"
)} )}
> >
<ha-radio <ha-radio
@ -183,39 +202,36 @@ export class DialogEnergyGasSettings
.hass=${this.hass} .hass=${this.hass}
include-domains='["sensor", "input_number"]' include-domains='["sensor", "input_number"]'
.value=${this._source.entity_energy_price} .value=${this._source.entity_energy_price}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_entity_input`, "ui.panel.config.energy.gas.dialog.cost_entity_input"
{ unit: this._pickedDisplayUnit || pickableUnit } )} ${unitPrice ? ` (${unitPrice})` : ""}`}
)}
@value-changed=${this._priceEntityChanged} @value-changed=${this._priceEntityChanged}
></ha-entity-picker>` ></ha-entity-picker>`
: ""} : ""}
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_number` "ui.panel.config.energy.gas.dialog.cost_number"
)} )}
> >
<ha-radio <ha-radio
value="number" value="number"
name="costs" name="costs"
.checked=${this._costs === "number"} .checked=${this._costs === "number"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
${this._costs === "number" ${this._costs === "number"
? html`<ha-textfield ? html`<ha-textfield
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.gas.dialog.cost_number_input`, "ui.panel.config.energy.gas.dialog.cost_number_input"
{ unit: this._pickedDisplayUnit || pickableUnit } )} ${unitPrice ? ` (${unitPrice})` : ""}`}
)}
class="price-options" class="price-options"
step=".01" step=".01"
type="number" type="number"
.value=${this._source.number_energy_price} .value=${this._source.number_energy_price}
@change=${this._numberPriceChanged} @change=${this._numberPriceChanged}
.suffix=${`${this.hass.config.currency}/${ .suffix=${unitPrice || ""}
this._pickedDisplayUnit || pickableUnit
}`}
> >
</ha-textfield>` </ha-textfield>`
: ""} : ""}

View File

@ -19,6 +19,12 @@ import "../../../../components/ha-radio";
import "../../../../components/ha-formfield"; import "../../../../components/ha-formfield";
import type { HaRadio } from "../../../../components/ha-radio"; import type { HaRadio } from "../../../../components/ha-radio";
import "../../../../components/entity/ha-entity-picker"; import "../../../../components/entity/ha-entity-picker";
import {
getStatisticMetadata,
getDisplayUnit,
isExternalStatistic,
} from "../../../../data/recorder";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
const energyUnitClasses = ["energy"]; const energyUnitClasses = ["energy"];
@ -37,6 +43,10 @@ export class DialogEnergyGridFlowSettings
@state() private _costs?: "no-costs" | "number" | "entity" | "statistic"; @state() private _costs?: "no-costs" | "number" | "entity" | "statistic";
@state() private _pickedDisplayUnit?: string | null;
@state() private _energy_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
@ -57,11 +67,24 @@ export class DialogEnergyGridFlowSettings
] ]
? "statistic" ? "statistic"
: "no-costs"; : "no-costs";
this._pickedDisplayUnit = getDisplayUnit(
this.hass,
this._source[
this._params.direction === "from"
? "stat_energy_from"
: "stat_energy_to"
],
params.metadata
);
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
this._params = undefined; this._params = undefined;
this._source = undefined; this._source = undefined;
this._pickedDisplayUnit = undefined;
this._error = undefined; this._error = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName }); fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
@ -71,6 +94,26 @@ export class DialogEnergyGridFlowSettings
return html``; return html``;
} }
const pickableUnit = this._energy_units?.join(", ") || "";
const unitPrice = this._pickedDisplayUnit
? `${this.hass.config.currency}/${this._pickedDisplayUnit}`
: undefined;
const externalSource =
this._source[
this._params.direction === "from"
? "stat_energy_from"
: "stat_energy_to"
] &&
isExternalStatistic(
this._source[
this._params.direction === "from"
? "stat_energy_from"
: "stat_energy_to"
]
);
return html` return html`
<ha-dialog <ha-dialog
open open
@ -85,9 +128,17 @@ export class DialogEnergyGridFlowSettings
> >
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div> <div>
${this.hass.localize( <p>
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.paragraph` ${this.hass.localize(
)} `ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.paragraph`
)}
</p>
<p>
${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.entity_para`,
{ unit: pickableUnit }
)}
</p>
</div> </div>
<ha-statistic-picker <ha-statistic-picker
@ -145,9 +196,9 @@ export class DialogEnergyGridFlowSettings
? "stat_cost" ? "stat_cost"
: "stat_compensation" : "stat_compensation"
]} ]}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_stat_input` `ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_stat_input`
)} )} (${this.hass.config.currency})`}
@value-changed=${this._priceStatChanged} @value-changed=${this._priceStatChanged}
></ha-statistic-picker>` ></ha-statistic-picker>`
: ""} : ""}
@ -160,6 +211,7 @@ export class DialogEnergyGridFlowSettings
value="entity" value="entity"
name="costs" name="costs"
.checked=${this._costs === "entity"} .checked=${this._costs === "entity"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
@ -169,9 +221,9 @@ export class DialogEnergyGridFlowSettings
.hass=${this.hass} .hass=${this.hass}
include-domains='["sensor", "input_number"]' include-domains='["sensor", "input_number"]'
.value=${this._source.entity_energy_price} .value=${this._source.entity_energy_price}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_entity_input` `ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_entity_input`
)} )} ${unitPrice ? ` (${unitPrice})` : ""}`}
@value-changed=${this._priceEntityChanged} @value-changed=${this._priceEntityChanged}
></ha-entity-picker>` ></ha-entity-picker>`
: ""} : ""}
@ -184,22 +236,20 @@ export class DialogEnergyGridFlowSettings
value="number" value="number"
name="costs" name="costs"
.checked=${this._costs === "number"} .checked=${this._costs === "number"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
${this._costs === "number" ${this._costs === "number"
? html`<ha-textfield ? html`<ha-textfield
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_number_input` `ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_number_input`
)} )} ${unitPrice ? ` (${unitPrice})` : ""}`}
class="price-options" class="price-options"
step=".01" step=".01"
type="number" type="number"
.value=${this._source.number_energy_price} .value=${this._source.number_energy_price}
.suffix=${this.hass.localize( .suffix=${unitPrice || ""}
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.cost_number_suffix`,
{ currency: this.hass.config.currency }
)}
@change=${this._numberPriceChanged} @change=${this._numberPriceChanged}
> >
</ha-textfield>` </ha-textfield>`
@ -261,7 +311,17 @@ export class DialogEnergyGridFlowSettings
}; };
} }
private _statisticChanged(ev: CustomEvent<{ value: string }>) { private async _statisticChanged(ev: CustomEvent<{ value: string }>) {
if (ev.detail.value) {
const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]);
this._pickedDisplayUnit = getDisplayUnit(
this.hass,
ev.detail.value,
metadata[0]
);
} else {
this._pickedDisplayUnit = undefined;
}
this._source = { this._source = {
...this._source!, ...this._source!,
[this._params!.direction === "from" [this._params!.direction === "from"

View File

@ -21,6 +21,7 @@ import type { HaRadio } from "../../../../components/ha-radio";
import { showConfigFlowDialog } from "../../../../dialogs/config-flow/show-dialog-config-flow"; import { showConfigFlowDialog } from "../../../../dialogs/config-flow/show-dialog-config-flow";
import { ConfigEntry, getConfigEntries } from "../../../../data/config_entries"; import { ConfigEntry, getConfigEntries } from "../../../../data/config_entries";
import { brandsUrl } from "../../../../util/brands-url"; import { brandsUrl } from "../../../../util/brands-url";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
const energyUnitClasses = ["energy"]; const energyUnitClasses = ["energy"];
@ -39,6 +40,8 @@ export class DialogEnergySolarSettings
@state() private _forecast?: boolean; @state() private _forecast?: boolean;
@state() private _energy_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
@ -50,6 +53,9 @@ export class DialogEnergySolarSettings
? { ...params.source } ? { ...params.source }
: emptySolarEnergyPreference(); : emptySolarEnergyPreference();
this._forecast = this._source.config_entry_solar_forecast !== null; this._forecast = this._source.config_entry_solar_forecast !== null;
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
@ -64,6 +70,8 @@ export class DialogEnergySolarSettings
return html``; return html``;
} }
const pickableUnit = this._energy_units?.join(", ") || "";
return html` return html`
<ha-dialog <ha-dialog
open open
@ -75,6 +83,12 @@ export class DialogEnergySolarSettings
@closed=${this.closeDialog} @closed=${this.closeDialog}
> >
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
${this.hass.localize(
"ui.panel.config.energy.solar.dialog.entity_para",
{ unit: pickableUnit }
)}
</div>
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}

View File

@ -14,11 +14,16 @@ import {
emptyWaterEnergyPreference, emptyWaterEnergyPreference,
WaterSourceTypeEnergyPreference, WaterSourceTypeEnergyPreference,
} from "../../../../data/energy"; } from "../../../../data/energy";
import { isExternalStatistic } from "../../../../data/recorder"; import {
getStatisticMetadata,
getDisplayUnit,
isExternalStatistic,
} from "../../../../data/recorder";
import { HassDialog } from "../../../../dialogs/make-dialog-manager"; import { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../../resources/styles"; import { haStyle, haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types"; import { HomeAssistant } from "../../../../types";
import { EnergySettingsWaterDialogParams } from "./show-dialogs-energy"; import { EnergySettingsWaterDialogParams } from "./show-dialogs-energy";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
@customElement("dialog-energy-water-settings") @customElement("dialog-energy-water-settings")
export class DialogEnergyWaterSettings export class DialogEnergyWaterSettings
@ -33,6 +38,10 @@ export class DialogEnergyWaterSettings
@state() private _costs?: "no-costs" | "number" | "entity" | "statistic"; @state() private _costs?: "no-costs" | "number" | "entity" | "statistic";
@state() private _pickedDisplayUnit?: string | null;
@state() private _water_units?: string[];
@state() private _error?: string; @state() private _error?: string;
public async showDialog( public async showDialog(
@ -42,6 +51,11 @@ export class DialogEnergyWaterSettings
this._source = params.source this._source = params.source
? { ...params.source } ? { ...params.source }
: emptyWaterEnergyPreference(); : emptyWaterEnergyPreference();
this._pickedDisplayUnit = getDisplayUnit(
this.hass,
params.source?.stat_energy_from,
params.metadata
);
this._costs = this._source.entity_energy_price this._costs = this._source.entity_energy_price
? "entity" ? "entity"
: this._source.number_energy_price : this._source.number_energy_price
@ -49,12 +63,16 @@ export class DialogEnergyWaterSettings
: this._source.stat_cost : this._source.stat_cost
? "statistic" ? "statistic"
: "no-costs"; : "no-costs";
this._water_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "water")
).units;
} }
public closeDialog(): void { public closeDialog(): void {
this._params = undefined; this._params = undefined;
this._source = undefined; this._source = undefined;
this._error = undefined; this._error = undefined;
this._pickedDisplayUnit = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName }); fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
@ -63,8 +81,15 @@ export class DialogEnergyWaterSettings
return html``; return html``;
} }
const pickableUnit = this._water_units?.join(", ") || "";
const unitPrice = this._pickedDisplayUnit
? `${this.hass.config.currency}/${this._pickedDisplayUnit}`
: undefined;
const externalSource = const externalSource =
this._source.stat_cost && isExternalStatistic(this._source.stat_cost); this._source.stat_energy_from &&
isExternalStatistic(this._source.stat_energy_from);
return html` return html`
<ha-dialog <ha-dialog
@ -77,6 +102,19 @@ export class DialogEnergyWaterSettings
@closed=${this.closeDialog} @closed=${this.closeDialog}
> >
${this._error ? html`<p class="error">${this._error}</p>` : ""} ${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
<p>
${this.hass.localize(
"ui.panel.config.energy.water.dialog.paragraph"
)}
</p>
<p>
${this.hass.localize(
"ui.panel.config.energy.water.dialog.entity_para",
{ unit: pickableUnit }
)}
</p>
</div>
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
@ -91,12 +129,12 @@ export class DialogEnergyWaterSettings
></ha-statistic-picker> ></ha-statistic-picker>
<p> <p>
${this.hass.localize(`ui.panel.config.energy.water.dialog.cost_para`)} ${this.hass.localize("ui.panel.config.energy.water.dialog.cost_para")}
</p> </p>
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.water.dialog.no_cost` "ui.panel.config.energy.water.dialog.no_cost"
)} )}
> >
<ha-radio <ha-radio
@ -108,14 +146,13 @@ export class DialogEnergyWaterSettings
</ha-formfield> </ha-formfield>
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_stat` "ui.panel.config.energy.water.dialog.cost_stat"
)} )}
> >
<ha-radio <ha-radio
value="statistic" value="statistic"
name="costs" name="costs"
.checked=${this._costs === "statistic"} .checked=${this._costs === "statistic"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
@ -125,15 +162,15 @@ export class DialogEnergyWaterSettings
.hass=${this.hass} .hass=${this.hass}
statistic-types="sum" statistic-types="sum"
.value=${this._source.stat_cost} .value=${this._source.stat_cost}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_stat_input` "ui.panel.config.energy.water.dialog.cost_stat_input"
)} )} (${this.hass.config.currency})`}
@value-changed=${this._priceStatChanged} @value-changed=${this._priceStatChanged}
></ha-statistic-picker>` ></ha-statistic-picker>`
: ""} : ""}
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_entity` "ui.panel.config.energy.water.dialog.cost_entity"
)} )}
> >
<ha-radio <ha-radio
@ -150,35 +187,36 @@ export class DialogEnergyWaterSettings
.hass=${this.hass} .hass=${this.hass}
include-domains='["sensor", "input_number"]' include-domains='["sensor", "input_number"]'
.value=${this._source.entity_energy_price} .value=${this._source.entity_energy_price}
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_entity_input` "ui.panel.config.energy.water.dialog.cost_entity_input"
)} )}${unitPrice ? ` (${unitPrice})` : ""}`}
@value-changed=${this._priceEntityChanged} @value-changed=${this._priceEntityChanged}
></ha-entity-picker>` ></ha-entity-picker>`
: ""} : ""}
<ha-formfield <ha-formfield
.label=${this.hass.localize( .label=${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_number` "ui.panel.config.energy.water.dialog.cost_number"
)} )}
> >
<ha-radio <ha-radio
value="number" value="number"
name="costs" name="costs"
.checked=${this._costs === "number"} .checked=${this._costs === "number"}
.disabled=${externalSource}
@change=${this._handleCostChanged} @change=${this._handleCostChanged}
></ha-radio> ></ha-radio>
</ha-formfield> </ha-formfield>
${this._costs === "number" ${this._costs === "number"
? html`<ha-textfield ? html`<ha-textfield
.label=${this.hass.localize( .label=${`${this.hass.localize(
`ui.panel.config.energy.water.dialog.cost_number_input` "ui.panel.config.energy.water.dialog.cost_number_input"
)} )}${unitPrice ? ` (${unitPrice})` : ""}`}
class="price-options" class="price-options"
step=".01" step=".01"
type="number" type="number"
.value=${this._source.number_energy_price} .value=${this._source.number_energy_price}
@change=${this._numberPriceChanged} @change=${this._numberPriceChanged}
.suffix=${`${this.hass.config.currency}/m³`} .suffix=${unitPrice || ""}
> >
</ha-textfield>` </ha-textfield>`
: ""} : ""}
@ -230,6 +268,16 @@ export class DialogEnergyWaterSettings
} }
private async _statisticChanged(ev: CustomEvent<{ value: string }>) { private async _statisticChanged(ev: CustomEvent<{ value: string }>) {
if (ev.detail.value) {
const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]);
this._pickedDisplayUnit = getDisplayUnit(
this.hass,
ev.detail.value,
metadata[0]
);
} else {
this._pickedDisplayUnit = undefined;
}
if (isExternalStatistic(ev.detail.value) && this._costs !== "statistic") { if (isExternalStatistic(ev.detail.value) && this._costs !== "statistic") {
this._costs = "no-costs"; this._costs = "no-costs";
} }

View File

@ -16,6 +16,7 @@ export interface EnergySettingsGridFlowDialogParams {
source?: source?:
| FlowFromGridSourceEnergyPreference | FlowFromGridSourceEnergyPreference
| FlowToGridSourceEnergyPreference; | FlowToGridSourceEnergyPreference;
metadata?: StatisticsMetaData;
direction: "from" | "to"; direction: "from" | "to";
saveCallback: ( saveCallback: (
source: source:
@ -26,11 +27,13 @@ export interface EnergySettingsGridFlowDialogParams {
export interface EnergySettingsGridFlowFromDialogParams { export interface EnergySettingsGridFlowFromDialogParams {
source?: FlowFromGridSourceEnergyPreference; source?: FlowFromGridSourceEnergyPreference;
metadata?: StatisticsMetaData;
saveCallback: (source: FlowFromGridSourceEnergyPreference) => Promise<void>; saveCallback: (source: FlowFromGridSourceEnergyPreference) => Promise<void>;
} }
export interface EnergySettingsGridFlowToDialogParams { export interface EnergySettingsGridFlowToDialogParams {
source?: FlowToGridSourceEnergyPreference; source?: FlowToGridSourceEnergyPreference;
metadata?: StatisticsMetaData;
saveCallback: (source: FlowToGridSourceEnergyPreference) => Promise<void>; saveCallback: (source: FlowToGridSourceEnergyPreference) => Promise<void>;
} }

View File

@ -1521,30 +1521,30 @@
"from": { "from": {
"header": "Configure grid consumption", "header": "Configure grid consumption",
"paragraph": "Grid consumption is the energy that flows from the energy grid to your home.", "paragraph": "Grid consumption is the energy that flows from the energy grid to your home.",
"energy_stat": "Consumed Energy (kWh)", "entity_para": "Pick a sensor which measures grid consumption in either of {unit}.",
"energy_stat": "Consumed Energy",
"cost_para": "Select how Home Assistant should keep track of the costs of the consumed energy.", "cost_para": "Select how Home Assistant should keep track of the costs of the consumed energy.",
"no_cost": "Do not track costs", "no_cost": "Do not track costs",
"cost_stat": "Use an entity tracking the total costs", "cost_stat": "Use an entity tracking the total costs",
"cost_stat_input": "Total Costs Entity", "cost_stat_input": "Entity with the total costs",
"cost_entity": "Use an entity with current price", "cost_entity": "Use an entity with current price",
"cost_entity_input": "Entity with the current price", "cost_entity_input": "Entity with the current price",
"cost_number": "Use a static price", "cost_number": "Use a static price",
"cost_number_input": "Price per kWh", "cost_number_input": "Price"
"cost_number_suffix": "{currency}/kWh"
}, },
"to": { "to": {
"header": "Configure grid production", "header": "Configure grid production",
"paragraph": "Grid production is the energy that flows from your solar panels to the grid.", "paragraph": "Grid production is the energy that flows from your solar panels to the grid.",
"energy_stat": "Energy returned to the grid (kWh)", "entity_para": "Pick a sensor which measures grid production in either of {unit}.",
"energy_stat": "Energy returned to the grid",
"cost_para": "Do you get money back when you return energy to the grid?", "cost_para": "Do you get money back when you return energy to the grid?",
"no_cost": "I do not get money back", "no_cost": "I do not get money back",
"cost_stat": "Use an entity tracking the total recieved money", "cost_stat": "Use an entity tracking the total recieved money",
"cost_stat_input": "Total Compensation Entity", "cost_stat_input": "Entity with the total compensation",
"cost_entity": "Use an entity with current rate", "cost_entity": "Use an entity with current rate",
"cost_entity_input": "Entity with the current rate", "cost_entity_input": "Entity with the current rate",
"cost_number": "Use a static rate", "cost_number": "Use a static rate",
"cost_number_input": "Rate per kWh", "cost_number_input": "Rate"
"cost_number_suffix": "{currency}/kWh"
} }
} }
}, },
@ -1561,7 +1561,8 @@
"stat_predicted_production": "Prediction of your solar energy production", "stat_predicted_production": "Prediction of your solar energy production",
"dialog": { "dialog": {
"header": "Configure solar panels", "header": "Configure solar panels",
"solar_production_energy": "Solar production energy (kWh)", "entity_para": "Pick a sensor which measures solar energy production in either of {unit}.",
"solar_production_energy": "Solar production energy",
"solar_production_forecast": "Solar production forecast", "solar_production_forecast": "Solar production forecast",
"solar_production_forecast_description": "Adding solar production forecast information will allow you to quickly see your expected production for today.", "solar_production_forecast_description": "Adding solar production forecast information will allow you to quickly see your expected production for today.",
"dont_forecast_production": "Don't forecast production", "dont_forecast_production": "Don't forecast production",
@ -1579,8 +1580,9 @@
"add_battery_system": "Add battery system", "add_battery_system": "Add battery system",
"dialog": { "dialog": {
"header": "Configure battery system", "header": "Configure battery system",
"energy_into_battery": "Energy going in to the battery (kWh)", "entity_para": "Pick sensors which measure energy going in to and out of the battery in either of {unit}.",
"energy_out_of_battery": "Energy coming out of the battery (kWh)" "energy_into_battery": "Energy going in to the battery",
"energy_out_of_battery": "Energy coming out of the battery"
} }
}, },
"gas": { "gas": {
@ -1593,18 +1595,18 @@
"add_gas_source": "Add gas source", "add_gas_source": "Add gas source",
"dialog": { "dialog": {
"header": "Configure gas consumption", "header": "Configure gas consumption",
"paragraph": "Gas consumption is the volume of gas that flows to your home.", "paragraph": "Gas consumption is measured either as the volume of gas that flows to your home or as the amount of energy contained in the gas.",
"energy_stat": "Consumed Energy (m³)", "entity_para": "Pick a sensor which measures gas consumption in either of {unit}.",
"cost_para": "Select how Home Assistant should keep track of the costs of the consumed energy.", "note_para": "Note: It is not possible to add both sensors measuring a volume of gas and sensors measuring the amount of energy contained in the gas.",
"no_cost": "Do not track costs", "cost_para": "Select how Home Assistant should keep track of the costs of the consumed gas.",
"cost_stat": "Use an entity tracking the total costs", "no_cost": "[%key:ui::panel::config::energy::grid::flow_dialog::from::no_cost%]",
"cost_stat_input": "Total Costs Entity", "cost_stat": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat%]",
"cost_entity": "Use an entity with current price", "cost_stat_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat_input%]",
"cost_entity_input": "Entity with the current price per {unit}", "cost_entity": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity%]",
"cost_number": "Use a static price", "cost_entity_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity_input%]",
"cost_number_input": "Price per {unit}", "cost_number": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]",
"gas_usage": "Gas usage", "cost_number_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]",
"m3_or_kWh": "ft³, m³, Wh, kWh, MWh or GJ" "gas_usage": "Gas usage"
} }
}, },
"water": { "water": {
@ -1618,16 +1620,16 @@
"dialog": { "dialog": {
"header": "Configure water consumption", "header": "Configure water consumption",
"paragraph": "Water consumption is the volume of water that flows to your home.", "paragraph": "Water consumption is the volume of water that flows to your home.",
"energy_stat": "Consumed water (m³ or gl)", "entity_para": "Pick a sensor which measures gas consumption in either of {unit}.",
"cost_para": "Select how Home Assistant should keep track of the costs of the consumed water.", "cost_para": "Select how Home Assistant should keep track of the costs of the consumed water.",
"no_cost": "Do not track costs", "no_cost": "[%key:ui::panel::config::energy::grid::flow_dialog::from::no_cost%]",
"cost_stat": "Use an entity tracking the total costs", "cost_stat": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat%]",
"cost_stat_input": "Total Costs Entity", "cost_stat_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat_input%]",
"cost_entity": "Use an entity with current price", "cost_entity": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity%]",
"cost_entity_input": "Entity with the current price per m³ or gl", "cost_entity_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity_input%]",
"cost_number": "Use a static price", "cost_number": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]",
"cost_number_input": "Price per m³ or gl", "cost_number_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]",
"water_usage": "Water usage (m³ or gl)" "water_usage": "Water usage"
} }
}, },
"device_consumption": { "device_consumption": {
@ -1640,8 +1642,8 @@
"add_device": "Add device", "add_device": "Add device",
"dialog": { "dialog": {
"header": "Add a device", "header": "Add a device",
"device_consumption_energy": "Device consumption energy (kWh)", "device_consumption_energy": "Device consumption energy",
"selected_stat_intro": "Select the entity that represents the device energy usage." "selected_stat_intro": "Select the energy sensor that measures the device's energy usage in either of {unit}."
} }
} }
}, },