evcc-io/vehicle/tesla/provider.go
2026-03-01 17:47:36 +01:00

146 lines
3.4 KiB
Go

package tesla
import (
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/tesla-proxy-client"
)
type Provider struct {
dataG func() (*tesla.VehicleData, error)
wakeup func() (*tesla.Vehicle, error)
}
func NewProvider(vehicle *tesla.Vehicle, cache time.Duration) *Provider {
impl := &Provider{
dataG: util.Cached(func() (*tesla.VehicleData, error) {
res, err := vehicle.Data()
return res, apiError(err)
}, cache),
wakeup: func() (*tesla.Vehicle, error) {
res, err := vehicle.Wakeup()
return res, apiError(err)
},
}
return impl
}
// Soc implements the api.Vehicle interface
func (v *Provider) Soc() (float64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
return float64(res.Response.ChargeState.UsableBatteryLevel), nil
}
var _ api.ChargeState = (*Provider)(nil)
// Status implements the api.ChargeState interface
func (v *Provider) Status() (api.ChargeStatus, error) {
status := api.StatusA // disconnected
res, err := v.dataG()
if err != nil {
return status, err
}
switch res.Response.ChargeState.ChargingState {
case "Stopped", "NoPower", "Complete":
status = api.StatusB
case "Charging":
status = api.StatusC
}
return status, nil
}
var _ api.ChargeRater = (*Provider)(nil)
// ChargedEnergy implements the api.ChargeRater interface
func (v *Provider) ChargedEnergy() (float64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
return res.Response.ChargeState.ChargeEnergyAdded, nil
}
var _ api.VehicleRange = (*Provider)(nil)
// Range implements the api.VehicleRange interface
func (v *Provider) Range() (int64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
// miles to km
return int64(kmPerMile * res.Response.ChargeState.BatteryRange), nil
}
var _ api.VehicleOdometer = (*Provider)(nil)
const kmPerMile = 1.609344
// Odometer implements the api.VehicleOdometer interface
func (v *Provider) Odometer() (float64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
// miles to km
return kmPerMile * res.Response.VehicleState.Odometer, nil
}
var _ api.VehicleFinishTimer = (*Provider)(nil)
// FinishTime implements the api.VehicleFinishTimer interface
func (v *Provider) FinishTime() (time.Time, error) {
res, err := v.dataG()
if err != nil {
return time.Time{}, err
}
return time.Now().Add(time.Duration(res.Response.ChargeState.MinutesToFullCharge) * time.Minute), nil
}
var _ api.VehicleClimater = (*Provider)(nil)
// Climater implements the api.VehicleClimater interface
func (v *Provider) Climater() (bool, error) {
res, err := v.dataG()
if err != nil {
return false, err
}
return res.Response.ClimateState.IsPreconditioning, nil
}
var _ api.VehiclePosition = (*Provider)(nil)
// Position implements the api.VehiclePosition interface
func (v *Provider) Position() (float64, float64, error) {
res, err := v.dataG()
if err != nil {
return 0, 0, err
}
return res.Response.DriveState.Latitude, res.Response.DriveState.Longitude, nil
}
var _ api.SocLimiter = (*Provider)(nil)
// GetLimitSoc implements the api.SocLimiter interface
func (v *Provider) GetLimitSoc() (int64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
return int64(res.Response.ChargeState.ChargeLimitSoc), nil
}
var _ api.Resurrector = (*Provider)(nil)
// WakeUp implements the api.Resurrector interface
func (v *Provider) WakeUp() error {
_, err := v.wakeup()
return apiError(err)
}