Repository navigation
feat(loadpoint): operator SoC override + EV columns always visible - #112
Conversation
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>
There was a problem hiding this comment.
💡 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".
| if anchor < 0 { | ||
| anchor = 0 | ||
| } |
There was a problem hiding this comment.
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 👍 / 👎.
| var v = Number(socInput.value); | ||
| if (!(v >= 0 && v <= 100)) return; |
There was a problem hiding this comment.
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 👍 / 👎.
| const lpActive = d.slots && d.slots.some(x => | ||
| x.loadpoint_w || x.loadpoint_soc_pct); |
There was a problem hiding this comment.
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 👍 / 👎.
Summary
Erik reported
current_soc_pct: 73on 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 socurrent_socequals 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.Also fixed
v=diag1→v=soc1so browsers reload the new JS.Test plan
go test ./...green incl. e2e.TestSetCurrentSoCReAnchors,TestSetCurrentSoCRejectsUnplugged,TestSetCurrentSoCClampsRange.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