Add ambient temperature gate to heating period detection
Adds heating_min_ambient_c (default 15°C) to season config. When outdoor temperature is at or above this threshold, SG-Ready is suppressed even if the calendar month is within the heating season. Prevents unnecessary heat pump boost activation on warm spring/autumn days. Logic: heating active = in_heating_month AND ambient < threshold Zero value (unset) disables the temperature gate (calendar-only, old behaviour). New test: TestHeatingPeriodAmbientSuppression covers warm-day suppression, cold-day pass-through, and summer month independence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -107,7 +107,7 @@ func (e *Engine) Decide(state collector.SystemState, now time.Time, wwBoostC flo
|
||||
|
||||
soc := state.BatterySOC
|
||||
gridW := state.GridPowerW // positive = import, negative = export
|
||||
heatingPeriod := e.isHeatingPeriod(now)
|
||||
heatingPeriod := e.isHeatingPeriod(now, state.AmbientTempC)
|
||||
wwWindow := e.isWWWindow(now)
|
||||
allowed := e.allowedConsumers(soc)
|
||||
|
||||
@@ -502,17 +502,37 @@ func (e *Engine) ApplyOverride(consumer Consumer, on bool, duration time.Duratio
|
||||
)
|
||||
}
|
||||
|
||||
// isHeatingPeriod returns true if the current month is within the heating season.
|
||||
func (e *Engine) isHeatingPeriod(now time.Time) bool {
|
||||
// isHeatingPeriod returns true if heating is appropriate given the current month
|
||||
// and outdoor temperature. If HeatingMinAmbientC is configured (> 0), ambient
|
||||
// temperatures above that threshold suppress SG-Ready even within the heating months.
|
||||
func (e *Engine) isHeatingPeriod(now time.Time, ambientC float64) bool {
|
||||
month := int(now.Month())
|
||||
start := e.cfg.Season.HeatingStartMonth
|
||||
end := e.cfg.Season.HeatingEndMonth
|
||||
|
||||
// Handles wrap-around: e.g. October(10) to April(4)
|
||||
var inMonth bool
|
||||
if start > end {
|
||||
return month >= start || month <= end
|
||||
inMonth = month >= start || month <= end
|
||||
} else {
|
||||
inMonth = month >= start && month <= end
|
||||
}
|
||||
return month >= start && month <= end
|
||||
|
||||
if !inMonth {
|
||||
return false
|
||||
}
|
||||
|
||||
// Temperature override: warm day within heating months → not a heating day
|
||||
threshold := e.cfg.Season.HeatingMinAmbientC
|
||||
if threshold > 0 && ambientC >= threshold {
|
||||
e.logger.Debug("heating period suppressed by ambient temperature",
|
||||
"ambient_c", ambientC,
|
||||
"threshold_c", threshold,
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// minRuntime returns the minimum runtime for a consumer.
|
||||
|
||||
Reference in New Issue
Block a user