hyundai-kia-connect-api 3.17.5__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.
@@ -1,16 +1,23 @@
1
1
  """ApiImpl.py"""
2
2
 
3
- # pylint:disable=unnecessary-pass,missing-class-docstring,invalid-name,missing-function-docstring,wildcard-import,unused-wildcard-import,unused-argument,missing-timeout
3
+ # pylint:disable=unnecessary-pass,missing-class-docstring,invalid-name,missing-function-docstring,wildcard-import,unused-wildcard-import,unused-argument,missing-timeout,logging-fstring-interpolation
4
4
 
5
5
  import datetime as dt
6
6
  import logging
7
7
  from dataclasses import dataclass
8
8
 
9
9
  import requests
10
-
10
+ from requests.exceptions import JSONDecodeError
11
11
  from .Token import Token
12
12
  from .Vehicle import Vehicle
13
- from .const import *
13
+ from .const import (
14
+ WINDOW_STATE,
15
+ CHARGE_PORT_ACTION,
16
+ OrderStatus,
17
+ DOMAIN,
18
+ VALET_MODE_ACTION,
19
+ VEHICLE_LOCK_ACTION,
20
+ )
14
21
  from .utils import get_child_value
15
22
 
16
23
  _LOGGER = logging.getLogger(__name__)
@@ -27,6 +34,7 @@ class ClimateRequestOptions:
27
34
  front_right_seat: int = None
28
35
  rear_left_seat: int = None
29
36
  rear_right_seat: int = None
37
+ steering_wheel: int = None
30
38
 
31
39
 
32
40
  @dataclass
@@ -37,6 +45,26 @@ class WindowRequestOptions:
37
45
  front_right: WINDOW_STATE = None
38
46
 
39
47
 
48
+ @dataclass
49
+ class ScheduleChargingClimateRequestOptions:
50
+ @dataclass
51
+ class DepartureOptions:
52
+ enabled: bool = None
53
+ days: list[int] = None # Sun=0, Mon=1, ..., Sat=6
54
+ time: dt.time = None
55
+
56
+ first_departure: DepartureOptions = None
57
+ second_departure: DepartureOptions = None
58
+ charging_enabled: bool = None
59
+ off_peak_start_time: dt.time = None
60
+ off_peak_end_time: dt.time = None
61
+ off_peak_charge_only_enabled: bool = None
62
+ climate_enabled: bool = None
63
+ temperature: float = None
64
+ temperature_unit: int = None
65
+ defrost: bool = None
66
+
67
+
40
68
  class ApiImpl:
41
69
  data_timezone = dt.timezone.utc
42
70
  temperature_range = None
@@ -57,10 +85,6 @@ class ApiImpl:
57
85
  Required for Kia USA as key is session specific"""
58
86
  return vehicles
59
87
 
60
- def get_last_updated_at(self, value) -> dt.datetime:
61
- """Convert last updated value of vehicle into into datetime"""
62
- pass
63
-
64
88
  def update_vehicle_with_cached_state(self, token: Token, vehicle: Vehicle) -> None:
65
89
  """Get cached vehicle data and update Vehicle instance with it"""
66
90
  pass
@@ -82,26 +106,39 @@ class ApiImpl:
82
106
  def update_geocoded_location(
83
107
  self, token: Token, vehicle: Vehicle, use_email: bool
84
108
  ) -> None:
85
- email_parameter = ""
86
- if use_email is True:
87
- email_parameter = "&email=" + token.username
88
-
89
- url = (
90
- "https://nominatim.openstreetmap.org/reverse?lat="
91
- + str(vehicle.location_latitude)
92
- + "&lon="
93
- + str(vehicle.location_longitude)
94
- + "&format=json&addressdetails=1&zoom=18"
95
- + email_parameter
96
- )
97
- response = requests.get(url)
98
- response = response.json()
99
- vehicle.geocode = (
100
- get_child_value(response, "display_name"),
101
- get_child_value(response, "address"),
102
- )
103
-
104
- def lock_action(self, token: Token, vehicle: Vehicle, action: str) -> str:
109
+ if vehicle.location_latitude and vehicle.location_longitude:
110
+ email_parameter = ""
111
+ if use_email is True:
112
+ email_parameter = "&email=" + token.username
113
+
114
+ url = (
115
+ "https://nominatim.openstreetmap.org/reverse?lat="
116
+ + str(vehicle.location_latitude)
117
+ + "&lon="
118
+ + str(vehicle.location_longitude)
119
+ + "&format=json&addressdetails=1&zoom=18"
120
+ + email_parameter
121
+ )
122
+ _LOGGER.debug(
123
+ f"{DOMAIN} - Running update geocode location with value: {url}"
124
+ )
125
+ response = requests.get(url)
126
+ _LOGGER.debug(f"{DOMAIN} - geocode location raw response: {response}")
127
+ try:
128
+ response = response.json()
129
+ except JSONDecodeError:
130
+ _LOGGER.debug(f"{DOMAIN} - failed to decode json for geocode location")
131
+ vehicle.geocode = None
132
+ else:
133
+ _LOGGER.debug(f"{DOMAIN} - geocode location json response: {response}")
134
+ vehicle.geocode = (
135
+ get_child_value(response, "display_name"),
136
+ get_child_value(response, "address"),
137
+ )
138
+
139
+ def lock_action(
140
+ self, token: Token, vehicle: Vehicle, action: VEHICLE_LOCK_ACTION
141
+ ) -> str:
105
142
  """Lock or unlocks a vehicle. Returns the tracking ID"""
106
143
  pass
107
144
 
@@ -129,6 +166,13 @@ class ApiImpl:
129
166
  """Sets charge limits. Returns the tracking ID"""
130
167
  pass
131
168
 
169
+ def set_charging_current(self, token: Token, vehicle: Vehicle, level: int) -> str:
170
+ """
171
+ feature only available for some regions.
172
+ Sets charge current level (1=100%, 2=90%, 3=60%). Returns the tracking ID
173
+ """
174
+ pass
175
+
132
176
  def set_windows_state(
133
177
  self, token: Token, vehicle: Vehicle, options: WindowRequestOptions
134
178
  ) -> str:
@@ -145,7 +189,7 @@ class ApiImpl:
145
189
  self, token: Token, vehicle: Vehicle, yyyymm_string: str
146
190
  ) -> None:
147
191
  """
148
- Europe feature only.
192
+ feature only available for some regions.
149
193
  Updates the vehicle.month_trip_info for the specified month.
150
194
 
151
195
  Default this information is None:
@@ -158,7 +202,7 @@ class ApiImpl:
158
202
  self, token: Token, vehicle: Vehicle, yyyymmdd_string: str
159
203
  ) -> None:
160
204
  """
161
- Europe feature only.
205
+ feature only available for some regions.
162
206
  Updates the vehicle.day_trip_info information for the specified day.
163
207
 
164
208
  Default this information is None:
@@ -166,3 +210,32 @@ class ApiImpl:
166
210
  day_trip_info: DayTripInfo = None
167
211
  """
168
212
  pass
213
+
214
+ def schedule_charging_and_climate(
215
+ self,
216
+ token: Token,
217
+ vehicle: Vehicle,
218
+ options: ScheduleChargingClimateRequestOptions,
219
+ ) -> str:
220
+ """
221
+ feature only available for some regions.
222
+ Schedule charging and climate control. Returns the tracking ID
223
+ """
224
+ pass
225
+
226
+ def start_hazard_lights(self, token: Token, vehicle: Vehicle) -> str:
227
+ """Turns on the hazard lights for 30 seconds"""
228
+ pass
229
+
230
+ def start_hazard_lights_and_horn(self, token: Token, vehicle: Vehicle) -> str:
231
+ """Turns on the hazard lights and horn for 30 seconds"""
232
+ pass
233
+
234
+ def valet_mode_action(
235
+ self, token: Token, vehicle: Vehicle, action: VALET_MODE_ACTION
236
+ ) -> str:
237
+ """
238
+ feature only available for some regions.
239
+ Activate or Deactivate valet mode. Returns the tracking ID
240
+ """
241
+ pass
@@ -0,0 +1,321 @@
1
+ """ApiImplType1.py"""
2
+
3
+ import datetime as dt
4
+ from typing import Optional
5
+
6
+ from .ApiImpl import (
7
+ ApiImpl,
8
+ )
9
+ from .Token import Token
10
+ from .Vehicle import Vehicle
11
+
12
+ from .utils import (
13
+ get_child_value,
14
+ parse_datetime,
15
+ )
16
+
17
+ from .const import (
18
+ DISTANCE_UNITS,
19
+ ENGINE_TYPES,
20
+ SEAT_STATUS,
21
+ TEMPERATURE_UNITS,
22
+ )
23
+
24
+ USER_AGENT_OK_HTTP: str = "okhttp/3.12.0"
25
+
26
+
27
+ class ApiImplType1(ApiImpl):
28
+ """ApiImplType1"""
29
+
30
+ def __init__(self) -> None:
31
+ """Initialize."""
32
+
33
+ def _get_authenticated_headers(
34
+ self, token: Token, ccs2_support: Optional[int] = None
35
+ ) -> dict:
36
+ return {
37
+ "Authorization": token.access_token,
38
+ "ccsp-service-id": self.CCSP_SERVICE_ID,
39
+ "ccsp-application-id": self.APP_ID,
40
+ "Stamp": self._get_stamp(),
41
+ "ccsp-device-id": token.device_id,
42
+ "Host": self.BASE_URL,
43
+ "Connection": "Keep-Alive",
44
+ "Accept-Encoding": "gzip",
45
+ "Ccuccs2protocolsupport": str(ccs2_support or 0),
46
+ "User-Agent": USER_AGENT_OK_HTTP,
47
+ }
48
+
49
+ def _update_vehicle_properties_ccs2(self, vehicle: Vehicle, state: dict) -> None:
50
+ if get_child_value(state, "Date"):
51
+ vehicle.last_updated_at = parse_datetime(
52
+ get_child_value(state, "Date"), self.data_timezone
53
+ )
54
+ else:
55
+ vehicle.last_updated_at = dt.datetime.now(self.data_timezone)
56
+
57
+ vehicle.odometer = (
58
+ get_child_value(state, "Drivetrain.Odometer"),
59
+ DISTANCE_UNITS[1],
60
+ )
61
+ vehicle.car_battery_percentage = get_child_value(
62
+ state, "Electronics.Battery.Level"
63
+ )
64
+
65
+ vehicle.engine_is_running = get_child_value(state, "DrivingReady")
66
+
67
+ air_temp = get_child_value(
68
+ state,
69
+ "Cabin.HVAC.Row1.Driver.Temperature.Value",
70
+ )
71
+
72
+ if air_temp != "OFF":
73
+ vehicle.air_temperature = (air_temp, TEMPERATURE_UNITS[1])
74
+
75
+ defrost_is_on = get_child_value(state, "Body.Windshield.Front.Defog.State")
76
+ if defrost_is_on in [0, 2]:
77
+ vehicle.defrost_is_on = False
78
+ elif defrost_is_on == 1:
79
+ vehicle.defrost_is_on = True
80
+
81
+ steer_wheel_heat = get_child_value(state, "Cabin.SteeringWheel.Heat.State")
82
+ if steer_wheel_heat in [0, 2]:
83
+ vehicle.steering_wheel_heater_is_on = False
84
+ elif steer_wheel_heat == 1:
85
+ vehicle.steering_wheel_heater_is_on = True
86
+
87
+ defrost_rear_is_on = get_child_value(state, "Body.Windshield.Rear.Defog.State")
88
+ if defrost_rear_is_on in [0, 2]:
89
+ vehicle.back_window_heater_is_on = False
90
+ elif defrost_rear_is_on == 1:
91
+ vehicle.back_window_heater_is_on = True
92
+
93
+ # TODO: status.sideMirrorHeat
94
+
95
+ vehicle.front_left_seat_status = SEAT_STATUS[
96
+ get_child_value(state, "Cabin.Seat.Row1.Driver.Climate.State")
97
+ ]
98
+
99
+ vehicle.front_right_seat_status = SEAT_STATUS[
100
+ get_child_value(state, "Cabin.Seat.Row1.Passenger.Climate.State")
101
+ ]
102
+
103
+ vehicle.rear_left_seat_status = SEAT_STATUS[
104
+ get_child_value(state, "Cabin.Seat.Row2.Left.Climate.State")
105
+ ]
106
+
107
+ vehicle.rear_right_seat_status = SEAT_STATUS[
108
+ get_child_value(state, "Cabin.Seat.Row2.Right.Climate.State")
109
+ ]
110
+
111
+ # TODO: status.doorLock
112
+
113
+ vehicle.front_left_door_is_open = get_child_value(
114
+ state, "Cabin.Door.Row1.Driver.Open"
115
+ )
116
+ vehicle.front_right_door_is_open = get_child_value(
117
+ state, "Cabin.Door.Row1.Passenger.Open"
118
+ )
119
+ vehicle.back_left_door_is_open = get_child_value(
120
+ state, "Cabin.Door.Row2.Left.Open"
121
+ )
122
+ vehicle.back_right_door_is_open = get_child_value(
123
+ state, "Cabin.Door.Row2.Right.Open"
124
+ )
125
+
126
+ # TODO: should the windows and trunc also be checked?
127
+ vehicle.is_locked = not (
128
+ vehicle.front_left_door_is_open
129
+ or vehicle.front_right_door_is_open
130
+ or vehicle.back_left_door_is_open
131
+ or vehicle.back_right_door_is_open
132
+ )
133
+
134
+ vehicle.hood_is_open = get_child_value(state, "Body.Hood.Open")
135
+ vehicle.front_left_window_is_open = get_child_value(
136
+ state, "Cabin.Window.Row1.Driver.Open"
137
+ )
138
+ vehicle.front_right_window_is_open = get_child_value(
139
+ state, "Cabin.Window.Row1.Passenger.Open"
140
+ )
141
+ vehicle.back_left_window_is_open = get_child_value(
142
+ state, "Cabin.Window.Row2.Left.Open"
143
+ )
144
+ vehicle.back_right_window_is_open = get_child_value(
145
+ state, "Cabin.Window.Row2.Right.Open"
146
+ )
147
+ vehicle.tire_pressure_rear_left_warning_is_on = bool(
148
+ get_child_value(state, "Chassis.Axle.Row2.Left.Tire.PressureLow")
149
+ )
150
+ vehicle.tire_pressure_front_left_warning_is_on = bool(
151
+ get_child_value(state, "Chassis.Axle.Row1.Left.Tire.PressureLow")
152
+ )
153
+ vehicle.tire_pressure_front_right_warning_is_on = bool(
154
+ get_child_value(state, "Chassis.Axle.Row1.Right.Tire.PressureLow")
155
+ )
156
+ vehicle.tire_pressure_rear_right_warning_is_on = bool(
157
+ get_child_value(state, "Chassis.Axle.Row2.Right.Tire.PressureLow")
158
+ )
159
+ vehicle.tire_pressure_all_warning_is_on = bool(
160
+ get_child_value(state, "Chassis.Axle.Tire.PressureLow")
161
+ )
162
+ vehicle.trunk_is_open = get_child_value(state, "Body.Trunk.Open")
163
+
164
+ vehicle.ev_battery_percentage = get_child_value(
165
+ state, "Green.BatteryManagement.BatteryRemain.Ratio"
166
+ )
167
+ vehicle.ev_battery_remain = get_child_value(
168
+ state, "Green.BatteryManagement.BatteryRemain.Value"
169
+ )
170
+ vehicle.ev_battery_capacity = get_child_value(
171
+ state, "Green.BatteryManagement.BatteryCapacity.Value"
172
+ )
173
+ vehicle.ev_battery_soh_percentage = get_child_value(
174
+ state, "Green.BatteryManagement.SoH.Ratio"
175
+ )
176
+ vehicle.ev_battery_is_plugged_in = get_child_value(
177
+ state, "Green.ChargingInformation.ElectricCurrentLevel.State"
178
+ )
179
+ vehicle.ev_battery_is_plugged_in = get_child_value(
180
+ state, "Green.ChargingInformation.ConnectorFastening.State"
181
+ )
182
+ charging_door_state = get_child_value(state, "Green.ChargingDoor.State")
183
+ if charging_door_state in [0, 2]:
184
+ vehicle.ev_charge_port_door_is_open = False
185
+ elif charging_door_state == 1:
186
+ vehicle.ev_charge_port_door_is_open = True
187
+
188
+ vehicle.total_driving_range = (
189
+ float(
190
+ get_child_value(
191
+ state,
192
+ "Drivetrain.FuelSystem.DTE.Total", # noqa
193
+ )
194
+ ),
195
+ DISTANCE_UNITS[
196
+ get_child_value(
197
+ state,
198
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
199
+ )
200
+ ],
201
+ )
202
+
203
+ if vehicle.engine_type == ENGINE_TYPES.EV:
204
+ # ev_driving_range is the same as total_driving_range for pure EV
205
+ vehicle.ev_driving_range = (
206
+ vehicle.total_driving_range,
207
+ vehicle.total_driving_range_unit,
208
+ )
209
+ # TODO: vehicle.ev_driving_range for non EV
210
+
211
+ vehicle.washer_fluid_warning_is_on = get_child_value(
212
+ state, "Body.Windshield.Front.WasherFluid.LevelLow"
213
+ )
214
+
215
+ vehicle.ev_estimated_current_charge_duration = (
216
+ get_child_value(state, "Green.ChargingInformation.Charging.RemainTime"),
217
+ "m",
218
+ )
219
+ vehicle.ev_estimated_fast_charge_duration = (
220
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.Standard"),
221
+ "m",
222
+ )
223
+ vehicle.ev_estimated_portable_charge_duration = (
224
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.ICCB"),
225
+ "m",
226
+ )
227
+ vehicle.ev_estimated_station_charge_duration = (
228
+ get_child_value(state, "Green.ChargingInformation.EstimatedTime.Quick"),
229
+ "m",
230
+ )
231
+ vehicle.ev_charge_limits_ac = get_child_value(
232
+ state, "Green.ChargingInformation.TargetSoC.Standard"
233
+ )
234
+ vehicle.ev_charge_limits_dc = get_child_value(
235
+ state, "Green.ChargingInformation.TargetSoC.Quick"
236
+ )
237
+ vehicle.ev_charging_current = get_child_value(
238
+ state, "Green.ChargingInformation.ElectricCurrentLevel.State"
239
+ )
240
+ vehicle.ev_v2l_discharge_limit = get_child_value(
241
+ state, "Green.Electric.SmartGrid.VehicleToLoad.DischargeLimitation.SoC"
242
+ )
243
+ vehicle.ev_target_range_charge_AC = (
244
+ get_child_value(
245
+ state,
246
+ "Green.ChargingInformation.DTE.TargetSoC.Standard", # noqa
247
+ ),
248
+ DISTANCE_UNITS[
249
+ get_child_value(
250
+ state,
251
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
252
+ )
253
+ ],
254
+ )
255
+ vehicle.ev_target_range_charge_DC = (
256
+ get_child_value(
257
+ state,
258
+ "Green.ChargingInformation.DTE.TargetSoC.Quick", # noqa
259
+ ),
260
+ DISTANCE_UNITS[
261
+ get_child_value(
262
+ state,
263
+ "Drivetrain.FuelSystem.DTE.Unit", # noqa
264
+ )
265
+ ],
266
+ )
267
+ vehicle.ev_first_departure_enabled = bool(
268
+ get_child_value(state, "Green.Reservation.Departure.Schedule1.Enable")
269
+ )
270
+
271
+ vehicle.ev_second_departure_enabled = bool(
272
+ get_child_value(state, "Green.Reservation.Departure.Schedule2.Enable")
273
+ )
274
+
275
+ # TODO: vehicle.ev_first_departure_days --> Green.Reservation.Departure.Schedule1.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
276
+ # TODO: vehicle.ev_second_departure_days --> Green.Reservation.Departure.Schedule2.(Mon,Tue,Wed,Thu,Fri,Sat,Sun) # noqa
277
+ # TODO: vehicle.ev_first_departure_time --> Green.Reservation.Departure.Schedule1.(Min,Hour) # noqa
278
+ # TODO: vehicle.ev_second_departure_time --> Green.Reservation.Departure.Schedule2.(Min,Hour) # noqa
279
+ # TODO: vehicle.ev_off_peak_charge_only_enabled --> unknown settings are in --> Green.Reservation.OffPeakTime and OffPeakTime2 # noqa
280
+
281
+ vehicle.washer_fluid_warning_is_on = get_child_value(
282
+ state, "Body.Windshield.Front.WasherFluid.LevelLow"
283
+ )
284
+ vehicle.brake_fluid_warning_is_on = get_child_value(
285
+ state, "Chassis.Brake.Fluid.Warning"
286
+ )
287
+
288
+ vehicle.fuel_level = get_child_value(state, "Drivetrain.FuelSystem.FuelLevel")
289
+ vehicle.fuel_level_is_low = get_child_value(
290
+ state, "Drivetrain.FuelSystem.LowFuelWarning"
291
+ )
292
+ vehicle.air_control_is_on = get_child_value(
293
+ state, "Cabin.HVAC.Row1.Driver.Blower.SpeedLevel"
294
+ )
295
+ vehicle.smart_key_battery_warning_is_on = bool(
296
+ get_child_value(state, "Electronics.FOB.LowBattery")
297
+ )
298
+
299
+ if get_child_value(state, "Location.GeoCoord.Latitude"):
300
+ location_last_updated_at = dt.datetime(
301
+ 2000, 1, 1, tzinfo=self.data_timezone
302
+ )
303
+ timestamp = get_child_value(state, "Location.TimeStamp")
304
+ if timestamp is not None:
305
+ location_last_updated_at = dt.datetime(
306
+ year=int(get_child_value(timestamp, "Year")),
307
+ month=int(get_child_value(timestamp, "Mon")),
308
+ day=int(get_child_value(timestamp, "Day")),
309
+ hour=int(get_child_value(timestamp, "Hour")),
310
+ minute=int(get_child_value(timestamp, "Min")),
311
+ second=int(get_child_value(timestamp, "Sec")),
312
+ tzinfo=self.data_timezone,
313
+ )
314
+
315
+ vehicle.location = (
316
+ get_child_value(state, "Location.GeoCoord.Latitude"),
317
+ get_child_value(state, "Location.GeoCoord.Longitude"),
318
+ location_last_updated_at,
319
+ )
320
+
321
+ vehicle.data = state