Skip to content

fix(loadpoint): a charger on one phase under a three-phase order is seen, and planned at its rate - #1796

Closed
frahlg wants to merge 1 commit into
masterfrom
fix/ev-one-phase
Closed

frahlg wants to merge 1 commit into
masterfrom
fix/ev-one-phase

Conversation

@frahlg

@frahlg frahlg commented Oct 22, 2026

Copy link
Copy Markdown
Member

Problem

Field report, 22 Oct 2026, v0.155.0-beta.1, Easee Cloud. The plan said "Charge EV at 7.6 kW" on three phases until 09:00, about 24 kWh. The car drew 3.13 kW all night, about 13.6 A on one phase (three phases at Easee's 6 A minimum would be 4.14 kW), and about 13 kWh arrived. Nothing told the household why, and the plan went on counting 7.6 kW.

How FTW itself can put an Easee on one phase

  • With a schedule and an empty loadpoint phase_mode, Core sends phase_mode: "auto" (resolvePhaseMode, controller.go:2232) and no phase_split_w.
  • Core counts an auto order on three phases above 3,680 W (defaultPhaseSplitW).
  • easee_cloud.lua pick_phases splits auto at voltage × max_amps_per_phase, which Core fills with the site fuse: 5,750 W at 25 A, 8,050 W at 35 A. Between the two splits Core counts three phases and the driver writes phaseMode=1 with amps = W/230, capped by the fuse and the charger.
  • A live switch back to three phases needs a pause and resume (driver comment), so an Easee can also stay on one phase.

The closed-loop sim now splits auto as the driver does. At 35 A a 7.59 kW auto order puts 16 A on L1 and a car that takes 3,130 W draws exactly the field numbers. A charger stuck on one phase gives the same signature.

The fuse limit is not wrong here. It reads the site meter: cutting a three-phase order by X A per phase lowers a one-phase draw by X A once the order is below the car's own current. It is the plan and the feedback that count the order's watts.

Change

  • The loadpoint controller compares the charger's fresh power with the site meter's phases read within 10 s of it, under a positive three-phase order (loadpoint/one_phase.go). When one phase carries all of the charger's current and the other two less than a third of it, for two minutes, the session is on one phase: that phase, the most it delivered there and the order in force then. Two minutes with every phase carrying its third, or unplugging, ends it. Below 2 kW it does not judge: a third would hide in the house load.
  • The plan counts that rate: LimitPower gives the delivered rate as the power for the session, so the plan and the goal's need (DeadlineNeed) stop counting the order's watts.
  • While a slot has energy left, the controller repeats the order that delivered the rate, instead of the plan's watts snapped to a three-phase step. Snapped, 3,130 W becomes 4,140 W, 6 A a phase, which a charger stuck on one phase turns into 1,380 W.
  • The verdict is Limited, a warning: "Charging on one phase", with the phase and its current (charging_phase, charging_phase_a). It explains a draw below the order only; a draw above the order is still judged against it.
  • Fuse protection is unchanged: the site meter's current per phase plus FTW's own orders that cannot have shown yet. The charger's reading takes no part in it.

Evidence

Field case (sim and replay) master this PR
Verdict, 3.13 kW on L1 under an 8.3 kW plan order Not following, "Asked for 8.3 kW charge, delivering 3.1 kW" Limited, "Charging on one phase", L1 at 13.6 A
Plan power for the session the order's steps up to 11,040 W 3,130 W
Order for a slot planned at 3,130 W 4,140 W (6 A a phase: 1,380 W on a stuck phase) the order that delivered 3,130 W
  • New sitesim rows: "charger stuck on one phase" and "Easee resolves auto to one phase" fail on master (no one-phase draw seen) and pass here; "three-phase car, heavy L1, export" (4,140 W beside 13 A on L1 and 3 kW export) is not reported. All existing rows keep their result with the new auto split in the adapter.
  • TestThreePhaseOrderDrawnOnOnePhaseIsLimited runs the real loadpoint controller, command evidence and the API.
  • Unit tests: TestOnePhaseDraw, TestOnePhaseHoldsForTheSession, TestLimitPowerCountsOnePhaseRate, TestOnePhaseRepeatsTheDeliveringOrder; web words in control-feedback.test.mjs.
  • go test ./internal/api/... ./internal/telemetry/... ./internal/control/... ./internal/loadpoint/... ./internal/sitesim/... ./internal/mpc/... ./cmd/ftw/... and node --test web/control-feedback.test.mjs pass.

Not in this PR

🤖 Generated with Claude Code

…een, and planned at its rate

Field report, v0.155.0-beta.1, Easee Cloud: a 7.6 kW three-phase plan
order drawn as 3.13 kW on one phase all night, about 13 of 24 kWh.
With a schedule and an empty phase mode Core sends auto and counts it
on three phases above 3,680 W; the Easee driver splits auto at the
fuse's current on one phase (8,050 W at 35 A) and locks phaseMode 1.
An Easee can also stay on one phase.

The loadpoint controller now compares the charger's fresh power with
the site meter's phases under a three-phase order. Two minutes with
all of the current on one phase and less than a third on the others
mark the session: the plan counts the rate delivered there
(LimitPower), the controller repeats the order that delivered it while
a slot has energy left, and the verdict is Limited, "Charging on one
phase", with the phase and its current. The fuse limit is unchanged.

The closed-loop sim splits auto as the Easee driver does and gains a
charger stuck on one phase.

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-22T05:31:05.426863Z 8ac9db7 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ac9db74f2

ℹ️ 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".

Comment on lines +2501 to +2502
if st, known := c.manager.State(lpCfg.ID); known && wantW > 0 && st.OnePhase > 0 && st.OnePhaseOrderW > 0 {
wantW = min(st.OnePhaseOrderW, maxW)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Separate the delivered-rate ceiling from the hardware order ceiling

When a detected 3,130 W session is replanned, LimitPower supplies 3,130 W as the MPC maximum, and coreReservePlan emits that value in LoadpointMaxPowerW. The preceding duty-plan branch therefore lowers maxW to 3,130 W, so this assignment clips the saved 7,590 W order back to 3,130 W. The final SnapChargeW(3130, 4140, 3130, steps) returns zero because the ceiling is below the charger's minimum. Consequently, the reserve/duty-plan path stops charging after detecting precisely the one-phase case this change addresses. Keep the modeled delivered-power ceiling separate from the legal hardware-order ceiling, and cover a directive containing LoadpointMaxPowerW in the regression test.

Useful? React with 👍 / 👎.

Comment on lines +59 to +60
case phase > 0 && below == 2:
return phase

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for generation before inferring the charger's phases

On a solar-equipped site, these absolute net meter currents can identify a correctly operating three-phase charger as single-phase. For example, a 4,140 W EV drawing 6 A per phase, balanced 4,140 W PV generation, and household currents of [18, 0.5, 0.5] A leave exactly [18, 0.5, 0.5] A at the meter; onePhaseDraw(4140, 230, ...) returns L1. After two minutes, LimitPower caps planning at 4,140 W and the controller repeats that order instead of allowing higher charging rates, potentially missing a departure goal despite available charger capacity. Net site-current magnitudes alone do not establish the EV's phase distribution; require corroborating charger evidence or account for background load and generation before latching this restriction.

Useful? React with 👍 / 👎.

@frahlg
frahlg marked this pull request as draft October 22, 2026 06:03
@frahlg

frahlg commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

Back to draft. Fredrik's direction for a one-phase car (22 Oct 2026): keep the charger on three phases, learn the car's phases from the site meter when charging starts, keep them on the car (the phases field in #1792), and plan with the per-phase current × V × the car's phases. This PR detects per session and repeats the delivering order instead, so it will be reworked on top of #1792 after v0.155.0-beta.2. The planner-step and phase-choice fixes for the same field night are in #1799.

@frahlg

frahlg commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

Replaced by #1801: the one-phase car is now seen from the site meter as an order rise on one phase, the charger stays on three phases, and the plan and order use the car's one-phase levels (Fredrik, 22 Oct 2026). The planner-step and phase-choice fixes for the same field night are in #1799.

@frahlg frahlg closed this Oct 22, 2026
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