diff --git a/core/site_optimizer.go b/core/site_optimizer.go index 0af96ef38..0b82b0d85 100644 --- a/core/site_optimizer.go +++ b/core/site_optimizer.go @@ -1237,6 +1237,15 @@ func applyPrecondition(lp loadpoint.API, demand []float32, minLen int) []float32 return demand } + // limit to the required charging duration, i.e. "all" must not demand beyond the plan goal + goal, _ := lp.GetPlanGoal() + if required := lp.GetPlanRequiredDuration(goal, lp.EffectiveMaxPower()); required < precondition { + precondition = required + } + if precondition <= 0 { + return demand + } + // TODO precise slot placement end := time.Until(ts) start := end - precondition diff --git a/core/site_optimizer_test.go b/core/site_optimizer_test.go index 634e90ebe..a459af0ab 100644 --- a/core/site_optimizer_test.go +++ b/core/site_optimizer_test.go @@ -47,6 +47,8 @@ func TestApplyPrecondition(t *testing.T) { // plan in 1h, 40min precondition: slots 1 (10min) and 2, 3 (full) lp.EXPECT().EffectivePlanTime().Return(time.Now().Add(time.Hour)).Times(1) lp.EXPECT().EffectivePlanStrategy().Return(api.PlanStrategy{Precondition: 40 * time.Minute}).Times(1) + lp.EXPECT().GetPlanGoal().Return(80.0, true).Times(1) + lp.EXPECT().GetPlanRequiredDuration(80.0, 8000.0).Return(2 * time.Hour).Times(1) res := applyPrecondition(lp, nil, 8) require.Len(t, res, 8) assert.InDeltaSlice(t, []float32{0, 2000. / 1.5, 2000, 2000, 0, 0, 0, 0}, res, 1) @@ -54,12 +56,32 @@ func TestApplyPrecondition(t *testing.T) { // existing demand is kept where higher lp.EXPECT().EffectivePlanTime().Return(time.Now().Add(time.Hour)).Times(1) lp.EXPECT().EffectivePlanStrategy().Return(api.PlanStrategy{Precondition: 30 * time.Minute}).Times(1) + lp.EXPECT().GetPlanGoal().Return(80.0, true).Times(1) + lp.EXPECT().GetPlanRequiredDuration(80.0, 8000.0).Return(2 * time.Hour).Times(1) res = applyPrecondition(lp, []float32{3000, 3000, 3000, 3000, 0, 0, 0, 0}, 8) assert.InDeltaSlice(t, []float32{3000, 3000, 3000, 3000, 0, 0, 0, 0}, res, 1) // plan beyond horizon lp.EXPECT().EffectivePlanTime().Return(time.Now().Add(24 * time.Hour)).Times(1) lp.EXPECT().EffectivePlanStrategy().Return(api.PlanStrategy{Precondition: time.Hour}).Times(1) + lp.EXPECT().GetPlanGoal().Return(80.0, true).Times(1) + lp.EXPECT().GetPlanRequiredDuration(80.0, 8000.0).Return(2 * time.Hour).Times(1) + assert.Nil(t, applyPrecondition(lp, nil, 8)) + + // "all" precondition is limited to the required charging duration (#33135) + lp.EXPECT().EffectivePlanTime().Return(time.Now().Add(time.Hour)).Times(1) + lp.EXPECT().EffectivePlanStrategy().Return(api.PlanStrategy{Precondition: 7 * 24 * time.Hour}).Times(1) + lp.EXPECT().GetPlanGoal().Return(80.0, true).Times(1) + lp.EXPECT().GetPlanRequiredDuration(80.0, 8000.0).Return(40 * time.Minute).Times(1) + res = applyPrecondition(lp, nil, 8) + require.Len(t, res, 8) + assert.InDeltaSlice(t, []float32{0, 2000. / 1.5, 2000, 2000, 0, 0, 0, 0}, res, 1) + + // goal already reached: no demand + lp.EXPECT().EffectivePlanTime().Return(time.Now().Add(time.Hour)).Times(1) + lp.EXPECT().EffectivePlanStrategy().Return(api.PlanStrategy{Precondition: 7 * 24 * time.Hour}).Times(1) + lp.EXPECT().GetPlanGoal().Return(80.0, true).Times(1) + lp.EXPECT().GetPlanRequiredDuration(80.0, 8000.0).Return(time.Duration(0)).Times(1) assert.Nil(t, applyPrecondition(lp, nil, 8)) }