Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loadpoint: make default vehicle an eventual default (BC) #19412

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions core/coordinator/coordinator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package coordinator

import (
"slices"
"sync"

"github.com/evcc-io/evcc/api"
Expand Down Expand Up @@ -64,23 +65,20 @@ func (c *Coordinator) Add(vehicle api.Vehicle) {
func (c *Coordinator) Delete(vehicle api.Vehicle) {
c.mu.Lock()

for i, v := range c.vehicles {
if v == vehicle {
c.vehicles = append(c.vehicles[:i], c.vehicles[i+1:]...)
if i := slices.Index(c.vehicles, vehicle); i >= 0 {
c.vehicles = slices.Delete(c.vehicles, i, i)

if o, ok := c.tracked[vehicle]; ok {
// defer call to SetVehicle to avoid deadlock on c.mu
defer func(o loadpoint.API) {
o.SetVehicle(nil)
}(o)
}
delete(c.tracked, vehicle)

break
if o, ok := c.tracked[vehicle]; ok {
// defer call to SetVehicle to avoid deadlock on c.mu
defer func(o loadpoint.API) {
o.SetVehicle(nil)
}(o)
}

delete(c.tracked, vehicle)
}

// unlock before deferred SetVehicle executes a this will round-trip back here
// unlock before deferred SetVehicle executes as this will round-trip back here
c.mu.Unlock()
}

Expand Down
17 changes: 8 additions & 9 deletions core/loadpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ type Loadpoint struct {
circuit api.Circuit // Circuit
chargeMeter api.Meter // Charger usage meter
vehicle api.Vehicle // Currently active vehicle
defaultVehicle api.Vehicle // Default vehicle (disables detection)
defaultVehicle api.Vehicle // Default vehicle (eventually after detection)
coordinator coordinator.API
socEstimator *soc.Estimator

Expand Down Expand Up @@ -520,8 +520,12 @@ func (lp *Loadpoint) evVehicleDisconnectHandler() {
// set default mode on disconnect
lp.defaultMode()

// set default vehicle (may be nil)
lp.setActiveVehicle(lp.defaultVehicle)
// set default vehicle if poll always is selected
var v api.Vehicle
if lp.GetSocConfig().Poll.Mode == loadpoint.PollAlways {
v = lp.defaultVehicle
}
lp.setActiveVehicle(v)

// soc update reset
lp.socUpdated = time.Time{}
Expand Down Expand Up @@ -644,11 +648,6 @@ func (lp *Loadpoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
lp.publish(keys.VehicleName, "")
lp.publish(keys.VehicleOdometer, 0.0)

// assign and publish default vehicle
if lp.defaultVehicle != nil {
lp.setActiveVehicle(lp.defaultVehicle)
}

// reset detection state
lp.publish(keys.VehicleDetectionActive, false)

Expand Down Expand Up @@ -1063,7 +1062,7 @@ func (lp *Loadpoint) updateChargerStatus() (bool, error) {
for _, ev := range statusEvents(prevStatus, status) {
lp.bus.Publish(ev)

// send connect/disconnect events except during startup
// don't send connect/disconnect events during startup
if prevStatus != api.StatusNone {
switch ev {
case evVehicleConnect:
Expand Down
23 changes: 12 additions & 11 deletions core/loadpoint_vehicle.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ func (lp *Loadpoint) vehicleHasFeature(f api.Feature) bool {

// vehicleUnidentified returns true if there are associated vehicles and detection is running.
// It will also reset the api cache at regular intervals.
// Detection is stopped after maximum duration and the "guest vehicle" message dispatched.
// Detection is stopped after maximum duration. A this time the default vehicle is assigned
// or the "guest vehicle" message dispatched.
func (lp *Loadpoint) vehicleUnidentified() bool {
if lp.vehicle != nil || lp.vehicleDetect.IsZero() || len(lp.coordinatedVehicles()) == 0 {
return false
Expand All @@ -226,7 +227,11 @@ func (lp *Loadpoint) vehicleUnidentified() bool {
// stop detection
if lp.clock.Since(lp.vehicleDetect) > vehicleDetectDuration {
lp.stopVehicleDetection()
lp.pushEvent(evVehicleUnidentified)
if lp.defaultVehicle != nil {
lp.setActiveVehicle(lp.defaultVehicle)
} else {
lp.pushEvent(evVehicleUnidentified)
}
return false
}

Expand All @@ -243,16 +248,12 @@ func (lp *Loadpoint) vehicleUnidentified() bool {

// vehicleDefaultOrDetect will assign and update default vehicle or start detection
func (lp *Loadpoint) vehicleDefaultOrDetect() {
if lp.defaultVehicle != nil {
if lp.vehicle != lp.defaultVehicle {
lp.setActiveVehicle(lp.defaultVehicle)
} else {
// default vehicle is already active, update odometer anyway
// need to do this here since setActiveVehicle would short-circuit
lp.addTask(lp.vehicleOdometer)
}
} else if len(lp.coordinatedVehicles()) > 0 && lp.connected() {
// start detection if there are multiple vehicles or only one but no default vehicle
if cv := len(lp.coordinatedVehicles()); cv > 1 || cv == 1 && lp.defaultVehicle == nil {
lp.setActiveVehicle(nil)
lp.startVehicleDetection()
} else {
lp.setActiveVehicle(lp.defaultVehicle) // maybe nil
}
}

Expand Down
6 changes: 6 additions & 0 deletions core/loadpoint_vehicle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/benbjohnson/clock"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/core/coordinator"
"github.com/evcc-io/evcc/core/loadpoint"
"github.com/evcc-io/evcc/core/settings"
"github.com/evcc-io/evcc/core/soc"
"github.com/evcc-io/evcc/util"
Expand Down Expand Up @@ -192,6 +193,9 @@ func TestDefaultVehicle(t *testing.T) {
assert.Equal(t, vehicle, lp.vehicle, "expected vehicle "+title(vehicle))
assert.Equal(t, 6.0, lp.effectiveMinCurrent(), "current")

// disconnect sets default vehicle only if poll mode: always
lp.Soc.Poll.Mode = loadpoint.PollAlways

// non-default vehicle disconnected
lp.evVehicleDisconnectHandler()
assert.Equal(t, dflt, lp.vehicle, "expected default vehicle")
Expand All @@ -203,6 +207,8 @@ func TestDefaultVehicle(t *testing.T) {
assert.Equal(t, mode, lp.GetMode(), "mode")
assert.Equal(t, current, lp.effectiveMinCurrent(), "current")

lp.Soc.Poll.Mode = loadpoint.PollConnected

// set non-default vehicle during disconnect - should be default on connect
lp.tasks.Clear()
lp.evVehicleConnectHandler()
Expand Down
Loading