Add WW boost enable/disable toggle (persistent flag file)

In summer the WW boost interferes with car charging priority.
A new / toggle on the WW consumer card persists to
/etc/ems/ww-boost-off (presence = disabled, absence = enabled).

- config: ww_boost_disable_file flag file path
- main: wwBoostDisabled mode, wwBoostToggleHandler, runCycle skips
  computeWWBoost when disabled
- status: WWBoostDisabled in pageData, toggle button in WW card
  showing  Boost aus /  Boost ein depending on state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 16:09:33 +02:00
parent 1b57293da9
commit afbb7bf62c
4 changed files with 64 additions and 16 deletions

View File

@@ -59,25 +59,27 @@ type Store struct {
strategic config.StrategicConfig
consumers map[engine.Consumer]*consumerRecord
fcResult *forecast.Result
monitorMode *monitor.Mode
tripMgr *trip.Manager
carOptions []CarOption
monitorMode *monitor.Mode
wwBoostDisabled *monitor.Mode
tripMgr *trip.Manager
carOptions []CarOption
}
// NewStore creates a new status store.
func NewStore(dryRun bool, wwConfigured bool, strategic config.StrategicConfig, mode *monitor.Mode, tm *trip.Manager, cars []CarOption) *Store {
func NewStore(dryRun bool, wwConfigured bool, strategic config.StrategicConfig, mode *monitor.Mode, wwBoostDisabled *monitor.Mode, tm *trip.Manager, cars []CarOption) *Store {
consumers := make(map[engine.Consumer]*consumerRecord, len(consumerOrder))
for _, c := range consumerOrder {
consumers[c] = &consumerRecord{}
}
return &Store{
dryRun: dryRun,
wwConfigured: wwConfigured,
strategic: strategic,
consumers: consumers,
monitorMode: mode,
tripMgr: tm,
carOptions: cars,
dryRun: dryRun,
wwConfigured: wwConfigured,
strategic: strategic,
consumers: consumers,
monitorMode: mode,
wwBoostDisabled: wwBoostDisabled,
tripMgr: tm,
carOptions: cars,
}
}
@@ -179,6 +181,7 @@ type pageData struct {
ErrMsg string
DryRun bool
MonitorOnly bool
WWBoostDisabled bool
BatterySOC float64
GridPowerW float64
PVProductionW float64
@@ -261,6 +264,7 @@ func (s *Store) Handler() http.HandlerFunc {
}
monitorOnly := s.monitorMode != nil && s.monitorMode.IsActive()
wwBoostDisabled := s.wwBoostDisabled != nil && s.wwBoostDisabled.IsActive()
now := time.Now()
s.mu.RLock()
@@ -271,6 +275,7 @@ func (s *Store) Handler() http.HandlerFunc {
ErrMsg: s.errMsg,
DryRun: s.dryRun,
MonitorOnly: monitorOnly,
WWBoostDisabled: wwBoostDisabled,
BatterySOC: s.state.BatterySOC,
GridPowerW: s.state.GridPowerW,
PVProductionW: s.state.PVProductionW,
@@ -902,6 +907,15 @@ h1 { font-size: 1.4rem; font-weight: 700; color: #14532d; }
<button type="submit" class="override-btn turn-off" title="WW-Solltemperatur auf Basiswert zurücksetzen, Boost für heute sperren">🌡️ Zurücksetzen</button>
</form>
{{end}}
{{if .IsWW}}
<form method="post" action="/ww/boost" style="flex-shrink:0">
{{if .WWBoostDisabled}}
<button type="submit" class="override-btn turn-on" title="WW Boost durch PV-Überschuss wieder erlauben">✅ Boost ein</button>
{{else}}
<button type="submit" class="override-btn turn-off" title="WW Boost dauerhaft deaktivieren (z.B. im Sommer)">⛔ Boost aus</button>
{{end}}
</form>
{{end}}
</div>
{{end}}