Add EV charging advice notification to status page

Uses hourly PV forecast data (watts per hour from forecast.solar) to
find the first contiguous block of hours where:
  PV production - base_load_w >= min_surplus_w

Shows a blue advice card on the status page:
  "Auto einstecken bis HH:MM Uhr"
  "Erwartetes Überschuss-Fenster: HH:MM – HH:MM Uhr"

Card is hidden when:
- No surplus window found (weak forecast day)
- Window has already started or passed
- A wallbox is currently active (car already charging)

Config: forecast.base_load_w (1000W), forecast.min_surplus_w (1800W)
Timestamp parsing handles both "HH:MM:SS" and "HH:MM" key formats.
Today: surplus window 11:00–13:00 (24.3 kWh forecast).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 10:30:58 +02:00
parent 5f22df3e0f
commit 0020f1268b
4 changed files with 143 additions and 9 deletions

View File

@@ -131,12 +131,14 @@ type ForecastConfig struct {
Enabled bool `yaml:"enabled"`
Lat float64 `yaml:"lat"`
Lon float64 `yaml:"lon"`
Declination int `yaml:"declination"` // panel tilt in degrees
Azimuth int `yaml:"azimuth"` // degrees from south (south=0, west=90)
KWp float64 `yaml:"kwp"` // installed peak power
FetchInterval string `yaml:"fetch_interval"` // how often to re-fetch during the day (e.g. "4h")
FetchWindowStart string `yaml:"fetch_window_start"` // e.g. "07:00" — no fetches before this
FetchWindowEnd string `yaml:"fetch_window_end"` // e.g. "19:00" — no fetches after this
Declination int `yaml:"declination"` // panel tilt in degrees
Azimuth int `yaml:"azimuth"` // degrees from south (south=0, west=90)
KWp float64 `yaml:"kwp"` // installed peak power
FetchInterval string `yaml:"fetch_interval"` // how often to re-fetch during the day
FetchWindowStart string `yaml:"fetch_window_start"` // e.g. "07:00"
FetchWindowEnd string `yaml:"fetch_window_end"` // e.g. "19:00"
BaseLoadW float64 `yaml:"base_load_w"` // typical house consumption for surplus estimate (W)
MinSurplusW float64 `yaml:"min_surplus_w"` // min export needed to trigger wallbox charging (W)
}
func (f *ForecastConfig) FetchIntervalParsed() time.Duration {