From 7f03cd786a11a99b8c2c49f2edb26e97f8d841cc Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 26 Oct 2026 07:22:27 +0100 Subject: [PATCH 1/2] fix(vendor): the flow diagram prints a size, never a minus Copied again from srcfl/ftw web/components/ftw-energy-flow.js at b4d2488d41ff046356a6710b1d173e38cdc96a64 (srcfl/ftw#1862). fmtKw prints the size of a power; the word under the bubble, such as "discharging", says the direction. The signed kW the component sums is unchanged. The provenance line is stamped with that commit and the digest is re-recorded with RECORD_VENDOR_DIGESTS=1, as tests/vendored.test.ts asks. Co-Authored-By: Claude Opus 5.5 --- .changeset/flow-size-no-minus.md | 5 +++++ src/vendor/ftw/digests.json | 2 +- src/vendor/ftw/ftw-energy-flow.js | 22 ++++++++++++---------- 3 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 .changeset/flow-size-no-minus.md diff --git a/.changeset/flow-size-no-minus.md b/.changeset/flow-size-no-minus.md new file mode 100644 index 0000000..c5da069 --- /dev/null +++ b/.changeset/flow-size-no-minus.md @@ -0,0 +1,5 @@ +--- +"ftw-webapp": patch +--- + +The vendored flow diagram prints a battery's power as a size, with "charging" or "discharging" under it, never a minus sign. It is the box's own copy, taken again from srcfl/ftw. diff --git a/src/vendor/ftw/digests.json b/src/vendor/ftw/digests.json index 280fb57..38bf938 100644 --- a/src/vendor/ftw/digests.json +++ b/src/vendor/ftw/digests.json @@ -3,7 +3,7 @@ "control-feedback.js": "389b5f227b7d125fa4138cc9c803660bfcff58e5ba50a18a4384c58704317d4a", "ftw-bar-chart.js": "08b61533ed52b0031a39e723278c812b2b27356c1d574b65dfd5603992065d82", "ftw-element.js": "7241b586582187cef2d76d3ee11bbc596c4f428cea3a5c8c84227e113aa3c1a0", - "ftw-energy-flow.js": "ced3308f92e0d49b41e7af5038a85e0986a0d879febf3b1541385028af5aa693", + "ftw-energy-flow.js": "b13905437d6de36748d5559399017f6f5596500ec4ff0e8d54bb2352b8dcaf64", "ftw-price-chart.js": "1833d8008f06f2eb8f6e2b9b0bb6ff91aafa1f54b81ed249d57bb4fda968a736", "price-math.js": "bc6b104259f76d799c0a9d7f1d8a780d897cb7dc0d7a3e16a6572fb9c626d508", "price-strip.js": "413b2946c311e910c9a052a8407a3a403ed6caca0e210307c6f3e951896c2b9b", diff --git a/src/vendor/ftw/ftw-energy-flow.js b/src/vendor/ftw/ftw-energy-flow.js index e638139..1e0c081 100644 --- a/src/vendor/ftw/ftw-energy-flow.js +++ b/src/vendor/ftw/ftw-energy-flow.js @@ -1,4 +1,4 @@ -// Vendored from srcfl/ftw web/components/ftw-energy-flow.js at 6d8e8704ccc8ee801fce16efd717a596e39e76ad. +// Vendored from srcfl/ftw web/components/ftw-energy-flow.js at b4d2488d41ff046356a6710b1d173e38cdc96a64. // Do not edit here; change the box source, then copy it here. // // — hero diagram for /next. @@ -1665,17 +1665,19 @@ function renderDailyParts(parts) { } function fmtKw(kw) { - // Input is kilowatts. Sub-kW values render as plain integer watts - // (no decimals) so a "30 W" import or "−12 W" battery trickle stays - // visible as the real number. The visual "idle / balanced" - // affordances (beam dimming, sub-label text) live on a separate - // ±FLOW_IDLE_W threshold; this formatter only handles display. + // Input is kilowatts, signed as Core sends them; the bubble prints the + // size only, because the UI never shows a raw minus. The word under it + // ("charging", "discharging", "exporting") says the direction. Sub-kW + // values render as plain integer watts (no decimals) so a "30 W" import + // or a "12 W" battery trickle stays visible as the real number. The + // visual "idle / balanced" affordances (beam dimming, sub-label text) + // live on a separate ±FLOW_IDLE_W threshold; this formatter only handles + // display. // // Sub-half-watt magnitudes round to 0 W — that's noise, not signal. - // `+ 0` normalises Math.round's −0 result to plain 0 so a tiny - // negative reading doesn't print as "-0 W". - if (Math.abs(kw) < 1) return `${Math.round(kw * 1000) + 0} W`; - return `${kw.toFixed(2)} kW`; + const size = Math.abs(kw); + if (size < 1) return `${Math.round(size * 1000)} W`; + return `${size.toFixed(2)} kW`; } // Collapse multi-planet corners into a single synthesized "combined" From 0a80d0239c7a9a4ca1f73e1147112cbf0ed809c5 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 26 Oct 2026 08:15:50 +0100 Subject: [PATCH 2/2] fix(vendor): take the flow diagram again from srcfl/ftw@cd68b449 The box's second review round: Home use in the middle keeps its sign, the planets keep printing sizes, and a battery FTW only observes says so under its title while the line under its size keeps the direction. Copied byte for byte; digests re-recorded. Co-Authored-By: Claude Opus 5.5 --- .changeset/flow-size-no-minus.md | 2 +- src/vendor/ftw/digests.json | 2 +- src/vendor/ftw/ftw-energy-flow.js | 38 +++++++++++++++++++------------ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.changeset/flow-size-no-minus.md b/.changeset/flow-size-no-minus.md index c5da069..ec9d2e1 100644 --- a/.changeset/flow-size-no-minus.md +++ b/.changeset/flow-size-no-minus.md @@ -2,4 +2,4 @@ "ftw-webapp": patch --- -The vendored flow diagram prints a battery's power as a size, with "charging" or "discharging" under it, never a minus sign. It is the box's own copy, taken again from srcfl/ftw. +The vendored flow diagram prints each device's power as a size, with "charging" or "discharging" under a battery, never a minus sign. Home use in the middle keeps its sign for now, and a battery FTW only observes says so under its title. It is the box's own copy, taken again from srcfl/ftw. diff --git a/src/vendor/ftw/digests.json b/src/vendor/ftw/digests.json index 38bf938..c2987fe 100644 --- a/src/vendor/ftw/digests.json +++ b/src/vendor/ftw/digests.json @@ -3,7 +3,7 @@ "control-feedback.js": "389b5f227b7d125fa4138cc9c803660bfcff58e5ba50a18a4384c58704317d4a", "ftw-bar-chart.js": "08b61533ed52b0031a39e723278c812b2b27356c1d574b65dfd5603992065d82", "ftw-element.js": "7241b586582187cef2d76d3ee11bbc596c4f428cea3a5c8c84227e113aa3c1a0", - "ftw-energy-flow.js": "b13905437d6de36748d5559399017f6f5596500ec4ff0e8d54bb2352b8dcaf64", + "ftw-energy-flow.js": "ef5ca158df1397a776d75b0ba94807c1992fe55aa6763cda0a72458bf643cd8e", "ftw-price-chart.js": "1833d8008f06f2eb8f6e2b9b0bb6ff91aafa1f54b81ed249d57bb4fda968a736", "price-math.js": "bc6b104259f76d799c0a9d7f1d8a780d897cb7dc0d7a3e16a6572fb9c626d508", "price-strip.js": "413b2946c311e910c9a052a8407a3a403ed6caca0e210307c6f3e951896c2b9b", diff --git a/src/vendor/ftw/ftw-energy-flow.js b/src/vendor/ftw/ftw-energy-flow.js index 1e0c081..b42a01e 100644 --- a/src/vendor/ftw/ftw-energy-flow.js +++ b/src/vendor/ftw/ftw-energy-flow.js @@ -1,4 +1,4 @@ -// Vendored from srcfl/ftw web/components/ftw-energy-flow.js at b4d2488d41ff046356a6710b1d173e38cdc96a64. +// Vendored from srcfl/ftw web/components/ftw-energy-flow.js at cd68b44947322eb1da3b0a86310e15b5121896a3. // Do not edit here; change the box source, then copy it here. // // — hero diagram for /next. @@ -656,12 +656,21 @@ class FtwEnergyFlow extends FtwElement { !p.aggregated && (layerClass === "ind" || aggregateMemberCount > 1) && Math.max(p._groupSize || 1, aggregateMemberCount || 1) > 1; + const grouped = p._groupSize > 1 && !!p.name; return renderCircleNode({ pos: p._pos, - value: p.placeholder ? "—" : fmtKw(p.kw), + // A planet prints its size; the word under it gives the direction, + // because the UI never shows a raw minus. The hub keeps Core's sign + // for Home use (#1768). + value: p.placeholder ? "—" : fmtKw(Math.abs(p.kw)), title: p.title, - nameLabel: p._groupSize > 1 && p.name ? p.name.toUpperCase() : null, - sub: p.sub, + // The title's second line names the device in a group, or says + // that FTW only observes it; a phone's larger title font has room + // for one word. A grouped device keeps its name there and says + // "observe only" under the size instead. + nameLabel: grouped ? p.name.toUpperCase() + : p.observeOnly ? (this._compact ? "OBSERVED" : "OBSERVE ONLY") : null, + sub: grouped && p.observeOnly ? "observe only" : p.sub, color: p.color, soc: p.placeholder ? null : p.soc, chargeLimit: p.placeholder ? null : p.chargeLimit, @@ -1665,19 +1674,18 @@ function renderDailyParts(parts) { } function fmtKw(kw) { - // Input is kilowatts, signed as Core sends them; the bubble prints the - // size only, because the UI never shows a raw minus. The word under it - // ("charging", "discharging", "exporting") says the direction. Sub-kW - // values render as plain integer watts (no decimals) so a "30 W" import - // or a "12 W" battery trickle stays visible as the real number. The - // visual "idle / balanced" affordances (beam dimming, sub-label text) - // live on a separate ±FLOW_IDLE_W threshold; this formatter only handles - // display. + // Input is kilowatts: a size for a planet, Home use as Core signs it + // for the hub. Sub-kW values render as plain integer watts (no + // decimals) so a "30 W" import or "12 W" battery trickle stays + // visible as the real number. The visual "idle / balanced" + // affordances (beam dimming, sub-label text) live on a separate + // ±FLOW_IDLE_W threshold; this formatter only handles display. // // Sub-half-watt magnitudes round to 0 W — that's noise, not signal. - const size = Math.abs(kw); - if (size < 1) return `${Math.round(size * 1000)} W`; - return `${size.toFixed(2)} kW`; + // `+ 0` normalises Math.round's −0 result to plain 0 so a tiny + // negative reading doesn't print as "-0 W". + if (Math.abs(kw) < 1) return `${Math.round(kw * 1000) + 0} W`; + return `${kw.toFixed(2)} kW`; } // Collapse multi-planet corners into a single synthesized "combined"