mirror of
https://github.com/home-assistant/frontend.git
synced 2026-01-13 18:57:33 +00:00
Compare commits
2 Commits
dev
...
power-sens
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d92319b9 | ||
|
|
308721583d |
@@ -131,9 +131,16 @@ export interface FlowToGridSourceEnergyPreference {
|
||||
number_energy_price: number | null;
|
||||
}
|
||||
|
||||
export interface PowerConfig {
|
||||
stat_rate?: string; // Standard single sensor
|
||||
stat_rate_inverted?: string; // Inverted single sensor
|
||||
stat_rate_from?: string; // Battery: discharge / Grid: consumption
|
||||
stat_rate_to?: string; // Battery: charge / Grid: return
|
||||
}
|
||||
|
||||
export interface GridPowerSourceEnergyPreference {
|
||||
// W meter
|
||||
stat_rate: string;
|
||||
power_config?: PowerConfig;
|
||||
}
|
||||
|
||||
export interface GridSourceTypeEnergyPreference {
|
||||
@@ -159,6 +166,7 @@ export interface BatterySourceTypeEnergyPreference {
|
||||
stat_energy_from: string;
|
||||
stat_energy_to: string;
|
||||
stat_rate?: string;
|
||||
power_config?: PowerConfig;
|
||||
}
|
||||
export interface GasSourceTypeEnergyPreference {
|
||||
type: "gas";
|
||||
|
||||
@@ -6,7 +6,13 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-button";
|
||||
import type { BatterySourceTypeEnergyPreference } from "../../../../data/energy";
|
||||
import "../../../../components/ha-formfield";
|
||||
import "../../../../components/ha-radio";
|
||||
import type { HaRadio } from "../../../../components/ha-radio";
|
||||
import type {
|
||||
BatterySourceTypeEnergyPreference,
|
||||
PowerConfig,
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
emptyBatteryEnergyPreference,
|
||||
energyStatisticHelpUrl,
|
||||
@@ -20,6 +26,8 @@ import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
|
||||
const energyUnitClasses = ["energy"];
|
||||
const powerUnitClasses = ["power"];
|
||||
|
||||
type PowerType = "none" | "standard" | "inverted" | "two_sensors";
|
||||
|
||||
@customElement("dialog-energy-battery-settings")
|
||||
export class DialogEnergyBatterySettings
|
||||
extends LitElement
|
||||
@@ -31,6 +39,10 @@ export class DialogEnergyBatterySettings
|
||||
|
||||
@state() private _source?: BatterySourceTypeEnergyPreference;
|
||||
|
||||
@state() private _powerType: PowerType = "none";
|
||||
|
||||
@state() private _powerConfig: PowerConfig = {};
|
||||
|
||||
@state() private _energy_units?: string[];
|
||||
|
||||
@state() private _power_units?: string[];
|
||||
@@ -48,12 +60,37 @@ export class DialogEnergyBatterySettings
|
||||
this._source = params.source
|
||||
? { ...params.source }
|
||||
: emptyBatteryEnergyPreference();
|
||||
|
||||
// Initialize power type from existing config
|
||||
if (params.source?.power_config) {
|
||||
const pc = params.source.power_config;
|
||||
this._powerConfig = { ...pc };
|
||||
if (pc.stat_rate_inverted) {
|
||||
this._powerType = "inverted";
|
||||
} else if (pc.stat_rate_from || pc.stat_rate_to) {
|
||||
this._powerType = "two_sensors";
|
||||
} else if (pc.stat_rate) {
|
||||
this._powerType = "standard";
|
||||
} else {
|
||||
this._powerType = "none";
|
||||
}
|
||||
} else if (params.source?.stat_rate) {
|
||||
// Legacy format - treat as standard
|
||||
this._powerType = "standard";
|
||||
this._powerConfig = { stat_rate: params.source.stat_rate };
|
||||
} else {
|
||||
this._powerType = "none";
|
||||
this._powerConfig = {};
|
||||
}
|
||||
|
||||
this._energy_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
|
||||
).units;
|
||||
this._power_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
|
||||
).units;
|
||||
|
||||
// Build energy exclude list
|
||||
const allSources: string[] = [];
|
||||
this._params.battery_sources.forEach((entry) => {
|
||||
allSources.push(entry.stat_energy_from);
|
||||
@@ -64,16 +101,44 @@ 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_rate)
|
||||
.filter((id) => id && id !== this._source?.stat_rate) as string[];
|
||||
|
||||
// Build power exclude list
|
||||
const powerIds: string[] = [];
|
||||
this._params.battery_sources.forEach((entry) => {
|
||||
if (entry.stat_rate) powerIds.push(entry.stat_rate);
|
||||
if (entry.power_config) {
|
||||
if (entry.power_config.stat_rate)
|
||||
powerIds.push(entry.power_config.stat_rate);
|
||||
if (entry.power_config.stat_rate_inverted)
|
||||
powerIds.push(entry.power_config.stat_rate_inverted);
|
||||
if (entry.power_config.stat_rate_from)
|
||||
powerIds.push(entry.power_config.stat_rate_from);
|
||||
if (entry.power_config.stat_rate_to)
|
||||
powerIds.push(entry.power_config.stat_rate_to);
|
||||
}
|
||||
});
|
||||
|
||||
const currentPowerIds = [
|
||||
this._powerConfig.stat_rate,
|
||||
this._powerConfig.stat_rate_inverted,
|
||||
this._powerConfig.stat_rate_from,
|
||||
this._powerConfig.stat_rate_to,
|
||||
params.source?.stat_rate,
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
this._excludeListPower = powerIds.filter(
|
||||
(id) => !currentPowerIds.includes(id)
|
||||
);
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._params = undefined;
|
||||
this._source = undefined;
|
||||
this._powerType = "none";
|
||||
this._powerConfig = {};
|
||||
this._error = undefined;
|
||||
this._excludeList = undefined;
|
||||
this._excludeListPower = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
return true;
|
||||
}
|
||||
@@ -93,7 +158,7 @@ export class DialogEnergyBatterySettings
|
||||
${this.hass.localize("ui.panel.config.energy.battery.dialog.header")}`}
|
||||
@closed=${this.closeDialog}
|
||||
>
|
||||
${this._error ? html`<p class="error">${this._error}</p>` : ""}
|
||||
${this._error ? html`<p class="error">${this._error}</p>` : nothing}
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
@@ -134,20 +199,126 @@ export class DialogEnergyBatterySettings
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._source.stat_rate}
|
||||
<p class="power-section-label">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.sensor_type"
|
||||
)}
|
||||
</p>
|
||||
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power"
|
||||
"ui.panel.config.energy.battery.dialog.type_none"
|
||||
)}
|
||||
.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-radio
|
||||
value="none"
|
||||
name="powerType"
|
||||
.checked=${this._powerType === "none"}
|
||||
@change=${this._handlePowerTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.type_standard"
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
>
|
||||
<ha-radio
|
||||
value="standard"
|
||||
name="powerType"
|
||||
.checked=${this._powerType === "standard"}
|
||||
@change=${this._handlePowerTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.type_inverted"
|
||||
)}
|
||||
>
|
||||
<ha-radio
|
||||
value="inverted"
|
||||
name="powerType"
|
||||
.checked=${this._powerType === "inverted"}
|
||||
@change=${this._handlePowerTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.type_two_sensors"
|
||||
)}
|
||||
>
|
||||
<ha-radio
|
||||
value="two_sensors"
|
||||
name="powerType"
|
||||
.checked=${this._powerType === "two_sensors"}
|
||||
@change=${this._handlePowerTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
|
||||
${this._powerType === "standard"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListPower}
|
||||
@value-changed=${this._standardPowerChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power_helper",
|
||||
{ unit: this._power_units?.join(", ") || "" }
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
${this._powerType === "inverted"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_inverted}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListPower}
|
||||
@value-changed=${this._invertedPowerChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.type_inverted_description"
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
${this._powerType === "two_sensors"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_from}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power_discharge"
|
||||
)}
|
||||
.excludeStatistics=${[
|
||||
...(this._excludeListPower || []),
|
||||
this._powerConfig.stat_rate_to,
|
||||
].filter((id): id is string => Boolean(id))}
|
||||
@value-changed=${this._dischargePowerChanged}
|
||||
></ha-statistic-picker>
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_to}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.power_charge"
|
||||
)}
|
||||
.excludeStatistics=${[
|
||||
...(this._excludeListPower || []),
|
||||
this._powerConfig.stat_rate_from,
|
||||
].filter((id): id is string => Boolean(id))}
|
||||
@value-changed=${this._chargePowerChanged}
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@@ -158,8 +329,7 @@ export class DialogEnergyBatterySettings
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._save}
|
||||
.disabled=${!this._source.stat_energy_from ||
|
||||
!this._source.stat_energy_to}
|
||||
.disabled=${!this._isValid()}
|
||||
slot="primaryAction"
|
||||
>
|
||||
${this.hass.localize("ui.common.save")}
|
||||
@@ -168,6 +338,29 @@ export class DialogEnergyBatterySettings
|
||||
`;
|
||||
}
|
||||
|
||||
private _isValid(): boolean {
|
||||
// Energy fields are always required
|
||||
if (!this._source?.stat_energy_from || !this._source?.stat_energy_to) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Power fields depend on selected type
|
||||
switch (this._powerType) {
|
||||
case "none":
|
||||
return true;
|
||||
case "standard":
|
||||
return !!this._powerConfig.stat_rate;
|
||||
case "inverted":
|
||||
return !!this._powerConfig.stat_rate_inverted;
|
||||
case "two_sensors":
|
||||
return (
|
||||
!!this._powerConfig.stat_rate_from && !!this._powerConfig.stat_rate_to
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private _statisticToChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._source = { ...this._source!, stat_energy_to: ev.detail.value };
|
||||
}
|
||||
@@ -176,13 +369,53 @@ export class DialogEnergyBatterySettings
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
}
|
||||
|
||||
private _powerChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._source = { ...this._source!, stat_rate: ev.detail.value };
|
||||
private _handlePowerTypeChanged(ev: Event) {
|
||||
const input = ev.currentTarget as HaRadio;
|
||||
this._powerType = input.value as PowerType;
|
||||
// Clear power config when switching types
|
||||
this._powerConfig = {};
|
||||
}
|
||||
|
||||
private _standardPowerChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
stat_rate: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _invertedPowerChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
stat_rate_inverted: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _dischargePowerChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
...this._powerConfig,
|
||||
stat_rate_from: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _chargePowerChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
...this._powerConfig,
|
||||
stat_rate_to: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private async _save() {
|
||||
try {
|
||||
await this._params!.saveCallback(this._source!);
|
||||
const source: BatterySourceTypeEnergyPreference = {
|
||||
type: "battery",
|
||||
stat_energy_from: this._source!.stat_energy_from,
|
||||
stat_energy_to: this._source!.stat_energy_to,
|
||||
};
|
||||
|
||||
// Only include power_config if a power type is selected
|
||||
if (this._powerType !== "none") {
|
||||
source.power_config = { ...this._powerConfig };
|
||||
}
|
||||
|
||||
await this._params!.saveCallback(source);
|
||||
this.closeDialog();
|
||||
} catch (err: any) {
|
||||
this._error = err.message;
|
||||
@@ -204,6 +437,13 @@ export class DialogEnergyBatterySettings
|
||||
ha-statistic-picker:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-formfield {
|
||||
display: block;
|
||||
}
|
||||
.power-section-label {
|
||||
margin-top: var(--ha-space-4);
|
||||
margin-bottom: var(--ha-space-2);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-button";
|
||||
import type { GridPowerSourceEnergyPreference } from "../../../../data/energy";
|
||||
import "../../../../components/ha-formfield";
|
||||
import "../../../../components/ha-radio";
|
||||
import type { HaRadio } from "../../../../components/ha-radio";
|
||||
import type { PowerConfig } from "../../../../data/energy";
|
||||
import { energyStatisticHelpUrl } from "../../../../data/energy";
|
||||
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
@@ -16,6 +19,8 @@ import type { EnergySettingsGridPowerDialogParams } from "./show-dialogs-energy"
|
||||
|
||||
const powerUnitClasses = ["power"];
|
||||
|
||||
type SensorType = "standard" | "inverted" | "two_sensors";
|
||||
|
||||
@customElement("dialog-energy-grid-power-settings")
|
||||
export class DialogEnergyGridPowerSettings
|
||||
extends LitElement
|
||||
@@ -25,7 +30,9 @@ export class DialogEnergyGridPowerSettings
|
||||
|
||||
@state() private _params?: EnergySettingsGridPowerDialogParams;
|
||||
|
||||
@state() private _source?: GridPowerSourceEnergyPreference;
|
||||
@state() private _sensorType: SensorType = "standard";
|
||||
|
||||
@state() private _powerConfig: PowerConfig = {};
|
||||
|
||||
@state() private _power_units?: string[];
|
||||
|
||||
@@ -37,23 +44,65 @@ export class DialogEnergyGridPowerSettings
|
||||
params: EnergySettingsGridPowerDialogParams
|
||||
): Promise<void> {
|
||||
this._params = params;
|
||||
this._source = params.source ? { ...params.source } : { stat_rate: "" };
|
||||
|
||||
const initialSourceIdPower = this._source.stat_rate;
|
||||
// Initialize from existing source
|
||||
if (params.source?.power_config) {
|
||||
const pc = params.source.power_config;
|
||||
this._powerConfig = { ...pc };
|
||||
if (pc.stat_rate_inverted) {
|
||||
this._sensorType = "inverted";
|
||||
} else if (pc.stat_rate_from || pc.stat_rate_to) {
|
||||
this._sensorType = "two_sensors";
|
||||
} else {
|
||||
this._sensorType = "standard";
|
||||
}
|
||||
} else if (params.source?.stat_rate) {
|
||||
// Legacy format - treat as standard
|
||||
this._sensorType = "standard";
|
||||
this._powerConfig = { stat_rate: params.source.stat_rate };
|
||||
} else {
|
||||
this._sensorType = "standard";
|
||||
this._powerConfig = {};
|
||||
}
|
||||
|
||||
this._power_units = (
|
||||
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
|
||||
).units;
|
||||
|
||||
this._excludeListPower = [
|
||||
...(this._params.grid_source?.power?.map((entry) => entry.stat_rate) ||
|
||||
[]),
|
||||
].filter((id) => id && id !== initialSourceIdPower) as string[];
|
||||
// Build exclude list from all power sources
|
||||
const excludeIds: string[] = [];
|
||||
this._params.grid_source?.power?.forEach((entry) => {
|
||||
if (entry.stat_rate) excludeIds.push(entry.stat_rate);
|
||||
if (entry.power_config) {
|
||||
if (entry.power_config.stat_rate)
|
||||
excludeIds.push(entry.power_config.stat_rate);
|
||||
if (entry.power_config.stat_rate_inverted)
|
||||
excludeIds.push(entry.power_config.stat_rate_inverted);
|
||||
if (entry.power_config.stat_rate_from)
|
||||
excludeIds.push(entry.power_config.stat_rate_from);
|
||||
if (entry.power_config.stat_rate_to)
|
||||
excludeIds.push(entry.power_config.stat_rate_to);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter out current source's IDs
|
||||
const currentIds = [
|
||||
this._powerConfig.stat_rate,
|
||||
this._powerConfig.stat_rate_inverted,
|
||||
this._powerConfig.stat_rate_from,
|
||||
this._powerConfig.stat_rate_to,
|
||||
params.source?.stat_rate,
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
this._excludeListPower = excludeIds.filter(
|
||||
(id) => !currentIds.includes(id)
|
||||
);
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._params = undefined;
|
||||
this._source = undefined;
|
||||
this._powerConfig = {};
|
||||
this._sensorType = "standard";
|
||||
this._error = undefined;
|
||||
this._excludeListPower = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
@@ -61,7 +110,7 @@ export class DialogEnergyGridPowerSettings
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._params || !this._source) {
|
||||
if (!this._params) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
@@ -77,24 +126,123 @@ export class DialogEnergyGridPowerSettings
|
||||
)}`}
|
||||
@closed=${this.closeDialog}
|
||||
>
|
||||
${this._error ? html`<p class="error">${this._error}</p>` : ""}
|
||||
${this._error ? html`<p class="error">${this._error}</p>` : nothing}
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.helpMissingEntityUrl=${energyStatisticHelpUrl}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._source.stat_rate}
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.sensor_type"
|
||||
)}
|
||||
</p>
|
||||
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_stat"
|
||||
"ui.panel.config.energy.grid.power_dialog.type_standard"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListPower}
|
||||
@value-changed=${this._powerStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_helper",
|
||||
{ unit: this._power_units?.join(", ") || "" }
|
||||
>
|
||||
<ha-radio
|
||||
value="standard"
|
||||
name="sensorType"
|
||||
.checked=${this._sensorType === "standard"}
|
||||
@change=${this._handleSensorTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.type_inverted"
|
||||
)}
|
||||
dialogInitialFocus
|
||||
></ha-statistic-picker>
|
||||
>
|
||||
<ha-radio
|
||||
value="inverted"
|
||||
name="sensorType"
|
||||
.checked=${this._sensorType === "inverted"}
|
||||
@change=${this._handleSensorTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.type_two_sensors"
|
||||
)}
|
||||
>
|
||||
<ha-radio
|
||||
value="two_sensors"
|
||||
name="sensorType"
|
||||
.checked=${this._sensorType === "two_sensors"}
|
||||
@change=${this._handleSensorTypeChanged}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
|
||||
${this._sensorType === "standard"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.helpMissingEntityUrl=${energyStatisticHelpUrl}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_stat"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListPower}
|
||||
@value-changed=${this._standardStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_helper",
|
||||
{ unit: this._power_units?.join(", ") || "" }
|
||||
)}
|
||||
dialogInitialFocus
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
${this._sensorType === "inverted"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.helpMissingEntityUrl=${energyStatisticHelpUrl}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_inverted}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_stat"
|
||||
)}
|
||||
.excludeStatistics=${this._excludeListPower}
|
||||
@value-changed=${this._invertedStatisticChanged}
|
||||
.helper=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.type_inverted_description"
|
||||
)}
|
||||
dialogInitialFocus
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
${this._sensorType === "two_sensors"
|
||||
? html`
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.helpMissingEntityUrl=${energyStatisticHelpUrl}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_from}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_from_grid"
|
||||
)}
|
||||
.excludeStatistics=${[
|
||||
...(this._excludeListPower || []),
|
||||
this._powerConfig.stat_rate_to,
|
||||
].filter((id): id is string => Boolean(id))}
|
||||
@value-changed=${this._fromStatisticChanged}
|
||||
dialogInitialFocus
|
||||
></ha-statistic-picker>
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.helpMissingEntityUrl=${energyStatisticHelpUrl}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
.value=${this._powerConfig.stat_rate_to}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.power_dialog.power_to_grid"
|
||||
)}
|
||||
.excludeStatistics=${[
|
||||
...(this._excludeListPower || []),
|
||||
this._powerConfig.stat_rate_from,
|
||||
].filter((id): id is string => Boolean(id))}
|
||||
@value-changed=${this._toStatisticChanged}
|
||||
></ha-statistic-picker>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@@ -105,7 +253,7 @@ export class DialogEnergyGridPowerSettings
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._save}
|
||||
.disabled=${!this._source.stat_rate}
|
||||
.disabled=${!this._isValid()}
|
||||
slot="primaryAction"
|
||||
>
|
||||
${this.hass.localize("ui.common.save")}
|
||||
@@ -114,16 +262,61 @@ export class DialogEnergyGridPowerSettings
|
||||
`;
|
||||
}
|
||||
|
||||
private _powerStatisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
private _isValid(): boolean {
|
||||
switch (this._sensorType) {
|
||||
case "standard":
|
||||
return !!this._powerConfig.stat_rate;
|
||||
case "inverted":
|
||||
return !!this._powerConfig.stat_rate_inverted;
|
||||
case "two_sensors":
|
||||
return (
|
||||
!!this._powerConfig.stat_rate_from && !!this._powerConfig.stat_rate_to
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleSensorTypeChanged(ev: Event) {
|
||||
const input = ev.currentTarget as HaRadio;
|
||||
this._sensorType = input.value as SensorType;
|
||||
// Clear config when switching types
|
||||
this._powerConfig = {};
|
||||
}
|
||||
|
||||
private _standardStatisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
stat_rate: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _invertedStatisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
stat_rate_inverted: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _fromStatisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
...this._powerConfig,
|
||||
stat_rate_from: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private _toStatisticChanged(ev: CustomEvent<{ value: string }>) {
|
||||
this._powerConfig = {
|
||||
...this._powerConfig,
|
||||
stat_rate_to: ev.detail.value,
|
||||
};
|
||||
}
|
||||
|
||||
private async _save() {
|
||||
try {
|
||||
await this._params!.saveCallback(this._source!);
|
||||
const source = {
|
||||
stat_rate: "", // will be overridden but needed to satisfy typescript
|
||||
power_config: { ...this._powerConfig },
|
||||
};
|
||||
await this._params!.saveCallback(source);
|
||||
this.closeDialog();
|
||||
} catch (err: any) {
|
||||
this._error = err.message;
|
||||
@@ -137,9 +330,15 @@ export class DialogEnergyGridPowerSettings
|
||||
ha-dialog {
|
||||
--mdc-dialog-max-width: 430px;
|
||||
}
|
||||
ha-formfield {
|
||||
display: block;
|
||||
}
|
||||
ha-statistic-picker {
|
||||
display: block;
|
||||
margin: var(--ha-space-4) 0;
|
||||
margin-top: var(--ha-space-4);
|
||||
}
|
||||
p {
|
||||
margin-bottom: var(--ha-space-2);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -3154,8 +3154,15 @@
|
||||
"delete_power": "Delete power sensor",
|
||||
"power_dialog": {
|
||||
"header": "Configure grid power",
|
||||
"sensor_type": "Sensor type",
|
||||
"type_standard": "Standard",
|
||||
"type_inverted": "Inverted",
|
||||
"type_inverted_description": "Positive values indicate exporting to the grid, negative values indicate importing from the grid.",
|
||||
"type_two_sensors": "Two sensors",
|
||||
"power_stat": "Power sensor",
|
||||
"power_helper": "Pick a sensor which measures grid power in either of {unit}. Positive values indicate importing electricity from the grid, negative values indicate exporting electricity to the grid."
|
||||
"power_helper": "Pick a sensor which measures grid power in either of {unit}. Positive values indicate importing electricity from the grid, negative values indicate exporting electricity to the grid.",
|
||||
"power_from_grid": "Power from grid",
|
||||
"power_to_grid": "Power to grid"
|
||||
},
|
||||
"flow_dialog": {
|
||||
"cost_entity_helper": "Any sensor with a unit of `{currency}/(valid energy unit)` (e.g. `{currency}/Wh` or `{currency}/kWh`) may be used and will be automatically converted.",
|
||||
@@ -3227,7 +3234,15 @@
|
||||
"energy_into_battery": "Energy charged into the battery",
|
||||
"energy_out_of_battery": "Energy discharged from the battery",
|
||||
"power": "Battery power",
|
||||
"power_helper": "Pick a sensor which measures the electricity flowing into and out of the battery in either of {unit}. Positive values indicate discharging the battery, negative values indicate charging the battery."
|
||||
"power_helper": "Pick a sensor which measures the electricity flowing into and out of the battery in either of {unit}. Positive values indicate discharging the battery, negative values indicate charging the battery.",
|
||||
"sensor_type": "Power sensor type",
|
||||
"type_none": "No power sensor",
|
||||
"type_standard": "Standard",
|
||||
"type_inverted": "Inverted",
|
||||
"type_inverted_description": "Positive values indicate charging, negative values indicate discharging.",
|
||||
"type_two_sensors": "Two sensors",
|
||||
"power_discharge": "Discharge power",
|
||||
"power_charge": "Charge power"
|
||||
}
|
||||
},
|
||||
"gas": {
|
||||
|
||||
Reference in New Issue
Block a user