Repository navigation
Conversation
Week and month totals come from the persisted charger ledger and the site import price. Hours without a price still count as energy and mark the cost partial. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
This was referenced Oct 13, 2026
4 of 5 tasks
This was referenced Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem and result
A household with a charger can see how much energy the car used, but not what that charging cost over a week or a month. This adds that, from history that already survives a restart.
Do not merge this until after the next stable release. It is self-contained (new read API, new card, no change to dispatch or pricing) and should wait so it does not ride into the release that is about to be cut. The changeset is
minorbecause the History and Energy views gain a visible capability; that bump needs the owner's approval in this PR.Last 7 days and last 30 days are rolling local days, including today, the same windows as
GET /api/energy/daily?days=N. They are not a Monday–Sunday week and not calendar month-to-date. The existing history tiles use month-to-date for their Month toggle; this feature uses 30 days because "a month of charging" on the 3rd of the month would otherwise be three days.History page with the EV charging card under the daily energy story
Same card after switching the daily chart to 30 days
Compact EV energy and cost under Week and month comparison
Scope and safety
Read-only. No new table and no change to what is sent to a charger. Energy is the persisted
vehicle_chargeledger, one asset per charger, joined to a loadpoint when the asset label is that loadpoint's driver name. Prices areprices.total_ore_kwhfor the configured zone: spot plus grid tariff, including VAT, the same import price savings and daily cost already use.How cost is attributed. The ledger does not meter which source fed the car. In each interval that also has site import and household use, grid import is shared between home use and EV charging in proportion to their energy. Only the car's grid share is priced. Solar and home-battery energy in that interval has no further cash cost, because grid energy was priced when it crossed the meter. This path does not trace whether the battery was filled from solar or from an earlier import, and it does not charge the car for export it displaced.
An interval with charger energy but no site import, export, solar, or household use is priced entirely as grid import. Grid-attributed energy with no covering price slot still counts in
energy_wh; its cost is omitted andcost_partialis true.Stale or missing prices do not drop the energy. A restart reads the same ledger and price rows; covered by
TestEVEnergySurvivesRestart.Overlapping open PRs: #1337 also edits
go/internal/api/api.go(one new route line here), and #1003 also editsweb/index.html. Those branches have right of way if they land first; this should rebase rather than rewrite them. #1177 changes history-card polling; this card copies the hidden-tab pause in a new file and does not edit that PR.API
GET /api/ev/energy(read tier){ "tz": "Europe/Stockholm", "currency": "SEK", "window": "rolling_local_days", "attribution_note": "...", "windows": [ { "id": "7d", "label": "Last 7 days", "attribution": "site_mix", "energy_wh": 8000, "grid_wh": 3200, "onsite_wh": 4800, "cost_ore": 640, "unpriced_wh": 0, "cost_partial": false, "chargers": [{ "asset_id": "...", "label": "easee", "loadpoint_id": "garage", "energy_wh": 6000, "cost_ore": 480, "cost_partial": false }], "daily": [{ "day": "2026-06-02", "energy_wh": 8000, "cost_ore": 640, "cost_partial": false, "chargers": [] }] }, { "id": "30d" } ] }attributionissite_mix,import_price(no site meter in those intervals), ormixed.currencycomes from the price config, defaulting to SEK. Cost is minor units (öre, cent), matching the rest of the API.dailyis the chart series.Where it shows
Screenshots above are Chrome against the real page with a mocked
/api/ev/energy, not a production site.Verification
All of those passed. The state tests cover two loadpoints sharing one interval, a missing price hour, a price that covers only half a bucket, solar surplus at zero cash cost, the 23-hour and 25-hour Europe/Stockholm days (including both occurrences of the repeated 02:30), and a close/reopen of the database.
No hardware run. The ledger rows in tests are the same shape the charger path already writes.
Open questions
minorchangeset, and merge only after the next stable release.Checklist
To show artifacts inline, enable in settings.