Skip to content

feat(loadpoint): operator SoC override + EV columns always visible - #112

Merged
frahlg merged 1 commit into
masterfrom
feat/loadpoint-soc-override
Apr 18, 2026
Merged

frahlg merged 1 commit into
masterfrom
feat/loadpoint-soc-override

Conversation

@frahlg

@frahlg frahlg commented Apr 18, 2026

Copy link
Copy Markdown
Member

Summary

Erik reported current_soc_pct: 73 on a car that was actually at 60 %. Easee is blind to the vehicle's BMS, so we can't automate this — but we also didn't give the operator a way to correct the drift. Now they can.

New

  • Manager.SetCurrentSoC(id, socPct) — re-anchors the session so current_soc equals the provided value; future observations accumulate from there. Rejects unplugged loadpoints (anchoring against charger noise after unplug is meaningless).
  • POST /api/loadpoints/{id}/soc — {"soc_pct": 60}. Triggers an MPC replan so the corrected SoC feeds straight into the next schedule.
  • UI — EV modal (clicking the EV card) gets a "Loadpoints (planner)" section with per-loadpoint SoC input + "Set" button. Disabled when unplugged. Refreshes the modal on success.

Also fixed

  • EV columns in the Diagnose per-slot table — now show whenever loadpoint state was tracked (plugged + SoC reported), not only when the DP chose to charge. Previously an "EV plugged but planner chose idle" snapshot hid the EV SoC trajectory entirely.
  • Cache-buster bumped v=diag1 → v=soc1 so browsers reload the new JS.

Test plan

  • go test ./... green incl. e2e.
  • New tests: TestSetCurrentSoCReAnchors, TestSetCurrentSoCRejectsUnplugged, TestSetCurrentSoCClampsRange.
  • @erikarenhill: hard-refresh the Pi's UI, click the EV card, correct your car's SoC, verify the Diagnose tab shows the corrected trajectory on the next replan.

Discord context

@frahlg: "APIt kommer inte ge någon faktisk SoC. Då måste vi koppla in bilens API vilket vi inte har. Så denna behöver på något sätt komma från användaren. Laddaren är blind för vilken bil det är."

Exactly — this PR gives the operator that path. Vehicle-API integrations (Tesla, VW, …) stay open as a follow-up if/when we want automatic SoC.

🤖 Generated with Claude Code

Easee (and most chargers) are blind to the vehicle's BMS. We infer
current SoC as plugin_soc_pct + delivered_wh / capacity, but if the
plug-in anchor was wrong the estimate drifts. Erik reported 73 %
shown while his car was actually at 60 %. Without a vehicle API
integration there's no automatic way to fix this — the operator
has to tell us.

## New

- `Manager.SetCurrentSoC(id, socPct)` — re-anchors the session so
  current_soc equals the provided value; future observations
  accumulate from there. Rejects unplugged loadpoints (anchoring
  against charger noise after unplug is meaningless).
- `POST /api/loadpoints/{id}/soc {soc_pct: N}` — endpoint, triggers a
  replan so the corrected SoC feeds into the next schedule.
- EV modal gets a "Loadpoints (planner)" section with per-loadpoint
  SoC input + "Set" button. Disabled when unplugged.

## Also

- EV columns in the Diagnose per-slot table now show whenever
  loadpoint state was tracked (plugged + SoC reported), not only
  when the DP decided to charge. Previously an "EV plugged but
  planner chose idle" snapshot hid the EV SoC trajectory entirely.
- Cache-buster bumped v=diag1 → v=soc1 so browsers reload the new
  app.js + diagnose.js.

## Tests

- `TestSetCurrentSoCReAnchors` — 9 kWh delivered with 25 % anchor
  infers 40 %; operator corrects to 60 %; further 3 kWh advances
  to ~65 %.
- `TestSetCurrentSoCRejectsUnplugged` — never-plugged + unplug-then-
  correct both return false.
- `TestSetCurrentSoCClampsRange` — clamps to [0, 100].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@frahlg
frahlg merged commit 0c01e5f into master Apr 18, 2026
1 check passed

@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: 0e7a94089c

ℹ️ 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 +287 to +289
if anchor < 0 {
anchor = 0
}

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 Remove anchor clamp that blocks valid SoC corrections

SetCurrentSoC promises to re-anchor so current_soc_pct matches the operator input, but clamping anchor to >= 0 breaks that whenever delivered_wh_session/capacity already exceeds the requested SoC (for example, 15 kWh delivered on a 60 kWh car and operator sets 10%). In that case the clamp forces anchor=0, and currentSoCPct is recomputed to ~25% instead of 10%, so the override silently fails in exactly the drift/plug-swap correction workflow this endpoint was added for.

Useful? React with 👍 / 👎.

Comment thread web/app.js
Comment on lines +1510 to +1511
var v = Number(socInput.value);
if (!(v >= 0 && v <= 100)) return;

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 Prevent empty SoC field from being treated as 0%

The click handler converts the input with Number(socInput.value), and Number("") becomes 0, which passes the current range check. If an operator clears the field and clicks Set, the UI posts {"soc_pct":0} unintentionally and resets the loadpoint SoC. The handler should explicitly reject empty input before numeric conversion.

Useful? React with 👍 / 👎.

Comment thread web/diagnose.js
Comment on lines +175 to +176
const lpActive = d.slots && d.slots.some(x =>
x.loadpoint_w || x.loadpoint_soc_pct);

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 Treat 0% EV SoC as active in Diagnose column toggling

The new EV-column gate relies on truthiness (x.loadpoint_w || x.loadpoint_soc_pct), so slots with tracked EV state at exactly 0% SoC are treated as inactive when charging power is also 0. This regresses the “always visible when tracked” intent for valid 0% snapshots (now possible via SoC override), causing EV columns to disappear even though loadpoint state exists.

Useful? React with 👍 / 👎.

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