Seat: fix retrieving list of vehicles (#9703)

This commit is contained in:
andig 2023-09-07 13:56:58 +02:00 • committed by GitHub
parent cec3de4770
commit a42affd827
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 16 deletions

View file

@ -8,7 +8,6 @@ import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/vehicle/seat"
"github.com/evcc-io/evcc/vehicle/seat/cupra"
"github.com/evcc-io/evcc/vehicle/vag/service"
"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
@ -51,7 +50,7 @@ func NewCupraFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("cupra").Redact(cc.User, cc.Password, cc.VIN)
ts, err := service.TokenRefreshServiceTokenSource(log, seat.TRSParams, seat.AuthParams, cc.User, cc.Password)
ts, err := service.TokenRefreshServiceTokenSource(log, cupra.TRSParams, cupra.AuthParams, cc.User, cc.Password)
if err != nil {
return nil, err
}

View file

@ -1,14 +1,22 @@
package vehicle
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/vehicle/seat"
"github.com/evcc-io/evcc/vehicle/seat/cupra"
"github.com/evcc-io/evcc/vehicle/vag/service"
"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
"github.com/evcc-io/evcc/vehicle/vw"
"golang.org/x/oauth2"
)
// https://github.com/trocotronic/weconnect
@ -50,18 +58,36 @@ func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("seat").Redact(cc.User, cc.Password, cc.VIN)
trs, err := service.TokenRefreshServiceTokenSource(log, seat.TRSParams, seat.AuthParams, cc.User, cc.Password)
trs, err := service.TokenRefreshServiceTokenSource(log, cupra.TRSParams, cupra.AuthParams, cc.User, cc.Password)
if err != nil {
return nil, err
}
ts := service.MbbTokenSource(log, trs, seat.AuthClientID)
api := vw.NewAPI(log, ts, seat.Brand, seat.Country)
api.Client.Timeout = cc.Timeout
// get OIDC user information
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))
ui, err := vwidentity.Config.NewProvider(ctx).UserInfo(ctx, trs)
if err != nil {
return nil, fmt.Errorf("failed getting user information: %w", err)
}
cc.VIN, err = ensureVehicle(cc.VIN, api.Vehicles)
mbbId, err := mbbUserId(log, trs, ui.Subject)
if err != nil {
return nil, fmt.Errorf("failed getting mbbUserId: %w", err)
}
ts := service.MbbTokenSource(log, trs, seat.AuthClientID)
api := seat.NewAPI(log, ts)
cc.VIN, err = ensureVehicle(
cc.VIN, func() ([]string, error) {
return api.Vehicles(mbbId)
},
)
if err == nil {
api := vw.NewAPI(log, ts, seat.Brand, seat.Country)
api.Client.Timeout = cc.Timeout
if err = api.HomeRegion(cc.VIN); err == nil {
v.Provider = vw.NewProvider(api, cc.VIN, cc.Cache)
}
@ -69,3 +95,28 @@ func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return v, err
}
func mbbUserId(log *util.Logger, ts oauth2.TokenSource, uid string) (string, error) {
client := request.NewHelper(log)
client.Transport = &oauth2.Transport{
Source: ts,
Base: client.Transport,
}
data := url.Values{
"scopeId": []string{"commonMandatoryFields"},
}
var mandatoryConsentInfo struct {
MbbUserId string `json:"mbbUserId"`
}
uri := fmt.Sprintf("https://profileintegrityservice.apps.emea.vwapps.io/iaa/pic/v1/users/%s/check-profile", uid)
req, err := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), request.URLEncoding)
if err == nil {
err = client.DoJSON(req, &mandatoryConsentInfo)
}
return mandatoryConsentInfo.MbbUserId, err
}

53
vehicle/seat/api.go Normal file
View file

@ -0,0 +1,53 @@
package seat
import (
"fmt"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"golang.org/x/oauth2"
)
// BaseURL is the API base url
const BaseURL = "https://mal-3a.prd.eu.dp.vwg-connect.com/api"
// API provides list of vehicles for Seat cars
type API struct {
*request.Helper
}
// NewAPI creates a new vehicle
func NewAPI(log *util.Logger, ts oauth2.TokenSource) *API {
v := &API{
Helper: request.NewHelper(log),
}
v.Client.Transport = &oauth2.Transport{
Source: ts,
Base: v.Client.Transport,
}
return v
}
// Vehicles implements the /vehicles response
func (v *API) Vehicles(userID string) ([]string, error) {
var res struct {
UserVehicles struct {
UserId string
Vehicle []struct {
Content string
}
}
}
uri := fmt.Sprintf("%s/usermanagement/users/v2/users/%s/vehicles", BaseURL, userID)
err := v.GetJSON(uri, &res)
var vehicles []string
for _, v := range res.UserVehicles.Vehicle {
vehicles = append(vehicles, v.Content)
}
return vehicles, err
}

View file

@ -0,0 +1,16 @@
package cupra
import "net/url"
// Authorization parameters
var AuthParams = url.Values{
"response_type": {"code id_token"}, // token
"client_id": {"30e33736-c537-4c72-ab60-74a7b92cfe83@apps_vw-dilab_com"},
"redirect_uri": {"cupraconnect://identity-kit/login"},
"scope": {"openid profile mbb"}, // cars birthdate nickname address phone
}
// TokenRefreshService parameters
var TRSParams = url.Values{
"brand": {"cupra"},
}

View file

@ -7,18 +7,13 @@ const (
Country = "ES"
// Authorization ClientID
AuthClientID = "9d183b70-d129-424f-9a26-c3778edf95e1"
AuthClientID = "9dcc70f0-8e79-423a-a3fa-4065d99088b4"
)
// Authorization parameters
var AuthParams = url.Values{
"response_type": {"code id_token"}, // token
"client_id": {"30e33736-c537-4c72-ab60-74a7b92cfe83@apps_vw-dilab_com"},
"redirect_uri": {"cupraconnect://identity-kit/login"},
"scope": {"openid profile mbb"}, // cars birthdate nickname address phone
}
// TokenRefreshService parameters
var TRSParams = url.Values{
"brand": {"cupra"},
"client_id": {"3c8e98bc-3ae9-4277-a563-d5ee65ddebba@apps_vw-dilab_com"},
"redirect_uri": {"seatconnect://identity-kit/login"},
"scope": {"openid profile"}, // address phone email birthdate nationalIdentifier cars mbb dealers badge nationality
}