hyundai-kia-connect-api 3.17.10__py2.py3-none-any.whl → 3.19.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")
@@ -636,32 +636,65 @@ class HyundaiBlueLinkAPIUSA(ApiImpl):
636
636
  _LOGGER.debug(f"{DOMAIN} - Stop engine response: {response.text}")
637
637
 
638
638
  def start_charge(self, token: Token, vehicle: Vehicle) -> None:
639
- pass
639
+ if vehicle.engine_type != ENGINE_TYPES.EV:
640
+ return {}
641
+
642
+ _LOGGER.debug(f"{DOMAIN} - Start charging..")
643
+
644
+ url = self.API_URL + "evc/charge/start"
645
+ headers = self._get_vehicle_headers(token, vehicle)
646
+ _LOGGER.debug(f"{DOMAIN} - Start charging headers: {headers}")
647
+
648
+ response = self.sessions.post(url, headers=headers)
649
+ _LOGGER.debug(
650
+ f"{DOMAIN} - Start charge response status code: {response.status_code}"
651
+ )
652
+ _LOGGER.debug(f"{DOMAIN} - Start charge response: {response.text}")
640
653
 
641
654
  def stop_charge(self, token: Token, vehicle: Vehicle) -> None:
642
- pass
655
+ if vehicle.engine_type != ENGINE_TYPES.EV:
656
+ return {}
643
657
 
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
- )
658
+ _LOGGER.debug(f"{DOMAIN} - Stop charging..")
659
+
660
+ url = self.API_URL + "evc/charge/stop"
661
+ headers = self._get_vehicle_headers(token, vehicle)
662
+ _LOGGER.debug(f"{DOMAIN} - Stop charging headers: {headers}")
663
+
664
+ response = self.sessions.post(url, headers=headers)
665
+ _LOGGER.debug(
666
+ f"{DOMAIN} - Stop charge response status code: {response.status_code}"
667
+ )
668
+ _LOGGER.debug(f"{DOMAIN} - Stop charge response: {response.text}")
669
+
670
+ def set_charge_limits(
671
+ self, token: Token, vehicle: Vehicle, ac: int, dc: int
672
+ ) -> str:
673
+ if vehicle.engine_type != ENGINE_TYPES.EV:
674
+ return {}
675
+
676
+ _LOGGER.debug(f"{DOMAIN} - Setting charge limits..")
677
+ url = self.API_URL + "evc/charge/targetsoc/set"
678
+ headers = self._get_vehicle_headers(token, vehicle)
679
+ _LOGGER.debug(f"{DOMAIN} - Setting charge limits: {headers}")
665
680
 
666
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
667
- return value
681
+ data = {
682
+ "targetSOClist": [
683
+ {
684
+ "plugType": 0,
685
+ "targetSOClevel": int(dc),
686
+ },
687
+ {
688
+ "plugType": 1,
689
+ "targetSOClevel": int(ac),
690
+ },
691
+ ]
692
+ }
693
+
694
+ _LOGGER.debug(f"{DOMAIN} - Setting charge limits body: {data}")
695
+
696
+ response = self.sessions.post(url, json=data, headers=headers)
697
+ _LOGGER.debug(
698
+ f"{DOMAIN} - Setting charge limits response status code: {response.status_code}"
699
+ )
700
+ _LOGGER.debug(f"{DOMAIN} - Setting charge limits: {response.text}")
@@ -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
@@ -57,6 +56,7 @@ from .utils import (
57
56
  get_child_value,
58
57
  get_index_into_hex_temp,
59
58
  get_hex_temp_into_index,
59
+ parse_datetime,
60
60
  )
61
61
 
62
62
  _LOGGER = logging.getLogger(__name__)
@@ -190,29 +190,11 @@ class KiaUvoApiAU(ApiImplType1):
190
190
  VIN=entry["vin"],
191
191
  timezone=self.data_timezone,
192
192
  engine_type=entry_engine_type,
193
+ ccu_ccs2_protocol_support=entry["ccuCCS2ProtocolSupport"],
193
194
  )
194
195
  result.append(vehicle)
195
196
  return result
196
197
 
197
- def get_last_updated_at(self, value) -> dt.datetime:
198
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - before {value}")
199
- if value is None:
200
- value = dt.datetime(2000, 1, 1, tzinfo=self.data_timezone)
201
- else:
202
- m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
203
- value = dt.datetime(
204
- year=int(m.group(1)),
205
- month=int(m.group(2)),
206
- day=int(m.group(3)),
207
- hour=int(m.group(4)),
208
- minute=int(m.group(5)),
209
- second=int(m.group(6)),
210
- tzinfo=self.data_timezone,
211
- )
212
-
213
- _LOGGER.debug(f"{DOMAIN} - last_updated_at - after {value}")
214
- return value
215
-
216
198
  def _get_time_from_string(self, value, timesection) -> dt.datetime.time:
217
199
  if value is not None:
218
200
  lastTwo = int(value[-2:])
@@ -228,15 +210,35 @@ class KiaUvoApiAU(ApiImplType1):
228
210
  return value
229
211
 
230
212
  def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
231
- status = self._get_cached_vehicle_state(token, vehicle)
232
- location = self._get_location(token, vehicle)
233
- self._update_vehicle_properties(
234
- vehicle,
235
- {
236
- "status": status,
237
- "vehicleLocation": location,
238
- },
239
- )
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
+ )
240
242
 
241
243
  if vehicle.engine_type == ENGINE_TYPES.EV:
242
244
  try:
@@ -253,8 +255,8 @@ class KiaUvoApiAU(ApiImplType1):
253
255
  """,
254
256
  exc_info=e,
255
257
  )
256
- else:
257
- self._update_vehicle_drive_info(vehicle, state)
258
+ else:
259
+ self._update_vehicle_drive_info(vehicle, state)
258
260
 
259
261
  def force_refresh_vehicle_state(self, token: Token, vehicle: Vehicle) -> None:
260
262
  status = self._get_forced_vehicle_state(token, vehicle)
@@ -287,8 +289,8 @@ class KiaUvoApiAU(ApiImplType1):
287
289
 
288
290
  def _update_vehicle_properties(self, vehicle: Vehicle, state: dict) -> None:
289
291
  if get_child_value(state, "status.time"):
290
- vehicle.last_updated_at = self.get_last_updated_at(
291
- get_child_value(state, "status.time")
292
+ vehicle.last_updated_at = parse_datetime(
293
+ get_child_value(state, "status.time"), self.data_timezone
292
294
  )
293
295
  else:
294
296
  vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
@@ -480,7 +482,7 @@ class KiaUvoApiAU(ApiImplType1):
480
482
  vehicle.ev_charge_limits_dc = [
481
483
  x["targetSOClevel"] for x in target_soc_list if x["plugType"] == 0
482
484
  ][-1]
483
- except:
485
+ except Exception:
484
486
  _LOGGER.debug(f"{DOMAIN} - SOC Levels couldn't be found. May not be an EV.")
485
487
  if (
486
488
  get_child_value(
@@ -636,8 +638,8 @@ class KiaUvoApiAU(ApiImplType1):
636
638
  vehicle.location = (
637
639
  get_child_value(state, "vehicleLocation.coord.lat"),
638
640
  get_child_value(state, "vehicleLocation.coord.lon"),
639
- self.get_last_updated_at(
640
- get_child_value(state, "vehicleLocation.time")
641
+ parse_datetime(
642
+ get_child_value(state, "vehicleLocation.time"), self.data_timezone
641
643
  ),
642
644
  )
643
645
  vehicle.data = state
@@ -647,18 +649,6 @@ class KiaUvoApiAU(ApiImplType1):
647
649
  vehicle.power_consumption_30d = get_child_value(state, "consumption30d")
648
650
  vehicle.daily_stats = get_child_value(state, "dailyStats")
649
651
 
650
- def _get_cached_vehicle_state(self, token: Token, vehicle: Vehicle) -> dict:
651
- url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/status/latest"
652
-
653
- response = requests.get(
654
- url, headers=self._get_authenticated_headers(token)
655
- ).json()
656
- _LOGGER.debug(f"{DOMAIN} - get_cached_vehicle_status response: {response}")
657
- _check_response_for_errors(response)
658
- response = response["resMsg"]
659
-
660
- return response
661
-
662
652
  def _get_location(self, token: Token, vehicle: Vehicle) -> dict:
663
653
  url = self.SPA_API_URL + "vehicles/" + vehicle.id + "/location/park"
664
654
 
@@ -669,7 +659,7 @@ class KiaUvoApiAU(ApiImplType1):
669
659
  _LOGGER.debug(f"{DOMAIN} - _get_location response: {response}")
670
660
  _check_response_for_errors(response)
671
661
  return response["resMsg"]["gpsDetail"]
672
- except:
662
+ except Exception:
673
663
  _LOGGER.debug(f"{DOMAIN} - _get_location failed")
674
664
  return None
675
665