From 92f2bd3d09cdc87223c0e73e76d8741ce39f4d73 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 13 Sep 2020 16:09:03 +0200 Subject: [PATCH] Download Tesla client id/secret if not configured (#332) * Download client id/secret if not configured * Change email to user to align with other vehicle apis --- go.mod | 1 + vehicle/tesla.go | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 78763413b..9c6999670 100644 --- a/go.mod +++ b/go.mod @@ -40,5 +40,6 @@ require ( github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e github.com/volkszaehler/mbmd v0.0.0-20200831092453-b235d6a65b21 golang.org/x/net v0.0.0-20200707034311-ab3426394381 + gopkg.in/ini.v1 v1.57.0 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c ) diff --git a/vehicle/tesla.go b/vehicle/tesla.go index 9bb5c9d1d..0ce56ef13 100644 --- a/vehicle/tesla.go +++ b/vehicle/tesla.go @@ -2,12 +2,14 @@ package vehicle import ( "errors" + "net/http" "time" "github.com/andig/evcc/api" "github.com/andig/evcc/provider" "github.com/andig/evcc/util" "github.com/jsgoecke/tesla" + "gopkg.in/ini.v1" ) // Tesla is an api.Vehicle implementation for Tesla cars @@ -28,19 +30,27 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) { Title string Capacity int64 ClientID, ClientSecret string - Email, Password string + User, Password string VIN string Cache time.Duration }{} - if err := util.DecodeOther(other, &cc); err != nil { return nil, err } + v := &Tesla{ + embed: &embed{cc.Title, cc.Capacity}, + } + + if cc.ClientID == "" { + // https://tesla-api.timdorr.com/api-basics/authentication + cc.ClientID, cc.ClientSecret = v.downloadClientID("https://pastebin.com/raw/pS7Z6yyP") + } + client, err := tesla.NewClient(&tesla.Auth{ ClientID: cc.ClientID, ClientSecret: cc.ClientSecret, - Email: cc.Email, + Email: cc.User, Password: cc.Password, }) if err != nil { @@ -52,10 +62,6 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) { return nil, err } - v := &Tesla{ - embed: &embed{cc.Title, cc.Capacity}, - } - if cc.VIN == "" && len(vehicles) == 1 { v.vehicle = vehicles[0].Vehicle } else { @@ -76,6 +82,23 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) { return v, nil } +// download client id and secret +func (v *Tesla) downloadClientID(uri string) (string, string) { + resp, err := http.Get(uri) + if err == nil { + defer resp.Body.Close() + + cfg, err := ini.Load(resp.Body) + if err == nil { + id := cfg.Section("").Key("TESLA_CLIENT_ID").String() + secret := cfg.Section("").Key("TESLA_CLIENT_SECRET").String() + return id, secret + } + } + + return "", "" +} + // chargeState implements the Vehicle.ChargeState interface func (v *Tesla) chargeState() (float64, error) { state, err := v.vehicle.ChargeState()