Compare commits

...

2 Commits

Author SHA1 Message Date
Petar Petrov 5acc65aa01 Add spacing between state of charge and capacity inputs 2026-06-02 11:58:20 +03:00
Petar Petrov 1cbc1878fc Add battery capacity option for weighted state of charge 2026-06-02 11:42:45 +03:00
4 changed files with 72 additions and 10 deletions
+1
View File
@@ -167,6 +167,7 @@ export interface BatterySourceTypeEnergyPreference {
stat_rate?: string; // always available if power_config is set
power_config?: PowerConfig;
stat_soc?: string;
capacity?: number; // usable capacity in kWh, used to weight the combined SOC
name?: string;
}
export interface GasSourceTypeEnergyPreference {
@@ -231,6 +231,24 @@ export class DialogEnergyBatterySettings
@value-changed=${this._statisticSocChanged}
></ha-statistic-picker>
<ha-input
.value=${this._source.capacity != null
? String(this._source.capacity)
: ""}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.capacity"
)}
.hint=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.capacity_helper"
)}
type="number"
step="any"
min="0"
@input=${this._capacityChanged}
>
<span slot="end">kWh</span>
</ha-input>
<ha-dialog-footer slot="footer">
<ha-button
appearance="plain"
@@ -314,6 +332,18 @@ export class DialogEnergyBatterySettings
};
}
private _capacityChanged(ev: InputEvent) {
const rawValue = (ev.target as HaInput).value;
const value = rawValue ? parseFloat(rawValue) : NaN;
this._source = {
...this._source!,
capacity: Number.isFinite(value) && value > 0 ? value : undefined,
};
if (this._source.capacity === undefined) {
delete this._source.capacity;
}
}
private async _save() {
try {
const source: BatterySourceTypeEnergyPreference = {
@@ -334,6 +364,10 @@ export class DialogEnergyBatterySettings
source.stat_soc = this._source!.stat_soc;
}
if (this._source!.capacity != null) {
source.capacity = this._source!.capacity;
}
await this._params!.saveCallback(source);
this.closeDialog();
} catch (err: any) {
@@ -351,7 +385,11 @@ export class DialogEnergyBatterySettings
display: block;
margin-bottom: var(--ha-space-4);
}
ha-statistic-picker:last-of-type {
ha-input {
margin-bottom: var(--ha-space-4);
--ha-input-padding-bottom: 0;
}
ha-input:last-of-type {
margin-bottom: 0;
}
`,
@@ -210,16 +210,37 @@ class HuiEnergyDistrubutionCard
// card's data when the selected period extends to now. For historical
// periods (yesterday, last week, ...) fall back to the generic icon.
if (periodIncludesNow(this._data)) {
const socValues = types
.battery!.map((source) =>
source.stat_soc
const socBatteries = types
.battery!.map((source) => ({
soc: source.stat_soc
? Number(this.hass.states[source.stat_soc]?.state)
: NaN
)
.filter((value) => Number.isFinite(value));
if (socValues.length) {
averageBatterySoc =
socValues.reduce((sum, value) => sum + value, 0) / socValues.length;
: NaN,
capacity: source.capacity,
}))
.filter((battery) => Number.isFinite(battery.soc));
if (socBatteries.length) {
// Weight each battery's SOC by its capacity so the combined value
// reflects the total stored energy. Batteries without a configured
// capacity assume the mean of the configured ones; when none are
// configured this falls back to an equally weighted (simple) average.
const configuredCapacities = socBatteries
.map((battery) => battery.capacity)
.filter((capacity) => capacity != null && capacity > 0) as number[];
const meanCapacity = configuredCapacities.length
? configuredCapacities.reduce((sum, value) => sum + value, 0) /
configuredCapacities.length
: 1;
let weightSum = 0;
let weightedSocSum = 0;
socBatteries.forEach((battery) => {
const capacity =
battery.capacity != null && battery.capacity > 0
? battery.capacity
: meanCapacity;
weightSum += capacity;
weightedSocSum += battery.soc * capacity;
});
averageBatterySoc = weightedSocSum / weightSum;
batteryIconPath = batteryLevelIconPath(averageBatterySoc);
}
}
+2
View File
@@ -4240,6 +4240,8 @@
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
"state_of_charge": "Battery state of charge sensor",
"state_of_charge_helper": "Sensor reporting battery state of charge as %.",
"capacity": "Battery capacity",
"capacity_helper": "Usable battery capacity in kWh. Used to weight the combined state of charge when you have multiple batteries of different sizes.",
"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.",
"sensor_type": "Type of power measurement",