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:
40
main.go
40
main.go
@@ -115,6 +115,12 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
// WW boost disable flag (persistent; presence of file = boost disabled)
|
||||
wwBoostDisabled := monitor.New(cfg.EMS.WWBoostDisableFile)
|
||||
if wwBoostDisabled.IsActive() {
|
||||
logger.Info("WW boost disabled via flag file", "flag_file", cfg.EMS.WWBoostDisableFile)
|
||||
}
|
||||
|
||||
// Trip mode manager (goal persistence + session learning)
|
||||
tripMgr := trip.New(cfg.EMS.TripGoalFile, cfg.EMS.SessionLogFile)
|
||||
if g := tripMgr.ActiveGoal(); g != nil {
|
||||
@@ -130,7 +136,7 @@ func main() {
|
||||
|
||||
// Status store (shared between HTTP handler and control loop)
|
||||
wwConfigured := cfg.Viessmann.InstallationID != ""
|
||||
statusStore := status.NewStore(*dryRun, wwConfigured, cfg.Strategic, monitorMode, tripMgr, carOptions)
|
||||
statusStore := status.NewStore(*dryRun, wwConfigured, cfg.Strategic, monitorMode, wwBoostDisabled, tripMgr, carOptions)
|
||||
|
||||
// Metrics HTTP server
|
||||
mux := http.NewServeMux()
|
||||
@@ -144,6 +150,7 @@ func main() {
|
||||
mux.HandleFunc("/trip", tripSetHandler(tripMgr, cfg, logger))
|
||||
mux.HandleFunc("/trip/cancel", tripCancelHandler(tripMgr, logger))
|
||||
mux.HandleFunc("/ww/reset", wwResetHandler(act, eng, cfg, logger))
|
||||
mux.HandleFunc("/ww/boost", wwBoostToggleHandler(wwBoostDisabled, logger))
|
||||
mux.HandleFunc("/", statusStore.Handler())
|
||||
|
||||
srv := &http.Server{
|
||||
@@ -172,12 +179,12 @@ func main() {
|
||||
logger.Info("EMS control loop started")
|
||||
|
||||
// Run once immediately
|
||||
runCycle(ctx, coll, eng, act, fc, m, statusStore, cfg, cfg.EMS.StateFile, logger, *dryRun, monitorMode, tripMgr)
|
||||
runCycle(ctx, coll, eng, act, fc, m, statusStore, cfg, cfg.EMS.StateFile, logger, *dryRun, monitorMode, wwBoostDisabled, tripMgr)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
runCycle(ctx, coll, eng, act, fc, m, statusStore, cfg, cfg.EMS.StateFile, logger, *dryRun, monitorMode, tripMgr)
|
||||
runCycle(ctx, coll, eng, act, fc, m, statusStore, cfg, cfg.EMS.StateFile, logger, *dryRun, monitorMode, wwBoostDisabled, tripMgr)
|
||||
|
||||
case sig := <-sigCh:
|
||||
logger.Info("received signal, shutting down", "signal", sig)
|
||||
@@ -204,6 +211,7 @@ func runCycle(
|
||||
logger *slog.Logger,
|
||||
dryRun bool,
|
||||
monitorMode *monitor.Mode,
|
||||
wwBoostDisabled *monitor.Mode,
|
||||
tripMgr *trip.Manager,
|
||||
) {
|
||||
now := time.Now()
|
||||
@@ -251,7 +259,10 @@ func runCycle(
|
||||
}
|
||||
|
||||
// Step 3: Run decision engine
|
||||
wwBoostC := computeWWBoost(fcResult, cfg)
|
||||
wwBoostC := 0.0
|
||||
if !wwBoostDisabled.IsActive() {
|
||||
wwBoostC = computeWWBoost(fcResult, cfg)
|
||||
}
|
||||
decisionStart := time.Now()
|
||||
actions := eng.Decide(state, now, wwBoostC)
|
||||
m.DecisionDuration.Observe(time.Since(decisionStart).Seconds())
|
||||
@@ -454,6 +465,27 @@ func tripCancelHandler(tm *trip.Manager, logger *slog.Logger) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// wwBoostToggleHandler toggles the WW boost disable flag on POST.
|
||||
func wwBoostToggleHandler(disabled *monitor.Mode, logger *slog.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
newState := !disabled.IsActive()
|
||||
if err := disabled.Set(newState); err != nil {
|
||||
logger.Error("WW boost toggle failed", "error", err)
|
||||
} else {
|
||||
if newState {
|
||||
logger.Info("WW boost disabled via web UI")
|
||||
} else {
|
||||
logger.Info("WW boost enabled via web UI")
|
||||
}
|
||||
}
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
// wwResetHandler resets the WW temperature to the configured base setpoint and
|
||||
// blocks further boosts for the rest of the day via an engine override.
|
||||
func wwResetHandler(act *actuator.Actuator, eng *engine.Engine, cfg *config.Config, logger *slog.Logger) http.HandlerFunc {
|
||||
|
||||
Reference in New Issue
Block a user