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

Twc+Tesla: let loadpoint ignore error to perform wakeup #8284

Merged
merged 8 commits into from
Jun 10, 2023
Merged
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
8 changes: 8 additions & 0 deletions api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ type errTimeoutError struct{}
func (errTimeoutError) Error() string { return "timeout" }
func (errTimeoutError) Timeout() bool { return true }
func (errTimeoutError) Temporary() bool { return true }

// ErrAsleep indicates that vehicle is asleep. Caller may chose to wake up the vehicle and retry.
var ErrAsleep error = errAsleep{}

type errAsleep struct{}

func (errAsleep) Error() string { return "asleep" }
func (errAsleep) Unwrap() error { return ErrTimeout }
8 changes: 8 additions & 0 deletions core/loadpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,14 @@ func (lp *Loadpoint) setLimit(chargeCurrent float64, force bool) error {
}

if err != nil {
v := lp.GetVehicle()
if vv, ok := v.(api.Resurrector); ok && errors.Is(err, api.ErrAsleep) {
// https://github.com/evcc-io/evcc/issues/8254
// wakeup vehicle
lp.log.DEBUG.Printf("max charge current: waking up vehicle")
return vv.WakeUp()
}

return fmt.Errorf("max charge current %.3gA: %w", chargeCurrent, err)
}

Expand Down
54 changes: 21 additions & 33 deletions vehicle/tesla.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package vehicle

import (
"context"
"errors"
"time"

"github.com/bogosj/tesla"
Expand Down Expand Up @@ -76,20 +77,29 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
v.Title_ = v.vehicle.DisplayName
}

v.dataG = provider.Cached(v.vehicle.Data, cc.Cache)
v.dataG = provider.Cached(func() (*tesla.VehicleData, error) {
res, err := v.vehicle.Data()
return res, v.apiError(err)
}, cc.Cache)

return v, nil
}

// apiError converts HTTP 408 error to ErrTimeout
func (v *Tesla) apiError(err error) error {
if err != nil && err.Error() == "408 Request Timeout" {
err = api.ErrAsleep
}
return err
}

// Soc implements the api.Vehicle interface
func (v *Tesla) Soc() (float64, error) {
res, err := v.dataG()

if err == nil {
return float64(res.Response.ChargeState.UsableBatteryLevel), nil
if err != nil {
return 0, err
}

return 0, err
return float64(res.Response.ChargeState.UsableBatteryLevel), nil
}

var _ api.ChargeState = (*Tesla)(nil)
Expand Down Expand Up @@ -188,51 +198,29 @@ var _ api.CurrentLimiter = (*Tesla)(nil)

// StartCharge implements the api.VehicleChargeController interface
func (v *Tesla) MaxCurrent(current int64) error {
return v.vehicle.SetChargingAmps(int(current))
return v.apiError(v.vehicle.SetChargingAmps(int(current)))
}

var _ api.Resurrector = (*Tesla)(nil)

func (v *Tesla) WakeUp() error {
_, err := v.vehicle.Wakeup()
return err
return v.apiError(err)
}

var _ api.VehicleChargeController = (*Tesla)(nil)

// StartCharge implements the api.VehicleChargeController interface
func (v *Tesla) StartCharge() error {
err := v.vehicle.StartCharging()

if err != nil && err.Error() == "408 Request Timeout" {
if _, err := v.vehicle.Wakeup(); err != nil {
return err
}

timer := time.NewTimer(90 * time.Second)

for {
select {
case <-timer.C:
return api.ErrTimeout
default:
time.Sleep(2 * time.Second)
if err := v.vehicle.StartCharging(); err == nil || err.Error() != "408 Request Timeout" {
return err
}
}
}
}

return err
return v.apiError(v.vehicle.StartCharging())
}

// StopCharge implements the api.VehicleChargeController interface
func (v *Tesla) StopCharge() error {
err := v.vehicle.StopCharging()
err := v.apiError(v.vehicle.StopCharging())

// ignore sleeping vehicle
if err != nil && err.Error() == "408 Request Timeout" {
if errors.Is(err, api.ErrAsleep) {
err = nil
}

Expand Down