evcc-io/vehicle/tesla/provider.go
2024-03-24 12:29:06 +01:00

140 lines
3.5 KiB
Go

package tesla
import (
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/provider"
"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: provider.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
}
// TODO api.Climater implementation has been removed as it drains battery. Re-check at a later time.
// 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
// }
// if res.Response.DriveState.Latitude != 0 || res.Response.DriveState.Longitude != 0 {
// return res.Response.DriveState.Latitude, res.Response.DriveState.Longitude, nil
// }
// return res.Response.DriveState.ActiveRouteLatitude, res.Response.DriveState.ActiveRouteLongitude, 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)
}