Repository navigation
Conversation
…1861) A loadpoint pinned to 3p with min = max = 3,800 W asked for less than three phases can run, 6 A each (4,140 W at 230 V). fuseConfig raised the order's minimum to 4,140 W above the 3,800 W maximum, SnapChargeW returned 0 for max < min, and every planned slot went out as 0 W with the reason "plan". The planner meanwhile got the one-phase step 3,800 W, and Charge now sent 3,800 W on three phases, 5.5 A each. phaseLimits holds a command to what its phases can run: the minimum is 6 A on each phase, a maximum below that rises to it, and a table with no level in reach gets that level. fuseConfig, FuseConfigs, the Charge now clamp and the planner's steps use it, so the plan, the fuse budget and the order agree on 4,140 W. A 3p pin counts as three-phase capable. SnapChargeW runs at the minimum when the maximum is below it. Where the loadpoint allows one phase and the level fits, the order runs on one phase, as before. A client's 3p Charge now below 6 A a phase now goes out on the loadpoint's own mode. On a 3p pin such a request gets no order and the reason below_phase_minimum, shown in the UI. Save and startup warn about a maximum or table below the phase minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the first commit found three paths that still used the raw configuration. On the loadpoint pinned to 3p with a 3,800 W maximum: - Spare solar snapped to the planner's [0, 4140] within the 3,800 W maximum and paused with 10 kW of export; without a table it sent 3,800 W on three phases. A wake-kick and the car's completion order sent 3,800 W on three phases too. - cap_amps_per_phase came from the raw maximum: 5.5 A under a 6 A order. - A plan level below the phase minimum ran at the minimum for the on-time of the lower level, so the slot over-delivered. tickConfig gives the tick's order the phase limits when the loadpoint's own limits cannot run on three phases; other loadpoints keep theirs. A plan level below the least order runs at that order for as long as the slot's energy lasts. The planner's reserve for Charge now at full power holds the order Core sends. Three surplus rows join the field matrix. The UI title reads "Below 6 A a phase". 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.
Fixes the main report in #1861. The second comment there (vehicle SoC confidence from Home Assistant) is not part of this PR, so this PR does not close the issue.
Problem
Field report, v0.155.1-beta.1: a loadpoint with
phase_mode: 3p, min = max = 3,800 W and steps[0, 3800]on a three-phase site. A charger cannot run three phases below 6 A each, 4,140 W at 230 V. The car did not charge all weekend, and the reason saidplan.Cause
Reproduced in a controller test on master:
3p)planfuseConfigraised the order's minimum to 4,140 W, above the 3,800 W maximum.SnapChargeWreturns 0 when max < min.threePhaseCapablewas false (max < 4,140 W), soPlanningStepsgave the one-phase table, while Core ordered three phases.3p)manualMinChargeWhad no3pcase, so the order skipped the phase minimum.autoDecision from the physics
An order the charger can run is 0, or at least 6 A on each phase it names. On a 3p pin with a maximum below that, the only way to charge is the lowest three-phase level, 6 A each, 340 W above the configured 3,800 W. 6 A is the least current any IEC charger offers, and the fuse clamp still applies after it. This is the workaround the reporter used by hand, and the car then charged. FTW warns about the setting on save and at startup and says what it orders. No new setting.
Where the loadpoint allows one phase and the level fits, the order runs on one phase, as before. Where no valid order exists, the reason says so:
below_phase_minimum, neverplan.Change
phaseLimits(cfg, mode, site)(manual_limits.go): the range a command on those phases can run. The minimum is 6 A on each phase; a maximum below it rises to it; a step table with no level in reach gets that level.fuseConfig,FuseConfigs(so the fuse budget waits for room for the real least order),clampManualPowerandPlanningStepsuse it.PlanningLimitswidens the session's range to the levels the charger can run. A 3p pin counts as three-phase capable.tickConfig: when a three-phase order's own limits cannot run, the whole tick uses the phase limits, so spare solar, a wake-kick, the car's completion order andcap_amps_per_phasename 4,140 W and 6 A too. Every other loadpoint keeps its own limits.SnapChargeWruns at the minimum when the maximum is below it, instead of returning 0. A plan level below the least order runs at that order for as long as the slot's energy lasts (2,070 Wh at a 3,600 W level runs 30 min at 4,140 W, not 34.5).mpc/deadline_directive.go).chargerPhaseMaxAfloors at 6 A, so a one-phase car on such a charger plans 1,380 W.PlanningSteps: a whole-amp ladder whose minimum and maximum fall between two whole amps keeps the highest (min = max = 3,800 W on one phase plans 3,680 W, which is what Core orders).holdPhaseModetreats a client's3pbelow 6 A a phase as the loadpoint's own mode (one phase where allowed). On a 3p pin such a request gets no order and the reasonbelow_phase_minimum. A Charge now at the configured maximum asks for full power, which is the phase minimum when the maximum is below it.below_phase_minimum: limited and warning in/api/control, a manual-status limit reason, and text in the on-box UI.LoadpointWarningsfor a maximum or table below the phase minimum. It shows on save (Settings → Chargers) and in the plan's warnings, and Core now logs all loadpoint warnings at startup.6 A · 4.1 kW, not7 A · 3.8 kW).Behaviour changes
3pnow runs on one phase where the loadpoint allows it (before: a three-phase order below 6 A that no charger runs). A Stop keeps the client's3p.below_phase_minimum("Below 6 A a phase"), notcharger_limit.Tests
Written first, failing on master:
go/internal/loadpoint/phase_minimum_test.go: the snap, planner steps and limits (three-phase car, one-phase car, unset), the controller's order for the old plan, the new plan and Charge now, one phase where allowed,below_phase_minimum, spare solar with the current cap, and a plan level below the minimum keeping the slot's energy.go/internal/mpc/deadline_directive_test.go: the reserve for Charge now at full power.go/internal/config/loadpoint_phase_minimum_test.go: warnings on save, and gone once fixed.api_clamped_no_draw_test.go,api_control_scenarios_test.go,manual_status_test.go,control-feedback.test.mjs,ev-manual-feedback.test.mjs,ev-charge-now-range.test.mjs.Field matrix (
TestSiteSimFieldMatrix): 31 newissue1861rows. Phase mode3pon the report's own table[0, 3800](one-phase level), a three-phase table cut by the maximum, and no table; planned and Charge now; fast and Easee timing; three- and one-phase cars; the deadline reserve; spare solar. Unset on a one-phase charger without a table.sitesim_field_known.txtstays emptyfieldRoomWnow also bounds the expected energy by the loadpoint maximum (never below 6 A a phase). The reviewer checked the 72 planned and restart rows where that maximum is below the charger's 16 A: outside the new rows the bound moves by 0.6 % or less, and no row changes outcome.make verify: clean ("vet + test + build clean") on both commits. The release Docker context check was skipped: no Docker daemon on this machine.Browser review
Local rig (sim-ferroamp, Core on this branch, sim-ocpp Easee, 3 × 20 A, the report's loadpoint). Home box not touched.
3phold: 0 W, "Below the phase minimum" (warning) in "Are we in control?", and "Not charging: 4 A is below 6 A on each phase, and no charger runs lower. Ask for 6 A or more." in the Charge now status.Review
Independent review by a Sonnet agent on the first commit, given the code and the issue, not my conclusions.
fuse_limit).cap_amps_per_phasewas 5.5 A under a 6 A order; a plan level below the minimum over-delivered the slot's energy; the planner reserved 3,800 W for a 4,140 W Charge now; the UI title "Below the phase minimum" was jargon.charging_phase_max_wfor a one-phase car on such a charger now reads 1,380 W, which is what it takes.easee_cloud.luarounds to the nearest amp, so that order runs at 6 A there; the sim does the same. A driver that floors would get 5 A and stop. The planned path in v0.155.1-beta.1 (#1799): EV loadpoint with min=max below 3-phase minimum silently charges 0 W #1861 sent 0 W, which no rounding helps.Overlap with open PRs
api_control_feedback.go,sitesim_field_test.goandweb/control-feedback.jsnext to these hunks. It already conflicts with master. Both sets of hunks add lines; whichever lands second needs a short rebase.snap.go,planning_steps.go,manual_limits.go,controller.goandcontroller_fuse_budget.go. Neither has moved since 21 Oct.Follow-ups, not in this PR
auto, min = max = 3,800 W, table[0, 3800], on a one-phase reading: the table's only level is above the charger's 16 A on one phase, so the shared fuse budget finds no step under its cap and orders 0 W withfuse_limit. It fails the same way on master. I left that row out of the matrix.FTWKit/Format/EV.swiftmaps manual limit reasons and falls back to "The main fuse limits charging right now", so it would blame the fuse forbelow_phase_minimum. It needs a line of its own.🤖 Generated with Claude Code