Skip to content

Commit

Permalink
Make vehicles config global instead of per loadpoint (BC) (#3827)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Aug 13, 2022
1 parent 3db40ac commit 1464b75
Show file tree
Hide file tree
Showing 21 changed files with 297 additions and 178 deletions.
8 changes: 4 additions & 4 deletions cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func runDump(cmd *cobra.Command, args []string) {
}
}

for _, v := range site.GetVehicles() {
d.DumpWithHeader(fmt.Sprintf("vehicle: %s", v.Title()), v)
}

for id, lpI := range site.LoadPoints() {
lp := lpI.(*core.LoadPoint)

Expand All @@ -86,9 +90,5 @@ func runDump(cmd *cobra.Command, args []string) {
if name := lp.ChargerRef; name != "" {
d.DumpWithHeader(fmt.Sprintf("charger: %s", name), cp.Charger(name))
}

for id, v := range lp.VehiclesRef {
d.DumpWithHeader(fmt.Sprintf("vehicle %d", id), cp.Vehicle(v))
}
}
}
12 changes: 9 additions & 3 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/pipe"
"github.com/evcc-io/evcc/util/sponsor"
"github.com/samber/lo"
"github.com/spf13/viper"
"golang.org/x/text/currency"
)
Expand Down Expand Up @@ -196,15 +197,20 @@ func configureSiteAndLoadpoints(conf config) (site *core.Site, err error) {
}

if err == nil {
site, err = configureSite(conf.Site, cp, loadPoints, tariffs)
// list of vehicles
vehicles := lo.MapToSlice(cp.vehicles, func(_ string, v api.Vehicle) api.Vehicle {
return v
})

site, err = configureSite(conf.Site, cp, loadPoints, vehicles, tariffs)
}
}

return site, err
}

func configureSite(conf map[string]interface{}, cp *ConfigProvider, loadPoints []*core.LoadPoint, tariffs tariff.Tariffs) (*core.Site, error) {
site, err := core.NewSiteFromConfig(log, cp, conf, loadPoints, tariffs)
func configureSite(conf map[string]interface{}, cp *ConfigProvider, loadPoints []*core.LoadPoint, vehicles []api.Vehicle, tariffs tariff.Tariffs) (*core.Site, error) {
site, err := core.NewSiteFromConfig(log, cp, conf, loadPoints, vehicles, tariffs)
if err != nil {
return nil, fmt.Errorf("failed configuring site: %w", err)
}
Expand Down
77 changes: 0 additions & 77 deletions core/coordinator.go

This file was deleted.

36 changes: 36 additions & 0 deletions core/coordinator/adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package coordinator

import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/core/loadpoint"
)

type adapter struct {
lp loadpoint.API
c *Coordinator
}

// NewAdapter exposes the coordinator for a given loadpoint.
// Using an adapter simplifies the method signatures seen from the loadpoint.
func NewAdapter(lp loadpoint.API, c *Coordinator) API {
return &adapter{
lp: lp,
c: c,
}
}

func (a *adapter) GetVehicles() []api.Vehicle {
return a.c.GetVehicles()
}

func (a *adapter) Acquire(v api.Vehicle) {
a.c.acquire(a.lp, v)
}

func (a *adapter) Release(v api.Vehicle) {
a.c.release(v)
}

func (a *adapter) IdentifyVehicleByStatus() api.Vehicle {
return a.c.identifyVehicleByStatus(a.lp)
}
11 changes: 11 additions & 0 deletions core/coordinator/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package coordinator

import "github.com/evcc-io/evcc/api"

// API is the coordinator API
type API interface {
GetVehicles() []api.Vehicle
Acquire(api.Vehicle)
Release(api.Vehicle)
IdentifyVehicleByStatus() api.Vehicle
}
84 changes: 84 additions & 0 deletions core/coordinator/coordinator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package coordinator

import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/core/loadpoint"
"github.com/evcc-io/evcc/util"
)

// Coordinator coordinates vehicle access between loadpoints
type Coordinator struct {
log *util.Logger
vehicles []api.Vehicle
tracked map[api.Vehicle]loadpoint.API
}

// New creates a coordinator for a set of vehicles
func New(log *util.Logger, vehicles []api.Vehicle) *Coordinator {
return &Coordinator{
log: log,
vehicles: vehicles,
tracked: make(map[api.Vehicle]loadpoint.API),
}
}

func (c *Coordinator) GetVehicles() []api.Vehicle {
return c.vehicles
}

func (c *Coordinator) acquire(owner loadpoint.API, vehicle api.Vehicle) {
if o, ok := c.tracked[vehicle]; ok && o != owner {
o.SetVehicle(nil)
}
c.tracked[vehicle] = owner
}

func (c *Coordinator) release(vehicle api.Vehicle) {
delete(c.tracked, vehicle)
}

// availableDetectibleVehicles is the list of vehicles that are currently not
// associated to another loadpoint and have a status api that allows for detection
func (c *Coordinator) availableDetectibleVehicles(owner loadpoint.API) []api.Vehicle {
var res []api.Vehicle

for _, vv := range c.vehicles {
if _, ok := vv.(api.ChargeState); ok {
if o, ok := c.tracked[vv]; o == owner || !ok {
res = append(res, vv)
}
}
}

return res
}

// identifyVehicleByStatus finds active vehicle by charge state
func (c *Coordinator) identifyVehicleByStatus(owner loadpoint.API) api.Vehicle {
available := c.availableDetectibleVehicles(owner)

var res api.Vehicle
for _, vehicle := range available {
if vs, ok := vehicle.(api.ChargeState); ok {
status, err := vs.Status()
if err != nil {
c.log.ERROR.Println("vehicle status:", err)
continue
}

c.log.DEBUG.Printf("vehicle status: %s (%s)", status, vehicle.Title())

// vehicle is plugged or charging, so it should be the right one
if status == api.StatusB || status == api.StatusC {
if res != nil {
c.log.WARN.Println("vehicle status: >1 matches, giving up")
return nil
}

res = vehicle
}
}
}

return res
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core
package coordinator

import (
"testing"
Expand Down Expand Up @@ -38,8 +38,8 @@ func TestVehicleDetectByStatus(t *testing.T) {
log := util.NewLogger("foo")
vehicles := []api.Vehicle{v1, v2}

lp := &LoadPoint{}
c := &vehicleCoordinator{make(map[api.Vehicle]loadpoint.API)}
var lp loadpoint.API
c := New(log, vehicles)

for _, tc := range tc {
t.Logf("%+v", tc)
Expand All @@ -49,7 +49,7 @@ func TestVehicleDetectByStatus(t *testing.T) {
v1.MockVehicle.EXPECT().Title().Return("v1").AnyTimes()
v2.MockVehicle.EXPECT().Title().Return("v2").AnyTimes()

res := c.identifyVehicleByStatus(log, lp, vehicles)
res := c.identifyVehicleByStatus(lp)
if tc.res != res {
t.Errorf("expected %v, got %v", tc.res, res)
}
Expand Down
24 changes: 24 additions & 0 deletions core/coordinator/dummy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package coordinator

import (
"github.com/evcc-io/evcc/api"
)

type dummy struct{}

// NewDummy creates a dummy coordinator without vehicles
func NewDummy() API {
return &dummy{}
}

func (a *dummy) GetVehicles() []api.Vehicle {
return nil
}

func (a *dummy) Acquire(v api.Vehicle) {}

func (a *dummy) Release(v api.Vehicle) {}

func (a *dummy) IdentifyVehicleByStatus() api.Vehicle {
return nil
}
Loading

0 comments on commit 1464b75

Please sign in to comment.