diff --git a/src/panels/config/energy/components/ha-energy-grid-settings.ts b/src/panels/config/energy/components/ha-energy-grid-settings.ts index f55c2d57b00a..f07961c98d59 100644 --- a/src/panels/config/energy/components/ha-energy-grid-settings.ts +++ b/src/panels/config/energy/components/ha-energy-grid-settings.ts @@ -366,6 +366,7 @@ export class EnergyGridSettings extends LitElement { ev.currentTarget.closest(".row").source; showEnergySettingsGridFlowFromDialog(this, { source: { ...origSource }, + metadata: this.statsMetadata?.[origSource.stat_energy_from], saveCallback: async (source) => { const flowFrom = energySourcesByType(this.preferences).grid![0] .flow_from; @@ -393,6 +394,7 @@ export class EnergyGridSettings extends LitElement { ev.currentTarget.closest(".row").source; showEnergySettingsGridFlowToDialog(this, { source: { ...origSource }, + metadata: this.statsMetadata?.[origSource.stat_energy_to], saveCallback: async (source) => { const flowTo = energySourcesByType(this.preferences).grid![0].flow_to; diff --git a/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts index 2dd5ce4e1510..fa628ea6b645 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-battery-settings.ts @@ -13,6 +13,7 @@ import { HomeAssistant } from "../../../../types"; import { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy"; import "@material/mwc-button/mwc-button"; import "../../../../components/entity/ha-statistic-picker"; +import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor"; const energyUnitClasses = ["energy"]; @@ -27,6 +28,8 @@ export class DialogEnergyBatterySettings @state() private _source?: BatterySourceTypeEnergyPreference; + @state() private _energy_units?: string[]; + @state() private _error?: string; public async showDialog( @@ -36,6 +39,9 @@ export class DialogEnergyBatterySettings this._source = params.source ? { ...params.source } : emptyBatteryEnergyPreference(); + this._energy_units = ( + await getSensorDeviceClassConvertibleUnits(this.hass, "energy") + ).units; } public closeDialog(): void { @@ -50,6 +56,8 @@ export class DialogEnergyBatterySettings return html``; } + const pickableUnit = this._energy_units?.join(", ") || ""; + return html` ${this._error ? html`

${this._error}

` : ""} +
+ ${this.hass.localize( + "ui.panel.config.energy.battery.dialog.entity_para", + { unit: pickableUnit } + )} +
{ this._params = params; + this._energy_units = ( + await getSensorDeviceClassConvertibleUnits(this.hass, "energy") + ).units; } public closeDialog(): void { @@ -47,6 +53,8 @@ export class DialogEnergyDeviceSettings return html``; } + const pickableUnit = this._energy_units?.join(", ") || ""; + return html` ${this._error}

` : ""}
${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 } )}
diff --git a/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts index e616c3a79751..fc8dd9250248 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-gas-settings.ts @@ -23,6 +23,7 @@ import { getDisplayUnit, isExternalStatistic, } from "../../../../data/recorder"; +import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor"; const gasDeviceClasses = ["gas", "energy"]; const gasUnitClasses = ["volume", "energy"]; @@ -40,10 +41,12 @@ export class DialogEnergyGasSettings @state() private _costs?: "no-costs" | "number" | "entity" | "statistic"; - @state() private _pickableUnit?: string; - @state() private _pickedDisplayUnit?: string | null; + @state() private _energy_units?: string[]; + + @state() private _gas_units?: string[]; + @state() private _error?: string; public async showDialog( @@ -65,12 +68,17 @@ export class DialogEnergyGasSettings : this._source.stat_cost ? "statistic" : "no-costs"; + this._energy_units = ( + await getSensorDeviceClassConvertibleUnits(this.hass, "energy") + ).units; + this._gas_units = ( + await getSensorDeviceClassConvertibleUnits(this.hass, "gas") + ).units; } public closeDialog(): void { this._params = undefined; this._source = undefined; - this._pickableUnit = undefined; this._pickedDisplayUnit = undefined; this._error = undefined; fireEvent(this, "dialog-closed", { dialog: this.localName }); @@ -82,15 +90,19 @@ export class DialogEnergyGasSettings } const pickableUnit = - this._pickableUnit || - (this._params.allowedGasUnitClass === undefined - ? "ft³, m³, Wh, kWh, MWh or GJ" + this._params.allowedGasUnitClass === undefined + ? [...(this._gas_units || []), ...(this._energy_units || [])].join(", ") : this._params.allowedGasUnitClass === "energy" - ? "Wh, kWh, MWh or GJ" - : "ft³ or m³"); + ? this._energy_units?.join(", ") || "" + : this._gas_units?.join(", ") || ""; + + const unitPrice = this._pickedDisplayUnit + ? `${this.hass.config.currency}/${this._pickedDisplayUnit}` + : undefined; const externalSource = - this._source.stat_cost && isExternalStatistic(this._source.stat_cost); + this._source.stat_energy_from && + isExternalStatistic(this._source.stat_energy_from); return html` ${this._error ? html`

${this._error}

` : ""} +
+

+ ${this.hass.localize("ui.panel.config.energy.gas.dialog.paragraph")} +

+

+ ${this.hass.localize( + "ui.panel.config.energy.gas.dialog.entity_para", + { unit: pickableUnit } + )} +

+

+ ${this.hass.localize("ui.panel.config.energy.gas.dialog.note_para")} +

+

- ${this.hass.localize(`ui.panel.config.energy.gas.dialog.cost_para`)} + ${this.hass.localize("ui.panel.config.energy.gas.dialog.cost_para")}

@@ -158,15 +177,15 @@ export class DialogEnergyGasSettings .hass=${this.hass} statistic-types="sum" .value=${this._source.stat_cost} - .label=${this.hass.localize( - `ui.panel.config.energy.gas.dialog.cost_stat_input` - )} + .label=${`${this.hass.localize( + "ui.panel.config.energy.gas.dialog.cost_stat_input" + )} (${this.hass.config.currency})`} @value-changed=${this._priceStatChanged} >
` : ""} ` : ""} ${this._costs === "number" ? html` ` : ""} diff --git a/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts index 68e9879bf876..f2dd0a0012af 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts @@ -19,6 +19,12 @@ import "../../../../components/ha-radio"; import "../../../../components/ha-formfield"; import type { HaRadio } from "../../../../components/ha-radio"; import "../../../../components/entity/ha-entity-picker"; +import { + getStatisticMetadata, + getDisplayUnit, + isExternalStatistic, +} from "../../../../data/recorder"; +import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor"; const energyUnitClasses = ["energy"]; @@ -37,6 +43,10 @@ export class DialogEnergyGridFlowSettings @state() private _costs?: "no-costs" | "number" | "entity" | "statistic"; + @state() private _pickedDisplayUnit?: string | null; + + @state() private _energy_units?: string[]; + @state() private _error?: string; public async showDialog( @@ -57,11 +67,24 @@ export class DialogEnergyGridFlowSettings ] ? "statistic" : "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 { this._params = undefined; this._source = undefined; + this._pickedDisplayUnit = undefined; this._error = undefined; fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -71,6 +94,26 @@ export class DialogEnergyGridFlowSettings 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` ${this._error ? html`

${this._error}

` : ""}
- ${this.hass.localize( - `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` + )} +

+

+ ${this.hass.localize( + `ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.entity_para`, + { unit: pickableUnit } + )} +

` : ""} @@ -160,6 +211,7 @@ export class DialogEnergyGridFlowSettings value="entity" name="costs" .checked=${this._costs === "entity"} + .disabled=${externalSource} @change=${this._handleCostChanged} >
@@ -169,9 +221,9 @@ export class DialogEnergyGridFlowSettings .hass=${this.hass} include-domains='["sensor", "input_number"]' .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` - )} + )} ${unitPrice ? ` (${unitPrice})` : ""}`} @value-changed=${this._priceEntityChanged} >` : ""} @@ -184,22 +236,20 @@ export class DialogEnergyGridFlowSettings value="number" name="costs" .checked=${this._costs === "number"} + .disabled=${externalSource} @change=${this._handleCostChanged} > ${this._costs === "number" ? html` ` @@ -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._params!.direction === "from" 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 3423932916fc..d6a47eefba2a 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts @@ -21,6 +21,7 @@ import type { HaRadio } from "../../../../components/ha-radio"; import { showConfigFlowDialog } from "../../../../dialogs/config-flow/show-dialog-config-flow"; import { ConfigEntry, getConfigEntries } from "../../../../data/config_entries"; import { brandsUrl } from "../../../../util/brands-url"; +import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor"; const energyUnitClasses = ["energy"]; @@ -39,6 +40,8 @@ export class DialogEnergySolarSettings @state() private _forecast?: boolean; + @state() private _energy_units?: string[]; + @state() private _error?: string; public async showDialog( @@ -50,6 +53,9 @@ export class DialogEnergySolarSettings ? { ...params.source } : emptySolarEnergyPreference(); this._forecast = this._source.config_entry_solar_forecast !== null; + this._energy_units = ( + await getSensorDeviceClassConvertibleUnits(this.hass, "energy") + ).units; } public closeDialog(): void { @@ -64,6 +70,8 @@ export class DialogEnergySolarSettings return html``; } + const pickableUnit = this._energy_units?.join(", ") || ""; + return html` ${this._error ? html`

${this._error}

` : ""} +
+ ${this.hass.localize( + "ui.panel.config.energy.solar.dialog.entity_para", + { unit: pickableUnit } + )} +
${this._error ? html`

${this._error}

` : ""} +
+

+ ${this.hass.localize( + "ui.panel.config.energy.water.dialog.paragraph" + )} +

+

+ ${this.hass.localize( + "ui.panel.config.energy.water.dialog.entity_para", + { unit: pickableUnit } + )} +

+

- ${this.hass.localize(`ui.panel.config.energy.water.dialog.cost_para`)} + ${this.hass.localize("ui.panel.config.energy.water.dialog.cost_para")}

@@ -125,15 +162,15 @@ export class DialogEnergyWaterSettings .hass=${this.hass} statistic-types="sum" .value=${this._source.stat_cost} - .label=${this.hass.localize( - `ui.panel.config.energy.water.dialog.cost_stat_input` - )} + .label=${`${this.hass.localize( + "ui.panel.config.energy.water.dialog.cost_stat_input" + )} (${this.hass.config.currency})`} @value-changed=${this._priceStatChanged} >
` : ""} ` : ""} ${this._costs === "number" ? html` ` : ""} @@ -230,6 +268,16 @@ export class DialogEnergyWaterSettings } 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") { this._costs = "no-costs"; } diff --git a/src/panels/config/energy/dialogs/show-dialogs-energy.ts b/src/panels/config/energy/dialogs/show-dialogs-energy.ts index 06eccf7b9c80..c9fea02a61e9 100644 --- a/src/panels/config/energy/dialogs/show-dialogs-energy.ts +++ b/src/panels/config/energy/dialogs/show-dialogs-energy.ts @@ -16,6 +16,7 @@ export interface EnergySettingsGridFlowDialogParams { source?: | FlowFromGridSourceEnergyPreference | FlowToGridSourceEnergyPreference; + metadata?: StatisticsMetaData; direction: "from" | "to"; saveCallback: ( source: @@ -26,11 +27,13 @@ export interface EnergySettingsGridFlowDialogParams { export interface EnergySettingsGridFlowFromDialogParams { source?: FlowFromGridSourceEnergyPreference; + metadata?: StatisticsMetaData; saveCallback: (source: FlowFromGridSourceEnergyPreference) => Promise; } export interface EnergySettingsGridFlowToDialogParams { source?: FlowToGridSourceEnergyPreference; + metadata?: StatisticsMetaData; saveCallback: (source: FlowToGridSourceEnergyPreference) => Promise; } diff --git a/src/translations/en.json b/src/translations/en.json index c063af08648e..3cc04a768832 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1520,30 +1520,30 @@ "from": { "header": "Configure grid consumption", "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.", "no_cost": "Do not track 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_input": "Entity with the current price", "cost_number": "Use a static price", - "cost_number_input": "Price per kWh", - "cost_number_suffix": "{currency}/kWh" + "cost_number_input": "Price" }, "to": { "header": "Configure grid production", "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?", "no_cost": "I do not get money back", "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_input": "Entity with the current rate", "cost_number": "Use a static rate", - "cost_number_input": "Rate per kWh", - "cost_number_suffix": "{currency}/kWh" + "cost_number_input": "Rate" } } }, @@ -1560,7 +1560,8 @@ "stat_predicted_production": "Prediction of your solar energy production", "dialog": { "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_description": "Adding solar production forecast information will allow you to quickly see your expected production for today.", "dont_forecast_production": "Don't forecast production", @@ -1578,8 +1579,9 @@ "add_battery_system": "Add battery system", "dialog": { "header": "Configure battery system", - "energy_into_battery": "Energy going in to the battery (kWh)", - "energy_out_of_battery": "Energy coming out of the battery (kWh)" + "entity_para": "Pick sensors which measure energy going in to and out of the battery in either of {unit}.", + "energy_into_battery": "Energy going in to the battery", + "energy_out_of_battery": "Energy coming out of the battery" } }, "gas": { @@ -1592,18 +1594,18 @@ "add_gas_source": "Add gas source", "dialog": { "header": "Configure gas consumption", - "paragraph": "Gas consumption is the volume of gas that flows to your home.", - "energy_stat": "Consumed Energy (m³)", - "cost_para": "Select how Home Assistant should keep track of the costs of the consumed energy.", - "no_cost": "Do not track costs", - "cost_stat": "Use an entity tracking the total costs", - "cost_stat_input": "Total Costs Entity", - "cost_entity": "Use an entity with current price", - "cost_entity_input": "Entity with the current price per {unit}", - "cost_number": "Use a static price", - "cost_number_input": "Price per {unit}", - "gas_usage": "Gas usage", - "m3_or_kWh": "ft³, m³, Wh, kWh, MWh or GJ" + "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.", + "entity_para": "Pick a sensor which measures gas consumption in either of {unit}.", + "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.", + "cost_para": "Select how Home Assistant should keep track of the costs of the consumed gas.", + "no_cost": "[%key:ui::panel::config::energy::grid::flow_dialog::from::no_cost%]", + "cost_stat": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat%]", + "cost_stat_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat_input%]", + "cost_entity": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity%]", + "cost_entity_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity_input%]", + "cost_number": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]", + "cost_number_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]", + "gas_usage": "Gas usage" } }, "water": { @@ -1617,16 +1619,16 @@ "dialog": { "header": "Configure water consumption", "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.", - "no_cost": "Do not track costs", - "cost_stat": "Use an entity tracking the total costs", - "cost_stat_input": "Total Costs Entity", - "cost_entity": "Use an entity with current price", - "cost_entity_input": "Entity with the current price per m³ or gl", - "cost_number": "Use a static price", - "cost_number_input": "Price per m³ or gl", - "water_usage": "Water usage (m³ or gl)" + "no_cost": "[%key:ui::panel::config::energy::grid::flow_dialog::from::no_cost%]", + "cost_stat": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat%]", + "cost_stat_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_stat_input%]", + "cost_entity": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity%]", + "cost_entity_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_entity_input%]", + "cost_number": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]", + "cost_number_input": "[%key:ui::panel::config::energy::grid::flow_dialog::from::cost_number%]", + "water_usage": "Water usage" } }, "device_consumption": { @@ -1639,8 +1641,8 @@ "add_device": "Add device", "dialog": { "header": "Add a device", - "device_consumption_energy": "Device consumption energy (kWh)", - "selected_stat_intro": "Select the entity that represents the device energy usage." + "device_consumption_energy": "Device consumption energy", + "selected_stat_intro": "Select the energy sensor that measures the device's energy usage in either of {unit}." } } },