Repository navigation
fix(loadpoint): a one-phase car on a three-phase charger is seen, planned and ordered as one - #1801
Conversation
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. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cbf16702e
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if s.test == nil { | ||
| switch { | ||
| case orderA-s.orderA >= onePhaseStepA: | ||
| s.test = &phaseTest{at: now, until: now.Add(settle + onePhaseHold), baseline: meter.A, fromA: s.orderA} |
There was a problem hiding this comment.
Capture the phase baseline before sending the increased order
If the charger applies an order and the site meter reports its effect before the next controller tick, this baseline already includes the charging-current rise. TickWithDispatch calls observePhases before issuing the current tick's command, so the increased commandedW is first examined on the following tick. A one-phase car that responds within that interval therefore shows no change against this baseline and remains undetected; the added integration tests avoid this by imposing a 40-second response delay. Retain the meter reading from before dispatch and associate it with the order increase so prompt responses also receive the corrected planning and command behavior.
Useful? React with 👍 / 👎.
| switch { | ||
| case rose == 2: | ||
| return -1 | ||
| case quiet == 2 && finite(drawA) && drawA >= 0.6*big && drawA <= 1.5*big: |
There was a problem hiding this comment.
Compare incremental charger draw with the phase-current rise
When a test starts while the car is already charging, big measures only the increase from the meter baseline, but drawA is the car's total current. For example, a one-phase car increasing from 7 A to 9 A produces a valid 2 A rise on one phase, yet its 9 A total draw exceeds the 3 A upper bound here and the verdict remains unknown. Consequently, later modest order increases cannot identify a car whose initial start was missed, even with a correct pre-order meter baseline. Store the charger's baseline draw with the test and compare its change with the meter's change, or account for the existing draw separately.
Useful? React with 👍 / 👎.
#1799 turns 192 B rows, 20 A rows and one #1795 row green. It makes 35 one-phase-car rows with planned charging fail on energy, verdict or a second cut: a one-phase car takes a third of a three-phase order, which #1801 (D) handles. One 32 A one-phase charger probe now shows the second cut of the netting row class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ed759ec to
74603d0
Compare
6cbf167 to
811d418
Compare
… cuts a running order (#1799) * fix(loadpoint): planned charging runs on three phases, and room never cuts a running order Field report, v0.155.0-beta.1, 3x20 A, Easee, phase_mode auto, a step table with one-phase levels: a three-phase car charged on one phase at about 3.3 kW all night, cut to 1,600 W and 0 W with every phase under its limit. Planned charging and Charge now run on three phases (Fredrik, 22 Oct 2026). auto is 3p; only surplus charging without a schedule may use one phase (day lock, dwell, then auto). An unset mode stays the driver's default. The planner gets explicit steps at or above 6 A on the car's phases, or the three-phase ladder; LimitPower's minimum is the lowest step. The controller snaps the plan to steps legal on its command's phases. The split between cars kept no credit for a one-phase order once the site cap passed the split, and cut it to the room on the car's own phase. Room now limits rises only: the current order is kept when the order it allows lands on as many phases or more. Only a measured overage cuts. The closed-loop sim splits auto as the Easee driver does and replays the night: master 1.92 kWh in 40 min with 5 cuts with room, now 6.79 kWh on three phases with none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(loadpoint): review findings on three-phase charging and the kept order A1: the split keeps the current order only when the order it allows lands on the same phases. 5,000 W moved from one phase to three adds 7.2 A to two phases that carried none of it. B1: a solar-only loadpoint with a goal charges from surplus, so its schedule no longer forces three phases; 2.5 kW of surplus goes out on one phase again instead of an order Easee turns into 3.3 A. B2, B4: threePhaseCapable decides from the step table, or the maximum, whether the charger reaches 6 A on three phases. If not, it is a one-phase charger: its steps and orders stay one-phase. If so, unset means auto: three phases, with orders raised to the 3p minimum, never a 2,300 W unset order Easee runs at 3.3 A. Each review probe is a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(control): field rows after three-phase charging #1799 turns 192 B rows, 20 A rows and one #1795 row green. It makes 35 one-phase-car rows with planned charging fail on energy, verdict or a second cut: a one-phase car takes a third of a three-phase order, which #1801 (D) handles. One 32 A one-phase charger probe now shows the second cut of the netting row class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
e1ab85f to
cdf8bd1
Compare
… and survives a restart Review findings on #1801: M1: the check compared the charger's whole draw with the meter's rise, so only a rise from about 0 A could mark a car. It now compares the change in the charger's draw since the baseline. M2: a three-phase verdict had no draw check, so a heat pump starting at 2 A a phase during a 2 A rise cleared a correct mark. It now needs the charger's draw to have risen by about the three phases' sum. M3: the first reading of a session had a zero baseline, and the mark lives in memory, so after a Core restart with the car charging it was never marked again. A reading with no baseline is no longer a test, and an unmarked car whose charger's whole draw shows on one phase while the other two carry less than a third of it, for 30 s, is marked. No three- or two-phase car can show that. Each review probe is a test, and each fails on the previous head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nned and ordered as one A one-phase car draws a three-phase order's current per phase on one phase. On the field table the planner got [0, 4800], the car took 1,600 W of a 4,800 W order, and the feedback said not following. The loadpoint now tests each rise of its three-phase order on the site meter: one phase rising by about the order's rise, the other two still, for 30 s within the charger's response time, while the charger's own reading shows that draw. That marks the session's car one-phase (State.CarPhases, the field a car profile can set later); a rise on all three phases clears it, and unplugging resets it. A house load does not follow the orders, and a two-phase car moves two phases, so neither is marked. Marked, the planner gets the car's one-phase levels, 6 A up to the charger's current per phase. The charger stays on three phases and the order is the plan's power times three, so its current per phase is what the car should take. The command carries expected_w, a third of the order, and command evidence compares the car with that. The verdict is Limited, "Charging on one phase, at most 3.7 kW". The fuse limit is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…field rows The field matrix showed two gaps. A charger that applies in 2 s has already taken a raise by the next reading, and a fuse ramp climbs 1 A at a time, so a test's baseline must be the meter read before the first raise since the order it measures from. A charger that declares no response time is now given 3 minutes, as the fuse limit counts it, not one. Field matrix on #1799: 55 D rows, 28 #1795 rows and one A row turn green. Every one-phase-car row now meets its energy, verdict and one-phase invariants. 25 of them still cut twice when a house step on the car's phase meets the second cut of the netting class; they are labelled netting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and survives a restart Review findings on #1801: M1: the check compared the charger's whole draw with the meter's rise, so only a rise from about 0 A could mark a car. It now compares the change in the charger's draw since the baseline. M2: a three-phase verdict had no draw check, so a heat pump starting at 2 A a phase during a 2 A rise cleared a correct mark. It now needs the charger's draw to have risen by about the three phases' sum. M3: the first reading of a session had a zero baseline, and the mark lives in memory, so after a Core restart with the car charging it was never marked again. A reading with no baseline is no longer a test, and an unmarked car whose charger's whole draw shows on one phase while the other two carry less than a third of it, for 30 s, is marked. No three- or two-phase car can show that. Each review probe is a test, and each fails on the previous head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Charging on one phase" ran before the limit guard, so a fuse limit, import limit, fuse cooldown, stale site meter, changed setpoint or a reading older than the order all read as limited/one_phase. The branch now runs after the waiting check; those verdicts come first, and a draw beyond tolerance is judged as for any car. The field matrix judged the car's draw against the full order and let only one_phase excuse a third of it. It now judges the draw against the command's expected_w, as Core does, so a marked car under a fuse limit reads fuse_limit without failing the verdict check. The known list does not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On master with #1802, the 39 one-phase car energy rows (D) and the one energy row labelled A pass with this branch; their lines and labels go. No row is new. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d993c05 to
af1288c
Compare
Builds on #1799 and #1802 (merged). Replaces draft #1796.
Problem
A one-phase car, as many plug-in hybrids are, draws a three-phase order's current per phase on one phase only. With the field site's Easee table and #1799, the planner got [0, 4800] W. A 4,800 W order is 7 A a phase, which the car took as 1,600 W, and the charger panel said "Not following" all night. Fredrik (22 Oct 2026): keep the charger on three phases, learn the car's phases from the site meter, plan with what it takes. This must not regress one-phase cars on mixed step tables.
Change
loadpoint/one_phase_car.go): each rise of the session's three-phase order by at least 2 A a phase starts a test. The test compares the site meter's phases with the reading taken before the first raise since the order it measures from. A one-phase car shows one phase rising by about the order's rise (between half of it and 2 A more) while the other two move at most max(1 A, a quarter of that). It must hold for 30 s within the charger's response time (its declared power age, at least 60 s; 3 minutes when it declares none), and the charger's own draw must have changed by about that much since the baseline (0.6–1.5×). A rise on all three phases, with the charger's draw up by about their sum, is a three-phase car and clears the mark. With no reading from before the car drew, as after a Core restart, the charger's own draw is the reference: an unmarked car whose whole draw shows on one phase while the other two carry less than a third of it, for 30 s, is marked; no three- or two-phase car can show that. A two-phase car moves two phases and is never marked. A house load does not follow FTW's orders, and with the car drawing nothing the charger's reading rules it out. The order may keep rising during a test, as a plan catching up does; a test whose order falls back is dropped.State.CarPhases = 1andCarPhase(1–3) for the session. Unplugging or a new session resets it. fix(charging): carry two-phase cars through plans, current limits and Easee #1792's car profilephasescan seed the same field later.OnePhaseCarSteps: 1,380–3,680 W at 16 A). The car's own maximum still caps it (LimitPower).power_winto amps as power / (V × phases), so this mapping sits in one place,computeCommandForBudget.expected_w, a third of the order. Command evidence compares the car's draw with that, so a car that does what it can is not "Not following". Drivers ignore the field.charging_phase,charging_phase_max_w). It applies only when the car draws its third within tolerance, after the limit guard, a changed setpoint and a response still due: a fuse-limited one-phase car readsfuse_limit.Evidence
Drows and oneArow, allenergy, turn green, and their lines go. No row is new. 338 cases, 31 fail:idle25 (export 13, readback 10, hold3p 2) andown-raise6 (relief). None fails fuse, stale, home-use, over-cut, cut, limit, energy, one-phase or verdict.expected_wwhen it carries one, as Core does. It used to judge against the full order and let onlyone_phaseexcuse a third of it, which would fail a fuse-limited one-phase car that readsfuse_limit. The matrix made two changes here: a test's baseline is the meter read before the first raise since its reference order, since a 2 s charger has applied it by the next reading; and a charger that declares no response time gets 3 minutes, as the fuse limit counts it.TestPhaseVerdict: car on L1/L3, a car below its order, three-phase, two-phase, a kettle while the car draws nothing, car plus kettle on one phase, not yet applied.TestOnePhaseCarMarkedFromTheMeter: marked after 30 s, cleared by a three-phase rise, reset by unplugging.TestOnePhaseCarPlansItsOwnLevels: reviewer's P4 now plans up to 3,680 W; a 10 A fuse holds it to 2,300 W.TestOnePhaseCarOrderNamesItsCurrent: a 3,680 W slot goes out as 11,100 W3pwithexpected_w3,700.TestOnePhaseCarThroughANight(real controller, command evidence, API): no not_following in 8 h; on fix(loadpoint): planned charging runs on three phases, and room never cuts a running order #1799 it said not following after 1 min 25 s.TestExpectedDrawReplacesTheOrder.go testfor api, telemetry, control, loadpoint, sitesim, mpc, config, ocpp and cmd/ftw, and the web feedback tests, pass.Review findings (independent review with #1802 and #1795)
TestOnePhaseCarMarkedOnALaterRiseTestHeatPumpDoesNotClearAOnePhaseCarTestOnePhaseCarMarkedAfterARestart(also: three- and two-phase cars are not marked)TestOnePhaseVerdictComesAfterLimits(13 cases; 6 failed before)The review found the fuse path clean and a wrong mark bounded by the fuse cap, which applies after the ×3.
Limits
The meter's phase currents are magnitudes (
phaseCurrentsA). With L1 exporting 10 A, a car taking 16 A on L1 reads as L1 falling, so a one-phase car is missed while its phase exports: daytime charging on a site with PV export. This waits for the export fix (fix(control): phase current takes its direction from the phase's power #1782) in the next beta.The mark comes after the first rise has shown, about 80 s at the start of a session in the sim. Until then the car takes the three-phase order's current, as before.
The planner learns the car's levels at its next replan; the order already follows the mark.
DeadlineNeed(goal at risk) still uses the charger's table.Surplus charging on auto is unchanged.
Old clients show the reason code
one_phaseuntil ftw-webapp and the app learn it.🤖 Generated with Claude Code