Repository navigation
fix(loadpoint): a charger is never asked for more current per phase than it supports - #1791
Merged
Merged
Conversation
When Core sends phase_mode 1p to a loadpoint that can run three phases, max_amps_per_phase was the site fuse. The surplus 1p lock hands back the whole step table, so a 16 A charger on a 25 A fuse got 18-25 A on one phase (simulatorprov 21 Oct 2026, case s5s). The order's per-phase limit now stops at the most the charger is known to take on one phase: max_charge_w over three phases, or the phase split, whichever is larger. It only ever lowers the limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When Core sends
phase_mode: 1pto a charger that can run three phases, theorder's
max_amps_per_phaseis the site fuse. Nothing in Core knows thecharger's own current per phase. In surplus mode the day's 1p lock hands back
the whole step table, so a 16 A charger on a 25 A fuse is offered 18–25 A on
one phase. The simulator run of 21 October (case s5s, Easee steps, phase mode
auto, 9.3 kW surplus, a plan with no PV) showed OCPPnumberPhases: 1at18–25 A; by the investigation, Easee Cloud gets
phaseMode=1and thendynamicChargerCurrentup to 25 A. Charge now on 1p does the same: in thenew test, a 7,360 W 1p hold on a 16 A charger beside 3 A of house load goes
out at 4,830 W, 21 A, with only the fuse room as its limit.
The owner's rule: the charger's own limits and the fuse decide. No new
setting.
Change
applyChargerPhaseLimit(ingo/internal/loadpoint/manual_limits.go) runsright after
applyInstallationLimits. When the order says1p, theloadpoint's phase mode is not
1pand the site has three phases, it lowersmax_amps_per_phaseto the charger's current per phase.applyCurrentCeilingthen cuts the watts to match and the order carries
charger_limit("Limitedby FTW's charger setting"). It never raises a limit.
The charger's current per phase is the larger of:
max_charge_w / (voltage × 3): what the charger takes per phase at itsmaximum on three phases;
phase_split_w / voltage(3,680 W, 16 A, when unset): whatautoalreadyputs on one phase, in Core (
PhaseFor) and in the drivers.Why the larger of the two
The maximum over three phases is the right source for a charger that switches
phases. The split alone gives the 32 A charger in the simulator's case s9
(22,080 W,
auto, no split) 16 A on one phase instead of 32 A.The maximum alone breaks one-phase chargers left on an empty phase mode. Core
treats an empty mode as able to run three phases: the surplus dwell and the
day's 1p lock both send it
1p. A 16 A one-phase charger has a 3,680 Wmaximum, and 3,680 W over three phases is 5.3 A. That is under 6 A, so
applyCurrentCeilingturns every 1p order into 0 W and the charger nevercharges from surplus. It also turns the common 11,000 W setting (what the
settings page writes for a new charger) into 15.9 A, which floors to 15 A.
Each of the two is a current the charger already takes, so the larger never
caps a charger below what Core already asks of it. In s5s it lowers 25 A to
16 A.
One case stays limited: a one-phase charger above 16 A (say 32 A, 7,360 W)
left on an empty phase mode gets 16 A on a 1p order. Master already gives
that charger a third of its current on every 3p order (7,360 W over three
phases is 10.7 A), so it needs phase mode
1p, an existing setting. With1pthis change does nothing. With nomax_charge_w, the split decides:16 A by default.
Not changed
The surplus phase choice, the step tables and
go/internal/control(exceptone test). Next-beta work stays out: the forecast-driven 1p lock (s5s still
never reaches 3p on a fresh box), the empty step table (s5) and the late
readback.
Tests
New, in
go/internal/loadpoint/controller_phase_choice_test.go:TestSurplusOnePhaseOfferStaysWithinTheCharger: the s5s repro (surplus,auto, Easee steps, 9.3 kW live surplus, plan with no PV). No order above16 A per phase; the 1p lock charges at 3,680 W. Second row: a 16 A one-phase
charger on an empty mode keeps 3,680 W on the same lock.
TestChargeNowOnOnePhaseKeepsTheChargersCurrent: Charge now on 1p.autofuse_limitcharger_limitfuse_limitcharger_limitauto1pEach rule alone fails a row, checked by swapping it in: the split alone
gives the 32 A three-phase charger 3,680 W. The maximum alone gives the
16 A one-phase charger on an empty mode 0 W, in surplus and on Charge now;
with the guard that skips limits under 6 A, its 1p orders keep the 25 A
fuse as their limit.
Changed:
ev_fuse_phase_room_test.go:217(
TestEVFuseOnePhaseOffersCountOnTheirPhase). The hold asks 5,520 W on 1p,24 A, of
roomTestCharger, which is a 16 A charger (11,040 W, steps 6–16 A).The test wanted at least 4,140 W (18 A) on L1. It now wants 3,680 W (16 A):
the car still climbs from 2,070 W (9 A beside 15 A) once L1 falls, and L1
still stays within 24 A, which is what the test checks.
Closed-loop simulation (sitesim), the s5s repro
Same plant as the rig: 25 A, house 1 A per phase, 10 kW PV, full battery,
surplus only,
auto, Easee steps, 5 minutes.fuse_limit150charger_limit54,fuse_limit96Simulator rig, case s5s
The real FTW binary against device-simulator over OCPP 1.6 and Modbus
(
reports/simulatorprov-20261021/rerun.sh, own ports withRIG_PORT_OFFSET=40000). 25 A, house 1 A per phase, 10 kW PV, full battery,surplus only,
auto, Easee steps, a fresh box, 5 minutes after plug-in.fuse_limit238fuse_limit127,charger_limit112The car's mean falls because the simulated charger draws any offer, spread
over three phases: it took 4,140–5,520 W from the 18–24 A orders that a real
16 A charger cannot take. The full criterion still fails because the box
never moves to 3p on a fresh box; that is the forecast-driven 1p lock,
next-beta work.
Commands
Both pass on 1467e17, rebased on master with #1783. The rig ran on 7d8a82f, the same change before the rebase.
make verifyran withGOFLAGS=-p=2on a shared laptop: vet, every Go suite and the build are clean.🤖 Generated with Claude Code