/ora2mqtt

GWM ORA Funky Cat to MQTT Bridge

Primary LanguageC#

Ziel

Hier entsteht eine Anwendung um den aktuellen Status eines GWM ORA Funky Cat per MQTT zu veröffentlichen und über MQTT Befehle an das Auto zu senden.

Ich will mitmachen...

Sehr gern! Ich hab aktuell auch noch keinen Plan, was die nächsten Schritte sind. Daher ist es am besten wenn du einen Issue aufmachst und sagst was du vorhast, kannst, willst, brauchst...

Was ich gemacht habe um zu dem aktuellen Stand zu kommen findest du unter How to...?

Falls du dabei Hilfe brauchst, kannst du auch einfach einen Issue aufmachst.

Status

Es gibt eine Kommandozeilenanwendung die unter Windows läuft und die aktuellen Werte auslesen und per MQTT veröffentlichen kann.

Im ersten Schritt muss die Konfigurationsdatei mit ora2mqtt configure erstellt werden. Dafür am besten einen zusätzlichen Account anlegen und das Auto für diesen Account freigeben. Anschließend kann die Anwendung mit ora2mqtt run oder einfach ora2mqtt gestartet werden. Damit sollten die aktuellen Werte im MQTT zu sehen sein.

Die Werte (SOC, Range und Odometer) können in evcc mit der folgenden Konfiguration eingebunden werden:

vehicles:
- name: ora
  type: custom
  title: Ora Funky Cat
  capacity: 45
  phases: 3
  soc:
    source: mqtt
    topic: GWM/<vin>/status/items/2013021/value
    timeout: 1m
  range:
    source: mqtt
    topic: GWM/<vin>/status/items/2011501/value
    timeout: 1m
  odometer:
    source: mqtt
    topic: GWM/<vin>/status/items/2103010/value
    timeout: 1m

Ich habe das inzwischen auch ein paar Stunden laufen lassen, während ich mit dem Auto unterwegs war. Die Daten werden auch dann übermittelt, wenn die offizielle App nicht genutzt wird. Auch der Token Refresh war erfolgreich.

Linux

Damit die Binaries unter Linux laufen, muss das root Zertifikat installiert werden. Dazu das gwm_root.pem Zertifikat aus dem Repository herunterladen und mit sudo cp gwm_root.pem /etc/ssl/certs/ in den Zertifikate Ordner des Systems kopieren.

Außerdem muss die openssl.cnf aus dem Repository heruntergeladen werden. Danach kann man die Binaries aus dem Release mit dem folgen Skript starten.

#/bin/bash

export OPENSSL_CONF=/path/to/the/file/openssl.cnf
cd /path/to/the/binary/ora2mqtt/

# restart when failed
while :
do
    ./ora2mqtt -i 60
    sleep 30
done

Das Skript startet das Programm in einer Endlosschleife neu, falls die Verbindung verloren wird. Außerdem wird das Polling-Interval von 10s auf 60s erhöht um die Anzahl der Anfragen an den GMW Server zu reduzieren.

Docker

Inzwischen gibt es auch einen Docker Container. Die config muss vorher mit ora2mqtt configure erstellt werden:

docker run -d --restart=unless-stopped -v ./ora2mqtt.yml:/config/ora2mqtt.yml zivillian/ora2mqtt:latest

Datenpunkte

Folgende Datenpunkte kann ich auslesen:

Datenpunkt Beschreibung
2011501 Reichweite in km
2013021 SOC
2013022
2013023
2041142 Ladevorgang aktiv
2042071
2042082 bool Flag, nur aktiv wenn geladen wird (aber nicht immer)
2078020
2101001 Reifendruck vl in kPa
2101002 Reifendruck vr in kPa
2101003 Reifendruck hl in kPa
2101004 Reifendruck hr in kPa
2101005 Reifentemperatur vl in °C
2101006 Reifentemperatur vr in °C
2101007 Reifentemperatur hl in °C
2101008 Reifentemperatur hr in °C
2102001
2102002
2102003
2102004
2102007
2102008
2102009
2102010
2103010 Kilometerstand in km
2201001 Innenraumtemperatur in zehntel °C
2202001 Klimaanlage an
2208001 Schloss offen
2210001 Fenster geschlossen vl
2210002 Fenster geschlossen vr
2210003 Fenster geschlossen hl
2210004 Fenster geschlossen hr
2210010
2210011
2210012
2210013
2222001
2310001

How it started?

Bei evcc hat jemand vorgeschlagen, dass man sich die App mal anschauen müsste...

How it's going...

Endpunkte

Es gibt mind. 4 API Endpunkte (für jede Region):

Das ist der Standard Endpunkt für die App. Hier findet die Authentifizierung statt, wird das User Profil verwaltet und früher gab es auch mal eine Community.

Über den Endpunkt findet die Kommunikation mit dem Auto statt. Dieser Endpunkt benötigt ein Client Zertifikat der GWM CA. Glücklicherweise liefert die APP eins mit das funktioniert.

Hier wird initial die Konfiguration für das tracking abgerufen und dann jeder Klick in der App als gzipped Json hochgeladen.

Bisher ist nur ein Request bekannt, über den sich die App ein individuelles Zertifikat ausstellt das für den Zugriff auf den eu-app-gateway Endpunkt genutzt wird.

HTTP Header

Jede Anfrage enthält sehr viele nicht standardisierte HTTP Header. Nicht alle werden benötigt, daher hier nur die relevanten:

Name Value Beschreibung
Rs 2 required
Terminal GW_APP_ORA required
Brand 3 required
accessToken JWT Ergebnis vom Login
language de/en/... beeinflusst Fehlermeldungen und muss für einige Request gesetzt sein
systemType 1 sometimes required
country DE wenn sich der Wert ändert, wird das accessToken ungültig

Wenn die Header fehlen liefert die API nur einen Fehler zurück. Manchmal steht drin, welcher Header fehlt.

Cert pinning

Das Root Zertifikat für den eu-app-gateway Endpunkt ist in der App gepinnt. Dafür bringt die App das Global Sign Root Zertifikat als Ressource mit (res/raw/globalsign_chain.crt). Wenn das in der App (in Version 1.8.1) ersetzt wird, kann der Traffic mit mitmproxy mitgeschnitten werden.

Client Cert

Der eu-app-gateway Endpunkt benötigt ein Client Zertifikat von der GWM CA. Die App enthält bereits ein Zertifikat. assets/gwm_general.cer enthält das Zertifikat, assets/gwm_general.key den dazu passenden private key und assets/gwm_root.pem die Zertifikatskette bis zur GWM CA.

Bei der ersten Anmeldung stellt sich die App ein eigenes Zertifikat aus. Das Zertfikat wird lokal auf dem Gerät abgelegt und kann ausgelesen werden, wenn das android:debuggable Flag gesetzt wurde.

Das Zertifikat liegt im Speicher unter files/pki/cert/cert, dazu gehören noch die Dateien files/pkey_data11, files/pkey_data21 und files/pkey_data31. Die 1 steht dabei für das n-te Zertifikat (weil das irgendwann abläuft und erneuert werden muss). Der mitgeliefert Key wird in der Datei files/pkey_data30 abgelegt.

pkey_data1x

Das ist der Public Key.

pkey_data2x

Das ist auch der Public Key, aber der RSA Parameter e wurde transformiert.

pkey_data3x

Das ist der Private Key - der RSA Parameter d wurde transformiert.

Transformation

Sowohl die mitgelieferten Schlüssel, als auch die Schlüssel des erstellten Client Zertifikats sind transformiert. Zusätzlich werden nur die RSA Parameter n, d und e abgespeichert - die weiteren Parameter p,q, dp, dq und qInv müssen berechnet werden. Der Code um die Transformation rückgängig zu machen und die fehlenden Paramter zu berechnen liegt in CertificateHandler.cs.

Alternativ geht das auch in python mit cryptography.hazmat.primitives.asymmetric.rsa.

How to...?

Ich habe die App mit apktool zerlegt und wieder zusammengebaut. Damit lassen sich die Zertifikate auslesen und ersetzen. Um zu verstehen, was in den Zertifikaten drin steht und was wie transformiert wird, war asn1js sehr hilfreich.

Um die modifizierte App installieren zu können, muss sie signiert sein - das geht relativ einfach mit uber-apk-signer.

Den Traffic kann man mit mitmproxy mitlesen. Dabei muss das Root Zertifikat auf dem Gerät oder Emulator installiert werden und das Client Zertifikat aus der App extrahiert, transformiert und mit angegeben werden.

Die App bringt einige native Binaries mit (relevant sind libbean.so und libbeancrypto.so) - da werden auch die Zertifikate und Private Keys verarbeitet. Mit Ghidra lässt sich das aber sehr gut untersuchen. Für den Crypto Part wird libtomcrypt genutzt - damit lässt sich dann auch die Transformation der RSA Parameter nachvollziehen.