hyundai-kia-connect-api 3.17.9__py2.py3-none-any.whl → 3.18.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.
@@ -5,7 +5,6 @@
5
5
  import datetime as dt
6
6
  import json
7
7
  import logging
8
- import re
9
8
 
10
9
  import pytz
11
10
  import requests
@@ -35,6 +34,7 @@ from .utils import (
35
34
  get_child_value,
36
35
  get_hex_temp_into_index,
37
36
  get_index_into_hex_temp,
37
+ parse_datetime,
38
38
  )
39
39
 
40
40
  import ssl
@@ -202,8 +202,8 @@ class KiaUvoApiCA(ApiImpl):
202
202
 
203
203
  # Calculate offset between vehicle last_updated_at and UTC
204
204
  self.vehicle_timezone = vehicle.timezone
205
- last_updated_at = self.get_last_updated_at(
206
- get_child_value(state, "status.lastStatusDate")
205
+ last_updated_at = parse_datetime(
206
+ get_child_value(state, "status.lastStatusDate"), self.data_timezone
207
207
  )
208
208
  now_utc: dt = dt.datetime.now(pytz.utc)
209
209
  offset = round((last_updated_at - now_utc).total_seconds() / 3600)
@@ -238,8 +238,8 @@ class KiaUvoApiCA(ApiImpl):
238
238
  def _update_vehicle_properties_base(self, vehicle: Vehicle, state: dict) -> None:
239
239
  _LOGGER.debug(f"{DOMAIN} - Old Vehicle Last Updated: {vehicle.last_updated_at}")
240
240
  self.vehicle_timezone = vehicle.timezone
241
- vehicle.last_updated_at = self.get_last_updated_at(
242
- get_child_value(state, "status.lastStatusDate")
241
+ vehicle.last_updated_at = parse_datetime(
242
+ get_child_value(state, "status.lastStatusDate"), self.data_timezone
243
243
  )
244
244
  _LOGGER.debug(
245
245
  f"{DOMAIN} - Current Vehicle Last Updated: {vehicle.last_updated_at}"
@@ -426,29 +426,10 @@ class KiaUvoApiCA(ApiImpl):
426
426
  vehicle.location = (
427
427
  get_child_value(state, "coord.lat"),
428
428
  get_child_value(state, "coord.lon"),
429
- self.get_last_updated_at(get_child_value(state, "time")),
429
+ parse_datetime(get_child_value(state, "time"), self.data_timezone),
430
430
  )
431
431
  vehicle.data["vehicleLocation"] = state
432
432
 
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
433
  def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
453
434
  # Vehicle Status Call
454
435
  url = self.API_URL + "lstvhclsts"
@@ -509,7 +490,7 @@ class KiaUvoApiCA(ApiImpl):
509
490
  if response["responseHeader"]["responseCode"] != 0:
510
491
  raise APIError("No Location Located")
511
492
  return response["result"]
512
- except:
493
+ except Exception:
513
494
  _LOGGER.warning(f"{DOMAIN} - Get vehicle location failed")
514
495
  return None
515
496
 
@@ -717,7 +698,7 @@ class KiaUvoApiCA(ApiImpl):
717
698
  vehicle.ev_charge_limits_dc = [
718
699
  x["level"] for x in state if x["plugType"] == 0
719
700
  ][-1]
720
- except:
701
+ except Exception:
721
702
  _LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
722
703
 
723
704
  def _get_charge_limits(self, token: Token, vehicle: Vehicle) -> dict:
@@ -5,14 +5,12 @@
5
5
  import datetime as dt
6
6
  import math
7
7
  import logging
8
- import re
9
8
  import uuid
10
9
  from time import sleep
11
10
  from urllib.parse import parse_qs, urlparse
12
11
 
13
12
  import pytz
14
13
  import requests
15
- from bs4 import BeautifulSoup
16
14
  from dateutil import tz
17
15
 
18
16
  from .ApiImpl import (
@@ -43,22 +41,28 @@ from .const import (
43
41
  TEMPERATURE_UNITS,
44
42
  VEHICLE_LOCK_ACTION,
45
43
  )
46
- from .exceptions import *
44
+ from .exceptions import (
45
+ AuthenticationError,
46
+ DuplicateRequestError,
47
+ RequestTimeoutError,
48
+ ServiceTemporaryUnavailable,
49
+ NoDataFound,
50
+ InvalidAPIResponseError,
51
+ APIError,
52
+ RateLimitingError,
53
+ )
47
54
  from .utils import (
48
55
  get_child_value,
49
56
  get_index_into_hex_temp,
50
57
  get_hex_temp_into_index,
58
+ parse_datetime,
51
59
  )
52
60
 
53
61
  _LOGGER = logging.getLogger(__name__)
54
62
 
55
63
  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
- )
59
- ACCEPT_HEADER_ALL: str = (
60
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" # noqa
61
- )
64
+ 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
65
+ ACCEPT_HEADER_ALL: str = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" # noqa
62
66
 
63
67
 
64
68
  def _check_response_for_errors(response: dict) -> None:
@@ -108,9 +112,7 @@ class KiaUvoApiCN(ApiImplType1):
108
112
  self.BASE_DOMAIN: str = "prd.cn-ccapi.kia.com"
109
113
  self.CCSP_SERVICE_ID: str = "9d5df92a-06ae-435f-b459-8304f2efcc67"
110
114
  self.APP_ID: str = "eea8762c-adfc-4ee4-8d7a-6e2452ddf342"
111
- self.BASIC_AUTHORIZATION: str = (
112
- "Basic OWQ1ZGY5MmEtMDZhZS00MzVmLWI0NTktODMwNGYyZWZjYzY3OnRzWGRrVWcwOEF2MlpaelhPZ1d6Snl4VVQ2eWVTbk5OUWtYWFBSZEtXRUFOd2wxcA=="
113
- )
115
+ self.BASIC_AUTHORIZATION: str = "Basic OWQ1ZGY5MmEtMDZhZS00MzVmLWI0NTktODMwNGYyZWZjYzY3OnRzWGRrVWcwOEF2MlpaelhPZ1d6Snl4VVQ2eWVTbk5OUWtYWFBSZEtXRUFOd2wxcA=="
114
116
  elif BRANDS[brand] == BRAND_HYUNDAI:
115
117
  self.BASE_DOMAIN: str = "prd.cn-ccapi.hyundai.com"
116
118
  self.CCSP_SERVICE_ID: str = "72b3d019-5bc7-443d-a437-08f307cf06e2"
@@ -210,25 +212,6 @@ class KiaUvoApiCN(ApiImplType1):
210
212
  result.append(vehicle)
211
213
  return result
212
214
 
213
- def get_last_updated_at(self, value) -> dt.datetime:
214
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
215
- if value is None:
216
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
217
- else:
218
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
219
- value = dt.datetime(
220
- year=int(m.group(1)),
221
- month=int(m.group(2)),
222
- day=int(m.group(3)),
223
- hour=int(m.group(4)),
224
- minute=int(m.group(5)),
225
- second=int(m.group(6)),
226
- tzinfo=self.data_timezone,
227
- )
228
-
229
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
230
- return value
231
-
232
215
  def _get_time_from_string(self, value, timesection) -> dt.datetime.time:
233
216
  if value is not None:
234
217
  lastTwo = int(value[-2:])
@@ -291,8 +274,8 @@ class KiaUvoApiCN(ApiImplType1):
291
274
 
292
275
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
293
276
  if get_child_value(state, "status.time"):
294
- vehicle.last_updated_at = self.get_last_updated_at(
295
- get_child_value(state, "status.time")
277
+ vehicle.last_updated_at = parse_datetime(
278
+ get_child_value(state, "status.time"), self.data_timezone
296
279
  )
297
280
  else:
298
281
  vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
@@ -486,7 +469,7 @@ class KiaUvoApiCN(ApiImplType1):
486
469
  vehicle.ev_charge_limits_dc = [
487
470
  x["targetSOClevel"] for x in target_soc_list if x["plugType"] == 0
488
471
  ][-1]
489
- except:
472
+ except Exception:
490
473
  _LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
491
474
  if (
492
475
  get_child_value(
@@ -642,8 +625,8 @@ class KiaUvoApiCN(ApiImplType1):
642
625
  vehicle.location = (
643
626
  get_child_value(state, "vehicleLocation.coord.lat"),
644
627
  get_child_value(state, "vehicleLocation.coord.lon"),
645
- self.get_last_updated_at(
646
- get_child_value(state, "vehicleLocation.time")
628
+ parse_datetime(
629
+ get_child_value(state, "vehicleLocation.time"), self.data_timezone
647
630
  ),
648
631
  )
649
632
  vehicle.data = state
@@ -675,7 +658,7 @@ class KiaUvoApiCN(ApiImplType1):
675
658
  _LOGGER.debug(f"{DOMAIN} - _get_location response: {response}")
676
659
  _check_response_for_errors(response)
677
660
  return response["resMsg"]
678
- except:
661
+ except Exception:
679
662
  _LOGGER.debug(f"{DOMAIN} - _get_location failed")
680
663
  return None
681
664
 
@@ -6,7 +6,6 @@ import base64
6
6
  import random
7
7
  import datetime as dt
8
8
  import logging
9
- import re
10
9
  import uuid
11
10
  from time import sleep
12
11
  from urllib.parse import parse_qs, urlparse
@@ -45,22 +44,29 @@ from .const import (
45
44
  TEMPERATURE_UNITS,
46
45
  VEHICLE_LOCK_ACTION,
47
46
  )
48
- from .exceptions import *
47
+ from .exceptions import (
48
+ AuthenticationError,
49
+ DuplicateRequestError,
50
+ RequestTimeoutError,
51
+ ServiceTemporaryUnavailable,
52
+ NoDataFound,
53
+ InvalidAPIResponseError,
54
+ APIError,
55
+ RateLimitingError,
56
+ DeviceIDError,
57
+ )
49
58
  from .utils import (
50
59
  get_child_value,
51
60
  get_index_into_hex_temp,
52
61
  get_hex_temp_into_index,
62
+ parse_datetime,
53
63
  )
54
64
 
55
65
  _LOGGER = logging.getLogger(__name__)
56
66
 
57
67
  USER_AGENT_OK_HTTP: str = "okhttp/3.12.0"
58
- USER_AGENT_MOZILLA: str = (
59
- "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
60
- )
61
- ACCEPT_HEADER_ALL: str = (
62
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" # noqa
63
- )
68
+ 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
69
+ ACCEPT_HEADER_ALL: str = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" # noqa
64
70
 
65
71
  SUPPORTED_LANGUAGES_LIST = [
66
72
  "en", # English
@@ -128,7 +134,6 @@ class KiaUvoApiEU(ApiImplType1):
128
134
  temperature_range = [x * 0.5 for x in range(28, 60)]
129
135
 
130
136
  def __init__(self, region: int, brand: int, language: str) -> None:
131
- self.ccu_ccs2_protocol_support = None
132
137
  language = language.lower()
133
138
  # Strip language variants (e.g. en-Gb)
134
139
  if len(language) > 2:
@@ -160,9 +165,7 @@ class KiaUvoApiEU(ApiImplType1):
160
165
  self.CFB: str = base64.b64decode(
161
166
  "RFtoRq/vDXJmRndoZaZQyfOot7OrIqGVFj96iY2WL3yyH5Z/pUvlUhqmCxD2t+D65SQ="
162
167
  )
163
- self.BASIC_AUTHORIZATION: str = (
164
- "Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==" # noqa
165
- )
168
+ self.BASIC_AUTHORIZATION: str = "Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==" # noqa
166
169
  self.LOGIN_FORM_HOST = "eu-account.hyundai.com"
167
170
  self.PUSH_TYPE = "GCM"
168
171
  elif BRANDS[self.brand] == BRAND_GENESIS:
@@ -173,9 +176,7 @@ class KiaUvoApiEU(ApiImplType1):
173
176
  self.CFB: str = base64.b64decode(
174
177
  "RFtoRq/vDXJmRndoZaZQyYo3/qFLtVReW8P7utRPcc0ZxOzOELm9mexvviBk/qqIp4A="
175
178
  )
176
- self.BASIC_AUTHORIZATION: str = (
177
- "Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==" # noqa
178
- )
179
+ self.BASIC_AUTHORIZATION: str = "Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==" # noqa
179
180
  self.LOGIN_FORM_HOST = "accounts-eu.genesis.com"
180
181
  self.PUSH_TYPE = "GCM"
181
182
 
@@ -294,25 +295,6 @@ class KiaUvoApiEU(ApiImplType1):
294
295
  result.append(vehicle)
295
296
  return result
296
297
 
297
- def get_last_updated_at(self, value) -> dt.datetime:
298
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
299
- if value is None:
300
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
301
- else:
302
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
303
- value = dt.datetime(
304
- year=int(m.group(1)),
305
- month=int(m.group(2)),
306
- day=int(m.group(3)),
307
- hour=int(m.group(4)),
308
- minute=int(m.group(5)),
309
- second=int(m.group(6)),
310
- tzinfo=self.data_timezone,
311
- )
312
-
313
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
314
- return value
315
-
316
298
  def _get_time_from_string(self, value, timesection) -> dt.datetime.time:
317
299
  if value is not None:
318
300
  lastTwo = int(value[-2:])
@@ -328,12 +310,29 @@ class KiaUvoApiEU(ApiImplType1):
328
310
  return value
329
311
 
330
312
  def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
331
- state = self._get_cached_vehicle_state(token, vehicle)
332
- self.ccu_ccs2_protocol_support = str(vehicle.ccu_ccs2_protocol_support)
313
+ url = self.SPA_API_URL + "vehicles/" + vehicle.id
314
+ is_ccs2 = vehicle.ccu_ccs2_protocol_support != 0
315
+ if is_ccs2:
316
+ url += "/ccs2/carstatus/latest"
317
+ else:
318
+ url += "/status/latest"
319
+
320
+ response = requests.get(
321
+ url,
322
+ headers=self._get_authenticated_headers(
323
+ token, vehicle.ccu_ccs2_protocol_support
324
+ ),
325
+ ).json()
326
+
327
+ _LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
328
+ _check_response_for_errors(response)
333
329
 
334
330
  if vehicle.ccu_ccs2_protocol_support == 0:
335
- self._update_vehicle_properties(vehicle, state)
331
+ self._update_vehicle_properties(
332
+ vehicle, response["resMsg"]["vehicleStatusInfo"]
333
+ )
336
334
  else:
335
+ state = response["resMsg"]["state"]["Vehicle"]
337
336
  self._update_vehicle_properties_ccs2(vehicle, state)
338
337
 
339
338
  if (
@@ -383,281 +382,10 @@ class KiaUvoApiEU(ApiImplType1):
383
382
  else:
384
383
  self._update_vehicle_drive_info(vehicle, state)
385
384
 
386
- def _update_vehicle_properties_ccs2(self, vehicle: Vehicle, state: dict) -> None:
387
- if get_child_value(state, "Date"):
388
- vehicle.last_updated_at = self.get_last_updated_at(
389
- get_child_value(state, "Date")
390
- )
391
- else:
392
- vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
393
-
394
- vehicle.odometer = (
395
- get_child_value(state, "Drivetrain.Odometer"),
396
- DISTANCE_UNITS[1],
397
- )
398
- vehicle.car_battery_percentage = get_child_value(
399
- state, "Electronics.Battery.Level"
400
- )
401
-
402
- vehicle.engine_is_running = get_child_value(state, "DrivingReady")
403
-
404
- air_temp = get_child_value(
405
- state,
406
- "Cabin.HVAC.Row1.Driver.Temperature.Value",
407
- )
408
-
409
- if air_temp != "OFF":
410
- vehicle.air_temperature = (air_temp, TEMPERATURE_UNITS[1])
411
-
412
- defrost_is_on = get_child_value(state, "Body.Windshield.Front.Defog.State")
413
- if defrost_is_on in [0, 2]:
414
- vehicle.defrost_is_on = False
415
- elif defrost_is_on == 1:
416
- vehicle.defrost_is_on = True
417
-
418
- steer_wheel_heat = get_child_value(state, "Cabin.SteeringWheel.Heat.State")
419
- if steer_wheel_heat in [0, 2]:
420
- vehicle.steering_wheel_heater_is_on = False
421
- elif steer_wheel_heat == 1:
422
- vehicle.steering_wheel_heater_is_on = True
423
-
424
- defrost_rear_is_on = get_child_value(state, "Body.Windshield.Rear.Defog.State")
425
- if defrost_rear_is_on in [0, 2]:
426
- vehicle.back_window_heater_is_on = False
427
- elif defrost_rear_is_on == 1:
428
- vehicle.back_window_heater_is_on = True
429
-
430
- # TODO: status.sideMirrorHeat
431
-
432
- vehicle.front_left_seat_status = SEAT_STATUS[
433
- get_child_value(state, "Cabin.Seat.Row1.Driver.Climate.State")
434
- ]
435
-
436
- vehicle.front_right_seat_status = SEAT_STATUS[
437
- get_child_value(state, "Cabin.Seat.Row1.Passenger.Climate.State")
438
- ]
439
-
440
- vehicle.rear_left_seat_status = SEAT_STATUS[
441
- get_child_value(state, "Cabin.Seat.Row2.Left.Climate.State")
442
- ]
443
-
444
- vehicle.rear_right_seat_status = SEAT_STATUS[
445
- get_child_value(state, "Cabin.Seat.Row2.Right.Climate.State")
446
- ]
447
-
448
- # TODO: status.doorLock
449
-
450
- vehicle.front_left_door_is_open = get_child_value(
451
- state, "Cabin.Door.Row1.Driver.Open"
452
- )
453
- vehicle.front_right_door_is_open = get_child_value(
454
- state, "Cabin.Door.Row1.Passenger.Open"
455
- )
456
- vehicle.back_left_door_is_open = get_child_value(
457
- state, "Cabin.Door.Row2.Left.Open"
458
- )
459
- vehicle.back_right_door_is_open = get_child_value(
460
- state, "Cabin.Door.Row2.Right.Open"
461
- )
462
-
463
- # TODO: should the windows and trunc also be checked?
464
- vehicle.is_locked = not (
465
- vehicle.front_left_door_is_open
466
- or vehicle.front_right_door_is_open
467
- or vehicle.back_left_door_is_open
468
- or vehicle.back_right_door_is_open
469
- )
470
-
471
- vehicle.hood_is_open = get_child_value(state, "Body.Hood.Open")
472
- vehicle.front_left_window_is_open = get_child_value(
473
- state, "Cabin.Window.Row1.Driver.Open"
474
- )
475
- vehicle.front_right_window_is_open = get_child_value(
476
- state, "Cabin.Window.Row1.Passenger.Open"
477
- )
478
- vehicle.back_left_window_is_open = get_child_value(
479
- state, "Cabin.Window.Row2.Left.Open"
480
- )
481
- vehicle.back_right_window_is_open = get_child_value(
482
- state, "Cabin.Window.Row2.Right.Open"
483
- )
484
- vehicle.tire_pressure_rear_left_warning_is_on = bool(
485
- get_child_value(state, "Chassis.Axle.Row2.Left.Tire.PressureLow")
486
- )
487
- vehicle.tire_pressure_front_left_warning_is_on = bool(
488
- get_child_value(state, "Chassis.Axle.Row1.Left.Tire.PressureLow")
489
- )
490
- vehicle.tire_pressure_front_right_warning_is_on = bool(
491
- get_child_value(state, "Chassis.Axle.Row1.Right.Tire.PressureLow")
492
- )
493
- vehicle.tire_pressure_rear_right_warning_is_on = bool(
494
- get_child_value(state, "Chassis.Axle.Row2.Right.Tire.PressureLow")
495
- )
496
- vehicle.tire_pressure_all_warning_is_on = bool(
497
- get_child_value(state, "Chassis.Axle.Tire.PressureLow")
498
- )
499
- vehicle.trunk_is_open = get_child_value(state, "Body.Trunk.Open")
500
-
501
- vehicle.ev_battery_percentage = get_child_value(
502
- state, "Green.BatteryManagement.BatteryRemain.Ratio"
503
- )
504
- vehicle.ev_battery_remain = get_child_value(
505
- state, "Green.BatteryManagement.BatteryRemain.Value"
506
- )
507
- vehicle.ev_battery_capacity = get_child_value(
508
- state, "Green.BatteryManagement.BatteryCapacity.Value"
509
- )
510
- vehicle.ev_battery_soh_percentage = get_child_value(
511
- state, "Green.BatteryManagement.SoH.Ratio"
512
- )
513
- vehicle.ev_battery_is_plugged_in = get_child_value(
514
- state, "Green.ChargingInformation.ElectricCurrentLevel.State"
515
- )
516
- vehicle.ev_battery_is_plugged_in = get_child_value(
517
- state, "Green.ChargingInformation.ConnectorFastening.State"
518
- )
519
- charging_door_state = get_child_value(state, "Green.ChargingDoor.State")
520
- if charging_door_state in [0, 2]:
521
- vehicle.ev_charge_port_door_is_open = False
522
- elif charging_door_state == 1:
523
- vehicle.ev_charge_port_door_is_open = True
524
-
525
- vehicle.total_driving_range = (
526
- float(
527
- get_child_value(
528
- state,
529
- "Drivetrain.FuelSystem.DTE.Total", # noqa
530
- )
531
- ),
532
- DISTANCE_UNITS[
533
- get_child_value(
534
- state,
535
- "Drivetrain.FuelSystem.DTE.Unit", # noqa
536
- )
537
- ],
538
- )
539
-
540
- if vehicle.engine_type == ENGINE_TYPES.EV:
541
- # ev_driving_range is the same as total_driving_range for pure EV
542
- vehicle.ev_driving_range = (
543
- vehicle.total_driving_range,
544
- vehicle.total_driving_range_unit,
545
- )
546
- # TODO: vehicle.ev_driving_range for non EV
547
-
548
- vehicle.washer_fluid_warning_is_on = get_child_value(
549
- state, "Body.Windshield.Front.WasherFluid.LevelLow"
550
- )
551
-
552
- vehicle.ev_estimated_current_charge_duration = (
553
- get_child_value(state, "Green.ChargingInformation.Charging.RemainTime"),
554
- "m",
555
- )
556
- vehicle.ev_estimated_fast_charge_duration = (
557
- get_child_value(state, "Green.ChargingInformation.EstimatedTime.Standard"),
558
- "m",
559
- )
560
- vehicle.ev_estimated_portable_charge_duration = (
561
- get_child_value(state, "Green.ChargingInformation.EstimatedTime.ICCB"),
562
- "m",
563
- )
564
- vehicle.ev_estimated_station_charge_duration = (
565
- get_child_value(state, "Green.ChargingInformation.EstimatedTime.Quick"),
566
- "m",
567
- )
568
- vehicle.ev_charge_limits_ac = get_child_value(
569
- state, "Green.ChargingInformation.TargetSoC.Standard"
570
- )
571
- vehicle.ev_charge_limits_dc = get_child_value(
572
- state, "Green.ChargingInformation.TargetSoC.Quick"
573
- )
574
- vehicle.ev_v2l_discharge_limit = get_child_value(
575
- state, "Green.Electric.SmartGrid.VehicleToLoad.DischargeLimitation.SoC"
576
- )
577
- vehicle.ev_target_range_charge_AC = (
578
- get_child_value(
579
- state,
580
- "Green.ChargingInformation.DTE.TargetSoC.Standard", # noqa
581
- ),
582
- DISTANCE_UNITS[
583
- get_child_value(
584
- state,
585
- "Drivetrain.FuelSystem.DTE.Unit", # noqa
586
- )
587
- ],
588
- )
589
- vehicle.ev_target_range_charge_DC = (
590
- get_child_value(
591
- state,
592
- "Green.ChargingInformation.DTE.TargetSoC.Quick", # noqa
593
- ),
594
- DISTANCE_UNITS[
595
- get_child_value(
596
- state,
597
- "Drivetrain.FuelSystem.DTE.Unit", # noqa
598
- )
599
- ],
600
- )
601
- vehicle.ev_first_departure_enabled = bool(
602
- get_child_value(state, "Green.Reservation.Departure.Schedule1.Enable")
603
- )
604
-
605
- vehicle.ev_second_departure_enabled = bool(
606
- get_child_value(state, "Green.Reservation.Departure.Schedule2.Enable")
607
- )
608
-
609
- # TODO: vehicle.ev_first_departure_days --> Green.Reservation.Departure.Schedule1.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
610
- # TODO: vehicle.ev_second_departure_days --> Green.Reservation.Departure.Schedule2.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
611
- # TODO: vehicle.ev_first_departure_time --> Green.Reservation.Departure.Schedule1.(Min,Hour) # noqa
612
- # TODO: vehicle.ev_second_departure_time --> Green.Reservation.Departure.Schedule2.(Min,Hour) # noqa
613
- # TODO: vehicle.ev_off_peak_charge_only_enabled --> unknown settings are in --> Green.Reservation.OffPeakTime and OffPeakTime2 # noqa
614
-
615
- vehicle.washer_fluid_warning_is_on = get_child_value(
616
- state, "Body.Windshield.Front.WasherFluid.LevelLow"
617
- )
618
- vehicle.brake_fluid_warning_is_on = get_child_value(
619
- state, "Chassis.Brake.Fluid.Warning"
620
- )
621
-
622
- vehicle.fuel_level = get_child_value(state, "Drivetrain.FuelSystem.FuelLevel")
623
- vehicle.fuel_level_is_low = get_child_value(
624
- state, "Drivetrain.FuelSystem.LowFuelWarning"
625
- )
626
- vehicle.air_control_is_on = get_child_value(
627
- state, "Cabin.HVAC.Row1.Driver.Blower.SpeedLevel"
628
- )
629
- vehicle.smart_key_battery_warning_is_on = bool(
630
- get_child_value(state, "Electronics.FOB.LowBattery")
631
- )
632
-
633
- if get_child_value(state, "Location.GeoCoord.Latitude"):
634
- location_last_updated_at = dt.datetime(
635
- 2000, 1, 1, tzinfo=self.data_timezone
636
- )
637
- timestamp = get_child_value(state, "Location.TimeStamp")
638
- if timestamp is not None:
639
- location_last_updated_at = dt.datetime(
640
- year=int(get_child_value(timestamp, "Year")),
641
- month=int(get_child_value(timestamp, "Mon")),
642
- day=int(get_child_value(timestamp, "Day")),
643
- hour=int(get_child_value(timestamp, "Hour")),
644
- minute=int(get_child_value(timestamp, "Min")),
645
- second=int(get_child_value(timestamp, "Sec")),
646
- tzinfo=self.data_timezone,
647
- )
648
-
649
- vehicle.location = (
650
- get_child_value(state, "Location.GeoCoord.Latitude"),
651
- get_child_value(state, "Location.GeoCoord.Longitude"),
652
- location_last_updated_at,
653
- )
654
-
655
- vehicle.data = state
656
-
657
385
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
658
386
  if get_child_value(state, "vehicleStatus.time"):
659
- vehicle.last_updated_at = self.get_last_updated_at(
660
- get_child_value(state, "vehicleStatus.time")
387
+ vehicle.last_updated_at = parse_datetime(
388
+ get_child_value(state, "vehicleStatus.time"), self.data_timezone
661
389
  )
662
390
  else:
663
391
  vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
@@ -853,7 +581,7 @@ class KiaUvoApiEU(ApiImplType1):
853
581
  vehicle.ev_charge_limits_dc = [
854
582
  x["targetSOClevel"] for x in target_soc_list if x["plugType"] == 0
855
583
  ][-1]
856
- except:
584
+ except Exception:
857
585
  _LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
858
586
  if (
859
587
  get_child_value(
@@ -1009,8 +737,8 @@ class KiaUvoApiEU(ApiImplType1):
1009
737
  vehicle.location = (
1010
738
  get_child_value(state, "vehicleLocation.coord.lat"),
1011
739
  get_child_value(state, "vehicleLocation.coord.lon"),
1012
- self.get_last_updated_at(
1013
- get_child_value(state, "vehicleLocation.time")
740
+ parse_datetime(
741
+ get_child_value(state, "vehicleLocation.time"), self.data_timezone
1014
742
  ),
1015
743
  )
1016
744
  vehicle.data = state
@@ -1028,7 +756,10 @@ class KiaUvoApiEU(ApiImplType1):
1028
756
  else:
1029
757
  url = url + "/ccs2/carstatus/latest"
1030
758
  response = requests.get(
1031
- url, headers=self._get_authenticated_headers(token)
759
+ url,
760
+ headers=self._get_authenticated_headers(
761
+ token, vehicle.ccu_ccs2_protocol_support
762
+ ),
1032
763
  ).json()
1033
764
  _LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
1034
765
  _check_response_for_errors(response)
@@ -1048,7 +779,7 @@ class KiaUvoApiEU(ApiImplType1):
1048
779
  _LOGGER.debug(f"{DOMAIN} - _get_location response: {response}")
1049
780
  _check_response_for_errors(response)
1050
781
  return response["resMsg"]["gpsDetail"]
1051
- except:
782
+ except Exception:
1052
783
  _LOGGER.warning(f"{DOMAIN} - _get_location failed")
1053
784
  return None
1054
785
 
@@ -1,12 +1,13 @@
1
1
  # pylint:disable=missing-class-docstring,missing-function-docstring,wildcard-import,unused-wildcard-import,invalid-name
2
2
  """Vehicle class"""
3
+
3
4
  import logging
4
5
  import datetime
5
6
  import typing
6
7
  from dataclasses import dataclass, field
7
8
 
8
9
  from .utils import get_float
9
- from .const import *
10
+ from .const import DISTANCE_UNITS
10
11
 
11
12
  _LOGGER = logging.getLogger(__name__)
12
13