Skip to content

fix(loadpoint): Charge now keeps charging after a restart - #1778

Merged
frahlg merged 1 commit into
masterfrom
fix/charge-now-survives-restart
Oct 21, 2026
Merged

frahlg merged 1 commit into
masterfrom
fix/charge-now-survives-restart

Conversation

@frahlg

@frahlg frahlg commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

Problem

Every update restarts Core, and a restart turned a running Charge now into a
pause. The simulator run before the beta showed it: before the restart,
11 040 W charging; 20 s later, the same charger and car, requested_w: 0,
manual_restore_unconfirmed: true, and the car stood still until someone
pressed Start again. Fredrik's rule (#1772):
Charge now runs until Stop, unplug or the car stops asking; nothing else
stops it.

Cause

The saved Charge now needs proof that the same car is still on the charger.
RestoreManualHold asked for a session ID that matches the saved one, but
most chargers never report a session ID: OCPP leaves it out of its reading
(ocpp/handlers.go pushReading), and of the bundled drivers only
easee_cloud sends one. The saved record had no session ID, the restore
answered unconfirmed, and the controller installed a pause and stopped
trying. It was not a race of a second, as first thought: the session ID never
arrives.

Change

go/internal/loadpoint/manual_hold_state.go, controller_hold_restore.go:

  • A saved Charge now without a session ID is checked by hardware identity
    alone. The same charger, still plugged in, resumes at once.
  • A saved Charge now with a session ID (Easee cloud) waits for the charger to
    report its session instead of pausing for good. The same session resumes; a
    different one pauses and asks for Start, as before.
  • While it waits, the charger gets 0 W, as it already did while the
    charger's identity was unknown. A socket reconnect during the wait no
    longer saves a pause over the stored choice; the next identity is checked
    against the record instead.

Unchanged: an observed unplug clears the hold (tickOne), Stop wins over a
restore (markManualExplicit), a car that stops asking releases it, and a
hold saved before the charger's identity was ever known still comes back as a
pause.

No setting and no timer. The accepted risk: with a charger that has no
session ID, an unplug and a new car while Core is down is invisible, so the
new car gets Charge now until it is full, unplugged or stopped. That costs
money at worst; the fuse guard is unchanged. A time limit would protect no
hardware and would stop Charge now after a longer outage, against the rule.

Tests

  • TestChargeNowWaitsForSessionAfterRestart: identity before session ID,
    with and without a socket reconnect while waiting. Fails before
    (stays at 0 W), passes after.
  • TestChargeNowWithoutSessionIDResumesAfterRestart: an OCPP-like charger
    without session IDs resumes at once; unplug ends it, and neither the next
    car nor a later restart inherits it. Fails before, passes after.
  • TestChargeNowDoesNotFollowAnotherSessionAfterRestart: a different session
    after a restart stays paused.
  • Two existing expectations encoded the bug and now say the opposite: the
    easee:ABC with no session rows in
    TestManualHoldRestoreRequiresHardwareAndActiveSession (now pending) and
    TestManualRestrictionSurvivesRestartWithoutHardwareIdentity (same
    hardware keeps its 4 140 W). The cases without hardware identity still
    pause.
  • make verify: passes (vet, all Go suites with -p 2, build).

Simulator (srcfl/device-simulator, OCPP charger, 25 A, s7-25)

rerun.sh <ref> <label> s7-25 from the pre-beta simulator report: OCPP
charger at 11 040 W under Charge now, house 3 A per phase, Core stopped for
20.6 s and started again. Both runs on the same base; only this commit
differs.

Before: master fc621be After: 2413095
Car before the stop (mean of 30 s) 10 971 W 10 971 W
While Core is down charger keeps 10.97 kW charger keeps 10.97 kW
~6 s after start 0 W, manual_hold, manual_restore_unconfirmed: true requested_w 11 040, manual_restore_unconfirmed: false
Lowest car power from stop to start + 60 s 0 W 7 759 W
Car, last 60 s of the test (150 s after start) 0 W, paused 10 971 W, charging
s7 verdict FAIL PASS

After the start the site-meter fuse guard held the car at 7.8 kW
(fuse_limit) for about 30 s, then raised it to 11 040 W. That looks like
the guard counting the car as house load until the charger's first
MeterValues arrive, and it is not changed here. The earlier baseline in the
report (dcdbd27) shows the same pause as fc621be.

My first attempt collided with another session's rig on the shared ports and
was discarded; both runs above used their own ports.

Follow-ups, not in this PR

  • Connector 0 Available read as an unplug could clear Charge now right
    after a charger boots; that is handled in
    #1779.
  • A charger socket reconnect (an OCPP Wi-Fi blip) during Charge now still
    turns it into a pause that asks for Start. That is deliberate in the code
    (TestManualStartWithoutHardwareCannotFollowAnotherSocket) and needs an
    owner decision under the same rule.
  • OCPP forgets its transaction across a Core restart (transactionID -1,
    session_wh 0), so FTW's last order is never restored for OCPP chargers
    and session energy starts again from zero.

🤖 Generated with Claude Code

A restart restored Charge now as a pause. The saved choice needs proof
that the same car is still on the charger, and the restore asked for a
session ID that most chargers never report (OCPP and every bundled
driver except easee_cloud). It answered "unconfirmed" and paused.

A saved choice without a session ID is now checked by hardware identity
alone; an observed unplug still ends it. A record with a session ID
waits for the charger to report one instead of pausing, and a socket
reconnect during that wait no longer saves a pause over it. A different
session still pauses as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 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-21T12:35:39.933109Z 2413095 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.

@frahlg
frahlg merged commit 8d5c6bf into master Oct 21, 2026
22 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