Add smart feed-in priority (#21813)

This commit is contained in:
andig 2025-06-27 09:03:46 +02:00 • committed by GitHub
parent 6ba804b106
commit 42ed7da2e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
63 changed files with 1645 additions and 1290 deletions

View file

@ -1,6 +1,6 @@
import { test, expect } from "@playwright/test";
import { start, stop, baseUrl } from "./evcc";
import { enableExperimental } from "./utils";
import { enableExperimental, expectModalVisible, expectModalHidden } from "./utils";
test.use({ baseURL: baseUrl() });
test.beforeAll(async () => {
@ -41,18 +41,21 @@ test.describe("battery settings", async () => {
await enableExperimental(page);
await page.getByTestId("topnavigation-button").click();
await page.getByTestId("topnavigation-battery").click();
const modal = page.getByTestId("battery-settings-modal");
await expectModalVisible(modal);
await page.getByRole("link", { name: "Grid charging 🧪" }).click();
await page.getByLabel("Price limit").selectOption({ label: "≤ 50.0 ct/kWh" });
await expect(page.getByTestId("battery-settings-modal")).toContainText("5.0 ct – 50.0 ct");
await modal.getByRole("link", { name: "Grid charging 🧪" }).click();
await modal.getByLabel("Price limit").selectOption({ label: "≤ 50.0 ct/kWh" });
await expect(modal).toContainText("5.0 ct – 50.0 ct");
await page.getByRole("button", { name: "Close" }).click();
await expect(page.getByTestId("battery-settings-modal")).not.toBeVisible();
await expectModalHidden(modal);
await page.getByTestId("energyflow").click();
await page.getByRole("button", { name: "grid charging active (≤ 50.0 ct)" }).click();
await expect(page.getByTestId("battery-settings-modal")).toBeVisible();
await page.getByLabel("Price limit").selectOption({ label: "≤ -10.0 ct/kWh" });
await page.getByRole("button", { name: "Close" }).click();
await expect(page.getByTestId("battery-settings-modal")).not.toBeVisible();
await expectModalVisible(modal);
await modal.getByLabel("Price limit").selectOption({ label: "≤ -10.0 ct/kWh" });
await modal.getByRole("button", { name: "Close" }).click();
await expectModalHidden(modal);
await expect(modal).not.toBeVisible();
await expect(page.getByRole("button", { name: "grid charging when ≤ -10.0 ct" })).toBeVisible();
});
});

45
tests/smart-feedin.evcc.yaml Executable file
View file

@ -0,0 +1,45 @@
interval: 0.1s
site:
title: Smart Feed-in
meters:
grid: grid
loadpoints:
- title: LP1
charger: charger1
mode: pv
- title: LP2
charger: charger2
mode: pv
meters:
- name: grid
type: template
template: demo-meter
power: -2000
chargers:
- name: charger1
type: template
template: demo-charger
status: C
power: 2000
- name: charger2
type: template
template: demo-charger
status: B
power: 0
tariffs:
currency: EUR
feedin:
type: fixed
price: 0.2 # EUR/kWh
zones:
- hours: 0-5
price: 0.4
- hours: 5-6
price: 0.6
- hours: 18-0
price: 0.4

View file

@ -0,0 +1,74 @@
import { test, expect } from "@playwright/test";
import { start, stop, baseUrl } from "./evcc";
import { expectModalHidden, expectModalVisible } from "./utils";
const CONFIG = "smart-feedin.evcc.yaml";
test.use({ baseURL: baseUrl() });
test.beforeAll(async () => {
await start(CONFIG);
});
test.afterAll(async () => {
await stop();
});
test.describe("smart feed-in priority", async () => {
test("no limit, normal charging", async ({ page }) => {
await page.goto("/");
await expect(page.getByTestId("vehicle-status-smartfeedinpriority")).not.toBeVisible();
});
test("feed-in above threshold, pause charging", async ({ page }) => {
await page.goto("/");
const lp = page.getByTestId("loadpoint").first();
// set limit
await lp.getByTestId("loadpoint-settings-button").nth(1).click();
const modal = page.getByTestId("loadpoint-settings-modal").first();
await expectModalVisible(modal);
await modal.getByLabel("Feed-in limit").selectOption("≥ 10.0 ct/kWh");
await modal.getByLabel("Close").click();
await expectModalHidden(modal);
// check status
await expect(lp.getByTestId("vehicle-status-smartfeedinpriority")).toBeVisible();
await expect(lp.getByTestId("vehicle-status-smartfeedinpriority")).toHaveText(/≥ 10\.0 ct/);
// remove limit
await lp.getByTestId("loadpoint-settings-button").nth(1).click();
await expectModalVisible(modal);
await modal.getByLabel("Feed-in limit").selectOption("none");
await modal.getByLabel("Close").click();
await expectModalHidden(modal);
// check status
await expect(lp.getByTestId("vehicle-status-smartfeedinpriority")).not.toBeVisible();
});
test("feed-in apply to all loadpoints", async ({ page }) => {
await page.goto("/");
const lp1 = page.getByTestId("loadpoint").first();
const lp2 = page.getByTestId("loadpoint").last();
await lp1.getByTestId("loadpoint-settings-button").nth(1).click();
const modal1 = page.getByTestId("loadpoint-settings-modal").first();
await expectModalVisible(modal1);
await modal1.getByLabel("Feed-in limit").selectOption("≥ 10.0 ct/kWh");
await modal1.getByRole("button", { name: "Apply everywhere?" }).click();
await modal1.getByLabel("Close").click();
await expectModalHidden(modal1);
// check lp1, lp2 status
await expect(lp1.getByTestId("vehicle-status-smartfeedinpriority")).toBeVisible();
await expect(lp1.getByTestId("vehicle-status-smartfeedinpriority")).toHaveText(/≥ 10\.0 ct/);
await expect(lp2.getByTestId("vehicle-status-smartfeedinpriority")).toBeVisible();
await expect(lp2.getByTestId("vehicle-status-smartfeedinpriority")).toHaveText(/≥ 10\.0 ct/);
// check lp2 setting
await lp2.getByTestId("loadpoint-settings-button").nth(1).click();
const modal2 = page.getByTestId("loadpoint-settings-modal").last();
await expectModalVisible(modal2);
await expect(modal2.getByLabel("Feed-in limit")).toHaveValue("0.1");
});
});