UX-54: a Forecast tab with the sun, the house and each battery's level, per hour
checks / unit (pull_request) Successful in 48m29s
infra-pin / fresh (pull_request) Successful in 1s

A new tab beside Home and Batteries for today and tomorrow: the solar
forecast, the solar measured so far, the house's expected use and each
battery's expected level, with the plan's own charge and give blocks under it.

- Blocks are Home's: today's are the plan's `runs`, tomorrow's come from the
  same builders (`homeview.runs_for()`), in the plan lines' words.
- The sun is what solarfc reads; a daily total is spread over the bell and the
  tab says so. The house is HouseProfile.estimator(), as the plan reads it.
- The level is new: `daycurve.curve()` gives each battery the role
  `modetrade.decide()` gives it and moves it hour by hour inside the plan's
  floor and ceiling. It is an estimate and counts on `solar_trust_pct`.
- Built on request (`GET forecast`), no Home Assistant call. Measured solar is
  kept per hour in memory from the reading control already takes.
- A part not known yet is a note: modes off, no forecast, learning, no
  forecast for tomorrow, a monthly cycle, no level, stopped, shadow.

No decision, command, timing or option key changes. Found, not changed:
`dayplan.plan()` over-counts a state-only forecast (DECISIONS/UX-54).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
glenn schrooyen
2026-10-26 19:38:59 +01:00
co-authored by Claude
parent a1d07030f8
commit b6b2d1b184
16 changed files with 1912 additions and 11 deletions
+34 -1
View File
@@ -42,7 +42,7 @@
"applies": {"restart": {"name": "Geldt na een herstart"}, "now": {"name": "Geldt meteen"}},
"home": {
"app": {"name": "Batterij-add-on"},
"tabs": {"home": "Start", "batteries": "Batterijen", "settings": "Instellingen", "setup": "Installatie", "label": "Schermen"},
"tabs": {"home": "Start", "batteries": "Batterijen", "forecast": "Prognose", "settings": "Instellingen", "setup": "Installatie", "label": "Schermen"},
"now": {"name": "Nu", "description": "Elke 3 seconden bijgewerkt.", "solar": "Zonnepanelen", "house": "Huis", "grid": "Net", "batteries": "Batterijen"},
"plan": {
"name": "Plan voor vandaag",
@@ -65,6 +65,24 @@
"no_prices": {"description": "Geen prijzen voor vandaag, dus de grafiek toont alleen het plan."},
"list": "Het plan in woorden"
},
"forecast": {
"name": "Prognose",
"day": "Dag",
"today": "Vandaag",
"tomorrow": "Morgen",
"sun": "Zon en huis",
"unit": "kWh per uur",
"forecast": "Zonneprognose",
"measured": "Zon gemeten",
"house": "Huisverbruik",
"levels": "Laadniveau",
"table": "Uur per uur",
"hour": "Uur",
"solar": "Zon",
"got": "Gemeten",
"use": "Huis",
"loading": "De prognose wordt geladen."
},
"peak": {"name": "Piekgrens", "this_month": "Piek van deze maand", "limit": "Grens", "none": "Nog niets gemeten", "unreadable": "Nu niet leesbaar"},
"attention": {"name": "Vraagt aandacht", "nothing": "Niets om na te kijken", "to_look": "na te kijken", "details": "Details", "alarm": "Alarm", "warning": "Waarschuwing", "info": "Info"},
"control": {"name": "Regeling", "stop": "Regeling stoppen", "start": "Regeling starten", "maint_start": "Nu een batterijcyclus starten", "maint_abort": "Batterijcyclus stoppen", "docs": "Documentatie van de add-on", "more": "Meer acties"},
@@ -353,6 +371,21 @@
"period_unmeasured": "Een deel van dit kwartier is niet gemeten.",
"prices": {"now": "Prijs nu {eur} per kWh, alles inbegrepen.", "today": "Vandaag: laagste {lo} om {lo_at}, hoogste {hi} om {hi_at}.", "none": "Geen prijzen voor vandaag."},
"tomorrow": {"known": "De prijzen van morgen zijn binnen.", "unknown": "De prijzen van morgen komen meestal na 13:00."},
"day": {
"modes_off": "Batterijmodi staan uit. Er wordt geen prognose gelezen en geen niveau gepland.",
"not_set": "Er is geen zonneprognose ingesteld. Zonder prognose wordt geen laadniveau gepland.",
"no_forecast": "De zonneprognose ontbreekt of is te oud. De niveaus komen terug als ze er weer is.",
"learning": "De add-on leert het verbruik van uw huis. De niveaus starten na één volle dag.",
"no_tomorrow": "Er is nog geen zonneprognose voor morgen. De niveaus stoppen bij zonsopgang.",
"estimate": "De prognose geeft één totaal voor de dag. De add-on verdeelt het over de uren.",
"trust": "De niveaus rekenen op {pct} % van de prognose.",
"cycle": "{name} doet de maandelijkse cyclus. Het niveau wordt niet getoond vanaf de start.",
"no_level": "{name} geeft nog geen laadniveau door. De niveaus worden niet getoond.",
"measured_from": "Gemeten zon telt vanaf {at}, toen de add-on startte.",
"tomorrow_total": "Verwachte zon morgen: {kwh}, we rekenen op {count}.",
"no_blocks": "Geen laad- of leverblokken gepland.",
"ahead": "De add-on plant prijzen ongeveer een dag vooruit. Blokken voor latere uren verschijnen als ze naderen."
},
"region": {"preset": "Heffingen en btw: {region}, cijfers van {year}.", "own": "Heffingen en btw: uw eigen bedrag."},
"peak_not_covered": "Geen piekgrens: deze meter meet geen kwartieren.",
"control": {"shadow": "Schaduwmodus: elke omvormer blijft op 0 W.", "running": "De regeling is actief.", "stopped": "De regeling is gestopt. Elke omvormer staat op 0 W."},