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

Tesla: validate vehicle current #13099

Merged
merged 4 commits into from
Mar 24, 2024
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
12 changes: 12 additions & 0 deletions charger/twc3.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,18 @@ func (c *Twc3) MaxCurrent(current int64) error {
return v.MaxCurrent(current)
}

var _ api.CurrentGetter = (*Twc3)(nil)

// GetMaxCurrent implements the api.CurrentGetter interface
func (c *Twc3) GetMaxCurrent() (float64, error) {
v, ok := c.lp.GetVehicle().(api.CurrentGetter)
if !ok {
return 0, api.ErrNotAvailable
}

return v.GetMaxCurrent()
}

var _ api.ChargeRater = (*Twc3)(nil)

// ChargedEnergy implements the api.ChargeRater interface
Expand Down
21 changes: 10 additions & 11 deletions core/loadpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,18 +689,17 @@ func (lp *Loadpoint) syncCharger() error {
if enabled == lp.enabled {
// sync max current
if charger, ok := lp.charger.(api.CurrentGetter); ok && enabled {
current, err := charger.GetMaxCurrent()
if err != nil {
return fmt.Errorf("charger get max current: %w", err)
}

// smallest adjustment most PWM-Controllers can do is: 100%÷256×0,6A = 0.234A
if math.Abs(lp.chargeCurrent-current) > 0.23 {
if lp.chargerUpdateCompleted() {
lp.log.WARN.Printf("charger logic error: current mismatch (got %.3gA, expected %.3gA)", current, lp.chargeCurrent)
if current, err := charger.GetMaxCurrent(); err == nil {
// smallest adjustment most PWM-Controllers can do is: 100%÷256×0,6A = 0.234A
if math.Abs(lp.chargeCurrent-current) > 0.23 {
if lp.chargerUpdateCompleted() {
lp.log.WARN.Printf("charger logic error: current mismatch (got %.3gA, expected %.3gA)", current, lp.chargeCurrent)
}
lp.chargeCurrent = current
lp.bus.Publish(evChargeCurrent, lp.chargeCurrent)
}
lp.chargeCurrent = current
lp.bus.Publish(evChargeCurrent, lp.chargeCurrent)
} else if !errors.Is(err, api.ErrNotAvailable) {
return fmt.Errorf("charger get max current: %w", err)
}
}

Expand Down
2 changes: 1 addition & 1 deletion vehicle/tesla.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
v := &Tesla{
embed: &cc.embed,
Provider: tesla.NewProvider(vehicle, cc.Cache),
Controller: tesla.NewController(vehicle.WithClient(tcc)),
Controller: tesla.NewController(vehicle, vehicle.WithClient(tcc)),
}

if v.Title_ == "" {
Expand Down
2 changes: 1 addition & 1 deletion vehicle/tesla/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ func TestCommandResponse(t *testing.T) {
v, err := client.Vehicle("abc")
require.NoError(t, err)

require.ErrorIs(t, NewController(v).ChargeEnable(true), api.ErrAsleep)
require.ErrorIs(t, NewController(v, v).ChargeEnable(true), api.ErrAsleep)
}
32 changes: 28 additions & 4 deletions vehicle/tesla/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package tesla
import (
"errors"
"slices"
"time"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/provider"
"github.com/evcc-io/evcc/util/sponsor"
"github.com/evcc-io/tesla-proxy-client"
)
Expand All @@ -13,14 +15,26 @@ const ProxyBaseUrl = "https://tesla.evcc.io"

type Controller struct {
vehicle *tesla.Vehicle
current int64
dataG provider.Cacheable[float64]
}

// NewController creates a vehicle current and charge controller
func NewController(vehicle *tesla.Vehicle) *Controller {
impl := &Controller{
vehicle: vehicle,
func NewController(ro, rw *tesla.Vehicle) *Controller {
v := &Controller{
vehicle: rw,
}
return impl

v.dataG = provider.ResettableCached(func() (float64, error) {
if v.current >= 6 {
// assume match above 6A to save API requests
return float64(v.current), nil
}
res, err := ro.Data()
return float64(res.Response.ChargeState.ChargeAmps), apiError(err)
}, time.Minute)

return v
}

var _ api.CurrentController = (*Controller)(nil)
Expand All @@ -31,9 +45,19 @@ func (v *Controller) MaxCurrent(current int64) error {
return api.ErrSponsorRequired
}

v.current = current
v.dataG.Reset()

return apiError(v.vehicle.SetChargingAmps(int(current)))
}

var _ api.CurrentGetter = (*Controller)(nil)

// StartCharge implements the api.VehicleChargeController interface
func (v *Controller) GetMaxCurrent() (float64, error) {
return v.dataG.Get()
}

var _ api.ChargeController = (*Controller)(nil)

// ChargeEnable implements the api.ChargeController interface
Expand Down
Loading