Read Aiways U5 State of Charge

Unfortunately there isn’t an easy way.
Here is, what worked for me. But it is not for the faint hearted:

  • Use PCAPdroid on Android to capture the communication of the Aiways app.
    This helper app does NOT require root access.
  • Activate TLS-Decryption in PCAPdroid and follow the wizard to generate a certificate and install it in Android. The guide can help you to test the decryption.
  • Choose HTTP-Server as traffic dump and the Aiways app as the target app.
    Start the dump with the play icon.
  • Open the Aiways app and navigate to the car data.
  • Back in PCAPdroid stop the dump and check the registered traffic. There should be a bunch of requests. Most of them contain the header data that you are interested in:
    • token
    • registerid
    • deviceid
  • These three can possible expire at any time (though they were stable for me for quite some time now. If they expire you have to capture them again for an update.
  • Use the Node RED flow to run your request.
    You MUST edit the node “Prep msg.config” and add your userid, vin, token, registerid, deviceid.
  • If all goes well, the result of the flow is the car data stored in msg.cardata at the output of the last node.

[{"id":"e5afc16c4577b23c","type":"inject","z":"c6ce30da03615610","name":"15 min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"900","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":4380,"wires":[["11644ec37221ea4b","de4928d8bfc625c1","bc00432297bace86"]]},{"id":"bc00432297bace86","type":"function","z":"c6ce30da03615610","name":"Prep msg.config","func":"\n/* \n* IMPORTANT:\n* The NPM package \"crypto\" is already part of Node.js \n* but it must be activated for Node RED in /config/node-red/settings.js:\n*    functionGlobalContext: {\n*        crypto:require(\"crypto\")\n*    },\n*/\nlet crypto = global.get(\"crypto\");\n\n// Date().toString() = i.e. 'Mon Sep 26 2022 16:51:05 GMT+0200 (Mitteleuropäische Sommerzeit)'\n// timeZoneParts = i.e. [ \"GMT+0200, \"GMT+02\", \"00\" ]\nlet timeZoneParts = Date().toString().match(/(GMT[\\+\\-]\\d\\d)(\\d\\d)/);\n\nmsg.config = {\n    userid: global.get(\"ha_secrets\").aiways_userid || \"\",\n    vin: global.get(\"ha_secrets\").aiways_vin || \"\",\n    // ALT:\n    // passwordmd5: crypto.createHash('md5').update(global.get(\"ha_secrets\").aiways_pwd || \"\").digest('hex'),\n    \n    // TEMPORÄRER HACK: Aus App-Request per PCAPdroid ermittelt\n    token: global.get(\"ha_secrets\").aiways_token || \"\",\n    registerid: global.get(\"ha_secrets\").aiways_registerid || \"\",\n    deviceid: global.get(\"ha_secrets\").aiways_deviceid || \"\",\n\n    language: \"de\",\n    version: \"1.3.0\",\n    platform: \"android\",\n    user_agent: \"okhttp/4.3.1\",\n\n    // apptimezone = i.e.: \"GMT+02:00\"\n    apptimezone: `${timeZoneParts[1]}:${timeZoneParts[2]}`,\n    // apptimezoneid = i.e.: \"Europe/Berlin\"\n    apptimezoneid: Intl.DateTimeFormat().resolvedOptions().timeZone,\n\n    contentType: \"application/json; charset=utf-8\",\n    acceptEncoding: \"gzip\",\n    CS_URL: \"https://coiapp-api-eu.ai-ways.com:10443/\",\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":4380,"wires":[["36ad1f6c6a1dd148","1fbeeb7a032e8871"]]},{"id":"36ad1f6c6a1dd148","type":"function","z":"c6ce30da03615610","name":"Prep second request:  POST Get Data","func":"// Based on: OpenWB-Module Aiways SOC:\n// https://github.com/snaptec/openWB/blob/bcb16dcb2902ca6ce21cd1036933a712d73bd44c/modules/soc_aiways/aiways_get_soc.py\n\n\n/*\n    #########################################################################\n    # Request2 \"app/vc/getCondition\"                                        #\n    # Get the current Condition of the car                                  #\n    # The data are located in data / vc                                       #\n    # \"soc\" contains the value for the current State of Charge)             #\n    #########################################################################\n*/\n\nlet PATH = \"app/vc/getCondition\"\n\nlet oHeaders = {\n    \"language\": msg.config.language,\n    \"token\": msg.config.token,\n    \"registerid\": msg.config.registerid,\n    \"deviceid\": msg.config.deviceid,\n    \"version\": msg.config.version,\n    \"platform\": msg.config.platform,\n    \"apptimezone\": msg.config.apptimezone,\n    \"apptimezoneid\": msg.config.apptimezoneid,\n    \"content-type\": msg.config.contentType,\n    \"accept-encoding\": msg.config.acceptEncoding,\n    \"user-agent\": msg.config.user_agent,\n}\n\n//PAYLOAD = {'userId': userId,'vin': vin}\nlet PAYLOAD = { \n    \"userId\": msg.config.userid, \n    \"vin\": msg.config.vin\n}\n\n//resp = requests.post(CS_URL + PATH, headers = headers, data = json.dumps(PAYLOAD))\nmsg.url = msg.config.CS_URL + PATH;\nmsg.method= \"POST\";\nmsg.headers = oHeaders;\n//msg.cookies= \"\";\nmsg.payload = JSON.stringify(PAYLOAD)\n\nreturn msg;\n\n/*\ndata = resp.json()[\"data\"]\nvc = data[\"vc\"]\nsoc = vc[\"soc\"]\nchargeSts = vc[\"chargeSts\"]\n*/\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":4380,"wires":[["7384c89403b9de48","f54cd7fcb6559682"]]},{"id":"4d685491d9e3a5a1","type":"debug","z":"c6ce30da03615610","name":"debug 10","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1040,"y":4380,"wires":[]},{"id":"1b0e67c3467ab9d8","type":"switch","z":"c6ce30da03615610","name":"HTTP 200 ?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":330,"y":4440,"wires":[["a446cc15c19d34ca"],[]]},{"id":"7384c89403b9de48","type":"http request","z":"c6ce30da03615610","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"7b79ba19.4d8194","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":850,"y":4380,"wires":[["4d685491d9e3a5a1","1b0e67c3467ab9d8"]]},{"id":"1fbeeb7a032e8871","type":"debug","z":"c6ce30da03615610","name":"debug 13","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":500,"y":4340,"wires":[]},{"id":"f54cd7fcb6559682","type":"debug","z":"c6ce30da03615610","name":"debug 14","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":840,"y":4340,"wires":[]},{"id":"7287ba84c0c8172a","type":"change","z":"c6ce30da03615610","name":"","rules":[{"t":"set","p":"cardata","pt":"msg","to":"payload.data.vc","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":4440,"wires":[["f71413d712d057df","03a2f2c364f55bac"]]},{"id":"a446cc15c19d34ca","type":"switch","z":"c6ce30da03615610","name":"payload.code == 0 ?","property":"payload.code","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":540,"y":4440,"wires":[["7287ba84c0c8172a"],[]]},{"id":"03a2f2c364f55bac","type":"debug","z":"c6ce30da03615610","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":980,"y":4440,"wires":[]},{"id":"7b79ba19.4d8194","type":"tls-config","name":"Ignore Invalid Cert","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false}]

Good luck.