Skip to content

fix(ev): resume after a 0 W standdown and span the Overview car notice - #1187

Merged
frahlg merged 2 commits into
masterfrom
fix/ev-resume-after-zero
Sep 8, 2026
Merged

frahlg merged 2 commits into
masterfrom
fix/ev-resume-after-zero

Conversation

@frahlg

@frahlg frahlg commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

Field report 2026-09-07 (Easee + Audi e-tron on v3.1.3-beta.1): a 0 W loadpoint offer writes Easee dynamicChargerCurrent = 0, which the app shows as Temporary charging limit 0 A / “user paused”. The contactor stays open, the car sees no voltage, and a later non-zero ev_set_current does not resume. Overview also squeezed the plugged-in car notice into one of twelve grid columns.

What changed

  • After a known 0 W command (plan, surplus, safety standdown), the next non-zero offer sends ev_resume and then ev_set_current.
  • #charging-notices is a full-width Overview banner instead of a one-word-wide column.

Out of scope

  • Easee driver should still treat a 0 A write as pause (paused_state) in srcfl/device-drivers.
  • First offer after process start does not send ev_resume (we have not issued a 0 W standdown in this run).

Tests

  • go test ./internal/loadpoint/
  • node --test web/dashboard-simplification.test.mjs

Note

Medium Risk
Changes live EV charger command sequencing on a safety-critical path; behavior is gated and well-tested but mis-timed resume could still affect charging recovery.

Overview
Fixes Easee-style chargers that treat a 0 W limit as a sticky user pause: when FTW had previously commanded 0 W and the next tick offers power again, dispatch now sends ev_resume before ev_set_current. The first positive offer after process start still skips resume (no prior standdown in this run).

On Overview, the plugged-in car notice is a dedicated #charging-notices host that spans the full 12-column grid (replacing a one-column squeeze). Styling moves from inline JS to CSS (flex layout, hidden state, mobile grid placement). Tests cover the 0 W → offer edge, stale site-meter recovery, and dashboard ordering/CSS expectations.

Reviewed by Cursor Bugbot for commit 9414c97. Bugbot is set up for automated code reviews on this repo. Configure here.

Easee treats dynamicChargerCurrent=0 as a sticky user pause. When the
loadpoint offer returns, send ev_resume before ev_set_current.

The plugged-in car notice is a direct child of the 12-column Overview
grid and must span the row, or it wraps a word per line.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_d2d1c8e9-1f04-43cd-80ef-71bea3eeff68)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 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-09-08T13:13:16.625805Z 729ff94 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.

The failed-goal replan test records each charger send. ev_resume on
the 0 W → manual Start edge is not the setpoint under test.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

@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: 729ff94381

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

// starts current. Skip the first command of a process (prevKnown
// false): that is not a standdown we issued.
if haveOffer {
c.resumeAfterZeroOffer(ctx, lpCfg, prevW, prevKnown, offerW)

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 Apply the new clamp before resuming OCPP chargers

When an OCPP charger previously accepted a higher rate and the post-standdown offer is lower (for example, after a fuse clamp), this bare ev_resume is routed to ocpp.Server.Command, which restores the last non-zero amperage before the following ev_set_current applies the new limit. Because the resume call waits for profile confirmation, the charger can draw at the stale higher rate during that interval, defeating the hardware-protection clamp; resume must carry the already-clamped offer or otherwise avoid restoring the old rate on this path.

AGENTS.md reference: AGENTS.md:L35-L37

Useful? React with 👍 / 👎.

Comment on lines 1936 to 1938
if w, ok := cmd["power_w"].(float64); ok {
offerW, haveOffer = w, true
c.manager.setCommandedForManual(lpCfg.ID, w, cmdReason, manualCommandUpdatedAt)

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 Retain the resume edge until resume succeeds

When ev_resume fails transiently but the subsequent ev_set_current succeeds, the manager has already been changed from 0 W to the positive offer here. The next tick therefore sees prevW > 0 and never retries ev_resume; on the sticky-pause chargers this change targets, the car remains paused for the entire positive plan interval until another zero edge or unplug occurs. Track a pending resume independently or clear it only after the resume succeeds.

Useful? React with 👍 / 👎.

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_7f346b03-f7b3-4c19-91ce-0e9fccc03257)

@frahlg
frahlg merged commit 5d56af6 into master Sep 8, 2026
19 checks passed
@frahlg
frahlg deleted the fix/ev-resume-after-zero branch September 8, 2026 13:23

@miravoss26 miravoss26 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fixes a real field-reported bug: Easee treats a 0 A dynamicChargerCurrent write as a sticky user-pause, so a later non-zero ev_set_current alone never reopens the contactor. resumeAfterZeroOffer now sends ev_resume first whenever the previous commanded value was known and ≤0 and the new offer is >0 — correctly skips the very first command of a process (prevKnown=false) so it's not misread as resuming a standdown FTW never issued.

Verified the ordering in tickOne: previousCommanded reads CommandedW/CommandedKnown before setCommandedForManual overwrites it, and resumeAfterZeroOffer fires before the actual ev_set_current send — matches the test assertions (sender.calls[1].action == "ev_resume", [2] == "ev_set_current"). TestTickResumesChargerWhenOfferReturns and TestTickFirstPositiveOfferDoesNotResume cover the two edges directly; the two updated dispatch-safety tests confirm exactly one ev_resume on the stale-meter-recovery paths. The mpc test adjustment (filtering non-ev_set_current actions before asserting on sent power) is a sensible accommodation, not a weakened assertion.

CSS/HTML part (#charging-notices spanning the full grid) is low-risk and unrelated to the dispatch change; no issue there. All CI green, no secrets/new deps/authz changes.

Safe to merge from my read.

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.

2 participants