112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
package vehicle
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/andig/evcc/api"
|
|
"github.com/andig/evcc/provider"
|
|
"github.com/andig/evcc/util"
|
|
"github.com/jsgoecke/tesla"
|
|
)
|
|
|
|
// Tesla is an api.Vehicle implementation for Tesla cars
|
|
type Tesla struct {
|
|
*embed
|
|
vehicle *tesla.Vehicle
|
|
chargeStateG func() (float64, error)
|
|
chargedEnergyG func() (float64, error)
|
|
}
|
|
|
|
// NewTeslaFromConfig creates a new Tesla vehicle
|
|
func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|
cc := struct {
|
|
Title string
|
|
Capacity int64
|
|
ClientID, ClientSecret string
|
|
Email, Password string
|
|
VIN string
|
|
Cache time.Duration
|
|
}{}
|
|
|
|
if err := util.DecodeOther(other, &cc); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client, err := tesla.NewClient(&tesla.Auth{
|
|
ClientID: cc.ClientID,
|
|
ClientSecret: cc.ClientSecret,
|
|
Email: cc.Email,
|
|
Password: cc.Password,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
vehicles, err := client.Vehicles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
v := &Tesla{
|
|
embed: &embed{cc.Title, cc.Capacity},
|
|
}
|
|
|
|
if cc.VIN == "" && len(vehicles) == 1 {
|
|
v.vehicle = vehicles[0].Vehicle
|
|
} else {
|
|
for _, vehicle := range vehicles {
|
|
if vehicle.Vin == cc.VIN {
|
|
v.vehicle = vehicle.Vehicle
|
|
}
|
|
}
|
|
}
|
|
|
|
if v.vehicle == nil {
|
|
return nil, errors.New("vin not found")
|
|
}
|
|
|
|
v.chargeStateG = provider.NewCached(v.chargeState, cc.Cache).FloatGetter()
|
|
v.chargedEnergyG = provider.NewCached(v.chargedEnergy, cc.Cache).FloatGetter()
|
|
|
|
return v, nil
|
|
}
|
|
|
|
// chargeState implements the Vehicle.ChargeState interface
|
|
func (v *Tesla) chargeState() (float64, error) {
|
|
state, err := v.vehicle.ChargeState()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return float64(state.BatteryLevel), nil
|
|
}
|
|
|
|
// ChargeState implements the Vehicle.ChargeState interface
|
|
func (v *Tesla) ChargeState() (float64, error) {
|
|
return v.chargeStateG()
|
|
}
|
|
|
|
// chargedEnergy implements the ChargeRater.ChargedEnergy interface
|
|
func (v *Tesla) chargedEnergy() (float64, error) {
|
|
state, err := v.vehicle.ChargeState()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return state.ChargeEnergyAdded, nil
|
|
}
|
|
|
|
// ChargedEnergy implements the ChargeRater.ChargedEnergy interface
|
|
func (v *Tesla) ChargedEnergy() (float64, error) {
|
|
return v.chargedEnergyG()
|
|
}
|
|
|
|
// depends on https://github.com/jsgoecke/tesla/issues/28
|
|
//
|
|
// CurrentPower implements the ChargeRater.CurrentPower interface
|
|
// func (v *Tesla) CurrentPower() (float64, error) {
|
|
// state, err := v.vehicle.ChargeState()
|
|
// if err != nil {
|
|
// return 0, err
|
|
// }
|
|
// return state.ChargerPower, err
|
|
// }
|