hyundai-kia-connect-api 3.17.6__py2.py3-none-any.whl → 3.32.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hyundai_kia_connect_api/ApiImpl.py +102 -29
- hyundai_kia_connect_api/ApiImplType1.py +321 -0
- hyundai_kia_connect_api/{HyundaiBlueLinkAPIUSA.py → HyundaiBlueLinkApiUSA.py} +295 -35
- hyundai_kia_connect_api/KiaUvoApiAU.py +77 -88
- hyundai_kia_connect_api/KiaUvoApiCA.py +70 -41
- hyundai_kia_connect_api/KiaUvoApiCN.py +30 -42
- hyundai_kia_connect_api/KiaUvoApiEU.py +466 -376
- hyundai_kia_connect_api/{KiaUvoAPIUSA.py → KiaUvoApiUSA.py} +98 -102
- hyundai_kia_connect_api/Vehicle.py +142 -19
- hyundai_kia_connect_api/VehicleManager.py +60 -19
- hyundai_kia_connect_api/__init__.py +5 -6
- hyundai_kia_connect_api/bluelink.py +457 -0
- hyundai_kia_connect_api/const.py +12 -1
- hyundai_kia_connect_api/utils.py +30 -3
- {hyundai_kia_connect_api-3.17.6.dist-info → hyundai_kia_connect_api-3.32.0.dist-info}/LICENSE +0 -1
- {hyundai_kia_connect_api-3.17.6.dist-info → hyundai_kia_connect_api-3.32.0.dist-info}/METADATA +53 -18
- hyundai_kia_connect_api-3.32.0.dist-info/RECORD +23 -0
- {hyundai_kia_connect_api-3.17.6.dist-info → hyundai_kia_connect_api-3.32.0.dist-info}/WHEEL +1 -1
- hyundai_kia_connect_api-3.32.0.dist-info/entry_points.txt +2 -0
- hyundai_kia_connect_api-3.17.6.dist-info/RECORD +0 -20
- {hyundai_kia_connect_api-3.17.6.dist-info → hyundai_kia_connect_api-3.32.0.dist-info}/AUTHORS.rst +0 -0
- {hyundai_kia_connect_api-3.17.6.dist-info → hyundai_kia_connect_api-3.32.0.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,6 @@ import datetime as dt
|
|
7
7
|
import math
|
8
8
|
import logging
|
9
9
|
import random
|
10
|
-
import re
|
11
10
|
import uuid
|
12
11
|
from time import sleep
|
13
12
|
from urllib.parse import parse_qs, urlparse
|
@@ -17,10 +16,10 @@ import requests
|
|
17
16
|
from dateutil import tz
|
18
17
|
|
19
18
|
from .ApiImpl import (
|
20
|
-
ApiImpl,
|
21
19
|
ClimateRequestOptions,
|
22
20
|
WindowRequestOptions,
|
23
21
|
)
|
22
|
+
from .ApiImplType1 import ApiImplType1
|
24
23
|
from .Token import Token
|
25
24
|
from .Vehicle import (
|
26
25
|
Vehicle,
|
@@ -43,19 +42,27 @@ from .const import (
|
|
43
42
|
ENGINE_TYPES,
|
44
43
|
OrderStatus,
|
45
44
|
)
|
46
|
-
from .exceptions import
|
45
|
+
from .exceptions import (
|
46
|
+
AuthenticationError,
|
47
|
+
DuplicateRequestError,
|
48
|
+
RequestTimeoutError,
|
49
|
+
ServiceTemporaryUnavailable,
|
50
|
+
NoDataFound,
|
51
|
+
InvalidAPIResponseError,
|
52
|
+
APIError,
|
53
|
+
RateLimitingError,
|
54
|
+
)
|
47
55
|
from .utils import (
|
48
56
|
get_child_value,
|
49
57
|
get_index_into_hex_temp,
|
50
58
|
get_hex_temp_into_index,
|
59
|
+
parse_datetime,
|
51
60
|
)
|
52
61
|
|
53
62
|
_LOGGER = logging.getLogger(__name__)
|
54
63
|
|
55
64
|
USER_AGENT_OK_HTTP: str = "okhttp/3.12.0"
|
56
|
-
USER_AGENT_MOZILLA: str = (
|
57
|
-
"Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19" # noqa
|
58
|
-
)
|
65
|
+
USER_AGENT_MOZILLA: str = "Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19" # noqa
|
59
66
|
|
60
67
|
|
61
68
|
def _check_response_for_errors(response: dict) -> None:
|
@@ -96,7 +103,7 @@ def _check_response_for_errors(response: dict) -> None:
|
|
96
103
|
raise APIError(f"Server returned: '{response['resMsg']}'")
|
97
104
|
|
98
105
|
|
99
|
-
class KiaUvoApiAU(
|
106
|
+
class KiaUvoApiAU(ApiImplType1):
|
100
107
|
data_timezone = tz.gettz("Australia/Sydney")
|
101
108
|
temperature_range = [x * 0.5 for x in range(34, 54)]
|
102
109
|
|
@@ -106,35 +113,18 @@ class KiaUvoApiAU(ApiImpl):
|
|
106
113
|
self.BASE_URL: str = "au-apigw.ccs.kia.com.au:8082"
|
107
114
|
self.CCSP_SERVICE_ID: str = "8acb778a-b918-4a8d-8624-73a0beb64289"
|
108
115
|
self.APP_ID: str = "4ad4dcde-be23-48a8-bc1c-91b94f5c06f8" # Android app ID
|
109
|
-
self.BASIC_AUTHORIZATION: str =
|
110
|
-
"Basic OGFjYjc3OGEtYjkxOC00YThkLTg2MjQtNzNhMGJlYjY0Mjg5OjdTY01NbTZmRVlYZGlFUEN4YVBhUW1nZVlkbFVyZndvaDRBZlhHT3pZSVMyQ3U5VA=="
|
111
|
-
)
|
116
|
+
self.BASIC_AUTHORIZATION: str = "Basic OGFjYjc3OGEtYjkxOC00YThkLTg2MjQtNzNhMGJlYjY0Mjg5OjdTY01NbTZmRVlYZGlFUEN4YVBhUW1nZVlkbFVyZndvaDRBZlhHT3pZSVMyQ3U5VA==" # noqa
|
112
117
|
elif BRANDS[brand] == BRAND_HYUNDAI:
|
113
118
|
self.BASE_URL: str = "au-apigw.ccs.hyundai.com.au:8080"
|
114
119
|
self.CCSP_SERVICE_ID: str = "855c72df-dfd7-4230-ab03-67cbf902bb1c"
|
115
120
|
self.APP_ID: str = "f9ccfdac-a48d-4c57-bd32-9116963c24ed" # Android app ID
|
116
|
-
self.BASIC_AUTHORIZATION: str =
|
117
|
-
"Basic ODU1YzcyZGYtZGZkNy00MjMwLWFiMDMtNjdjYmY5MDJiYjFjOmU2ZmJ3SE0zMllOYmhRbDBwdmlhUHAzcmY0dDNTNms5MWVjZUEzTUpMZGJkVGhDTw=="
|
118
|
-
)
|
121
|
+
self.BASIC_AUTHORIZATION: str = "Basic ODU1YzcyZGYtZGZkNy00MjMwLWFiMDMtNjdjYmY5MDJiYjFjOmU2ZmJ3SE0zMllOYmhRbDBwdmlhUHAzcmY0dDNTNms5MWVjZUEzTUpMZGJkVGhDTw==" # noqa
|
119
122
|
|
120
123
|
self.USER_API_URL: str = "https://" + self.BASE_URL + "/api/v1/user/"
|
121
124
|
self.SPA_API_URL: str = "https://" + self.BASE_URL + "/api/v1/spa/"
|
122
125
|
self.SPA_API_URL_V2: str = "https://" + self.BASE_URL + "/api/v2/spa/"
|
123
126
|
self.CLIENT_ID: str = self.CCSP_SERVICE_ID
|
124
127
|
|
125
|
-
def _get_authenticated_headers(self, token: Token) -> dict:
|
126
|
-
return {
|
127
|
-
"Authorization": token.access_token,
|
128
|
-
"ccsp-service-id": self.CCSP_SERVICE_ID,
|
129
|
-
"ccsp-application-id": self.APP_ID,
|
130
|
-
"ccsp-device-id": token.device_id,
|
131
|
-
"Stamp": self._get_stamp(),
|
132
|
-
"Host": self.BASE_URL,
|
133
|
-
"Connection": "Keep-Alive",
|
134
|
-
"Accept-Encoding": "gzip",
|
135
|
-
"User-Agent": USER_AGENT_OK_HTTP,
|
136
|
-
}
|
137
|
-
|
138
128
|
def _get_control_headers(self, token: Token) -> dict:
|
139
129
|
control_token, _ = self._get_control_token(token)
|
140
130
|
authenticated_headers = self._get_authenticated_headers(token)
|
@@ -200,29 +190,11 @@ class KiaUvoApiAU(ApiImpl):
|
|
200
190
|
VIN=entry["vin"],
|
201
191
|
timezone=self.data_timezone,
|
202
192
|
engine_type=entry_engine_type,
|
193
|
+
ccu_ccs2_protocol_support=entry["ccuCCS2ProtocolSupport"],
|
203
194
|
)
|
204
195
|
result.append(vehicle)
|
205
196
|
return result
|
206
197
|
|
207
|
-
def get_last_updated_at(self, value) -> dt.datetime:
|
208
|
-
_LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
|
209
|
-
if value is None:
|
210
|
-
value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
|
211
|
-
else:
|
212
|
-
m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
|
213
|
-
value = dt.datetime(
|
214
|
-
year=int(m.group(1)),
|
215
|
-
month=int(m.group(2)),
|
216
|
-
day=int(m.group(3)),
|
217
|
-
hour=int(m.group(4)),
|
218
|
-
minute=int(m.group(5)),
|
219
|
-
second=int(m.group(6)),
|
220
|
-
tzinfo=self.data_timezone,
|
221
|
-
)
|
222
|
-
|
223
|
-
_LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
|
224
|
-
return value
|
225
|
-
|
226
198
|
def _get_time_from_string(self, value, timesection) -> dt.datetime.time:
|
227
199
|
if value is not None:
|
228
200
|
lastTwo = int(value[-2:])
|
@@ -238,17 +210,40 @@ class KiaUvoApiAU(ApiImpl):
|
|
238
210
|
return value
|
239
211
|
|
240
212
|
def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
213
|
+
url = self.SPA_API_URL + "vehicles/" + vehicle.id
|
214
|
+
is_ccs2 = vehicle.ccu_ccs2_protocol_support != 0
|
215
|
+
if is_ccs2:
|
216
|
+
url += "/ccs2/carstatus/latest"
|
217
|
+
else:
|
218
|
+
url += "/status/latest"
|
219
|
+
|
220
|
+
response = requests.get(
|
221
|
+
url,
|
222
|
+
headers=self._get_authenticated_headers(
|
223
|
+
token, vehicle.ccu_ccs2_protocol_support
|
224
|
+
),
|
225
|
+
).json()
|
226
|
+
|
227
|
+
_LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
|
228
|
+
_check_response_for_errors(response)
|
229
|
+
|
230
|
+
if is_ccs2:
|
231
|
+
state = response["resMsg"]["state"]["Vehicle"]
|
232
|
+
self._update_vehicle_properties_ccs2(vehicle, state)
|
233
|
+
else:
|
234
|
+
location = self._get_location(token, vehicle)
|
235
|
+
self._update_vehicle_properties(
|
236
|
+
vehicle,
|
237
|
+
{
|
238
|
+
"status": response["resMsg"],
|
239
|
+
"vehicleLocation": location,
|
240
|
+
},
|
241
|
+
)
|
250
242
|
|
251
|
-
if
|
243
|
+
if (
|
244
|
+
vehicle.engine_type == ENGINE_TYPES.EV
|
245
|
+
or vehicle.engine_type == ENGINE_TYPES.PHEV
|
246
|
+
):
|
252
247
|
try:
|
253
248
|
state = self._get_driving_info(token, vehicle)
|
254
249
|
except Exception as e:
|
@@ -278,15 +273,19 @@ class KiaUvoApiAU(ApiImpl):
|
|
278
273
|
)
|
279
274
|
# Only call for driving info on cars we know have a chance of supporting it.
|
280
275
|
# Could be expanded if other types do support it.
|
281
|
-
if
|
276
|
+
if (
|
277
|
+
vehicle.engine_type == ENGINE_TYPES.EV
|
278
|
+
or vehicle.engine_type == ENGINE_TYPES.PHEV
|
279
|
+
):
|
282
280
|
try:
|
283
281
|
state = self._get_driving_info(token, vehicle)
|
284
282
|
except Exception as e:
|
285
|
-
# we don't know if all car types provide this
|
286
|
-
#
|
287
|
-
#
|
283
|
+
# we don't know if all car types (ex: ICE cars) provide this
|
284
|
+
# information. We also don't know what the API returns if
|
285
|
+
# the info is unavailable. So, catch any exception and move on.
|
288
286
|
_LOGGER.exception(
|
289
287
|
"""Failed to parse driving info. Possible reasons:
|
288
|
+
- incompatible vehicle (ICE)
|
290
289
|
- new API format
|
291
290
|
- API outage
|
292
291
|
""",
|
@@ -297,21 +296,22 @@ class KiaUvoApiAU(ApiImpl):
|
|
297
296
|
|
298
297
|
def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
|
299
298
|
if get_child_value(state, "status.time"):
|
300
|
-
vehicle.last_updated_at =
|
301
|
-
get_child_value(state, "status.time")
|
299
|
+
vehicle.last_updated_at = parse_datetime(
|
300
|
+
get_child_value(state, "status.time"), self.data_timezone
|
302
301
|
)
|
303
302
|
else:
|
304
303
|
vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
|
305
304
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
305
|
+
if get_child_value(state, "status.odometer.value"):
|
306
|
+
vehicle.odometer = (
|
307
|
+
get_child_value(state, "status.odometer.value"),
|
308
|
+
DISTANCE_UNITS[
|
309
|
+
get_child_value(
|
310
|
+
state,
|
311
|
+
"status.odometer.unit",
|
312
|
+
)
|
313
|
+
],
|
314
|
+
)
|
315
315
|
vehicle.car_battery_percentage = get_child_value(state, "status.battery.batSoc")
|
316
316
|
vehicle.engine_is_running = get_child_value(state, "status.engine")
|
317
317
|
|
@@ -490,7 +490,7 @@ class KiaUvoApiAU(ApiImpl):
|
|
490
490
|
vehicle.ev_charge_limits_dc = [
|
491
491
|
x["targetSOClevel"] for x in target_soc_list if x["plugType"] == 0
|
492
492
|
][-1]
|
493
|
-
except:
|
493
|
+
except Exception:
|
494
494
|
_LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
|
495
495
|
if (
|
496
496
|
get_child_value(
|
@@ -646,8 +646,8 @@ class KiaUvoApiAU(ApiImpl):
|
|
646
646
|
vehicle.location = (
|
647
647
|
get_child_value(state, "vehicleLocation.coord.lat"),
|
648
648
|
get_child_value(state, "vehicleLocation.coord.lon"),
|
649
|
-
|
650
|
-
get_child_value(state, "vehicleLocation.time")
|
649
|
+
parse_datetime(
|
650
|
+
get_child_value(state, "vehicleLocation.time"), self.data_timezone
|
651
651
|
),
|
652
652
|
)
|
653
653
|
vehicle.data = state
|
@@ -657,18 +657,6 @@ class KiaUvoApiAU(ApiImpl):
|
|
657
657
|
vehicle.power_consumption_30d = get_child_value(state, "consumption30d")
|
658
658
|
vehicle.daily_stats = get_child_value(state, "dailyStats")
|
659
659
|
|
660
|
-
def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
|
661
|
-
url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/status/latest"
|
662
|
-
|
663
|
-
response = requests.get(
|
664
|
-
url, headers=self._get_authenticated_headers(token)
|
665
|
-
).json()
|
666
|
-
_LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
|
667
|
-
_check_response_for_errors(response)
|
668
|
-
response = response["resMsg"]
|
669
|
-
|
670
|
-
return response
|
671
|
-
|
672
660
|
def _get_location(self, token: Token, vehicle: Vehicle) -> dict:
|
673
661
|
url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/location/park"
|
674
662
|
|
@@ -679,7 +667,7 @@ class KiaUvoApiAU(ApiImpl):
|
|
679
667
|
_LOGGER.debug(f"{DOMAIN} - _get_location response: {response}")
|
680
668
|
_check_response_for_errors(response)
|
681
669
|
return response["resMsg"]["gpsDetail"]
|
682
|
-
except:
|
670
|
+
except Exception:
|
683
671
|
_LOGGER.debug(f"{DOMAIN} - _get_location failed")
|
684
672
|
return None
|
685
673
|
|
@@ -867,7 +855,7 @@ class KiaUvoApiAU(ApiImpl):
|
|
867
855
|
yyyymm_string,
|
868
856
|
) -> None:
|
869
857
|
"""
|
870
|
-
|
858
|
+
feature only available for some regions.
|
871
859
|
Updates the vehicle.month_trip_info for the specified month.
|
872
860
|
|
873
861
|
Default this information is None:
|
@@ -911,7 +899,7 @@ class KiaUvoApiAU(ApiImpl):
|
|
911
899
|
yyyymmdd_string,
|
912
900
|
) -> None:
|
913
901
|
"""
|
914
|
-
|
902
|
+
feature only available for some regions.
|
915
903
|
Updates the vehicle.day_trip_info information for the specified day.
|
916
904
|
|
917
905
|
Default this information is None:
|
@@ -985,6 +973,7 @@ class KiaUvoApiAU(ApiImpl):
|
|
985
973
|
battery_care_consumption=day["batteryMgPwrCsp"],
|
986
974
|
regenerated_energy=day["regenPwr"],
|
987
975
|
distance=day["calculativeOdo"],
|
976
|
+
distance_unit=vehicle.odometer_unit,
|
988
977
|
)
|
989
978
|
drivingInfo["dailyStats"].append(processedDay)
|
990
979
|
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
# pylint:disable=unused-argument,missing-timeout,logging-fstring-interpolation,bare-except,invalid-name,missing-function-docstring
|
4
4
|
|
5
|
+
import time
|
5
6
|
import datetime as dt
|
6
7
|
import json
|
7
8
|
import logging
|
8
|
-
import re
|
9
9
|
|
10
10
|
import pytz
|
11
11
|
import requests
|
@@ -35,6 +35,7 @@ from .utils import (
|
|
35
35
|
get_child_value,
|
36
36
|
get_hex_temp_into_index,
|
37
37
|
get_index_into_hex_temp,
|
38
|
+
parse_datetime,
|
38
39
|
)
|
39
40
|
|
40
41
|
import ssl
|
@@ -69,6 +70,7 @@ class KiaUvoApiCA(ApiImpl):
|
|
69
70
|
def __init__(self, region: int, brand: int, language: str) -> None:
|
70
71
|
self.vehicle_timezone = self.data_timezone
|
71
72
|
self.LANGUAGE: str = language
|
73
|
+
self.brand = brand
|
72
74
|
if BRANDS[brand] == BRAND_KIA:
|
73
75
|
self.BASE_URL: str = "kiaconnect.ca"
|
74
76
|
elif BRANDS[brand] == BRAND_HYUNDAI:
|
@@ -94,8 +96,14 @@ class KiaUvoApiCA(ApiImpl):
|
|
94
96
|
"sec-fetch-mode": "cors",
|
95
97
|
"sec-fetch-site": "same-origin",
|
96
98
|
}
|
97
|
-
self.
|
98
|
-
|
99
|
+
self._sessions = None
|
100
|
+
|
101
|
+
@property
|
102
|
+
def sessions(self):
|
103
|
+
if not self._sessions:
|
104
|
+
self._sessions = requests.Session()
|
105
|
+
self._sessions.mount("https://" + self.BASE_URL, cipherAdapter())
|
106
|
+
return self._sessions
|
99
107
|
|
100
108
|
def _check_response_for_errors(self, response: dict) -> None:
|
101
109
|
"""
|
@@ -202,8 +210,8 @@ class KiaUvoApiCA(ApiImpl):
|
|
202
210
|
|
203
211
|
# Calculate offset between vehicle last_updated_at and UTC
|
204
212
|
self.vehicle_timezone = vehicle.timezone
|
205
|
-
last_updated_at =
|
206
|
-
get_child_value(state, "status.lastStatusDate")
|
213
|
+
last_updated_at = parse_datetime(
|
214
|
+
get_child_value(state, "status.lastStatusDate"), self.data_timezone
|
207
215
|
)
|
208
216
|
now_utc: dt = dt.datetime.now(pytz.utc)
|
209
217
|
offset = round((last_updated_at - now_utc).total_seconds() / 3600)
|
@@ -238,15 +246,19 @@ class KiaUvoApiCA(ApiImpl):
|
|
238
246
|
def _update_vehicle_properties_base(self, vehicle: Vehicle, state: dict) -> None:
|
239
247
|
_LOGGER.debug(f"{DOMAIN} - Old Vehicle Last Updated: {vehicle.last_updated_at}")
|
240
248
|
self.vehicle_timezone = vehicle.timezone
|
241
|
-
vehicle.last_updated_at =
|
242
|
-
get_child_value(state, "status.lastStatusDate")
|
249
|
+
vehicle.last_updated_at = parse_datetime(
|
250
|
+
get_child_value(state, "status.lastStatusDate"), self.data_timezone
|
243
251
|
)
|
244
252
|
_LOGGER.debug(
|
245
253
|
f"{DOMAIN} - Current Vehicle Last Updated: {vehicle.last_updated_at}"
|
246
254
|
)
|
247
255
|
# Converts temp to usable number. Currently only support celsius.
|
248
256
|
# Future to do is check unit in case the care itself is set to F.
|
249
|
-
if
|
257
|
+
if (
|
258
|
+
get_child_value(state, "status.airTemp.value") is not None
|
259
|
+
and get_child_value(state, "status.airTemp.value") != "OFF"
|
260
|
+
and get_child_value(state, "status.airTemp.value")[-1] == "H"
|
261
|
+
):
|
250
262
|
tempIndex = get_hex_temp_into_index(
|
251
263
|
get_child_value(state, "status.airTemp.value")
|
252
264
|
)
|
@@ -426,29 +438,10 @@ class KiaUvoApiCA(ApiImpl):
|
|
426
438
|
vehicle.location = (
|
427
439
|
get_child_value(state, "coord.lat"),
|
428
440
|
get_child_value(state, "coord.lon"),
|
429
|
-
|
441
|
+
parse_datetime(get_child_value(state, "time"), self.data_timezone),
|
430
442
|
)
|
431
443
|
vehicle.data["vehicleLocation"] = state
|
432
444
|
|
433
|
-
def get_last_updated_at(self, value) -> dt.datetime:
|
434
|
-
_LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
|
435
|
-
if value is None:
|
436
|
-
value = dt.datetime(2000, 1, 1, tzinfo=self.vehicle_timezone)
|
437
|
-
else:
|
438
|
-
m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
|
439
|
-
value = dt.datetime(
|
440
|
-
year=int(m.group(1)),
|
441
|
-
month=int(m.group(2)),
|
442
|
-
day=int(m.group(3)),
|
443
|
-
hour=int(m.group(4)),
|
444
|
-
minute=int(m.group(5)),
|
445
|
-
second=int(m.group(6)),
|
446
|
-
tzinfo=self.vehicle_timezone,
|
447
|
-
)
|
448
|
-
|
449
|
-
_LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
|
450
|
-
return value
|
451
|
-
|
452
445
|
def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
|
453
446
|
# Vehicle Status Call
|
454
447
|
url = self.API_URL + "lstvhclsts"
|
@@ -509,7 +502,7 @@ class KiaUvoApiCA(ApiImpl):
|
|
509
502
|
if response["responseHeader"]["responseCode"] != 0:
|
510
503
|
raise APIError("No Location Located")
|
511
504
|
return response["result"]
|
512
|
-
except:
|
505
|
+
except Exception:
|
513
506
|
_LOGGER.warning(f"{DOMAIN} - Get vehicle location failed")
|
514
507
|
return None
|
515
508
|
|
@@ -590,18 +583,33 @@ class KiaUvoApiCA(ApiImpl):
|
|
590
583
|
)
|
591
584
|
if vehicle.engine_type == ENGINE_TYPES.EV:
|
592
585
|
payload = {
|
593
|
-
"hvacInfo": {
|
594
|
-
"airCtrl": int(options.climate),
|
595
|
-
"defrost": options.defrost,
|
596
|
-
"heating1": options.heating,
|
597
|
-
"airTemp": {
|
598
|
-
"value": hex_set_temp,
|
599
|
-
"unit": 0,
|
600
|
-
"hvacTempType": 1,
|
601
|
-
},
|
602
|
-
},
|
603
586
|
"pin": token.pin,
|
604
587
|
}
|
588
|
+
climate_settings = {
|
589
|
+
"airCtrl": int(options.climate),
|
590
|
+
"defrost": options.defrost,
|
591
|
+
"heating1": options.heating,
|
592
|
+
"airTemp": {
|
593
|
+
"value": hex_set_temp,
|
594
|
+
"unit": 0,
|
595
|
+
"hvacTempType": 1,
|
596
|
+
},
|
597
|
+
}
|
598
|
+
if BRANDS[self.brand] == BRAND_KIA:
|
599
|
+
payload["remoteControl"] = climate_settings
|
600
|
+
payload["remoteControl"].update(
|
601
|
+
{
|
602
|
+
"igniOnDuration": options.duration,
|
603
|
+
"seatHeaterVentCMD": {
|
604
|
+
"drvSeatOptCmd": options.front_left_seat,
|
605
|
+
"astSeatOptCmd": options.front_right_seat,
|
606
|
+
"rlSeatOptCmd": options.rear_left_seat,
|
607
|
+
"rrSeatOptCmd": options.rear_right_seat,
|
608
|
+
},
|
609
|
+
}
|
610
|
+
)
|
611
|
+
else:
|
612
|
+
payload["hvacInfo"] = climate_settings
|
605
613
|
else:
|
606
614
|
payload = {
|
607
615
|
"setting": {
|
@@ -656,6 +664,10 @@ class KiaUvoApiCA(ApiImpl):
|
|
656
664
|
synchronous: bool = False,
|
657
665
|
timeout: int = 0,
|
658
666
|
) -> OrderStatus:
|
667
|
+
if timeout < 0:
|
668
|
+
return OrderStatus.TIMEOUT
|
669
|
+
start_time = dt.datetime.now()
|
670
|
+
|
659
671
|
url = self.API_URL + "rmtsts"
|
660
672
|
headers = self.API_HEADERS
|
661
673
|
headers["accessToken"] = token.access_token
|
@@ -668,10 +680,27 @@ class KiaUvoApiCA(ApiImpl):
|
|
668
680
|
last_action_completed = (
|
669
681
|
response["result"]["transaction"]["apiStatusCode"] != "null"
|
670
682
|
)
|
683
|
+
|
671
684
|
if last_action_completed:
|
672
685
|
action_status = response["result"]["transaction"]["apiStatusCode"]
|
673
686
|
_LOGGER.debug(f"{DOMAIN} - Last action_status: {action_status}")
|
674
|
-
|
687
|
+
|
688
|
+
if response["responseHeader"]["responseCode"] == 1:
|
689
|
+
return OrderStatus.FAILED
|
690
|
+
elif response["result"]["transaction"]["apiResult"] == "C":
|
691
|
+
return OrderStatus.SUCCESS
|
692
|
+
elif response["result"]["transaction"]["apiResult"] == "P":
|
693
|
+
if not synchronous:
|
694
|
+
return OrderStatus.PENDING
|
695
|
+
else:
|
696
|
+
timedelta = dt.datetime.now() - start_time
|
697
|
+
time_left = timeout - timedelta.seconds - 10
|
698
|
+
time.sleep(10)
|
699
|
+
return self.check_action_status(
|
700
|
+
token, vehicle, action_id, synchronous, time_left
|
701
|
+
)
|
702
|
+
|
703
|
+
return OrderStatus.FAILED
|
675
704
|
|
676
705
|
def start_charge(self, token: Token, vehicle: Vehicle) -> str:
|
677
706
|
url = self.API_URL + "evc/rcstrt"
|
@@ -717,7 +746,7 @@ class KiaUvoApiCA(ApiImpl):
|
|
717
746
|
vehicle.ev_charge_limits_dc = [
|
718
747
|
x["level"] for x in state if x["plugType"] == 0
|
719
748
|
][-1]
|
720
|
-
except:
|
749
|
+
except Exception:
|
721
750
|
_LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
|
722
751
|
|
723
752
|
def _get_charge_limits(self, token: Token, vehicle: Vehicle) -> dict:
|