Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIA USA Support #88

Closed
cdnninja opened this issue Oct 17, 2021 · 28 comments
Closed

KIA USA Support #88

cdnninja opened this issue Oct 17, 2021 · 28 comments
Labels
enhancement New feature or request

Comments

@cdnninja
Copy link
Collaborator

To continue the conversation on #80 specific for Kia. @mbbush.

@cdnninja cdnninja added the enhancement New feature or request label Oct 17, 2021
@mbbush
Copy link

mbbush commented Oct 17, 2021

I put the mock responses file at
mbbush#1

@cdnninja
Copy link
Collaborator Author

That should be helpful down the road. Looks like it is missing what header values to pass in to get the responses. Could you try this to get more details on how it works? https://github.com/fuatakgun/kia_uvo/wiki/How-to-reverse-engineer-app-traffic-on-Android-phone

@mbbush
Copy link

mbbush commented Oct 17, 2021

So here's what I've got so far from the web app:

POST https://owners.kia.com/apps/services/owners/apiGateway with request body:

{ 
  "userId": $USERNAME,
  "password": $PASSWORD,
  "userType": "1",
  "vin": "",
  "action": "authenticateUser"
  }

Returns a body with some data including an array of vehicle objects under payload.vehicleSummary. The most relevant fields seem to be "vin", "vehicleIdentifier", "modelName", "modelYear", "nickName", "fuelType" and "vehicleKey". There's also a cookie which contains the JSESSIONID which seems to be how subsequent requests are authenticated.

When I use curl to output the cookie file, it looks like this (actual session value deliberately somewhat mangled)

# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_owners.kia.com	FALSE	/	TRUE	0	JSESSIONID	node0abcde123za00000000000000000000.node0

That cookie is then sent in subsequent requests to authenticate.

@mbbush
Copy link

mbbush commented Oct 17, 2021

I can see a request to GET https://owners.kia.com/apps/services/owners/getvehicleinfo.html/vehicleFeature/1/vehicleStatus/1/enrollment/1/maintenance/1/dtc/1 which uses that cookie, and a header named vinkey, which is a uuid, although I haven't figured out where it comes from yet. This request returns json containing lots of useful data about the car.

Still TODO:

  • Figure out how to refresh the data
  • make some sort of more organized collection of requests/responses and share them in a useful format. I use insomnia.rest at work for sharing "here's an api you can call manually", so I'll probably create an insomnia collection. It's the same idea as postman, but with some cool extra features.

How similar or dissimilar does this sound to the way it works in CA or EU? I haven't read the existing source code yet; I should probably do that...

@mbbush
Copy link

mbbush commented Oct 17, 2021

ok, so this api is funky.

To login, you have to make a POST request, with a JSON body, but set the content type to application/x-www-form-urlencoded. All other combinations of sending the data I've tried (form data sent with the content type for form data, json with json content type), you don't get a response body, but you still get the session cookie. The one other thing that worked was sending form data with a single key consisting of the url-encoded json body, and no value. Yuck.

Anyways, this works, and returns a body and a session cookie. Still working on the subsequent requests.

import requests
import json

payload = { 
  "userId": "user",
  "password": "PASSWORD",
  "userType": "1",
  "vin": "",
  "action": "authenticateUser"
  }
 
 r = requests.post('https://owners.kia.com/apps/services/owners/apiGateway', data=json.dumps(payload), headers={'Content-Type': 'application/x-www-form-urlencoded'})

@cdnninja
Copy link
Collaborator Author

cdnninja commented Oct 18, 2021 via email

@mbbush
Copy link

mbbush commented Oct 18, 2021

I'll get started on spying on the app, then. It's been a long time since I've dealt with intercepting SSL traffic, so I'm not sure how long it'll take me.

I did see a couple properties in the manifest file that looked like they could be flipped to allow insecure requests/easy debugging, so maybe I'll try that first.

Why do you say you think this is "front ended by aws amazon gateway"? I definitely got the impression that this was not using some of the aws-managed products like Api Gateway or Cognito, simply because it uses a funky non-standard auth mechanism, and the aws-managed products generally do a pretty good job of conforming to standards. I also didn't see any aws-like response headers.

@mbbush
Copy link

mbbush commented Oct 18, 2021

You're right. The app uses a completely different api that is going to be far easier to use. I spent entirely too long fumbling around with various methods until I found HTTP Toolkit, which basically takes care of everything when I run it with an android emulator.

The endpoints look like this:
image

The authUser endpoint returns a session id in the sid response header, which is included in subsequent requests.

They also have many custom headers, plus the date, were required; if I omitted them the request returned an error response saying "missing required headers".

Details are in #90

@cdnninja
Copy link
Collaborator Author

I have merged this to the main branch. If others want to test please give it a try. At this point it looks to just get the basic data at this point.

@Ceer123
Copy link

Ceer123 commented Oct 27, 2021

I loaded the latest version to test this. I have a Kia Niro EV in USA. I am getting this error in the log

2021-10-27 12:05:38 DEBUG (MainThread) [custom_components.kia_uvo] kia_uvo - async_setup_entry started - homeassistant.config_entries.ConfigEntry object at 0x7f6edccafca0>

2021-10-27 12:05:38 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry MYUSERNAME for kia_uvo
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 304, in async_setup
result = await component.async_setup_entry(hass, self) # type: ignore
File "/config/custom_components/kia_uvo/init.py", line 134, in async_setup_entry
vehicle: Vehicle = Vehicle(
File "/config/custom_components/kia_uvo/Vehicle.py", line 40, in init
self.model = token.vehicle_model
AttributeError: 'Token' object has no attribute 'vehicle_model'

@cdnninja
Copy link
Collaborator Author

@mbbush this something you could look at? I assume it's still working for you for basic data?

@mbbush
Copy link

mbbush commented Oct 28, 2021 via email

@tchoward
Copy link

tchoward commented Nov 2, 2021

I seem to get past login, but then I see the same as above.

File "/usr/src/homeassistant/homeassistant/config_entries.py", line 304, in async_setup
result = await component.async_setup_entry(hass, self) # type: ignore
File "/config/custom_components/kia_uvo/init.py", line 134, in async_setup_entry
vehicle: Vehicle = Vehicle(
File "/config/custom_components/kia_uvo/Vehicle.py", line 40, in init
self.model = token.vehicle_model
AttributeError: 'Token' object has no attribute 'vehicle_model'

_

@cdnninja
Copy link
Collaborator Author

cdnninja commented Nov 4, 2021

@mbbush have you had a chance to look at this?

@mbbush
Copy link

mbbush commented Nov 4, 2021 via email

@cdnninja
Copy link
Collaborator Author

cdnninja commented Nov 8, 2021

Commits have been done to get this closer to functional. Please provide feedback and future PRs. Thanks to everyone involved getting it this far.

@dahlb
Copy link
Contributor

dahlb commented Nov 9, 2021

I put in PRs for what I think is everything populating except temperature, which I'm working on but will take me a few days (first F in code base of C)

@cdnninja
Copy link
Collaborator Author

cdnninja commented Nov 9, 2021

Huge thank you @dahlb this has really pushed the USA Kia support forward. Great to see!

@dahlb
Copy link
Contributor

dahlb commented Nov 10, 2021

@mbbush I don't know how to get the Uvo USA apk, but from the previous comments I'm guessing you found it. Can you point me to where you got it or throw your copy up somewhere for me to grab which would be even better as I assume it was already modified by apk-mitm

@mbbush
Copy link

mbbush commented Nov 10, 2021

Since I'm in the USA, I just downloaded it from google play and then used ADB to pull it off the phone.

I remember that I tried several different tools and really struggled with them, before finding the one I mentioned in a comment above, which made it really easy. I don't remember whether I needed some of the partial work I'd done with the other tools to work with the good one.

The apk itself is also packaged in several layers. There are actually four apks, each containing different components, but it looks like the most relevant parts are in the base.apk

It looks like I have several versions, some of which are for x86 (to use on the emulator) and some of which are for arm. Some are quite possibly patched by something, some are zipped, some are extracted. It's a mess. But I'm happy to share the mess with you! https://mega.nz/file/TR5ERATL#oIPtw-89kWz0ZoYTPE0WN5F9YJammdOd4OJbffHhPKg

@dahlb
Copy link
Contributor

dahlb commented Nov 10, 2021

@mbbush thanks base.apk worked great and helped me finish force update

hoping to populate these methods next one at a time
lock_action
start_climate
start_charge

@Ceer123
Copy link

Ceer123 commented Nov 11, 2021

Thanks for the work on this so far. My setup is working pretty good now. One thing I noticed was every time there is an update all the sensors switch to Unavailable for about 4 seconds. Is this a known issue? If not I will add some logs.
image

@dahlb
Copy link
Contributor

dahlb commented Nov 11, 2021 via email

@tchoward
Copy link

Thanks for all the work on this...

What I am seeing:

  1. When my car is not being driven and not charging (PHEV) it shows battery, range, etc as zero.
    image
  2. Errors from the log are below.
Logger: homeassistant.util.logging
Source: util/logging.py:105
First occurred: November 10, 2021, 6:47:13 AM (33 occurrences)
Last logged: 8:52:27 AM

Exception in update when dispatching 'kia_uvo_update_0': () Traceback (most recent call last): File "/config/custom_components/kia_uvo/KiaUvoEntity.py", line 21, in update self.async_write_ha_state() File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 486, in async_write_ha_state self._async_write_ha_state() File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 519, in _async_write_ha_state state = self._stringify_state() File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 492, in _stringify_state if (state := self.state) is None: File "/config/custom_components/kia_uvo/sensor.py", line 100, in state return self.vehicle.kia_uvo_api.get_temperature_range_by_region()[int(value, 16)] ValueError: invalid literal for int() with base 16: '0xLOW'

@dahlb
Copy link
Contributor

dahlb commented Nov 11, 2021

@tchoward

  1. I believe this is the same as the issue tracked here Battery Incorrect Report - Drops to zero randomly #55 and I've seen it on my EV too it is an artifact of Kia's api but work arounds are being discussed

  2. can you add that stack trace to feat: add F for USA and leave other regions with C #115 that is the pr to address temperatures in USA and currently that pr wouldn't handle that scenario of the car's temp being too low, but if your'e willing to test a fix I could add an improvement to that so it does

@dahlb
Copy link
Contributor

dahlb commented Nov 11, 2021

added the other actions in a pr, has every other action; once I figured out the offset being -5.0 instead of -5 was the problem for a while the rest was very fast

still want to fix

  1. validate and log errors for responses that aren't successful, will be helpful in next fix too
  2. auth sessions errors handled gracefully (create new session and keep working)
  3. check status of action until finish and then trigger update for attributes

@dahlb
Copy link
Contributor

dahlb commented Nov 14, 2021

@cdnninja I think this is fully implemented now, unless I missed something?

@cdnninja
Copy link
Collaborator Author

Nope. I think we can close this an open issues if needed great work @dahlb and @mbbush. Great to see this working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants