diff --git a/charger/twc3.go b/charger/twc3.go index 1ec03994c..416e8848b 100644 --- a/charger/twc3.go +++ b/charger/twc3.go @@ -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 diff --git a/core/loadpoint.go b/core/loadpoint.go index 80e6d5d94..0f9a85d50 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -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) } } diff --git a/vehicle/tesla.go b/vehicle/tesla.go index 2a9c9429c..62b9acf58 100644 --- a/vehicle/tesla.go +++ b/vehicle/tesla.go @@ -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_ == "" { diff --git a/vehicle/tesla/api_test.go b/vehicle/tesla/api_test.go index f67746925..19b02f359 100644 --- a/vehicle/tesla/api_test.go +++ b/vehicle/tesla/api_test.go @@ -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) } diff --git a/vehicle/tesla/controller.go b/vehicle/tesla/controller.go index 0152ca8ef..61cf046d0 100644 --- a/vehicle/tesla/controller.go +++ b/vehicle/tesla/controller.go @@ -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" ) @@ -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) @@ -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