mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-17 07:34:21 +01:00
Add flow rate picker to gas, water, and water device energy dialogs (#29693)
* Add flow rate picker to gas, water, and water device energy dialogs Add optional flow rate (stat_rate) picker to gas source, water source, and water device configuration dialogs, matching the pattern used for power tracking in grid/solar/battery sources and energy devices. - Add stat_rate to GasSourceTypeEnergyPreference and WaterSourceTypeEnergyPreference - Collect gas/water stat_rate in getReferencedStatisticIdsPower() - Add flow rate ha-statistic-picker filtered to volume_flow_rate device class - Move entity help text to picker helper props for cleaner layout * Apply suggestions from code review Co-authored-by: Norbert Rittel <norbert@rittel.de> --------- Co-authored-by: Norbert Rittel <norbert@rittel.de>
This commit is contained in:
@@ -159,6 +159,9 @@ export interface GasSourceTypeEnergyPreference {
|
||||
// kWh/volume meter
|
||||
stat_energy_from: string;
|
||||
|
||||
// Flow rate (m³/h, L/min, etc.)
|
||||
stat_rate?: string;
|
||||
|
||||
// $ meter
|
||||
stat_cost: string | null;
|
||||
|
||||
@@ -174,6 +177,9 @@ export interface WaterSourceTypeEnergyPreference {
|
||||
// volume meter
|
||||
stat_energy_from: string;
|
||||
|
||||
// Flow rate (L/min, gal/min, m³/h, etc.)
|
||||
stat_rate?: string;
|
||||
|
||||
// $ meter
|
||||
stat_cost: string | null;
|
||||
|
||||
@@ -368,6 +374,9 @@ export const getReferencedStatisticIdsPower = (
|
||||
|
||||
for (const source of prefs.energy_sources) {
|
||||
if (source.type === "gas" || source.type === "water") {
|
||||
if (source.stat_rate) {
|
||||
statIDs.push(source.stat_rate);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -389,6 +398,7 @@ export const getReferencedStatisticIdsPower = (
|
||||
}
|
||||
}
|
||||
statIDs.push(...prefs.device_consumption.map((d) => d.stat_rate));
|
||||
statIDs.push(...prefs.device_consumption_water.map((d) => d.stat_rate));
|
||||
|
||||
return statIDs.filter(Boolean) as string[];
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
|
||||
import type { EnergySettingsDeviceWaterDialogParams } from "./show-dialogs-energy";
|
||||
|
||||
const volumeUnitClasses = ["volume"];
|
||||
const flowRateUnitClasses = ["volume_flow_rate"];
|
||||
|
||||
@customElement("dialog-energy-device-settings-water")
|
||||
export class DialogEnergyDeviceSettingsWater
|
||||
@@ -36,10 +37,14 @@ export class DialogEnergyDeviceSettingsWater
|
||||
|
||||
@state() private _volume_units?: string[];
|
||||
|
||||
@state() private _flow_rate_units?: string[];
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _excludeList?: string[];
|
||||
|
||||
private _excludeListFlowRate?: string[];
|
||||
|
||||
private _possibleParents: DeviceConsumptionEnergyPreference[] = [];
|
||||
|
||||
public async showDialog(
|
||||
@@ -51,9 +56,15 @@ export class DialogEnergyDeviceSettingsWater
|
||||
this._volume_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "water")
|
||||
).units;
|
||||
this._flow_rate_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "volume_flow_rate")
|
||||
).units;
|
||||
this._excludeList = this._params.device_consumptions
|
||||
.map((entry) => entry.stat_consumption)
|
||||
.filter((id) => id !== this._device?.stat_consumption);
|
||||
this._excludeListFlowRate = this._params.device_consumptions
|
||||
.map((entry) => entry.stat_rate)
|
||||
.filter((id) => id && id !== this._device?.stat_rate) as string[];
|
||||
|
||||
this._open = true;
|
||||
}
|
||||
@@ -92,6 +103,7 @@ export class DialogEnergyDeviceSettingsWater
|
||||
this._device = undefined;
|
||||
this._error = undefined;
|
||||
this._excludeList = undefined;
|
||||
this._excludeListFlowRate = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@@ -134,12 +146,6 @@ export class DialogEnergyDeviceSettingsWater
|
||||
@closed=${this._dialogClosed}
|
||||
>
|
||||
${this._error ? html`<p class="error">${this._error}</p>` : ""}
|
||||
<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption_water.dialog.selected_stat_intro",
|
||||
{ unit: pickableUnit }
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
@@ -151,9 +157,28 @@ export class DialogEnergyDeviceSettingsWater
|
||||
)}
|
||||
.excludeStatistics=${this._excludeList}
|
||||
@value-changed=${this._statisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption_water.dialog.selected_stat_intro",
|
||||
{ unit: pickableUnit }
|
||||
)}
|
||||
autofocus
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${flowRateUnitClasses}
|
||||
.value=${this._device?.stat_rate}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption_water.dialog.device_consumption_water_flow_rate"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListFlowRate}
|
||||
@value-changed=${this._flowRateStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption_water.dialog.selected_stat_intro",
|
||||
{ unit: this._flow_rate_units?.join(", ") || "" }
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-textfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.device_consumption_water.dialog.display_name"
|
||||
@@ -216,6 +241,20 @@ export class DialogEnergyDeviceSettingsWater
|
||||
this._computePossibleParents();
|
||||
}
|
||||
|
||||
private _flowRateStatisticChanged(ev: ValueChangedEvent<string>) {
|
||||
if (!this._device) {
|
||||
return;
|
||||
}
|
||||
const newDevice = {
|
||||
...this._device,
|
||||
stat_rate: ev.detail.value,
|
||||
} as DeviceConsumptionEnergyPreference;
|
||||
if (!newDevice.stat_rate) {
|
||||
delete newDevice.stat_rate;
|
||||
}
|
||||
this._device = newDevice;
|
||||
}
|
||||
|
||||
private _nameChanged(ev) {
|
||||
const newDevice = {
|
||||
...this._device!,
|
||||
@@ -252,7 +291,9 @@ export class DialogEnergyDeviceSettingsWater
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-statistic-picker {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
ha-select {
|
||||
display: block;
|
||||
|
||||
@@ -30,6 +30,7 @@ import type { EnergySettingsGasDialogParams } from "./show-dialogs-energy";
|
||||
|
||||
const gasDeviceClasses = ["gas", "energy"];
|
||||
const gasUnitClasses = ["volume", "energy"];
|
||||
const flowRateUnitClasses = ["volume_flow_rate"];
|
||||
|
||||
@customElement("dialog-energy-gas-settings")
|
||||
export class DialogEnergyGasSettings
|
||||
@@ -52,10 +53,14 @@ export class DialogEnergyGasSettings
|
||||
|
||||
@state() private _gas_units?: string[];
|
||||
|
||||
@state() private _flow_rate_units?: string[];
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _excludeList?: string[];
|
||||
|
||||
private _excludeListFlowRate?: string[];
|
||||
|
||||
public async showDialog(
|
||||
params: EnergySettingsGasDialogParams
|
||||
): Promise<void> {
|
||||
@@ -81,9 +86,15 @@ export class DialogEnergyGasSettings
|
||||
this._gas_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "gas")
|
||||
).units;
|
||||
this._flow_rate_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "volume_flow_rate")
|
||||
).units;
|
||||
this._excludeList = this._params.gas_sources
|
||||
.map((entry) => entry.stat_energy_from)
|
||||
.filter((id) => id !== this._source?.stat_energy_from);
|
||||
this._excludeListFlowRate = this._params.gas_sources
|
||||
.map((entry) => entry.stat_rate)
|
||||
.filter((id) => id && id !== this._source?.stat_rate) as string[];
|
||||
|
||||
this._open = true;
|
||||
}
|
||||
@@ -99,6 +110,7 @@ export class DialogEnergyGasSettings
|
||||
this._pickedDisplayUnit = undefined;
|
||||
this._error = undefined;
|
||||
this._excludeList = undefined;
|
||||
this._excludeListFlowRate = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@@ -146,12 +158,6 @@ export class DialogEnergyGasSettings
|
||||
<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>
|
||||
@@ -169,9 +175,28 @@ export class DialogEnergyGasSettings
|
||||
)}
|
||||
.excludeStatistics=${this._excludeList}
|
||||
@value-changed=${this._statisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.gas.dialog.entity_para",
|
||||
{ unit: pickableUnit }
|
||||
)}
|
||||
autofocus
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${flowRateUnitClasses}
|
||||
.value=${this._source.stat_rate}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.gas.dialog.gas_flow_rate"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListFlowRate}
|
||||
@value-changed=${this._flowRateStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.gas.dialog.flow_rate_para",
|
||||
{ unit: this._flow_rate_units?.join(", ") || "" }
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<p>
|
||||
${this.hass.localize("ui.panel.config.energy.gas.dialog.cost_para")}
|
||||
</p>
|
||||
@@ -341,6 +366,13 @@ export class DialogEnergyGasSettings
|
||||
};
|
||||
}
|
||||
|
||||
private _flowRateStatisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
stat_rate: ev.detail.value || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private async _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
if (ev.detail.value) {
|
||||
const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]);
|
||||
@@ -380,6 +412,10 @@ export class DialogEnergyGasSettings
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-statistic-picker {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
ha-formfield {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
|
||||
import type { EnergySettingsWaterDialogParams } from "./show-dialogs-energy";
|
||||
|
||||
const flowRateUnitClasses = ["volume_flow_rate"];
|
||||
|
||||
@customElement("dialog-energy-water-settings")
|
||||
export class DialogEnergyWaterSettings
|
||||
extends LitElement
|
||||
@@ -41,10 +43,14 @@ export class DialogEnergyWaterSettings
|
||||
|
||||
@state() private _water_units?: string[];
|
||||
|
||||
@state() private _flow_rate_units?: string[];
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _excludeList?: string[];
|
||||
|
||||
private _excludeListFlowRate?: string[];
|
||||
|
||||
public async showDialog(
|
||||
params: EnergySettingsWaterDialogParams
|
||||
): Promise<void> {
|
||||
@@ -62,9 +68,15 @@ export class DialogEnergyWaterSettings
|
||||
this._water_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "water")
|
||||
).units;
|
||||
this._flow_rate_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "volume_flow_rate")
|
||||
).units;
|
||||
this._excludeList = this._params.water_sources
|
||||
.map((entry) => entry.stat_energy_from)
|
||||
.filter((id) => id !== this._source?.stat_energy_from);
|
||||
this._excludeListFlowRate = this._params.water_sources
|
||||
.map((entry) => entry.stat_rate)
|
||||
.filter((id) => id && id !== this._source?.stat_rate) as string[];
|
||||
|
||||
this._open = true;
|
||||
}
|
||||
@@ -79,6 +91,7 @@ export class DialogEnergyWaterSettings
|
||||
this._source = undefined;
|
||||
this._error = undefined;
|
||||
this._excludeList = undefined;
|
||||
this._excludeListFlowRate = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@@ -108,19 +121,6 @@ export class DialogEnergyWaterSettings
|
||||
@closed=${this._dialogClosed}
|
||||
>
|
||||
${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
|
||||
.hass=${this.hass}
|
||||
@@ -133,9 +133,28 @@ export class DialogEnergyWaterSettings
|
||||
)}
|
||||
.excludeStatistics=${this._excludeList}
|
||||
@value-changed=${this._statisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.water.dialog.entity_para",
|
||||
{ unit: pickableUnit }
|
||||
)}
|
||||
autofocus
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${flowRateUnitClasses}
|
||||
.value=${this._source.stat_rate}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.water.dialog.water_flow_rate"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListFlowRate}
|
||||
@value-changed=${this._flowRateStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.water.dialog.flow_rate_para",
|
||||
{ unit: this._flow_rate_units?.join(", ") || "" }
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<p>
|
||||
${this.hass.localize("ui.panel.config.energy.water.dialog.cost_para")}
|
||||
</p>
|
||||
@@ -287,6 +306,13 @@ export class DialogEnergyWaterSettings
|
||||
};
|
||||
}
|
||||
|
||||
private _flowRateStatisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
stat_rate: ev.detail.value || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private async _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
if (
|
||||
ev.detail.value &&
|
||||
@@ -320,6 +346,10 @@ export class DialogEnergyWaterSettings
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-statistic-picker {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
ha-formfield {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -3936,7 +3936,9 @@
|
||||
"cost_entity_helper_volume": "volume",
|
||||
"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"
|
||||
"gas_usage": "Gas consumption",
|
||||
"gas_flow_rate": "Gas flow rate",
|
||||
"flow_rate_para": "Optionally pick a sensor which measures the gas flow rate in either of {unit}."
|
||||
}
|
||||
},
|
||||
"water": {
|
||||
@@ -3960,7 +3962,9 @@
|
||||
"cost_entity_helper": "Any entity with a unit of `{currency}/(valid water unit)` (e.g. `{currency}/gal` or `{currency}/m³`) may be used and will be automatically converted.",
|
||||
"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"
|
||||
"water_usage": "Water consumption",
|
||||
"water_flow_rate": "Water flow rate",
|
||||
"flow_rate_para": "Optionally pick a sensor which measures the water flow rate in either of {unit}."
|
||||
}
|
||||
},
|
||||
"device_consumption": {
|
||||
@@ -3992,7 +3996,8 @@
|
||||
"header": "Add a water device",
|
||||
"display_name": "Display name",
|
||||
"device_consumption_water": "Device water consumption",
|
||||
"selected_stat_intro": "Select the water sensor that measures the device's water usage in either of {unit}.",
|
||||
"device_consumption_water_flow_rate": "Device water flow rate",
|
||||
"selected_stat_intro": "Select the water sensor that measures the device's water consumption in either of {unit}.",
|
||||
"included_in_device": "Upstream device",
|
||||
"included_in_device_helper": "If this device is already counted by another device (such as a water meter measured by the main water supply), selecting the upstream device prevents duplicate water tracking.",
|
||||
"no_upstream_devices": "No eligible upstream devices"
|
||||
|
||||
Reference in New Issue
Block a user