Skip to content

fix(loadpoint): the deadline reserve orders a small car the charger's minimum, not 0 W - #1807

Open
frahlg wants to merge 1 commit into
masterfrom
fix/ev-deadline-car-below-min
Open

frahlg wants to merge 1 commit into
masterfrom
fix/ev-deadline-car-below-min

Conversation

@frahlg

@frahlg frahlg commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Problem

With no plan (planner down or stale), Core runs a saved goal on its deadline reserve. On a charger without a step table, the reserve gave a car whose own maximum is below the charger's minimum an order of 0 W. Example: a plug-in hybrid with max_w 3,680 W on an 11 or 22 kW charger whose minimum is 4,140 W. The car stood still until a plan came back. Chargers with a step table were fine.

An independent review of #1806 found it on 22 Oct 2026. The bug predates that PR. It hits any car with a known maximum, not only cars marked one-phase.

Cause

withDeadlineReserve (mpc/deadline_directive.go) takes its on-power from DeadlineNeed, which holds it to the car with LimitPower(st, st.AllowedStepsW). When the car's maximum is below the charger's lowest step, LimitPower keeps that one step. Without a table it had no step to keep, so it returned 3,680–3,680 W. SnapChargeW(…, min 4140, max 3680, nil) then returns 0, because max < min.

The plan path never hits this. PlanningLimits passes PlanningSteps, whose ladder starts at 4,140 W, so LimitPower keeps 4,140 W and the plan orders it.

Fix

LimitPower: without steps, the charger's minimum is the one step it keeps, so the maximum is never below it. The reserve now orders 4,140 W, as the plan does, and the car takes what it can. This follows the owner's rule that Charge now and planned charging just run: Core never sends 0 W because the car's own maximum is lower. Nothing changes when a table exists or when the car's maximum reaches the charger's minimum.

Evidence

Each new test fails on master 16c4ad0 and passes here:

  • loadpoint: TestLimitPowerKeepsTheChargersLowestStep and TestDeadlineNeedHoldsToTheCar add the stepless 3.7 kW car. On master: power 3680–3680, want 4140.
  • mpc: TestGoalReserveGivesASmallCarTheChargersMinimum goes through SlotDirectiveAt with no plan, for 11,040 W and 22,080 W chargers. On master: LoadpointMaxPowerW: 0, LoadpointEnergyWh: 0.
  • control: TestJoinedNoPlanGoalSmallCarGetsChargerMinimum runs the reserve through the controller to the driver order. On master: orders [0]. Here: 4,140 W.
  • Field matrix: a new use, noplan, adds a saved goal, no plan, and the session car's maximum bound as internal/cars binds it. Two rows run the home box site (3 × 16 A, phase mode unset, no table, 4,140–11,000 W) with a one-phase car of 3,680 W, fast2s and easee40s. On master both fail idle: offer 0 W (EV deadline reserve), 0.0 kWh in 1 h, idle with room for 55m37s. Here both pass with 2.3 kWh, and the known list is unchanged. Peak phase is 20.0 A during the kettle step, the same as Charge now on that site.
  • go vet ./internal/... ./cmd/ftw/... and go test ./internal/... ./cmd/ftw/... pass on ed675d7, 60 packages. The matrix has 342 cases and 29 failing rows, the same 29 as on master.

Limits

  • The reserve still uses the charger's own steps for a car marked one-phase (CarPhases == 1), as the fix(loadpoint): plan a one-phase car above the charger's minimum, not at it #1806 notes say. The controller orders three times the reserve, within the charger's maximum, so such a car draws its full current on its phase. Fuse protection stays with the site meter's measured current per phase. Before this fix, the same car got 0 W from the reserve.
  • A three-phase car whose maximum is 3,680 W is ordered 4,140 W and draws less than the order, as on the plan path. This PR does not change how the verdict reads that.
  • Not run on the device-simulator rig or on a real site.

🤖 Generated with Claude Code

… minimum, not 0 W

With no plan, the deadline reserve held a car to its own maximum with
LimitPower(st, st.AllowedStepsW). Without a step table there was no
lowest step to keep, so a 3,680 W plug-in hybrid on a 4,140-11,040 W
charger got 3,680-3,680 W, and SnapChargeW returned 0 because max < min.
The plan path gets PlanningSteps' ladder and already orders 4,140 W.

LimitPower now keeps the charger's minimum as that one step when there
are no steps, so the reserve orders what the plan orders and the car
takes what it can.

Tests fail on master 16c4ad0: LimitPower and DeadlineNeed, the reserve
through SlotDirectiveAt (11 and 22 kW chargers), the controller's order,
and two field-matrix rows with a new use, noplan (0 W, idle 55 min on
master; 2.3 kWh in 1 h here). The known list is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T14:30:51.800890Z ed675d7 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant