Hyundai-Kia-Connect / kia_uvo

A Home Assistant HACS integration that supports Kia Connect(Uvo) and Hyundai Bluelink. The integration supports the EU, Canada and the USA.
MIT License
433 stars 85 forks source link

Incorrect time zone causes force refresh and climate_start to fail #488

Closed torbjornaxelsson closed 1 year ago

torbjornaxelsson commented 1 year ago

Please check Services, Known Bug / Issues and Troubleshooting over here first: https://github.com/fuatakgun/kia_uvo/blob/master/README.md Region and Brand of car Canada, Hyundai EV

Version of the integration 2.0.46

Describe the bug I couldn't get climate_start to work, the car just wouldn't react. After digging through the logs I saw that the command fails due to a force refresh being triggered immediately after. It seems the cause is that the time zone in hyundai_kia_connect_api is hardcoded to UTC. Since I'm in the PST zone, when the API calculates time since last update it ends up being off by 8 hours.

More generally, the bug causes a force refresh to be run after every API command.

Configuring the force refresh interval to be longer than 8 hours makes the start_climate command work again.

Proposed solution: Pull the time zone from HomeAssistant settings (or system time), or allow it to be configured by the user.

Debug logs if an error occurred See below, time differential calculated to 28876.490582 seconds which is just over 8 hours.

2022-12-13** 20:36:30.051 DEBUG (SyncWorker_1) [hyundai_kia_connect_api.KiaUvoApiCA] hyundai_kia_connect_api - Planned start_climate payload {'hvacInfo': {'airCtrl': 1, 'defrost': 1, 'heating1': 1, 'airTemp': {'value': '10H', 'unit': 0, 'hvacTempType': 1}}, 'pin': 'xxxx'}

2022-12-13 20:36:30.488 DEBUG (SyncWorker_1) [hyundai_kia_connect_api.KiaUvoApiCA] hyundai_kia_connect_api - Received start_climate response {'responseHeader': {'responseCode': 0, 'responseDesc': 'Success'}}

2022-12-13 20:36:30.490 DEBUG (SyncWorker_4) [hyundai_kia_connect_api.VehicleManager] hyundai_kia_connect_api - Time differential in seconds: 28876.490582

2022-12-13 20:36:36.142 DEBUG (SyncWorker_4) [hyundai_kia_connect_api.KiaUvoApiCA] hyundai_kia_connect_api - Received forced vehicle data ....
cdnninja commented 1 year ago

We have a few timezones that are valid here. Your timezone which is where we configure blackout. Then we have the API returned timezone which is the last updated value. We have to convert between these two. I will take a look to see if we have a mistake on this.

I am not sold this stops the car from starting since typically the API will fail on the second call not the first. We may have two issues.

torbjornaxelsson commented 1 year ago

The Hyundai Canada service doesn't seem to specify a timezone, it responds with an integer value which seems to be in my time zone, not UTC. I just got the response 20221214100609 and it's 10:07AM here.

I had a look at the hyundai_kia_connect_api and it seems in the ApiImpl class, timezone is set to utc and I can't find anywhere it is changed. In the KiaUvoApiCA class, get_last_updated_at seems to rely on self.data_timezone to parse the value from Hyundai Canada, so it gets interpreted as UTC when it's actually a PST value.

As far as the failed climate_start call - the API call responds with success, however vehicle climate never starts. In the Hyundai mobile app I can view transaction history. After around 3 minutes it shows up in the history as a Climate Start call with status Failed.

I can't think of any explanation other than the force refresh somehow interfering with the ongoing climate_start command. Possibly in the vehicle itself, not the API.

torbjornaxelsson commented 1 year ago

I wrote a python script that uses the hyundai_kia_connect_api to test the issue in isolation. Running this script results in climate start failure. If I remove the last line with vm.force_refresh_vehicle_state line at the end, climate start succeeds.

import logging
from hyundai_kia_connect_api import *

logging.basicConfig(level=logging.DEBUG)

vm = VehicleManager(region=2, brand=2, username="x", password="x", pin="x")
vm.check_and_refresh_token()

climate_request_options = ClimateRequestOptions(
    set_temp=23,
    climate=1,
    heating=1,
    defrost=1,
)

vm.start_climate('x', climate_request_options)

vm.force_refresh_vehicle_state(vm.get_vehicle('x'))

Note that the API responds with success, even when climate failes to actually start DEBUG:hyundai_kia_connect_api.KiaUvoApiCA:hyundai_kia_connect_api - Received start_climate response {'responseHeader': {'responseCode': 0, 'responseDesc': 'Success'}}

cdnninja commented 1 year ago

You are awesome! Always appreciate PRs ;).

I am in canada and not seeing this behavior. I am located in MST. In my case after lets say a force update I see the following in logs:

hyundai_kia_connect_api - Time differential in seconds: 32.952199 which implies for me atleast timezone works. I however am a Kia user - we have the same codebase but maybe Hyundai uses different timezones. If you change your time zone in the mobile app does it change how it responds?

Interesting find on the force refresh. Longer term I need to finish action tracking. It will tell us if climate is done processing at which point we can call the update. In the meantime we can delay the call or remove it entirely.

torbjornaxelsson commented 1 year ago

I can't find a timezone setting in the Android app or the web interface (mybluelink.ca). I'm not sure how they determine which time zone the vehicle is in. For you, is the time returned from the Kia API in UTC or your timezone?

I ran a climate start from mybluelink.ca now, it seems the way it's tracking the result is by calling https://mybluelink.ca/tods/api/rmtsts every 10 seconds. Here are examples of the response. I think apiResult P is pending or progress, apiResult C is completed.

Also, just noticed below that apiStartDate and apiEndDate seem to be in UTC whereas lastStatusDate is in my time zone. Curious.

{"responseHeader":{"responseCode":0,"responseDesc":"Success"},"result":{"transaction":{"apiCode":"RMT-E0301","apiStartDate":"20221214192418","apiEndDate":"20221214192418","apiResult":"P","apiStatusCode":"null"}}}

{"responseHeader":{"responseCode":0,"responseDesc":"Success"},"result":{"transaction":{"apiCode":"RMT-E0301","apiStartDate":"20221214192418","apiEndDate":"20221214192418","apiResult":"C","apiStatusCode":"200"},"vehicle":{"lastStatusDate":"20221214112426","airCtrlOn":true,"engine":false,"doorLock":true,"doorOpen":{"frontLeft":0,"frontRight":0,"backLeft":0,"backRight":0},"trunkOpen":false,"airTempUnit":"C","airTemp":{"value":"06H","unit":0},"defrost":true,"acc":false,"evStatus":{"batteryCharge":false,"batteryStatus":74,"batteryPlugin":0,"remainTime2":{"etc1":{"value":11,"unit":1},"etc2":{"value":970,"unit":1},"etc3":{"value":215,"unit":1},"atc":{"value":0,"unit":1}},"drvDistance":[{"rangeByFuel":{"gasModeRange":{"value":0.0,"unit":1},"evModeRange":{"value":300.0,"unit":1},"totalAvailableRange":{"value":300.0,"unit":1}},"type":2}]},"hoodOpen":false,"transCond":true,"steerWheelHeat":0,"sideBackWindowHeat":0,"dte":{},"tirePressureLamp":{"tirePressureLampAll":0},"battery":{"batSoc":84,"batState":0,"batSignalReferenceValue":{}},"remoteIgnition":true,"seatHeaterVentInfo":{},"sleepModeCheck":false,"lampWireStatus":{"headLamp":{},"stopLamp":{},"turnSignalLamp":{}},"windowOpen":{},"engineRuntime":{}}}}
torbjornaxelsson commented 1 year ago

For now, I'm running kia_uvo.update in homeassistant 30 seconds after climate_start, that seems to work. force_update is not required. But I suppose polling https://mybluelink.ca/tods/api/rmtsts is the proper way to do it

torbjornaxelsson commented 1 year ago

Quick update, I found the timezone setting in the car itself, accessed through the center console touch screen. It only lets me pick Canadian time zones, I changed it from Pacific to Eastern. Now the lastStatusDate value is reported in Eastern time and the offset error has changed from 8 to 5 hours.

cdnninja commented 1 year ago

I just checked my car and confirmed my car is reporting UTC for lastStatusDate.

2022-12-14 11:42:21.872 DEBUG (SyncWorker_2) [hyundai_kia_connect_api.KiaUvoApiCA] hyundai_kia_connect_api - Current Vehicle Last Updated: 2022-12-14 18:41:58+00:00

As you can see the update occurred minutes prior to log. This is right after a force update.

So this is another curve ball from the API. My gut thought is this is either

  1. All Hyundai's reporting timezones that change.
  2. Specific to a model of car or year. What year and model is your car?
cdnninja commented 1 year ago

Few other notes as you dig in. last action tracking is partially functional in our API just not implemented for home assistant yet. It can be viewed here: https://github.com/Hyundai-Kia-Connect/hyundai_kia_connect_api/blob/67ca3702dc446a2090d27097f85b36d666522568/hyundai_kia_connect_api/KiaUvoApiCA.py#L517-L533

This purely tells you if it is "done" not if successful.

Could you check what your "Get Vehicles Response:" log entry shows? I wonder if yours reports a timezone for the car. Mine doesn't but mine is also UTC.

torbjornaxelsson commented 1 year ago

My "Get Vehicles Response" does not show the timezone. I have a 2021 Kona EV, no idea if this is specific to my vehicle or for all Hyundai vehicles.

Here's an idea. When we do a force refresh, the response lastStatusDate will be equal to current time in the timezone the API uses. By comparing lastStatusDate to system time at this point, the offset can be calculated. That solution would be general and not relying on figuring out settings for different countries/vehicles.

On a related note, I happened to se that in KiaUvoApiEU the timezone is hardcoded to Berlin, maybe by someone who had the same offset issue?

I didn't realize last action tracking was already in the API, nice work! I tested the call and it works for me. For Home assistant integration it would be useful for this function to return the full API response. That way success/failure can be logged, and on success the command responds with the latest vehicle data which probably could be used to vehicle state in Home assistant.

cdnninja commented 1 year ago

I do like that idea to calculate time zone. It would need to factor in a big of room and just look at nearest hour delta. Is this something you would considering writing and creating a PR for? Thinking we put this to CA only for now.

As for EU yes that region always returns in the Berlin time zone.

As for last action tracking yes needs some digging in since not all regions support it. We had it implemented in 1.x of this but it had some odd logic that didn't transfer over just yet. Just need time to add it. Also open to contributions on it. Typically starting with making sure api is ready for it on all regions. It will be a bit before I spend time on that one.

torbjornaxelsson commented 1 year ago

I'll have a go at the time zone calculation, will submit a PR when I get the chance!

I see what you mean about tracking actions being a bit tricky. I could conceivably come up with a solution for CA, but it might not work for other regions. Where do you think the logic for checking status should be, fully within the API or let the Home Assistant integration handle the job of checking status every X seconds?

cdnninja commented 1 year ago

Home assistant will need to schedule the call. Otherwise library will lock up the event loop as it waits. So I think the api may be close for CA but haven't tested that it works for all calls yet. So I would say first is testing that out confirming they return the tracking ids and work. If so we can ensure other apis consistently return something predictable, one I think also does action tracking.

At one point we play with the logic in this repo to consume it. Most likely similar to the 1.8 version. I have another issue in here for action tracking though so let's move that chat over to that.

torbjornaxelsson commented 1 year ago

Alright, had a crack at the timezone issue - see (https://github.com/Hyundai-Kia-Connect/hyundai_kia_connect_api/pull/187)

Let's continue discussion on last action tracking in #440