From 362620ba07797f29204209a82df710f65a2a34f2 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Sat, 18 Jul 2026 11:50:43 +0200 Subject: [PATCH] Battery (experimental): restore priority/buffer soc constraint (#31900) --- .../components/Battery/BatteryConfigCard.vue | 24 +++++++++++++++---- tests/battery-experimental.spec.ts | 16 +++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/assets/js/components/Battery/BatteryConfigCard.vue b/assets/js/components/Battery/BatteryConfigCard.vue index 89d973fc2..fa106b361 100644 --- a/assets/js/components/Battery/BatteryConfigCard.vue +++ b/assets/js/components/Battery/BatteryConfigCard.vue @@ -102,8 +102,7 @@ import InlineSocSelect from "./InlineSocSelect.vue"; // Battery usage controls for the experimental page. The logic is intentionally duplicated // from the classic BatteryUsageSettings.vue (slated for removal) so the two can diverge -// during the transition. Difference here: priority and buffer SoC are independent, there is -// no priority < buffer constraint. +// during the transition. export default defineComponent({ name: "BatteryConfigCard", components: { Card, InlineSocSelect }, @@ -135,14 +134,21 @@ export default defineComponent({ priorityOptions() { const options = []; for (let i = 100; i >= 0; i -= 5) { - options.push({ value: i, name: this.fmtSoc(i) }); + const disabled = + i > this.selectedBufferSoc && + !(this.selectedBufferSoc == this.selectedPrioritySoc); + options.push({ value: i, name: this.fmtSoc(i), disabled }); } return options; }, bufferOptions() { const options = []; for (let i = 100; i >= 5; i -= 5) { - options.push({ value: i, name: this.fmtSoc(i) }); + options.push({ + value: i, + name: this.fmtSoc(i), + disabled: i < this.selectedPrioritySoc, + }); } return options; }, @@ -180,7 +186,15 @@ export default defineComponent({ }, methods: { changePrioritySoc($event: Event) { - this.savePrioritySoc(parseInt(($event.target as HTMLInputElement).value, 10)); + const soc = parseInt(($event.target as HTMLInputElement).value, 10); + if (soc > (this.bufferSoc || 100)) { + this.saveBufferSoc(soc); + if (soc > this.bufferStartSoc && this.bufferStartSoc > 0) { + this.setBufferStartSoc(soc); + } + } else { + this.savePrioritySoc(soc); + } }, changeBufferStart($event: Event) { this.setBufferStartSoc(parseInt(($event.target as HTMLInputElement).value, 10)); diff --git a/tests/battery-experimental.spec.ts b/tests/battery-experimental.spec.ts index 9ebdc5807..774d391bd 100644 --- a/tests/battery-experimental.spec.ts +++ b/tests/battery-experimental.spec.ts @@ -73,6 +73,22 @@ test.describe("experimental battery page", async () => { await prioritySoc.selectOption("30"); await expect(prioritySoc).toHaveValue("30"); + // values crossing the other threshold are not selectable (prioritySoc 30, bufferSoc 80) + await expect(prioritySoc.getByRole("option", { name: "85%", exact: true })).toHaveAttribute( + "disabled", + "" + ); + await expect(bufferSoc.getByRole("option", { name: "25%", exact: true })).toHaveAttribute( + "disabled", + "" + ); + + // equal values unlock higher priorities; selecting one raises the buffer instead + await prioritySoc.selectOption("80"); + await prioritySoc.selectOption("85"); + await expect(bufferSoc).toHaveValue("85"); + await expect(prioritySoc).toHaveValue("80"); + // discharge control is offered for the controllable battery and toggles on const discharge = page.getByRole("switch", { name: /Prevent home battery/ }); await expect(discharge).not.toBeChecked();