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.
@@ -10,7 +10,7 @@ import requests
10
10
 
11
11
  from .Token import Token
12
12
  from .Vehicle import Vehicle
13
- from .const import *
13
+ from .const import WINDOW_STATE, CHARGE_PORT_ACTION, OrderStatus
14
14
  from .utils import get_child_value
15
15
 
16
16
  _LOGGER = logging.getLogger(__name__)
@@ -57,10 +57,6 @@ class ApiImpl:
57
57
  Required for Kia USA as key is session specific"""
58
58
  return vehicles
59
59
 
60
- def get_last_updated_at(self, value) -> dt.datetime:
61
- """Convert last updated value of vehicle into into datetime"""
62
- pass
63
-
64
60
  def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
65
61
  """Get cached vehicle data and update Vehicle instance with it"""
66
62
  pass
@@ -1,7 +1,23 @@
1
+ import datetime as dt
2
+ from typing import Optional
3
+
1
4
  from .ApiImpl import (
2
5
  ApiImpl,
3
6
  )
4
7
  from .Token import Token
8
+ from .Vehicle import Vehicle
9
+
10
+ from .utils import (
11
+ get_child_value,
12
+ parse_datetime,
13
+ )
14
+
15
+ from .const import (
16
+ DISTANCE_UNITS,
17
+ ENGINE_TYPES,
18
+ SEAT_STATUS,
19
+ TEMPERATURE_UNITS,
20
+ )
5
21
 
6
22
  USER_AGENT_OK_HTTP: str = "okhttp/3.12.0"
7
23
 
@@ -10,7 +26,9 @@ class ApiImplType1(ApiImpl):
10
26
  def __init__(self) -> None:
11
27
  """Initialize."""
12
28
 
13
- def _get_authenticated_headers(self, token: Token) -> dict:
29
+ def _get_authenticated_headers(
30
+ self, token: Token, ccs2_support: Optional[int] = None
31
+ ) -> dict:
14
32
  return {
15
33
  "Authorization": token.access_token,
16
34
  "ccsp-service-id": self.CCSP_SERVICE_ID,
@@ -20,6 +38,277 @@ class ApiImplType1(ApiImpl):
20
38
  "Host": self.BASE_URL,
21
39
  "Connection": "Keep-Alive",
22
40
  "Accept-Encoding": "gzip",
23
- "Ccuccs2protocolsupport": self.ccu_ccs2_protocol_support,
41
+ "Ccuccs2protocolsupport": str(ccs2_support or 0),
24
42
  "User-Agent": USER_AGENT_OK_HTTP,
25
43
  }
44
+
45
+ def _update_vehicle_properties_ccs2(self, vehicle: Vehicle, state: dict) -> None:
46
+ if get_child_value(state, "Date"):
47
+ vehicle.last_updated_at = parse_datetime(
48
+ get_child_value(state, "Date"), self.data_timezone
49
+ )
50
+ else:
51
+ vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
52
+
53
+ vehicle.odometer = (
54
+ get_child_value(state, "Drivetrain.Odometer"),
55
+ DISTANCE_UNITS[1],
56
+ )
57
+ vehicle.car_battery_percentage = get_child_value(
58
+ state, "Electronics.Battery.Level"
59
+ )
60
+
61
+ vehicle.engine_is_running = get_child_value(state, "DrivingReady")
62
+
63
+ air_temp = get_child_value(
64
+ state,
65
+ "Cabin.HVAC.Row1.Driver.Temperature.Value",
66
+ )
67
+
68
+ if air_temp != "OFF":
69
+ vehicle.air_temperature = (air_temp, TEMPERATURE_UNITS[1])
70
+
71
+ defrost_is_on = get_child_value(state, "Body.Windshield.Front.Defog.State")
72
+ if defrost_is_on in [0, 2]:
73
+ vehicle.defrost_is_on = False
74
+ elif defrost_is_on == 1:
75
+ vehicle.defrost_is_on = True
76
+
77
+ steer_wheel_heat = get_child_value(state, "Cabin.SteeringWheel.Heat.State")
78
+ if steer_wheel_heat in [0, 2]:
79
+ vehicle.steering_wheel_heater_is_on = False
80
+ elif steer_wheel_heat == 1:
81
+ vehicle.steering_wheel_heater_is_on = True
82
+
83
+ defrost_rear_is_on = get_child_value(state, "Body.Windshield.Rear.Defog.State")
84
+ if defrost_rear_is_on in [0, 2]:
85
+ vehicle.back_window_heater_is_on = False
86
+ elif defrost_rear_is_on == 1:
87
+ vehicle.back_window_heater_is_on = True
88
+
89
+ # TODO: status.sideMirrorHeat
90
+
91
+ vehicle.front_left_seat_status = SEAT_STATUS[
92
+ get_child_value(state, "Cabin.Seat.Row1.Driver.Climate.State")
93
+ ]
94
+
95
+ vehicle.front_right_seat_status = SEAT_STATUS[
96
+ get_child_value(state, "Cabin.Seat.Row1.Passenger.Climate.State")
97
+ ]
98
+
99
+ vehicle.rear_left_seat_status = SEAT_STATUS[
100
+ get_child_value(state, "Cabin.Seat.Row2.Left.Climate.State")
101
+ ]
102
+
103
+ vehicle.rear_right_seat_status = SEAT_STATUS[
104
+ get_child_value(state, "Cabin.Seat.Row2.Right.Climate.State")
105
+ ]
106
+
107
+ # TODO: status.doorLock
108
+
109
+ vehicle.front_left_door_is_open = get_child_value(
110
+ state, "Cabin.Door.Row1.Driver.Open"
111
+ )
112
+ vehicle.front_right_door_is_open = get_child_value(
113
+ state, "Cabin.Door.Row1.Passenger.Open"
114
+ )
115
+ vehicle.back_left_door_is_open = get_child_value(
116
+ state, "Cabin.Door.Row2.Left.Open"
117
+ )
118
+ vehicle.back_right_door_is_open = get_child_value(
119
+ state, "Cabin.Door.Row2.Right.Open"
120
+ )
121
+
122
+ # TODO: should the windows and trunc also be checked?
123
+ vehicle.is_locked = not (
124
+ vehicle.front_left_door_is_open
125
+ or vehicle.front_right_door_is_open
126
+ or vehicle.back_left_door_is_open
127
+ or vehicle.back_right_door_is_open
128
+ )
129
+
130
+ vehicle.hood_is_open = get_child_value(state, "Body.Hood.Open")
131
+ vehicle.front_left_window_is_open = get_child_value(
132
+ state, "Cabin.Window.Row1.Driver.Open"
133
+ )
134
+ vehicle.front_right_window_is_open = get_child_value(
135
+ state, "Cabin.Window.Row1.Passenger.Open"
136
+ )
137
+ vehicle.back_left_window_is_open = get_child_value(
138
+ state, "Cabin.Window.Row2.Left.Open"
139
+ )
140
+ vehicle.back_right_window_is_open = get_child_value(
141
+ state, "Cabin.Window.Row2.Right.Open"
142
+ )
143
+ vehicle.tire_pressure_rear_left_warning_is_on = bool(
144
+ get_child_value(state, "Chassis.Axle.Row2.Left.Tire.PressureLow")
145
+ )
146
+ vehicle.tire_pressure_front_left_warning_is_on = bool(
147
+ get_child_value(state, "Chassis.Axle.Row1.Left.Tire.PressureLow")
148
+ )
149
+ vehicle.tire_pressure_front_right_warning_is_on = bool(
150
+ get_child_value(state, "Chassis.Axle.Row1.Right.Tire.PressureLow")
151
+ )
152
+ vehicle.tire_pressure_rear_right_warning_is_on = bool(
153
+ get_child_value(state, "Chassis.Axle.Row2.Right.Tire.PressureLow")
154
+ )
155
+ vehicle.tire_pressure_all_warning_is_on = bool(
156
+ get_child_value(state, "Chassis.Axle.Tire.PressureLow")
157
+ )
158
+ vehicle.trunk_is_open = get_child_value(state, "Body.Trunk.Open")
159
+
160
+ vehicle.ev_battery_percentage = get_child_value(
161
+ state, "Green.BatteryManagement.BatteryRemain.Ratio"
162
+ )
163
+ vehicle.ev_battery_remain = get_child_value(
164
+ state, "Green.BatteryManagement.BatteryRemain.Value"
165
+ )
166
+ vehicle.ev_battery_capacity = get_child_value(
167
+ state, "Green.BatteryManagement.BatteryCapacity.Value"
168
+ )
169
+ vehicle.ev_battery_soh_percentage = get_child_value(
170
+ state, "Green.BatteryManagement.SoH.Ratio"
171
+ )
172
+ vehicle.ev_battery_is_plugged_in = get_child_value(
173
+ state, "Green.ChargingInformation.ElectricCurrentLevel.State"
174
+ )
175
+ vehicle.ev_battery_is_plugged_in = get_child_value(
176
+ state, "Green.ChargingInformation.ConnectorFastening.State"
177
+ )
178
+ charging_door_state = get_child_value(state, "Green.ChargingDoor.State")
179
+ if charging_door_state in [0, 2]:
180
+ vehicle.ev_charge_port_door_is_open = False
181
+ elif charging_door_state == 1:
182
+ vehicle.ev_charge_port_door_is_open = True
183
+
184
+ vehicle.total_driving_range = (
185
+ float(
186
+ get_child_value(
187
+ state,
188
+ "Drivetrain.FuelSystem.DTE.Total", # noqa
189
+ )
190
+ ),
191
+ DISTANCE_UNITS[
192
+ get_child_value(
193
+ state,
194
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
195
+ )
196
+ ],
197
+ )
198
+
199
+ if vehicle.engine_type == ENGINE_TYPES.EV:
200
+ # ev_driving_range is the same as total_driving_range for pure EV
201
+ vehicle.ev_driving_range = (
202
+ vehicle.total_driving_range,
203
+ vehicle.total_driving_range_unit,
204
+ )
205
+ # TODO: vehicle.ev_driving_range for non EV
206
+
207
+ vehicle.washer_fluid_warning_is_on = get_child_value(
208
+ state, "Body.Windshield.Front.WasherFluid.LevelLow"
209
+ )
210
+
211
+ vehicle.ev_estimated_current_charge_duration = (
212
+ get_child_value(state, "Green.ChargingInformation.Charging.RemainTime"),
213
+ "m",
214
+ )
215
+ vehicle.ev_estimated_fast_charge_duration = (
216
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.Standard"),
217
+ "m",
218
+ )
219
+ vehicle.ev_estimated_portable_charge_duration = (
220
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.ICCB"),
221
+ "m",
222
+ )
223
+ vehicle.ev_estimated_station_charge_duration = (
224
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.Quick"),
225
+ "m",
226
+ )
227
+ vehicle.ev_charge_limits_ac = get_child_value(
228
+ state, "Green.ChargingInformation.TargetSoC.Standard"
229
+ )
230
+ vehicle.ev_charge_limits_dc = get_child_value(
231
+ state, "Green.ChargingInformation.TargetSoC.Quick"
232
+ )
233
+ vehicle.ev_v2l_discharge_limit = get_child_value(
234
+ state, "Green.Electric.SmartGrid.VehicleToLoad.DischargeLimitation.SoC"
235
+ )
236
+ vehicle.ev_target_range_charge_AC = (
237
+ get_child_value(
238
+ state,
239
+ "Green.ChargingInformation.DTE.TargetSoC.Standard", # noqa
240
+ ),
241
+ DISTANCE_UNITS[
242
+ get_child_value(
243
+ state,
244
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
245
+ )
246
+ ],
247
+ )
248
+ vehicle.ev_target_range_charge_DC = (
249
+ get_child_value(
250
+ state,
251
+ "Green.ChargingInformation.DTE.TargetSoC.Quick", # noqa
252
+ ),
253
+ DISTANCE_UNITS[
254
+ get_child_value(
255
+ state,
256
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
257
+ )
258
+ ],
259
+ )
260
+ vehicle.ev_first_departure_enabled = bool(
261
+ get_child_value(state, "Green.Reservation.Departure.Schedule1.Enable")
262
+ )
263
+
264
+ vehicle.ev_second_departure_enabled = bool(
265
+ get_child_value(state, "Green.Reservation.Departure.Schedule2.Enable")
266
+ )
267
+
268
+ # TODO: vehicle.ev_first_departure_days --> Green.Reservation.Departure.Schedule1.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
269
+ # TODO: vehicle.ev_second_departure_days --> Green.Reservation.Departure.Schedule2.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
270
+ # TODO: vehicle.ev_first_departure_time --> Green.Reservation.Departure.Schedule1.(Min,Hour) # noqa
271
+ # TODO: vehicle.ev_second_departure_time --> Green.Reservation.Departure.Schedule2.(Min,Hour) # noqa
272
+ # TODO: vehicle.ev_off_peak_charge_only_enabled --> unknown settings are in --> Green.Reservation.OffPeakTime and OffPeakTime2 # noqa
273
+
274
+ vehicle.washer_fluid_warning_is_on = get_child_value(
275
+ state, "Body.Windshield.Front.WasherFluid.LevelLow"
276
+ )
277
+ vehicle.brake_fluid_warning_is_on = get_child_value(
278
+ state, "Chassis.Brake.Fluid.Warning"
279
+ )
280
+
281
+ vehicle.fuel_level = get_child_value(state, "Drivetrain.FuelSystem.FuelLevel")
282
+ vehicle.fuel_level_is_low = get_child_value(
283
+ state, "Drivetrain.FuelSystem.LowFuelWarning"
284
+ )
285
+ vehicle.air_control_is_on = get_child_value(
286
+ state, "Cabin.HVAC.Row1.Driver.Blower.SpeedLevel"
287
+ )
288
+ vehicle.smart_key_battery_warning_is_on = bool(
289
+ get_child_value(state, "Electronics.FOB.LowBattery")
290
+ )
291
+
292
+ if get_child_value(state, "Location.GeoCoord.Latitude"):
293
+ location_last_updated_at = dt.datetime(
294
+ 2000, 1, 1, tzinfo=self.data_timezone
295
+ )
296
+ timestamp = get_child_value(state, "Location.TimeStamp")
297
+ if timestamp is not None:
298
+ location_last_updated_at = dt.datetime(
299
+ year=int(get_child_value(timestamp, "Year")),
300
+ month=int(get_child_value(timestamp, "Mon")),
301
+ day=int(get_child_value(timestamp, "Day")),
302
+ hour=int(get_child_value(timestamp, "Hour")),
303
+ minute=int(get_child_value(timestamp, "Min")),
304
+ second=int(get_child_value(timestamp, "Sec")),
305
+ tzinfo=self.data_timezone,
306
+ )
307
+
308
+ vehicle.location = (
309
+ get_child_value(state, "Location.GeoCoord.Latitude"),
310
+ get_child_value(state, "Location.GeoCoord.Longitude"),
311
+ location_last_updated_at,
312
+ )
313
+
314
+ vehicle.data = state
@@ -4,7 +4,6 @@
4
4
 
5
5
  import logging
6
6
  import time
7
- import re
8
7
  import datetime as dt
9
8
  import pytz
10
9
  import requests
@@ -19,7 +18,7 @@ from .const import (
19
18
  TEMPERATURE_UNITS,
20
19
  ENGINE_TYPES,
21
20
  )
22
- from .utils import get_child_value, get_float
21
+ from .utils import get_child_value, get_float, parse_datetime
23
22
  from .ApiImpl import ApiImpl, ClimateRequestOptions
24
23
  from .Token import Token
25
24
  from .Vehicle import DailyDrivingStats, Vehicle
@@ -235,8 +234,8 @@ class HyundaiBlueLinkAPIUSA(ApiImpl):
235
234
  return None
236
235
 
237
236
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
238
- vehicle.last_updated_at = self.get_last_updated_at(
239
- get_child_value(state, "vehicleStatus.dateTime")
237
+ vehicle.last_updated_at = parse_datetime(
238
+ get_child_value(state, "vehicleStatus.dateTime"), self.data_timezone
240
239
  )
241
240
  vehicle.total_driving_range = (
242
241
  get_child_value(
@@ -428,8 +427,9 @@ class HyundaiBlueLinkAPIUSA(ApiImpl):
428
427
  vehicle.location = (
429
428
  get_child_value(state, "vehicleStatus.vehicleLocation.coord.lat"),
430
429
  get_child_value(state, "vehicleStatus.vehicleLocation.coord.lon"),
431
- self.get_last_updated_at(
432
- get_child_value(state, "vehicleStatus.vehicleLocation.time")
430
+ parse_datetime(
431
+ get_child_value(state, "vehicleStatus.vehicleLocation.time"),
432
+ self.data_timezone,
433
433
  ),
434
434
  )
435
435
  vehicle.air_control_is_on = get_child_value(state, "vehicleStatus.airCtrlOn")
@@ -640,28 +640,3 @@ class HyundaiBlueLinkAPIUSA(ApiImpl):
640
640
 
641
641
  def stop_charge(self, token: Token, vehicle: Vehicle) -> None:
642
642
  pass
643
-
644
- def get_last_updated_at(self, value) -> dt.datetime:
645
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
646
- if value is None:
647
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
648
- else:
649
- value = (
650
- value.replace("-", "")
651
- .replace("T", "")
652
- .replace(":", "")
653
- .replace("Z", "")
654
- )
655
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
656
- value = dt.datetime(
657
- year=int(m.group(1)),
658
- month=int(m.group(2)),
659
- day=int(m.group(3)),
660
- hour=int(m.group(4)),
661
- minute=int(m.group(5)),
662
- second=int(m.group(6)),
663
- tzinfo=self.data_timezone,
664
- )
665
-
666
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
667
- return value
@@ -4,7 +4,6 @@
4
4
  import datetime as dt
5
5
  import logging
6
6
  import random
7
- import re
8
7
  import secrets
9
8
  import ssl
10
9
  import string
@@ -29,7 +28,7 @@ from .const import (
29
28
  TEMPERATURE_UNITS,
30
29
  VEHICLE_LOCK_ACTION,
31
30
  )
32
- from .utils import get_child_value
31
+ from .utils import get_child_value, parse_datetime
33
32
 
34
33
  _LOGGER = logging.getLogger(__name__)
35
34
 
@@ -278,10 +277,11 @@ class KiaUvoAPIUSA(ApiImpl):
278
277
 
279
278
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
280
279
  """Get cached vehicle data and update Vehicle instance with it"""
281
- vehicle.last_updated_at = self.get_last_updated_at(
280
+ vehicle.last_updated_at = parse_datetime(
282
281
  get_child_value(
283
282
  state, "lastVehicleInfo.vehicleStatusRpt.vehicleStatus.syncDate.utc"
284
- )
283
+ ),
284
+ self.data_timezone,
285
285
  )
286
286
  vehicle.odometer = (
287
287
  get_child_value(state, "vehicleConfig.vehicleDetail.vehicle.mileage"),
@@ -515,8 +515,9 @@ class KiaUvoAPIUSA(ApiImpl):
515
515
  vehicle.location = (
516
516
  get_child_value(state, "lastVehicleInfo.location.coord.lat"),
517
517
  get_child_value(state, "lastVehicleInfo.location.coord.lon"),
518
- self.get_last_updated_at(
519
- get_child_value(state, "lastVehicleInfo.location.syncDate.utc")
518
+ parse_datetime(
519
+ get_child_value(state, "lastVehicleInfo.location.syncDate.utc"),
520
+ self.data_timezone,
520
521
  ),
521
522
  )
522
523
 
@@ -534,25 +535,6 @@ class KiaUvoAPIUSA(ApiImpl):
534
535
 
535
536
  vehicle.data = state
536
537
 
537
- def get_last_updated_at(self, value) -> dt.datetime:
538
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
539
- if value is None:
540
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
541
- else:
542
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
543
- value = dt.datetime(
544
- year=int(m.group(1)),
545
- month=int(m.group(2)),
546
- day=int(m.group(3)),
547
- hour=int(m.group(4)),
548
- minute=int(m.group(5)),
549
- second=int(m.group(6)),
550
- tzinfo=self.data_timezone,
551
- )
552
-
553
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
554
- return value
555
-
556
538
  def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
557
539
  url = self.API_URL + "cmm/gvi"
558
540
 
@@ -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
@@ -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:
@@ -106,16 +113,12 @@ class KiaUvoApiAU(ApiImplType1):
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=="
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=="
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/"
@@ -187,29 +190,11 @@ class KiaUvoApiAU(ApiImplType1):
187
190
  VIN=entry["vin"],
188
191
  timezone=self.data_timezone,
189
192
  engine_type=entry_engine_type,
193
+ ccu_ccs2_protocol_support=entry["ccuCCS2ProtocolSupport"],
190
194
  )
191
195
  result.append(vehicle)
192
196
  return result
193
197
 
194
- def get_last_updated_at(self, value) -> dt.datetime:
195
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
196
- if value is None:
197
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
198
- else:
199
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
200
- value = dt.datetime(
201
- year=int(m.group(1)),
202
- month=int(m.group(2)),
203
- day=int(m.group(3)),
204
- hour=int(m.group(4)),
205
- minute=int(m.group(5)),
206
- second=int(m.group(6)),
207
- tzinfo=self.data_timezone,
208
- )
209
-
210
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
211
- return value
212
-
213
198
  def _get_time_from_string(self, value, timesection) -> dt.datetime.time:
214
199
  if value is not None:
215
200
  lastTwo = int(value[-2:])
@@ -225,15 +210,35 @@ class KiaUvoApiAU(ApiImplType1):
225
210
  return value
226
211
 
227
212
  def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
228
- status = self._get_cached_vehicle_state(token, vehicle)
229
- location = self._get_location(token, vehicle)
230
- self._update_vehicle_properties(
231
- vehicle,
232
- {
233
- "status": status,
234
- "vehicleLocation": location,
235
- },
236
- )
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
+ )
237
242
 
238
243
  if vehicle.engine_type == ENGINE_TYPES.EV:
239
244
  try:
@@ -250,8 +255,8 @@ class KiaUvoApiAU(ApiImplType1):
250
255
  """,
251
256
  exc_info=e,
252
257
  )
253
- else:
254
- self._update_vehicle_drive_info(vehicle, state)
258
+ else:
259
+ self._update_vehicle_drive_info(vehicle, state)
255
260
 
256
261
  def force_refresh_vehicle_state(self, token: Token, vehicle: Vehicle) -> None:
257
262
  status = self._get_forced_vehicle_state(token, vehicle)
@@ -284,8 +289,8 @@ class KiaUvoApiAU(ApiImplType1):
284
289
 
285
290
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
286
291
  if get_child_value(state, "status.time"):
287
- vehicle.last_updated_at = self.get_last_updated_at(
288
- get_child_value(state, "status.time")
292
+ vehicle.last_updated_at = parse_datetime(
293
+ get_child_value(state, "status.time"), self.data_timezone
289
294
  )
290
295
  else:
291
296
  vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
@@ -477,7 +482,7 @@ class KiaUvoApiAU(ApiImplType1):
477
482
  vehicle.ev_charge_limits_dc = [
478
483
  x["targetSOClevel"] for x in target_soc_list if x["plugType"] == 0
479
484
  ][-1]
480
- except:
485
+ except Exception:
481
486
  _LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
482
487
  if (
483
488
  get_child_value(
@@ -633,8 +638,8 @@ class KiaUvoApiAU(ApiImplType1):
633
638
  vehicle.location = (
634
639
  get_child_value(state, "vehicleLocation.coord.lat"),
635
640
  get_child_value(state, "vehicleLocation.coord.lon"),
636
- self.get_last_updated_at(
637
- get_child_value(state, "vehicleLocation.time")
641
+ parse_datetime(
642
+ get_child_value(state, "vehicleLocation.time"), self.data_timezone
638
643
  ),
639
644
  )
640
645
  vehicle.data = state
@@ -644,18 +649,6 @@ class KiaUvoApiAU(ApiImplType1):
644
649
  vehicle.power_consumption_30d = get_child_value(state, "consumption30d")
645
650
  vehicle.daily_stats = get_child_value(state, "dailyStats")
646
651
 
647
- def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
648
- url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/status/latest"
649
-
650
- response = requests.get(
651
- url, headers=self._get_authenticated_headers(token)
652
- ).json()
653
- _LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
654
- _check_response_for_errors(response)
655
- response = response["resMsg"]
656
-
657
- return response
658
-
659
652
  def _get_location(self, token: Token, vehicle: Vehicle) -> dict:
660
653
  url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/location/park"
661
654
 
@@ -666,7 +659,7 @@ class KiaUvoApiAU(ApiImplType1):
666
659
  _LOGGER.debug(f"{DOMAIN} - _get_location response: {response}")
667
660
  _check_response_for_errors(response)
668
661
  return response["resMsg"]["gpsDetail"]
669
- except:
662
+ except Exception:
670
663
  _LOGGER.debug(f"{DOMAIN} - _get_location failed")
671
664
  return None
672
665