Kia (EU): use refresh_token as password (#23523)
This commit is contained in:
parent
a9ec457b57
commit
fab9464cb6
3 changed files with 99 additions and 25 deletions
|
|
@ -5,8 +5,14 @@ products:
|
|||
generic: Bluelink
|
||||
requirements:
|
||||
description:
|
||||
en: Some models (e.g. Niro EV) switch internally to 2 phases at low charging currents (< 8A). In cases where the wallbox also measures the phase currents, this leads to undesirable fluctuations in the charging power. The remedy here is to set the minimum charging current to 8A.
|
||||
de: Manche Modelle (z.B. Niro EV) schalten bei geringen Ladeströmen (< 8A) intern auf 2 Phasen um. In den Fällen, in denen die Wallbox auch die Phasenströme misst, führt das zu unerwünschten Schwankungen der Ladeleistung. Abhilfe schafft hier, den Mindestladestrom auf 8A zu setzen.
|
||||
en: |
|
||||
Instead of your account's password, the password field needs to be filled with a `refresh_token` ([instructions](https://github.com/evcc-io/evcc/wiki/Kia:-Refresh%E2%80%90Token-ermitteln#english-version)).
|
||||
|
||||
Some models (e.g. Niro EV) switch internally to 2 phases at low charging currents (< 8A). In cases where the wallbox also measures the phase currents, this leads to undesirable fluctuations in the charging power. The remedy here is to set the minimum charging current to 8A.
|
||||
de: |
|
||||
Anstelle des Passworts muss in das Passwort-Feld ein `refresh_token` eingetragen werden ([Anleitung](https://github.com/evcc-io/evcc/wiki/Kia:-Refresh%E2%80%90Token-ermitteln)).
|
||||
|
||||
Manche Modelle (z.B. Niro EV) schalten bei geringen Ladeströmen (< 8A) intern auf 2 Phasen um. In den Fällen, in denen die Wallbox auch die Phasenströme misst, führt das zu unerwünschten Schwankungen der Ladeleistung. Abhilfe schafft hier, den Mindestladestrom auf 8A zu setzen.
|
||||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-language
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
BrandAuthUrl: "https://eu-account.hyundai.com/auth/realms/euhyundaiidm/protocol/openid-connect/auth?client_id=%s&scope=openid+profile+email+phone&response_type=code&hkid_session_reset=true&redirect_uri=%s/api/v1/user/integration/redirect/login&ui_locales=%s&state=%s:%s",
|
||||
PushType: "GCM",
|
||||
Cfb: "RFtoRq/vDXJmRndoZaZQyfOot7OrIqGVFj96iY2WL3yyH5Z/pUvlUhqmCxD2t+D65SQ=",
|
||||
Brand: "hyundai",
|
||||
// for oauth2??
|
||||
// LoginFormHost: "https://idpconnect-eu.hyundai.com",
|
||||
// AuthClientID: "6d477c38-3ca4-4cf3-9557-2a1929a94654",
|
||||
|
|
@ -54,6 +55,7 @@ func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
PushType: "APNS",
|
||||
Cfb: "wLTVxwidmH8CfJYBWSnHD6E0huk0ozdiuygB4hLkM5XCgzAL1Dk5sE36d/bx5PFMbZs=",
|
||||
LoginFormHost: "https://idpconnect-eu.kia.com",
|
||||
Brand: "kia",
|
||||
}
|
||||
|
||||
return newBluelinkFromConfig("kia", other, settings)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type Config struct {
|
|||
PushType string
|
||||
Cfb string
|
||||
LoginFormHost string
|
||||
Brand string
|
||||
}
|
||||
|
||||
// Identity implements the Kia/Hyundai bluelink identity.
|
||||
|
|
@ -247,6 +248,7 @@ func (v *Identity) brandLoginHyundaiEU(cookieClient *request.Helper, user, passw
|
|||
return code, err
|
||||
}
|
||||
|
||||
/* Unused for now
|
||||
func (v *Identity) brandLoginKiaEU(user, password string) (string, error) {
|
||||
cookieClient := request.NewHelper(v.log)
|
||||
cookieClient.Client.Jar, _ = cookiejar.New(&cookiejar.Options{
|
||||
|
|
@ -255,7 +257,8 @@ func (v *Identity) brandLoginKiaEU(user, password string) (string, error) {
|
|||
|
||||
headers := map[string]string{
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19_CCS_APP_AOS",
|
||||
// "User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
|
||||
}
|
||||
|
||||
data := url.Values{
|
||||
|
|
@ -334,6 +337,7 @@ func (v *Identity) brandLoginKiaEU(user, password string) (string, error) {
|
|||
|
||||
return code, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (v *Identity) bluelinkLogin(cookieClient *request.Helper, user, password string) (string, error) {
|
||||
data := map[string]interface{}{
|
||||
|
|
@ -385,6 +389,31 @@ func (v *Identity) exchangeCodeHyundaiEU(accCode string) (*oauth2.Token, error)
|
|||
return util.TokenWithExpiry(&token), err
|
||||
}
|
||||
|
||||
func (v *Identity) exchangeCodeKiaEURefreshToken(accCode string) (*oauth2.Token, error) {
|
||||
uri := v.config.LoginFormHost + "/auth/api/v2/user/oauth2/token"
|
||||
headers := map[string]string{
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19_CCS_APP_AOS",
|
||||
}
|
||||
data := url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {accCode},
|
||||
"client_id": {v.config.CCSPServiceID},
|
||||
"client_secret": {"secret"},
|
||||
}
|
||||
|
||||
var token oauth2.Token
|
||||
|
||||
req, _ := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), headers)
|
||||
err := v.DoJSON(req, &token)
|
||||
|
||||
// manually set the refresh token
|
||||
token.RefreshToken = accCode
|
||||
|
||||
return util.TokenWithExpiry(&token), err
|
||||
}
|
||||
|
||||
/* Unused for now
|
||||
func (v *Identity) exchangeCodeKiaEU(accCode string) (*oauth2.Token, error) {
|
||||
uri := v.config.LoginFormHost + "/auth/api/v2/user/oauth2/token"
|
||||
headers := map[string]string{
|
||||
|
|
@ -406,26 +435,61 @@ func (v *Identity) exchangeCodeKiaEU(accCode string) (*oauth2.Token, error) {
|
|||
|
||||
return util.TokenWithExpiry(&token), err
|
||||
}
|
||||
*/
|
||||
|
||||
// RefreshToken implements oauth.TokenRefresher
|
||||
func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
|
||||
headers := map[string]string{
|
||||
"Authorization": "Basic " + v.config.BasicToken,
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "okhttp/3.10.0",
|
||||
}
|
||||
|
||||
data := url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"redirect_uri": {"https://www.getpostman.com/oauth2/callback"},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPost, v.config.URI+TokenURL, strings.NewReader(data.Encode()), headers)
|
||||
|
||||
var res oauth2.Token
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, &res)
|
||||
var err error
|
||||
var uri string
|
||||
var headers map[string]string
|
||||
var data url.Values
|
||||
switch v.config.Brand {
|
||||
case "hyundai":
|
||||
uri = v.config.URI + TokenURL
|
||||
headers = map[string]string{
|
||||
"Authorization": "Basic " + v.config.BasicToken,
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
// "User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19_CCS_APP_AOS",
|
||||
"User-Agent": "okhttp/3.10.0",
|
||||
}
|
||||
|
||||
data = url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"redirect_uri": {"https://www.getpostman.com/oauth2/callback"},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
}
|
||||
|
||||
case "kia":
|
||||
uri = v.config.LoginFormHost + "/auth/api/v2/user/oauth2/token"
|
||||
headers = map[string]string{
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19_CCS_APP_AOS",
|
||||
}
|
||||
data = url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {token.RefreshToken},
|
||||
"client_id": {v.config.CCSPServiceID},
|
||||
"client_secret": {"secret"},
|
||||
}
|
||||
default:
|
||||
err = errors.New("Unsupported brand")
|
||||
}
|
||||
|
||||
// request token only if we didn't run unto the default branch
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = v.DoJSON(req, &res)
|
||||
// carry over the old refresh token (if any and not populated already)
|
||||
if res.RefreshToken == "" && token.RefreshToken != "" {
|
||||
res.RefreshToken = token.RefreshToken
|
||||
}
|
||||
|
||||
return util.TokenWithExpiry(&res), err
|
||||
|
|
@ -438,13 +502,15 @@ func (v *Identity) Login(user, password, language, brand string) (err error) {
|
|||
var code string
|
||||
switch brand {
|
||||
case "kia":
|
||||
code, err = v.brandLoginKiaEU(user, password)
|
||||
if err == nil {
|
||||
var token *oauth2.Token
|
||||
if token, err = v.exchangeCodeKiaEU(code); err == nil {
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
}
|
||||
// the "password" now is the refresh token ...
|
||||
// code, err = v.brandLoginKiaEU(user, password)
|
||||
// if err == nil {
|
||||
var token *oauth2.Token
|
||||
if token, err = v.exchangeCodeKiaEURefreshToken(password); err == nil {
|
||||
v.TokenSource = oauth.RefreshTokenSource(token, v)
|
||||
}
|
||||
v.deviceID, err = v.getDeviceID()
|
||||
// }
|
||||
case "hyundai":
|
||||
v.deviceID, err = v.getDeviceID()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue