Skip to content

fix(web): the Charge now slider stops at the most Core can order - #1808

Merged
frahlg merged 2 commits into
masterfrom
fix/charge-now-slider-steps
Oct 25, 2026
Merged

frahlg merged 2 commits into
masterfrom
fix/charge-now-slider-steps

Conversation

@frahlg

@frahlg frahlg commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Problem

v0.155.1-beta.1 (#1804) runs Charge now on one phase for a charger that cannot run three, and the API now reports phases: 1 for it. The slider's top was still wrong. It took its range from max_charge_w, but Core treats a hold as a ceiling and floors it to allowed_steps_w within max_charge_w (clampManualPower → floorChargeW).

A one-phase charger with max_charge_w: 7360 and allowed_steps_w: [0, 1380, 2300, 3680]:

Slider Readout at the top Status after Start Core's order
master 16c4ad0 6–32 A 32 A · 7.4 kW 32 A requested 3,680 W
this branch 6–16 A 16 A · 3.7 kW FTW received 16 A 3,680 W

Change

evChargeNowTopW(lp) in web/app.js returns the highest step at or below max_charge_w, or max_charge_w when there is no table. The slider's top, its readout and the idle line ("Starts at up to …") use it. Amps are still W / (V × phases), with the phases the API reports. The bottom of the range and the sent phase_mode do not change.

A three-phase table that goes past the maximum now stops at the step Core can order: table [0, 4140, 6900, 11040] with max_charge_w: 7360 reads 10 A, where master read 11 A.

Evidence

  • web/ev-charge-now-range.test.mjs builds the real buildManualChargeSection with a small fake DOM, reads the slider and readout, and clicks Start. On master, 3 of 4 cases fail (max 32 against 16, and 11 against 10). The no-table case passes on both, as it should.
  • npm test: 874 pass, 0 fail.
  • Browser, local rig (sim-ferroamp, Core on this branch, sim-ocpp easee-charge-up -plug, the loadpoint above, 25 A fuse): Overview → Check charging and battery level → Charge now. Before: slider max 32, "32 A · 7.4 kW", banner "32 A requested". After a reload: max 16, "16 A · 3.7 kW", idle line "Starts at up to 16 A · 3.7 kW". A new Start reads "FTW received 16 A", and /api/loadpoints shows requested_w: 3680, requested_a: 16. No console errors apart from the dev build's version check (503).

Overlap

Draft #1792 (two-phase charging) changes the same maxA line. Whichever lands second rebases: #1792's Math.floor for two phases applies to wToA(evChargeNowTopW(lp)).

Paired follow-ups, not in this PR

The other clients copy the box page's range and need the same change. Each one also has to read allowed_steps_w, which neither parses today.

  • ftw-webapp: chargeCurrent in src/lib/format/ev.ts.
  • ftw-app (iOS): EV.current(_:) and EV.watts(_:amps:) in appleApp/FTWKit/Sources/FTWKit/Format/EV.swift. Android has no Charge now.

Known limits, left as they are

  • Amps between steps. Core floors the hold, so on the table above, 7–9 A orders 6 A and 11–15 A orders 10 A, while the readout shows the slider's amps.
  • A table not on whole amps at 230 V. Easee's 11,100 W at three phases reads 16 A, but 16 × 690 = 11,040 W floors to the step below. Master does the same with that maximum.

🤖 Generated with Claude Code

The Codex finding, fixed in d120b27

At the top of the slider, Core now orders the top step exactly. Before the fix, a top step that is not a whole number of amps rounded down, and Core floored the order to the step below. Three phases, 230 V, steps ending 9,700 / 10,400 W:

Readout at the top Sent at the top Core orders
bde379c 15 A · 10.3 kW 10,350 W 9,700 W
d120b27 15 A · 10.4 kW 10,400 W 10,400 W

One step below the top, 14 A sends 9,660 W as before. Core floors that to 6,900 W, and the readout still says 9.7 kW: the between-steps limit this PR already lists. npm test: 877 pass, 0 fail, including three new cases for this example.

Rendered with the real buildManualChargeSection and the box's stylesheets. From the top: the Codex example; the same charger with Charge now running at the top; the one-phase charger; a charger with no step table:

The slider took its top from max_charge_w. Core floors a hold to the
step table within that maximum, so a one-phase charger rated 7,360 W
with the table [0, 1380, 2300, 3680] read 6–32 A and "32 A · 7.4 kW"
while Core ordered 3,680 W. The top is now the highest step at or
below max_charge_w, or max_charge_w when there is no table. The
phases the API reports still set the amps.

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-22T14:32:01.219900Z bde379c 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: bde379c139

ℹ️ 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 thread web/app.js Outdated

var minA = Math.max(1, Math.round(wToA((lp && lp.min_charge_w) || 0)) || 6);
var maxA = Math.round(wToA((lp && lp.max_charge_w) || 0)) || 16;
var maxA = Math.round(wToA(evChargeNowTopW(lp))) || 16;

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 Preserve access to the highest step when converting to amps

When the highest table entry is below max_charge_w and rounds down to whole amps, this change makes that previously reachable charging level impossible to request. For example, at three phases and 230 V, a maximum of 11,000 W with steps ending in [9700, 10400] previously submitted 11,040 W, which Core clamped to 10,400 W. The new maximum is 15 A, submitting only 10,350 W; clampManualPower → floorChargeW then selects 9,700 W, and the slider cannot go higher. Preserve the exact top-step wattage in the submitted hold or otherwise ensure the amp conversion does not lower the ceiling below that step, and add a non-whole-amp regression case.

Useful? React with 👍 / 👎.

The top took whole amps from the top step, and a step off whole amps
rounded down. At three phases and 230 V, with max_charge_w 11,000 and a
table ending [9700, 10400], the top read 15 A and sent 10,350 W, which
Core floored to 9,700 W, so 10,400 W could not be ordered. At the top
the slider now sends the top step's watts, and the readout and the
idle line show them: "15 A · 10.4 kW". Below the top it still sends
its amps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg merged commit 3aad0d8 into master Oct 25, 2026
17 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