Skip to content

Commit

Permalink
Planner: improve plan selection (#18211)
Browse files Browse the repository at this point in the history
  • Loading branch information
naltatis authored Jan 15, 2025
1 parent 8170191 commit 285b22e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 16 deletions.
47 changes: 31 additions & 16 deletions core/loadpoint_effective.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package core

import (
"sort"
"slices"
"time"

"github.com/evcc-io/evcc/api"
Expand Down Expand Up @@ -31,20 +31,39 @@ func (lp *Loadpoint) EffectivePriority() int {
return lp.GetPriority()
}

type plan struct {
Id int
Start time.Time // last possible start time
End time.Time // user-selected finish time
Soc int
}

func (lp *Loadpoint) nextActivePlan(maxPower float64, plans []plan) *plan {
for i, p := range plans {
requiredDuration := lp.GetPlanRequiredDuration(float64(p.Soc), maxPower)
plans[i].Start = p.End.Add(-requiredDuration)
}

// sort plans by start time
slices.SortStableFunc(plans, func(i, j plan) int {
return i.Start.Compare(j.Start)
})

if len(plans) > 0 {
return &plans[0]
}

return nil
}

// nextVehiclePlan returns the next vehicle plan time, soc and id
func (lp *Loadpoint) nextVehiclePlan() (time.Time, int, int) {
if v := lp.GetVehicle(); v != nil {
type plan struct {
Time time.Time
Soc int
Id int
}

var plans []plan

// static plan
if planTime, soc := vehicle.Settings(lp.log, v).GetPlanSoc(); soc != 0 {
plans = append(plans, plan{Id: 1, Soc: soc, Time: planTime})
plans = append(plans, plan{Id: 1, Soc: soc, End: planTime})
}

// repeating plans
Expand All @@ -59,16 +78,12 @@ func (lp *Loadpoint) nextVehiclePlan() (time.Time, int, int) {
continue
}

plans = append(plans, plan{Id: index + 2, Soc: rp.Soc, Time: time})
plans = append(plans, plan{Id: index + 2, Soc: rp.Soc, End: time})
}

// sort plans by time
sort.Slice(plans, func(i, j int) bool {
return plans[i].Time.Before(plans[j].Time)
})

if len(plans) > 0 {
return plans[0].Time, plans[0].Soc, plans[0].Id
// calculate earliest required plan start
if plan := lp.nextActivePlan(lp.EffectiveMaxPower(), plans); plan != nil {
return plan.End, plan.Soc, plan.Id
}
}
return time.Time{}, 0, 0
Expand Down
37 changes: 37 additions & 0 deletions core/loadpoint_effective_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package core

import (
"testing"
"time"

"github.com/benbjohnson/clock"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)

Expand Down Expand Up @@ -68,3 +71,37 @@ func TestEffectiveMinMaxCurrent(t *testing.T) {
assert.Equal(t, tc.effectiveMax, lp.effectiveMaxCurrent(), "max")
}
}

func TestNextPlan(t *testing.T) {
clock := clock.NewMock()

ctrl := gomock.NewController(t)
lp := NewLoadpoint(util.NewLogger("foo"), nil)
lp.charger = api.NewMockCharger(ctrl)

for _, tc := range []struct {
planId int
plans []plan
}{
{1, []plan{
{Id: 1, End: clock.Now().Add(8 * time.Hour), Soc: 10},
{Id: 2, End: clock.Now().Add(10 * time.Hour), Soc: 10},
}},
{1, []plan{
{Id: 1, End: clock.Now().Add(8 * time.Hour), Soc: 20},
{Id: 2, End: clock.Now().Add(9 * time.Hour), Soc: 20},
}},
{2, []plan{
{Id: 2, End: clock.Now().Add(8 * time.Hour), Soc: 20},
{Id: 1, End: clock.Now().Add(9 * time.Hour), Soc: 20},
}},
{2, []plan{
{Id: 1, End: clock.Now().Add(8 * time.Hour), Soc: 10},
{Id: 2, End: clock.Now().Add(10 * time.Hour), Soc: 60},
}},
} {
res := lp.nextActivePlan(1e4, tc.plans)
require.NotNil(t, res)
assert.Equal(t, tc.planId, res.Id)
}
}
1 change: 1 addition & 0 deletions tests/plan.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ test.describe("repeating", async () => {
const plan1 = modal.getByTestId("plan-entry").nth(0);
await plan1.getByTestId("static-plan-day").selectOption({ index: 1 });
await plan1.getByTestId("static-plan-time").fill("09:30");
await plan1.getByTestId("static-plan-soc").selectOption("80%");
await plan1.getByTestId("static-plan-active").click();

// add repeating plan for tomorrow
Expand Down

0 comments on commit 285b22e

Please sign in to comment.