From 93e244db0547a9d754183a946dff54609f941890 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 19 Oct 2026 17:24:38 +0200 Subject: [PATCH] fix(web): remove the timing note under the energy flow The Overview showed a long line under the diagram with the current balance, a 10 s energy mean, its clock range, age, basis and timing caveats. It repeated the house value and read as debug output. Home use still shows current power, marked estimated, and the diagram still shows missing or paused data. Co-Authored-By: Claude Opus 5.5 --- .changeset/remove-home-use-timing-note.md | 5 ++++ web/app.js | 9 ------ web/components/energy-flow-readings.js | 34 ----------------------- web/energy-flow-readings.test.mjs | 27 ++---------------- 4 files changed, 8 insertions(+), 67 deletions(-) create mode 100644 .changeset/remove-home-use-timing-note.md diff --git a/.changeset/remove-home-use-timing-note.md b/.changeset/remove-home-use-timing-note.md new file mode 100644 index 000000000..a78cd39a7 --- /dev/null +++ b/.changeset/remove-home-use-timing-note.md @@ -0,0 +1,5 @@ +--- +"ftw": patch +--- + +Remove the timing note under the Overview energy flow. Home use still shows current power, and the diagram still marks missing or paused data. diff --git a/web/app.js b/web/app.js index 5220659b2..e0be5262e 100644 --- a/web/app.js +++ b/web/app.js @@ -565,15 +565,6 @@ } var opts = energyFlowOpts(data); opts.live = lastFlowLive; lastFlowReadings = window.ftwFlowReadingsFromStatus(data, opts); - var homeNote = document.getElementById("home-use-estimate"); - if (!homeNote) { - homeNote = document.createElement("p"); - homeNote.id = "home-use-estimate"; - homeNote.className = "muted"; - flowEl.insertAdjacentElement("afterend", homeNote); - } - homeNote.textContent = lastFlowReadings.homeEstimateNote || ""; - homeNote.hidden = !homeNote.textContent; (lastFlowReadings.planets || []).forEach(function (p) { if (p.role !== "ev" || p.placeholder || !p.name) return; var lpEv = loadpointsByDriver && loadpointsByDriver[p.name]; diff --git a/web/components/energy-flow-readings.js b/web/components/energy-flow-readings.js index d32ad6092..0ccd48a8c 100644 --- a/web/components/energy-flow-readings.js +++ b/web/components/energy-flow-readings.js @@ -39,39 +39,6 @@ export function fmtKwhShort(kwh) { return kwh.toFixed(2); } -function usableHomeEstimate(estimate) { - const from = num(estimate?.from_ms), to = num(estimate?.to_ms); - const age = num(estimate?.end_age_ms); - return num(estimate?.watts) !== null && estimate.watts >= 0 && - from !== null && to !== null && from > 0 && to > from && to - from <= 300000 && - to < 8640000000000000 && age !== null && age >= 0 && age <= 180000; -} - -export function homeEstimateNote(estimate, live = true, powerBalanceW = null) { - if (!estimate) return ""; - if (!live) return "Home use estimate paused · no live data"; - const current = powerBalanceW === null ? "" : - `Estimated home use ${(powerBalanceW / 1000).toFixed(1)} kW · latest power readings; device delays may differ.`; - if (current && !usableHomeEstimate(estimate)) return current; - if (num(estimate.watts) === null) { - if (estimate.reason === "charger_source_time_unavailable") return "Home use estimate unavailable · charger source time unknown"; - const sourceAge = num(estimate.source_age_ms); - return "Home use estimate unavailable · waiting for source observations" + - (sourceAge > 0 ? ` · last source report ${Math.ceil(sourceAge / 1000)} s old` : ""); - } - if (!usableHomeEstimate(estimate)) { - return "Home use estimate unavailable · readings are too old"; - } - const from = new Date(estimate.from_ms), to = new Date(estimate.to_ms); - const options = {hour:"2-digit", minute:"2-digit", second:"2-digit", hourCycle:"h23", timeZoneName:"short"}; - if (from.toDateString() !== to.toDateString()) Object.assign(options, {year:"numeric", month:"short", day:"numeric"}); - const period = new Intl.DateTimeFormat("en-GB", options).formatRange(from, to); - const age = estimate.end_age_ms === 0 ? "ended now" : `ended ${Math.ceil(estimate.end_age_ms / 1000)} s ago`; - const basis = {counters:"energy counters", power_integral:"sampled power", mixed:"charger energy + sampled power"}[estimate.energy_basis] || "energy estimate"; - const timing = estimate.timing_basis === "source" ? "Device clocks may differ." : "Includes arrival times; device delay is unknown."; - return `${current || "Home use unavailable · no current power balance."} Energy mean ${(estimate.watts / 1000).toFixed(1)} kW · ${Math.round((estimate.to_ms - estimate.from_ms) / 1000)} s window · ${period} · ${age} · ${basis}. ${timing}`; -} - function planetColor(role, watts, thresholdW) { if (watts === undefined || watts === null) { if (role === "grid" || role === "pv") return "var(--fg-muted)"; @@ -259,7 +226,6 @@ export function flowReadingsFromStatus(status, opts) { return { load: loadW === null ? null : loadW / 1000, loadEstimated: hasEstimate, - homeEstimateNote: homeEstimateNote(status?.load_estimate, opts?.live !== false, powerBalanceW), planets: withControlMarks(planets, status?.control_feedback, opts?.live !== false), selfPoweredPctToday, }; diff --git a/web/energy-flow-readings.test.mjs b/web/energy-flow-readings.test.mjs index 1195be768..4af56e4c3 100644 --- a/web/energy-flow-readings.test.mjs +++ b/web/energy-flow-readings.test.mjs @@ -1,9 +1,9 @@ import assert from "node:assert/strict"; import { describe, it } from "node:test"; -import { flowReadingsFromStatus, fmtKwhShort, homeEstimateNote } from "./components/energy-flow-readings.js"; +import { flowReadingsFromStatus, fmtKwhShort } from "./components/energy-flow-readings.js"; -it("shows current household power and keeps the energy mean with its own period and age", () => { +it("shows current household power without a note about the past energy mean", () => { const estimate = {watts: 886, from_ms: Date.UTC(2026,9,18,10), to_ms: Date.UTC(2026,9,18,10,1), age_ms: 90000, end_age_ms:60000, energy_basis:'mixed', timing_basis: 'mixed'}; const status = {load_w: 1800, load_estimate: estimate, energy:{today:{load_wh:2000,import_wh:500,history_quality:'estimated'}}}; const result = flowReadingsFromStatus(status); @@ -11,18 +11,7 @@ it("shows current household power and keeps the energy mean with its own period assert.equal(result.loadEstimated, true); assert.equal(status.load_w, 1800); assert.equal(result.selfPoweredPctToday, null); - assert.match(result.homeEstimateNote, /Estimated home use 1.8 kW/); - assert.match(result.homeEstimateNote, /Energy mean 0.9 kW/); - assert.match(result.homeEstimateNote, /60 s window/); - assert.match(result.homeEstimateNote, /\d{2}:00:00.+\d{2}:01:00/); - assert.match(result.homeEstimateNote, /ended 60 s ago/); - assert.match(result.homeEstimateNote, /charger energy \+ sampled power/); - assert.match(result.homeEstimateNote, /Includes arrival times/); - assert.match(homeEstimateNote(estimate, false), /paused/); - assert.match(homeEstimateNote({...estimate, end_age_ms: 181000}), /too old/); - assert.match(homeEstimateNote({...estimate, from_ms:estimate.to_ms-300000,age_ms:210000}), /300 s window/); - assert.match(homeEstimateNote({watts:null,reason:'charger_source_time_unavailable'}), /source time unknown/); - assert.match(homeEstimateNote({watts: null}), /unavailable/); + assert.equal("homeEstimateNote" in result, false); assert.equal(flowReadingsFromStatus({...status,load_estimate:{watts:null}}).load, 1.8); assert.equal(flowReadingsFromStatus({...status,load_estimate:{...estimate,end_age_ms:181000}}).load, 1.8); assert.equal(flowReadingsFromStatus({...status,load_w:null}).load, null); @@ -32,13 +21,8 @@ it("never lets a past zero mean overwrite a positive current Load", () => { const status={load_w:1234,history_quality:"complete",load_estimate:{watts:0,from_ms:1000,to_ms:11000,end_age_ms:60000}}; const result=flowReadingsFromStatus(status); assert.equal(result.load,1.234); - assert.match(result.homeEstimateNote,/Estimated home use 1.2 kW/); - assert.match(result.homeEstimateNote,/Energy mean 0.0 kW/); - assert.match(result.homeEstimateNote,/ended 60 s ago/); const missing=flowReadingsFromStatus({...status,load_w:null,history_quality:"incomplete"}); assert.equal(missing.load,null); - assert.match(missing.homeEstimateNote,/no current power balance/); - assert.match(missing.homeEstimateNote,/Energy mean 0.0 kW/); }); it("keeps a qualified power balance visible while the energy interval is unavailable", () => { @@ -47,10 +31,6 @@ it("keeps a qualified power balance visible while the energy interval is unavail const result = flowReadingsFromStatus(status); assert.equal(result.load, 1.234); assert.equal(result.loadEstimated, true); - assert.match(result.homeEstimateNote, /latest power readings/); - assert.match(result.homeEstimateNote, /device delays may differ/); - assert.doesNotMatch(result.homeEstimateNote, /\d+ s mean|unavailable|ended now/); - assert.match(flowReadingsFromStatus(status,{live:false}).homeEstimateNote, /paused/); assert.equal(status.load_estimate.watts, null); } }); @@ -61,7 +41,6 @@ it("distinguishes a real zero balance from missing, invalid or stale inputs", () for (const value of [undefined, null, "0", NaN, Infinity, -1]) { const result = flowReadingsFromStatus({...base,load_w:value}); assert.equal(result.load,null); - assert.match(result.homeEstimateNote,/unavailable/); } });