Battery: fix stale grid charge limit reset (#30013)

This commit is contained in:
Michael Geers 2026-05-19 11:07:39 +02:00 • committed by GitHub
parent 178cc7a694
commit c61e3faac9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 103 additions and 14 deletions

View file

@ -60,7 +60,7 @@ export default defineComponent({
description: lp ? t("loadpointDescription") : t("batteryDescription"),
limitLabel: co2 ? t("co2Limit") : t("priceLimit"),
currentPriceLabel: co2 ? t("co2Label") : t("priceLabel"),
resetWarningText: t("resetWarning"),
resetWarningKey: "smartCost.resetWarning",
activeHoursLabel: t("activeHoursLabel"),
};
},

View file

@ -53,7 +53,7 @@ export default defineComponent({
limitLabel: t("priceLimit"),
activeHoursLabel: t("activeHoursLabel"),
currentPriceLabel: t("priceLabel"),
resetWarningText: t("resetWarning"),
resetWarningKey: "smartFeedInPriority.resetWarning",
};
},
},

View file

@ -123,7 +123,7 @@ export default defineComponent({
optionsStartAtZero: Boolean,
activeHoursLabel: { type: String, required: true },
currentPriceLabel: String,
resetWarningText: String,
resetWarningKey: String,
limitDirection: { type: String as PropType<LimitDirection>, default: "below" },
highlightColor: { type: String as PropType<HighlightColor>, default: "text-primary" },
isSlotActive: {
@ -261,6 +261,11 @@ export default defineComponent({
limitOperator() {
return this.limitDirection === "below" ? "≤" : "≥";
},
resetWarningText() {
return this.$t(this.resetWarningKey!, {
limit: this.formatValue(this.currentLimit!),
});
},
},
watch: {
currentLimit() {

View file

@ -8,7 +8,7 @@
{{ $t("batterySettings.usageTab") }}
</h3>
<BatteryUsageSettings style="max-width: 950px" v-bind="batteryUsageProps" />
<template v-if="gridChargePossible">
<template v-if="gridChargeVisible">
<hr class="my-5" />
<h3 class="fw-normal my-4 mt-5">
{{ $t("batterySettings.gridChargeTab") }}
@ -61,6 +61,9 @@ export default defineComponent({
devices.some(({ controllable }) => controllable) && this.state.smartCostAvailable
);
},
gridChargeVisible() {
return this.gridChargePossible || this.state.batteryGridChargeLimit !== null;
},
gridChargeTariff() {
const { forecast, smartCostType } = this.state;
return smartCostType === SMART_COST_TYPE.CO2 ? forecast?.co2 : forecast?.grid;

View file

@ -254,11 +254,6 @@ loadpoints:
tariffs:
currency: EUR # three letter ISO-4217 currency code (default EUR)
grid:
type: template
template: demo-dynamic-grid
min: 0.18
max: 0.41
feedin:
type: fixed
price: 0.08 # EUR/kWh
@ -268,8 +263,3 @@ tariffs:
kwp: 15.5
sunrise: 7
sunset: 17
co2:
type: template
template: demo-co2-forecast
base: 350
variation: 0.4

View file

@ -0,0 +1,39 @@
interval: 0.1s
site:
title: Battery Settings
meters:
grid: grid
battery: battery
meters:
- name: grid
type: template
template: demo-meter
power: 1000
- name: battery
type: template
template: demo-battery
power: -1000
soc: 50
capacity: 20
controllable: true
loadpoints:
- title: Carport
charger: charger
mode: now
chargers:
- name: charger
type: template
template: demo-charger
status: B
enabled: true
maxcurrent: 16
tariffs:
currency: EUR
grid:
type: fixed
price: 0.30

View file

@ -0,0 +1,44 @@
import { test, expect } from "@playwright/test";
import { start, stop, baseUrl } from "./evcc";
test.use({ baseURL: baseUrl() });
test.describe.configure({ mode: "parallel" });
const CONFIG = "smart-cost-reset-warning.evcc.yaml";
const PRESET_LIMITS = "smart-cost-reset-warning.sql";
test.afterEach(async () => {
await stop();
});
test.describe("smart cost reset warning", async () => {
const limitWarningText = "However, there is still a limit of 12.0 ct/kWh.";
test("loadpoint: stale limit can be removed without dynamic tariff", async ({ page }) => {
await start(CONFIG, PRESET_LIMITS);
await page.goto("/");
const loadpoint = page.getByTestId("loadpoint").first();
await loadpoint.getByTestId("loadpoint-settings-button").last().click();
const modal = page.getByTestId("loadpoint-settings-modal").first();
await expect(modal).toBeVisible();
await expect(modal.getByText(limitWarningText)).toBeVisible();
const removeLimit = modal.getByRole("link", { name: "Remove limit" });
await expect(removeLimit).toBeVisible();
await removeLimit.click();
await expect(modal.getByText(limitWarningText)).not.toBeVisible();
});
test("battery: stale limit can be removed without dynamic tariff", async ({ page }) => {
await start(CONFIG, PRESET_LIMITS);
await page.goto("/#/battery");
await expect(page.getByRole("heading", { name: "Grid charging" })).toBeVisible();
await expect(page.getByText(limitWarningText)).toBeVisible();
const removeLimit = page.getByRole("link", { name: "Remove limit" });
await expect(removeLimit).toBeVisible();
await removeLimit.click();
await expect(page.getByText(limitWarningText)).not.toBeVisible();
});
});

View file

@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS `settings` (
`key` text
, `value` text
, PRIMARY KEY(`key`)
);
INSERT INTO settings("key", "value") VALUES ("batteryGridChargeLimit", "0.12");
INSERT INTO settings("key", "value") VALUES ("lp1.smartCostLimit", "0.12");