Skip to content

fix(ev): explain vehicle completion without a no-power alarm - #1980

Merged
frahlg merged 4 commits into
srcfl:masterfrom
segran2:fix/1976-vehicle-completed
Nov 8, 2026
Merged

frahlg merged 4 commits into
srcfl:masterfrom
segran2:fix/1976-vehicle-completed

Conversation

@segran2

@segran2 segran2 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Problem and behavior

Fixes #1976. A car that has stopped at its own charge limit can draw 0 W while Core still asks for charging because vehicle SoC is missing or stale. The driver already reports request_active=false, but feedback could still say not_following/no_power_response and optional recovery could restart the vehicle.

This change uses that existing, explicit driver signal to explain “The charger reports that the car has finished or paused charging”, with a prompt to check the car's charge limit and schedule. It never infers a full battery, rewrites SoC or marks the charging goal complete.

  • Fresh vehicle-stop evidence, an accepted positive order and measured near-zero power produce vehicle_not_requesting/waiting/info. ControlStates uses the same result, so control.not_following does not fire solely on this explained zero draw.
  • Missing/stale request evidence, failed/unconfirmed commands, safety stops, a lower order held by the charger and unexpected draw keep their own diagnoses.
  • RequestKnown distinguishes explicit vehicle refusal from legacy telemetry without the field. Optional resume and vehicle-wake retries are avoided while the current vehicle explicitly declines power. Normal recovery returns when the vehicle requests charging again.
  • No driver changes, settings changes, public diagnostic endpoints or local-only instrumentation are included. vehicle_request_active is an additive optional feedback field. A patch changeset is included.

Validation

On this standalone branch based on ec8ce36192cfe9947b63f7ed9e388c28ecc375a5:

  • make verify: passed. Docker-daemon-dependent checks skipped in this environment.
  • npm test: 902 passed, no failures.
  • Targeted go test -race for API, loadpoint and cmd/ftw: passed.
  • Regressions cover a sustained vehicle stop, notification verdict, missing/active request evidence, stale readings, failed/unconfirmed commands, a lower held current offer, unexpected power, suppressed optional retries and recovery after a new active vehicle request.

Hardware evidence and limits

Real Audi e-tron + Easee Cloud + Pixii, 6 November 2026, CET (Europe/Stockholm). The owner reported 72% before charging, an 80% vehicle limit, and confirmed 80% after the test.

The field run used v0.159.0-beta.1+local.3 (1c385a353b91cb8596c99494843031b82811424b), which carried this correction alongside unrelated local diagnostics/pilot patches. This PR excludes those patches; the standalone upstream build has automated validation, not a separate field deployment. Charger/vehicle firmware versions were not recorded.

  • Observed charging at approximately 10.3 kW.
  • 17:54:20: charger Completed, request_active=false, measured 0 W, while the accepted order remained 10,350 W. Core correctly reported vehicle_not_requesting/waiting/info in 18 five-second monitor samples; no false no-power alarm.
  • No accepted optional ev_resume after the vehicle's stop in the retained command trace; no later auto-resume in the retained Easee log.
  • 17:55:54: manual charging was inactive and the loadpoint returned to the plan at 0 W. The observer did not change or renew any owner hold.
  • No control-loop stall in the test journal window, no trace drops/write errors. Maximum sampled absolute site phase current 24.1 A against a configured 25 A fuse; shorter transients are not excluded.

Completed alone does not prove 80%: the final level is owner-confirmed, not independently timestamped BMS telemetry. No physical fault injection or safety-limit test was performed. Detailed private diagnostic bundles remain local and are not attached publicly.

Review and overlap

Draft pending human review of the rendered EV view. An AI browser preview exercised the actual before/after formatter with simulated status rows; this is not a human UI acceptance check.

#1537 and #1905 also touch feedback. This is a separate vehicle-request/completion path and adds no pilot-current or load-balancer inference; the regression fixture is independent of their evTrace extensions. Their changes/reviews are not superseded. No automatic reviewers are requested.

Signed-off-by: Segran <goran@andersson-stehag.se>
@segran2
segran2 marked this pull request as ready for review November 6, 2026 22:41
frahlg and others added 2 commits November 8, 2026 08:04
…ollowing

Core's own 0 W stop (vehicle_not_requesting) is following again. The
case where the driver says the car stopped while Core still offers power
gets its own reason, vehicle_declined, so one reason means one thing.

The verdict, resume suppression and wake suppression now need the stop
to last SessionCompletionTimeout while Core offers current, using the
loadpoint manager's existing timer, plus fresh charger data. A reason-50
blip during the handshake or after Core's own pause no longer hides a
failed start or blocks the resume or contactor cycle that pause needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg

frahlg commented Nov 8, 2026

Copy link
Copy Markdown
Member

Maintainer commits on top (6957b2c, after merging current master):

  • vehicle_not_requesting is back in the following list: it is Core's own 0 W stop after its debounce, and Core is in control there. The new case — the driver says the car stopped while Core still offers more than 100 W — has its own reason, vehicle_declined (waiting/info, title "Car stopped charging"), so one reason does not mean two things.
  • The decline needs 90 s (SessionCompletionTimeout), reusing the manager's notRequestingSince timer. A brief request_active=false during the session handshake keeps waiting_response/no_power_response.
  • chargerIdleForWake is back to master's form; the request check moved into vehicleDeclinesOffer, which checks freshness. This also restores the contactor kick and ev_resume after Core's own pause.

Tests for the blip, the lasting decline, Core's own stop and the controller side; each fails without its fix. The iOS app needs words for vehicle_declined in a paired ftw-app change.

# Conflicts:
#	go/internal/api/api_control_feedback.go
#	web/control-feedback.test.mjs
@frahlg
frahlg merged commit 452ce62 into srcfl:master Nov 8, 2026
22 checks passed
frahlg added a commit to srcfl/ftw-app that referenced this pull request Nov 8, 2026
…nal (#166)

* feat(ios): the control sheet keeps what happened, from the box's journal

On 8 Nov 2026 the owner's app said "FTW is not in control" while Core
asked the battery for 4.2 kW of charge and it took 1.2 kW (06:14-06:29).
Once it passed, nothing showed it. Core now keeps a control journal
(GET /api/control/journal, srcfl/ftw feat/control-journal).

The control sheet reads it when it opens and when the stream's facts
change, and lists the last day's warnings, alarms and notices under what
needs a look now, newest first: the time, the device by the name the
sheet already uses, the live row's words, and for a device "asked X,
delivered Y on average" from the box's means. A dispatch block says FTW
was not in control and why; a source says the device was not reporting;
a plan quarter behind the plan has a line of its own. A device line that
only repeats a dispatch block or a quiet source is left out, and
back-to-back stretches of one verdict read as one. Only what still holds
takes the alarm colour. A box that answers 404 shows nothing new. None
of it reaches lane 0, the widgets or the watch.

The words catch up with Core: import_limit, load_balancer_limit and
charger_pilot_limit (srcfl/ftw#1537, #1905), one_phase, vehicle_declined
(srcfl/ftw#1980), the setup reasons that block dispatch, the pilot and
limit currents in Numbers, and "site power limit" for the cool-down.
fuse_limit no longer says the rate rises when the house uses less; Core
does not report that. English and Swedish.

The demo box keeps the same morning: a 3 s dispatch block at a restart,
the battery stretch with its notice and the quarter behind the plan, and
the charger quiet for seven minutes.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ios): keep a device line unless a block held for all of it

A device line was dropped on any overlap with a dispatch block or a
quiet source, so a minute offline could hide two hours of stale
readings. A cancelled read no longer says the box did not answer, and a
box without the journal is asked again each time, so one that updates
while the app runs shows its journal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

---------

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

EV feedback reports no power response after Easee Completed at the vehicle's 80% charge limit

2 participants