BMW connected drive in IPS?

so erstmal nicht.
welche Version de moduls (beta? git?) hast Du genau verwendet?
welches BMW-Modell (konventionell/hybrid/e)?
und dann wäre debug sinnvoll (an demel42@web.de)
vielleicht sehe ich was
demel

Hallo Demel…

Es hat gestern Abend dann doch noch geklappt…
Wobei ich nicht genau sagen kann, woran es am Ende gelegen hat. Es hat am Ende in einer Kombi aus Versuchen mit IPS neu starten, Instanz neu einrichten, … funktioniert.
Modul habe ich verschiedene Möglichkeiten getestet. Problem hatte ich mit allen Varianten. Aktuell verwende ich die Git Variante.
BMW ist ein Hybrid.

Werde das mal beobachten…

Vielen Dank für Deine schnelle Rückmeldung.

Grüße Jochen

okidoki, um so besser
demel

Nachdem mein Mini SE nun in der Garage steht, habe ich natürlich gleich das BMW Connected Drive Modul mit dem Mini SE (Mini Connected Drive) getestet.

Funktioniert sofort und perfekt :wink:

Bis gestern lief’s problemlos. Jetzt finde ich im Debug-Log „Bad Request“ und „Client disabled“. Natürlich kommen keine Daten zurück. Das Ganze mit 2 Accounts.

„Bad Request“ auch beim Abholen des Tokens. Die BMW bzw. Mini App laufen problemlos.

Hat das Problem noch jemand?

Hallo,
willkommen im Club, @dmeyer8803 hatte mich schon vorgestern angeschrieben wegen des gleichen Problems und ich habe dann festgestellt, das das auch bei mir so ist

äussert sich mit dieser meldung:

06.08.2021, 16:55:30 | GetToken_2 | jbody=Array<LF>(<LF> [error] => client disabled<LF> [error_description] => provided clients are disabled<LF>)<LF>

ich suche im internet, ob das sonst noch wo auftaucht…

demel

1 „Gefällt mir“

Kurzer Zwischenstand: ist kein spezifisches Problem funktioniert auch „woanders“ nicht :cry:

[lsiddiquee/bmw-connected-drive] Has the api stopped working ? (#6)
Yes it is broken again. Will update once i found the correct keyYes it is broken again. Will update once i found the correct key

echt blöd, aber da es keine offizielle API gibt, ist das immer ein ein ziemliches reverse-engeneering, aufgrund der Verschlüsslung besonders tricky (und übersteigt mein Fähigkeiten).
bleibe dran

demel

1 „Gefällt mir“

Danke für deine Mühe! :+1:

Ist echt blöd, das BMW (wie auch manch andere) hier noch keine offizielle API anbieten :frowning_face:

Hilft vielleicht dieses Git weiter?

Da gab’s gestern eine Änderung…

Super vielen Dank für Deinen Einsatz, top :+1: :+1: :+1:

heute gab es eine Änderung in dem Github-Repository, die wohl eine Lösung darstellt.
Habe ich auf die Schnelle noch nicht verstanden, das ist auf jeden Fall mehr als nur ein neuer Identifier.

Ich schaue mal …

Gruss
demel

2 „Gefällt mir“

hallo,

so … nun habe ich es endlich geschafft, die Token zu bekommen.

Könntet ihr das mit diesem Script bitte man Gegentesten?

user und password natürlich ergänzen.

Wenn es klappt, müsste in der letzen Zeile so etwas stehen:

access_token=aaaaaaa, refresh_token=rrrrrr, expires_in=3599

<?php

declare(strict_types=1);

$user = 'xxx@xxx.xxx';
$password = 'yyyy';

$region = 'RestOfWorld';

$serverEndpoints = [
    'NorthAmerica' => 'b2vapi.bmwgroup.us',
    'RestOfWorld'  => 'b2vapi.bmwgroup.com',
];

$oauthEndpoints = [
    'NorthAmerica' => 'login.bmwusa.com/gcdm',
    'RestOfWorld'  => 'customer.bmwgroup.com/gcdm',
];

$oauthAuthorization = [
    'NorthAmerica' => 'NTQzOTRhNGItYjZjMS00NWZlLWI3YjItOGZkM2FhOTI1M2FhOmQ5MmYzMWMwLWY1NzktNDRmNS1hNzdkLTk2NmY4ZjAwZTM1MQ==',
    'RestOfWorld'  => 'MzFjMzU3YTAtN2ExZC00NTkwLWFhOTktMzNiOTcyNDRkMDQ4OmMwZTMzOTNkLTcwYTItNGY2Zi05ZDNjLTg1MzBhZjY0ZDU1Mg==',
];

$oauthCodeVerifier = [
    'NorthAmerica' => 'KDarcVUpgymBDCgHDH0PwwMfzycDxu1joeklioOhwXA',
    'RestOfWorld'  => '7PsmfPS5MpaNt0jEcPpi-B7M7u0gs1Nzw6ex0Y9pa-0',
];

$oauthClientId = [
    'NorthAmerica' => '54394a4b-b6c1-45fe-b7b2-8fd3aa9253aa',
    'RestOfWorld'  => '31c357a0-7a1d-4590-aa99-33b97244d048',
];

$oauthState = [
    'NorthAmerica' => 'rgastJbZsMtup49-Lp0FMQ',
    'RestOfWorld'  => 'cEG9eLAIi6Nv-aaCAniziE_B6FPoobva3qr5gukilYw',
];

$oauth_client_id = $oauthClientId[$region];
$oauth_state = $oauthState[$region];
$oauth_endpoint = $oauthEndpoints[$region];
$oauth_host = 'customer.bmwgroup.com';
$oauth_authorization = $oauthAuthorization[$region];
$oauth_code_verifier = $oauthCodeVerifier[$region];

$user_agent = 'IP-Symcon'; // __CLASS__

$oauth_redirect_uri = 'com.bmw.connected://oauth';
$oauth_scope = 'openid profile email offline_access smacc vehicle_data perseus dlm svds cesim vsapi remote_services fupo authenticate_user';

$auth_url = 'https://' . $oauth_endpoint . '/oauth/authenticate';
$token_url = 'https://' . $oauth_endpoint . '/oauth/token';

$postfields = [
    'client_id'       => $oauth_client_id,
    'response_type'   => 'code',
    'redirect_uri'    => $oauth_redirect_uri,
    'state'           => $oauth_state,
    'nonce'           => 'login_nonce',
    'scope'           => $oauth_scope,
    'grant_type'      => 'authorization_code',
    'username'        => $user,
    'password'        => $password,
];

$header = [
    'User-Agent: ' . $user_agent,
    'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
];

echo 'url=' . $auth_url . PHP_EOL;
echo 'header=' . print_r($header, true) . PHP_EOL;
echo 'postfields=' . print_r($postfields, true) . PHP_EOL;

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $auth_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_setopt($ch, CURLOPT_MAXREDIRS, 50);
curl_setopt($ch, CURLOPT_HTTP09_ALLOWED, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
curl_setopt($ch, CURLOPT_TCP_KEEPALIVE, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '');
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);

$response = curl_exec($ch);
$cerrno = curl_errno($ch);
$cerror = $cerrno ? curl_error($ch) : '';
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

$curl_info = curl_getinfo($ch);
$header_size = $curl_info['header_size'];
$header = substr($response, 0, $header_size);
$response = substr($response, $header_size);

echo 'errno=' . $cerrno . '(' . $cerror . '), httpcode=' . $httpcode . ', response=' . $response . PHP_EOL;

preg_match_all('|Set-Cookie: (.*);|U', $header, $results);
$cookies = explode(';', implode(';', $results[1]));
echo 'cookies=' . print_r($cookies, true) . PHP_EOL;

$jdata = json_decode($response, true);
$redirect_to = $jdata['redirect_to'];
$redirect_uri = substr($redirect_to, strlen('redirect_uri='));
$redirect_parts = parse_url($redirect_uri);
parse_str($redirect_parts['query'], $redirect_opts);

$header = [
    'User-Agent: ' . $user_agent,
    'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
];
foreach ($cookies as $cookie) {
    $header[] = 'Cookie: ' . $cookie;
}

$postfields = [
    'client_id'     => $redirect_opts['client_id'],
    'response_type' => $redirect_opts['response_type'],
    'redirect_uri'  => $oauth_redirect_uri,
    'state'         => $redirect_opts['state'],
    'nonce'         => 'login_nonce',
    'scope'         => $redirect_opts['scope'],
    'authorization' => $redirect_opts['authorization'],
];

echo 'url=' . $auth_url . PHP_EOL;
echo 'header=' . print_r($header, true) . PHP_EOL;
echo 'postfields=' . print_r($postfields, true) . PHP_EOL;

curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));

$response = curl_exec($ch);
$cerrno = curl_errno($ch);
$cerror = $cerrno ? curl_error($ch) : '';
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response != false) {
    $curl_info = curl_getinfo($ch);
    $header_size = $curl_info['header_size'];
    $header = substr($response, 0, $header_size);
    $response = substr($response, $header_size);
}

echo 'errno=' . $cerrno . '(' . $cerror . '), httpcode=' . $httpcode . ', header=' . $header . ', response=' . $response . PHP_EOL;

preg_match_all('|Set-Cookie: (.*);|U', $header, $results);
$cookies = explode(';', implode(';', $results[1]));
echo 'cookies=' . print_r($cookies, true) . PHP_EOL;

$code = false;
foreach (explode(PHP_EOL, $header) as $line) {
    if (preg_match('/^location: (.*)$/', $line, $r)) {
        $p = parse_url($r[1]);
        if (isset($p['query'])) {
            parse_str($p['query'], $o);
            if (isset($o['code'])) {
                $code = $o['code'];
            }
        }
    }
}

echo 'code=' . $code . PHP_EOL;

$header = [
    'User-Agent: ' . $user_agent,
    'Content-Type: application/x-www-form-urlencoded',
    'Authorization: Basic ' . $oauth_authorization,
];
foreach ($cookies as $cookie) {
    $header[] = 'Cookie: ' . $cookie;
}

$postfields = [
    'redirect_uri'  => $oauth_redirect_uri,
    'grant_type'    => 'authorization_code',
    'code'          => $code,
    'code_verifier' => $oauth_code_verifier,
];

echo 'url=' . $token_url . PHP_EOL;
echo 'header=' . print_r($header, true) . PHP_EOL;
echo 'postfields=' . print_r($postfields, true) . PHP_EOL;

curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));

$response = curl_exec($ch);
$cerrno = curl_errno($ch);
$cerror = $cerrno ? curl_error($ch) : '';
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response != false) {
    $curl_info = curl_getinfo($ch);
    $header_size = $curl_info['header_size'];
    $header = substr($response, 0, $header_size);
    $response = substr($response, $header_size);
}

curl_close($ch);

echo 'errno=' . $cerrno . '(' . $cerror . '), httpcode=' . $httpcode . ', header=' . $header . ', response=' . $response . PHP_EOL;

$jdata = json_decode($response, true);

$access_token = $jdata['access_token'];
$refresh_token = $jdata['refresh_token'];
$expires_in = $jdata['expires_in'];

echo 'access_token=' . $access_token . ', refresh_token=' . $refresh_token . ', expires_in=' . $expires_in . PHP_EOL;

Danke & Gruß
demel

2 „Gefällt mir“

Moin,

also bei mir würde es so funktionieren.

Danke für die Arbeit.
Attain

Würde bei mir auch funktionieren. :+1:

(getestet für BMW und Mini)

Hallo Demel,

danke für Deinen Einsatz. Bei mir geht es auch (getestet mit BMW i3)

VG Heiko

Hallo,

danke für eure Test, dann passt es ja. Ich werde dann die neue Login-Prozedur in das Modul einbauen. Bin mir unsicher, ob ich vor dem nächsten WE dazu komme aber auf jeden Fall den geößten Schritt geschafft

melde mich
demel

1 „Gefällt mir“

Hallo,

erster Schritt ist getan, ich habe das Login im Modul implementiert. Ist NICHT im Modul-Store, weil das Modul ja von @fonzo ist, also erstmal nur über die Module-Instanz mit der URL https://github.com/demel42/IPSymconBMWConnectedDrive. Wichtig: der Zweig ist oauth_api.

Was funktioniert?

  • Login, Token
  • Abruf der Daten
    => da ich kein Hybrid/Elektro habe, kann ich nicht überprüfen, ob die spezifischen Daten kämen → bitte gegenprüfen, das sind die Calls GetNavigationData(), GetEfficiency(), GetChargingProfile()

Was funktioniert (noch) nicht

  • alle Kommandos, die scheinen mehr oder minder komplett anders zu sein

Gruß
demel

Auf die Schnelle…

Test mit 530e (Hybrid):

Sieht ok aus (wobei die Ladekapazitäten ziemlicher Unfug sind, aber SoC, Reichweite,Ladekabelstatus und Ladezyklus stimmen (was mir wichtig ist)) :+1:

Beim Mini SE (BEV) funzt es auch:

Allerdings ist auch hier die „Ladekapazität“ schief (aktuell 68kWh beim Mini SE wären ein Traum ;)). Die „maximale Ladekapazität“, SoC, Reichweite, Ladekabel-Status und Zyklus passen aber auch hier.

SUUUUPER!!! :+1: :+1: :+1: :+1: :partying_face:

hmm,
müsstest mir mal ein Debug mailen.
vielleicht sehe ich was …

Hallo demel,

habe ein Debug von meinem BMW i3 (BEV) gesendet.

VG Heiko