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

Custom vehicle: add limitsoc #13100

Merged
merged 4 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 1 addition & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ type CurrentLimiter interface {

// SocLimiter returns the soc limit
type SocLimiter interface {
// TODO rename LimitSoc
TargetSoc() (float64, error)
GetLimitSoc() (int64, error)
}

// VehicleChargeController allows to start/stop the charging session on the vehicle side
Expand Down
6 changes: 3 additions & 3 deletions cmd/dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ func (d *dumper) Dump(name string, v interface{}) {
}

if v, ok := v.(api.SocLimiter); ok {
if targetSoc, err := v.TargetSoc(); err != nil {
fmt.Fprintf(w, "Target Soc:\t%v\n", err)
if limitSoc, err := v.GetLimitSoc(); err != nil {
fmt.Fprintf(w, "Limit Soc:\t%v\n", err)
} else {
fmt.Fprintf(w, "Target Soc:\t%.0f%%\n", targetSoc)
fmt.Fprintf(w, "Limit Soc:\t%d%%\n", limitSoc)
}
}

Expand Down
10 changes: 5 additions & 5 deletions core/loadpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1421,19 +1421,19 @@ func (lp *Loadpoint) publishSocAndRange() {

// vehicle target soc
// TODO take vehicle api limits into account
targetSoc := 100
apiLimitSoc := 100
if vs, ok := lp.GetVehicle().(api.SocLimiter); ok {
if limit, err := vs.TargetSoc(); err == nil {
targetSoc = int(math.Trunc(limit))
lp.log.DEBUG.Printf("vehicle soc limit: %.0f%%", limit)
if limit, err := vs.GetLimitSoc(); err == nil {
apiLimitSoc = int(limit)
lp.log.DEBUG.Printf("vehicle soc limit: %d%%", limit)
lp.publish(keys.VehicleTargetSoc, limit)
naltatis marked this conversation as resolved.
Show resolved Hide resolved
} else if !errors.Is(err, api.ErrNotAvailable) {
lp.log.ERROR.Printf("vehicle soc limit: %v", err)
}
}

// use minimum of vehicle and loadpoint
limitSoc := min(targetSoc, lp.effectiveLimitSoc())
limitSoc := min(apiLimitSoc, lp.effectiveLimitSoc())

var d time.Duration
if lp.charging() {
Expand Down
2 changes: 1 addition & 1 deletion server/http_config_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func testInstance(instance any) map[string]testResult {
}

if dev, ok := instance.(api.SocLimiter); ok {
val, err := dev.TargetSoc()
val, err := dev.GetLimitSoc()
res["socLimit"] = makeResult(val, err)
}

Expand Down
6 changes: 3 additions & 3 deletions vehicle/bluelink/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,14 @@ func (v *Provider) Odometer() (float64, error) {

var _ api.SocLimiter = (*Provider)(nil)

// TargetSoc implements the api.SocLimiter interface
func (v *Provider) TargetSoc() (float64, error) {
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
res, err := v.statusG()

if err == nil {
for _, targetSOC := range res.EvStatus.ReservChargeInfos.TargetSocList {
if targetSOC.PlugType == plugTypeAC {
return float64(targetSOC.TargetSocLevel), nil
return int64(targetSOC.TargetSocLevel), nil
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions vehicle/saic/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ func (v *Provider) Odometer() (float64, error) {

var _ api.SocLimiter = (*Provider)(nil)

// TargetSoc implements the api.SocLimiter interface
func (v *Provider) TargetSoc() (float64, error) {
var result = 0
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
result := 0
res, err := v.status.Get()
if err != nil {
return 0, err
Expand All @@ -139,7 +139,7 @@ func (v *Provider) TargetSoc() (float64, error) {
result = TargetSocVals[res.ChrgMgmtData.BmsOnBdChrgTrgtSOCDspCmd]
}

return float64(result), err
return int64(result), err
}

var _ api.Resurrector = (*Provider)(nil)
Expand Down
6 changes: 3 additions & 3 deletions vehicle/seat/cupra/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ func (v *Provider) Climater() (bool, error) {

var _ api.SocLimiter = (*Provider)(nil)

// TargetSoc implements the api.SocLimiter interface
func (v *Provider) TargetSoc() (float64, error) {
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
res, err := v.statusG()
return float64(res.Services.Charging.TargetPct), err
return int64(res.Services.Charging.TargetPct), err
}

var _ api.VehicleChargeController = (*Provider)(nil)
Expand Down
6 changes: 3 additions & 3 deletions vehicle/skoda/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ func (v *Provider) Odometer() (odo float64, err error) {

var _ api.SocLimiter = (*Provider)(nil)

// TargetSoc implements the api.SocLimiter interface
func (v *Provider) TargetSoc() (float64, error) {
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
res, err := v.settingsG()
if err == nil {
return float64(res.TargetStateOfChargeInPercent), nil
return int64(res.TargetStateOfChargeInPercent), nil
}

return 0, err
Expand Down
6 changes: 3 additions & 3 deletions vehicle/tesla/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ func (v *Provider) FinishTime() (time.Time, error) {

var _ api.SocLimiter = (*Provider)(nil)

// TargetSoc implements the api.SocLimiter interface
func (v *Provider) TargetSoc() (float64, error) {
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
return float64(res.Response.ChargeState.ChargeLimitSoc), nil
return int64(res.Response.ChargeState.ChargeLimitSoc), nil
}

var _ api.Resurrector = (*Provider)(nil)
Expand Down
34 changes: 20 additions & 14 deletions vehicle/vehicle.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/evcc-io/evcc/util"
)

//go:generate go run ../cmd/tools/decorate.go -f decorateVehicle -b api.Vehicle -t "api.ChargeState,Status,func() (api.ChargeStatus, error)" -t "api.VehicleRange,Range,func() (int64, error)" -t "api.VehicleOdometer,Odometer,func() (float64, error)" -t "api.VehicleClimater,Climater,func() (bool, error)" -t "api.CurrentController,MaxCurrent,func(int64) error" -t "api.Resurrector,WakeUp,func() error"
//go:generate go run ../cmd/tools/decorate.go -f decorateVehicle -b api.Vehicle -t "api.SocLimiter,GetLimitSoc,func() (int64, error)" -t "api.ChargeState,Status,func() (api.ChargeStatus, error)" -t "api.VehicleRange,Range,func() (int64, error)" -t "api.VehicleOdometer,Odometer,func() (float64, error)" -t "api.VehicleClimater,Climater,func() (bool, error)" -t "api.CurrentController,MaxCurrent,func(int64) error" -t "api.Resurrector,WakeUp,func() error"

// Vehicle is an api.Vehicle implementation with configurable getters and setters.
type Vehicle struct {
Expand All @@ -25,6 +25,7 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Vehicle, error
var cc struct {
embed `mapstructure:",squash"`
Soc provider.Config
LimitSoc *provider.Config
Status *provider.Config
Range *provider.Config
Odometer *provider.Config
Expand All @@ -47,15 +48,24 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Vehicle, error
socG: socG,
}

// decorate range
var limitSoc func() (int64, error)
if cc.LimitSoc != nil {
limitSoc, err = provider.NewIntGetterFromConfig(*cc.LimitSoc)
if err != nil {
return nil, fmt.Errorf("limitSoc: %w", err)
}
}

// decorate status
var status func() (api.ChargeStatus, error)
if cc.Status != nil {
statusG, err := provider.NewStringGetterFromConfig(*cc.Status)
get, err := provider.NewStringGetterFromConfig(*cc.Status)
if err != nil {
return nil, fmt.Errorf("status: %w", err)
}
status = func() (api.ChargeStatus, error) {
s, err := statusG()
s, err := get()
if err != nil {
return api.StatusNone, err
}
Expand All @@ -66,56 +76,52 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Vehicle, error
// decorate range
var rng func() (int64, error)
if cc.Range != nil {
rangeG, err := provider.NewIntGetterFromConfig(*cc.Range)
rng, err = provider.NewIntGetterFromConfig(*cc.Range)
if err != nil {
return nil, fmt.Errorf("range: %w", err)
}
rng = rangeG
}

// decorate odometer
var odo func() (float64, error)
if cc.Odometer != nil {
odoG, err := provider.NewFloatGetterFromConfig(*cc.Odometer)
odo, err = provider.NewFloatGetterFromConfig(*cc.Odometer)
if err != nil {
return nil, fmt.Errorf("odometer: %w", err)
}
odo = odoG
}

// decorate climater
var climater func() (bool, error)
if cc.Climater != nil {
climateG, err := provider.NewBoolGetterFromConfig(*cc.Climater)
climater, err = provider.NewBoolGetterFromConfig(*cc.Climater)
if err != nil {
return nil, fmt.Errorf("climater: %w", err)
}
climater = climateG
}

// decorate maxCurrent
var maxCurrent func(int64) error
if cc.MaxCurrent != nil {
maxCurrentS, err := provider.NewIntSetterFromConfig("maxCurrent", *cc.MaxCurrent)
maxCurrent, err = provider.NewIntSetterFromConfig("maxCurrent", *cc.MaxCurrent)
if err != nil {
return nil, fmt.Errorf("maxCurrent: %w", err)
}
maxCurrent = maxCurrentS
}

// decorate wakeup
var wakeup func() error
if cc.Wakeup != nil {
wakeupS, err := provider.NewBoolSetterFromConfig("wakeup", *cc.Wakeup)
set, err := provider.NewBoolSetterFromConfig("wakeup", *cc.Wakeup)
if err != nil {
return nil, fmt.Errorf("wakeup: %w", err)
}
wakeup = func() error {
return wakeupS(true)
return set(true)
}
}

return decorateVehicle(v, status, rng, odo, climater, maxCurrent, wakeup), nil
return decorateVehicle(v, limitSoc, status, rng, odo, climater, maxCurrent, wakeup), nil
}

// Soc implements the api.Vehicle interface
Expand Down
Loading
Loading