Skip to content

fix(control): a battery order on its way counts on each phase - #1805

Merged
frahlg merged 2 commits into
masterfrom
fix/ev-one-phase-battery-order
Oct 22, 2026
Merged

frahlg merged 2 commits into
masterfrom
fix/ev-one-phase-battery-order

Conversation

@frahlg

@frahlg frahlg commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

For v0.155.1-beta.1.

Problem

A car on a one-phase charger (pinned 1p, or auto on a charger with no three-phase step) sits at 0 W, shown as limited by the main fuse, while every phase is far below its limit. It happens whenever Core has just raised the battery.

Seen in the local rig on master 8ac2750: 25 A × 3 fuse, site meter at −0.68 A on each phase, Charge now 32 A on a one-phase charger, and Core sent 0 W (fuse_limit) for 42 s. In a test with a 16 A fuse, 3 A of house load and a battery order that rises 1.5 kW every 30 s, the car did not start for 9 minutes. A three-phase car on the same site started at once.

It is not new. It came with 47799bd (#1695, 17 Oct), so every beta from v0.147.2-beta.1 has it, including v0.155.0-beta.1. Stable v0.130.4 does not.

Cause

ev_fuse_budget.go puts a loadpoint that is not 3p in a one-phase pool, so its room is one phase's: (limit − busiest phase) × 230 V. pendingBatteryCommandsW gives the battery's not-yet-shown order in total watts, and that total was taken off the one-phase room. A three-phase battery puts a third of it on each phase, so it counted three times there. In the rig: 5,364 W of room − 4,703 W of battery order = 661 W, under the 1,610 W a start needs (1,380 W + 230 W margin). Once the order had shown (20 s), the 35 s idle-start wait still had to pass: 42 s in all.

Change

The battery's unshown order now goes beside the chargers' unshown offers before the room is worked out: in total import, and as the same current on each phase (withBatteryOrders). The later "minus total" steps go. The hourly import ceiling's start test keeps its total.

This follows the fuse rule: the site meter's measured current per phase, plus our own orders that cannot have shown yet, on the phases they land on. pendingBatteryCommandsW is never negative, so nothing gains credit.

  • A three-phase charger's cap is exactly as before: (limit − amps) × 690 − w.
  • A one-phase pool now takes a third of the battery's total off its phase.
  • Core already assumes every battery is three-phase (fuse_phase.go). A one-phase battery on the car's phase is counted at a third of its draw there, as it already is for a three-phase car.
  • The import_limit / fuse_limit label compares rooms that now include the battery order; it can change only while the import ceiling is on.

Evidence

  • TestEVHardLimitBatteryOrderCountsOnEachPhase: meter −466 W, −0.68 A on each phase, 4,703 W battery order. On master the 1p and auto cases fail with cap 0.0 W, want 3565.9 W; 3p passes on both. With the fix all three pass.
  • go test ./internal/... ./cmd/ftw/... passes; go vet is clean. The field matrix is unchanged: no known row moves.
  • Rig replay and the busy 16 A case (scratch tests, not committed): with the fix the one-phase car starts in 2 s at 2,300 W.

Independent review

A separate review compared master and this branch on the same random inputs: about 120,000 steps, a heat-stress run, and a run with voltage or phase count at 0. The inputs covered 1–3 site phases, 1–2 chargers, 0–2 batteries, missing or partial phase currents, and the import ceiling on and off.

  • A three-phase pool's cap is identical to master in every step; the largest difference was 7e-12 W. Adding the same current on each phase to the heat level is the same as subtracting the total afterwards.
  • The new cap is never lower than master's. It is higher only for a one-phase pool on a site with two or three phases and valid phase currents.
  • The battery order is subtracted from the import ceiling's room once, as before. Meters without phase currents and a zero voltage or phase count give caps identical to master.
  • Fixed here (433d70b): the hourly idle start's label compared the ceiling's room without the battery order against the fuse's room with it. A car the ceiling held read fuse_limit, also on three-phase pools. Both sides now count the order. TestEVHardLimitIdleCeilingLabelCountsBatteryOrder fails without that line.
  • Residual, not new in kind: a one-phase battery on the car's phase is counted at a third of its draw there. That is the three-phase battery assumption in fuse_phase.go, and master already gives a three-phase car the same amps on the same battery. A phase near its limit still gets nothing. Any overshoot lasts until the meter shows the car and the cut lands.

Why nothing caught it

  • The field matrix has no one-phase case with a battery, and its battery follows a slow fixed plan, so its pending order stays small. Its idle check allows a minute plus the charger delay, so a single 42 s wait passes.
  • The device-simulator rig had no one-phase charger. A scenario with one is being added to the release run.

Follow-ups (not here)

  • sim-ocpp's easee-charge-up model ignores numberPhases and draws three-phase on a one-phase order; sim-ferroamp's meter never includes the car.
  • The Charge now slider on a one-phase charger reads to max_charge_w (32 A · 7.4 kW) while the step table ends at 16 A (3.68 kW).

🤖 Generated with Claude Code

A one-phase charger's room is one phase's, but Core took the battery's
whole unshown order off it, so a three-phase battery counted three times.
With 4,703 W of battery order the car's phase had 661 W left, under the
1,610 W a start needs, and Charge now sat at 0 W (fuse_limit) with every
phase near 0 A. The order now goes beside the chargers' unshown offers:
in total import, and the same current on each phase. A three-phase
charger's cap does not change.

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-22T11:36:56.022597Z ff7077c 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.

… sides

The fuse's room now holds our unshown battery order, so the hourly idle
start's label compared the ceiling's room without it against the fuse's
room with it, and a car the ceiling held read fuse_limit. Both sides now
count the order, as the start test itself does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg merged commit 5b697a5 into master Oct 22, 2026
22 checks passed
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