tesla-fleet-api 0.5.5__py3-none-any.whl → 0.5.7__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.
@@ -9,3 +9,18 @@ from .partner import Partner
9
9
  from .user import User
10
10
  from .vehicle import Vehicle
11
11
  from .vehiclespecific import VehicleSpecific
12
+
13
+
14
+ __all__ = [
15
+ "TeslaFleetApi",
16
+ "TeslaFleetOAuth",
17
+ "Teslemetry",
18
+ "Tessie",
19
+ "Charging",
20
+ "Energy",
21
+ "EnergySpecific",
22
+ "Partner",
23
+ "User",
24
+ "Vehicle",
25
+ "VehicleSpecific",
26
+ ]
tesla_fleet_api/const.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from enum import Enum
4
4
  import logging
5
5
 
6
- VERSION = "0.5.5"
6
+ VERSION = "0.5.7"
7
7
  LOGGER = logging.getLogger(__package__)
8
8
  SERVERS = {
9
9
  "na": "https://fleet-api.prd.na.vn.cloud.tesla.com",
tesla_fleet_api/energy.py CHANGED
@@ -91,7 +91,7 @@ class Energy:
91
91
  self,
92
92
  energy_site_id: int,
93
93
  disallow_charge_from_grid_with_solar_installed: bool | None = None,
94
- customer_preferred_export_rule: EnergyExportMode|str | None = None,
94
+ customer_preferred_export_rule: EnergyExportMode | str | None = None,
95
95
  ) -> dict[str, Any]:
96
96
  """Allow/disallow charging from the grid and exporting energy to the grid."""
97
97
  return await self._request(
@@ -114,6 +114,7 @@ class Forbidden(TeslaFleetError):
114
114
 
115
115
  message = "Access to this resource is not authorized, developers should check required Scope."
116
116
  status = 403
117
+ key = "Unauthorized missing scopes"
117
118
 
118
119
 
119
120
  class UnsupportedVehicle(TeslaFleetError):
@@ -15,7 +15,7 @@ from .vehicle import Vehicle
15
15
  class TeslaFleetApi:
16
16
  """Class describing the Tesla Fleet API."""
17
17
 
18
- server: str
18
+ server: str | None = None
19
19
  session: aiohttp.ClientSession
20
20
  headers: dict[str, str]
21
21
  raise_for_status: bool
@@ -23,7 +23,7 @@ class TeslaFleetApi:
23
23
  def __init__(
24
24
  self,
25
25
  session: aiohttp.ClientSession,
26
- access_token: str,
26
+ access_token: str | None = None,
27
27
  region: str | None = None,
28
28
  server: str | None = None,
29
29
  raise_for_status: bool = True,
@@ -38,9 +38,10 @@ class TeslaFleetApi:
38
38
  self.session = session
39
39
  self.access_token = access_token
40
40
 
41
- if region and not server and region not in SERVERS:
42
- raise ValueError(f"Region must be one of {', '.join(SERVERS.keys())}")
43
- self.server = server or SERVERS.get(region)
41
+ if region is not None:
42
+ if not server and region not in SERVERS:
43
+ raise ValueError(f"Region must be one of {', '.join(SERVERS.keys())}")
44
+ self.server = server or SERVERS.get(region)
44
45
  self.raise_for_status = raise_for_status
45
46
 
46
47
  LOGGER.debug("Using server %s", self.server)
@@ -61,7 +62,8 @@ class TeslaFleetApi:
61
62
  for server in SERVERS.values():
62
63
  self.server = server
63
64
  try:
64
- response = await (self.user.region()).get("response")
65
+ region_response = await self.user.region()
66
+ response = region_response.get("response")
65
67
  if response:
66
68
  self.server = response["fleet_api_base_url"]
67
69
  LOGGER.debug("Using server %s", self.server)
@@ -74,9 +76,9 @@ class TeslaFleetApi:
74
76
  self,
75
77
  method: Method,
76
78
  path: str,
77
- params: dict[str:Any] | None = None,
78
- json: dict[str:Any] | None = None,
79
- ):
79
+ params: dict[str, Any] | None = None,
80
+ json: dict[str, Any] | None = None,
81
+ ) -> dict[str, Any] | str:
80
82
  """Send a request to the Tesla Fleet API."""
81
83
 
82
84
  if not self.server:
@@ -125,7 +127,7 @@ class TeslaFleetApi:
125
127
  LOGGER.debug("Response Text: %s", data)
126
128
  return data
127
129
 
128
- async def status(self):
130
+ async def status(self) -> str:
129
131
  """This endpoint returns the string "ok" if the API is operating normally. No HTTP headers are required."""
130
132
  if not self.server:
131
133
  raise ValueError("Server was not set at init. Call find_server() first.")
@@ -42,7 +42,9 @@ class TeslaFleetOAuth(TeslaFleetApi):
42
42
  """Get the login URL."""
43
43
  return f"https://auth.tesla.com/oauth2/v3/authorize?response_type=code&client_id={self.client_id}&redirect_uri={redirect_uri}&scope={' '.join(scopes)}&state={state}"
44
44
 
45
- async def get_refresh_token(self, client_secret: str, code: str, redirect_uri: str):
45
+ async def get_refresh_token(
46
+ self, client_secret: str, code: str, redirect_uri: str
47
+ ) -> None:
46
48
  """Get the refresh token."""
47
49
  async with self.session.post(
48
50
  "https://auth.tesla.com/oauth2/v3/token",
@@ -63,13 +65,13 @@ class TeslaFleetOAuth(TeslaFleetApi):
63
65
  region = code.split("_")[0].lower()
64
66
  self.server = SERVERS.get(region)
65
67
 
66
- async def check_access_token(self) -> str | None:
68
+ async def check_access_token(self) -> dict[str, Any] | None:
67
69
  """Get the access token."""
68
70
  if self.access_token and self.expires > time.time():
69
- return
71
+ return None
70
72
  return await self.refresh_access_token()
71
73
 
72
- async def refresh_access_token(self) -> str:
74
+ async def refresh_access_token(self) -> dict[str, Any]:
73
75
  """Refresh the access token."""
74
76
  if not self.refresh_token:
75
77
  raise ValueError("Refresh token is missing")
@@ -93,9 +95,9 @@ class TeslaFleetOAuth(TeslaFleetApi):
93
95
  self,
94
96
  method: Method,
95
97
  path: str,
96
- params: dict | None = None,
97
- data: dict | None = None,
98
- ):
98
+ params: dict[str, Any] | None = None,
99
+ data: dict[str, Any] | None = None,
100
+ ) -> str | dict[str, Any]:
99
101
  """Send a request to the Tesla Fleet API."""
100
102
  await self.check_access_token()
101
103
  return await super()._request(method, path, params, data)
@@ -52,7 +52,8 @@ class Teslemetry(TeslaFleetApi):
52
52
  LOGGER.debug("Using server %s", self.server)
53
53
  return resp
54
54
 
55
- async def find_server(self):
55
+ # TODO: type this properly, it probably should return something
56
+ async def find_server(self) -> None:
56
57
  """Find the server URL for the Tesla Fleet API."""
57
58
  await self.metadata(True)
58
59
 
@@ -60,9 +61,9 @@ class Teslemetry(TeslaFleetApi):
60
61
  self,
61
62
  method: Method,
62
63
  path: str,
63
- params: dict[str:Any] | None = None,
64
- json: dict[str:Any] | None = None,
65
- ):
64
+ params: dict[str, Any] | None = None,
65
+ json: dict[str, Any] | None = None,
66
+ ) -> str | dict[str, Any]:
66
67
  """Send a request to the Teslemetry API."""
67
68
  async with rate_limit:
68
69
  return await super()._request(method, path, params, json)
tesla_fleet_api/tessie.py CHANGED
@@ -2,7 +2,6 @@ import aiohttp
2
2
  from typing import Any
3
3
  from .teslafleetapi import TeslaFleetApi
4
4
  from .const import Method
5
- from .vehiclespecific import VehicleSpecific
6
5
 
7
6
 
8
7
  class Tessie(TeslaFleetApi):
@@ -23,7 +22,7 @@ class Tessie(TeslaFleetApi):
23
22
  energy_scope=False,
24
23
  )
25
24
 
26
- async def find_server(self):
25
+ async def find_server(self) -> str:
27
26
  """Find the server URL for the Tesla Fleet API."""
28
27
  raise NotImplementedError("Do not use this function for Tessie.")
29
28
 
@@ -24,6 +24,10 @@ class Vehicle:
24
24
  def specific(self, vehicle_tag: str | int) -> VehicleSpecific:
25
25
  """Creates a class for each vehicle."""
26
26
  return VehicleSpecific(self, vehicle_tag)
27
+
28
+ def pre2021(self, vin: str) -> bool:
29
+ """Checks if a vehicle is pre-2021."""
30
+ return vin[9] <= "L"
27
31
 
28
32
  async def actuate_trunk(
29
33
  self, vehicle_tag: str | int, which_trunk: Trunk | str
@@ -426,13 +430,29 @@ class Vehicle:
426
430
  )
427
431
 
428
432
  async def set_scheduled_departure(
429
- self, vehicle_tag: str | int, enable: bool, time: int
433
+ self,
434
+ vehicle_tag: str | int,
435
+ enable: bool = True,
436
+ preconditioning_enabled: bool = False,
437
+ preconditioning_weekdays_only: bool = False,
438
+ departure_time: int = 0,
439
+ off_peak_charging_enabled: bool = False,
440
+ off_peak_charging_weekdays_only: bool = False,
441
+ end_off_peak_time: int = 0,
430
442
  ) -> dict[str, Any]:
431
443
  """Sets a time at which departure should be completed. The time parameter is minutes after midnight (e.g: time=120 schedules departure for 2:00am vehicle local time)."""
432
444
  return await self._request(
433
445
  Method.POST,
434
446
  f"api/1/vehicles/{vehicle_tag}/command/set_scheduled_departure",
435
- json={"preconditioning_enabled": enable, "departure_time": time},
447
+ json={
448
+ "enable": enable,
449
+ "preconditioning_enabled": preconditioning_enabled,
450
+ "preconditioning_weekdays_only": preconditioning_weekdays_only,
451
+ "departure_time": departure_time,
452
+ "off_peak_charging_enabled": off_peak_charging_enabled,
453
+ "off_peak_charging_weekdays_only": off_peak_charging_weekdays_only,
454
+ "end_off_peak_time": end_off_peak_time,
455
+ },
436
456
  )
437
457
 
438
458
  async def set_sentry_mode(self, vehicle_tag: str | int, on: bool) -> dict[str, Any]:
@@ -551,7 +571,7 @@ class Vehicle:
551
571
  lon: float | None = None,
552
572
  ) -> dict[str, Any]:
553
573
  """Turns on HomeLink (used to open and close garage doors)."""
554
- data = {}
574
+ data: dict[str, str | float] = {}
555
575
  if token:
556
576
  data["token"] = token
557
577
  if lat and lon:
@@ -726,12 +746,11 @@ class Vehicle:
726
746
  endpoints: List[VehicleDataEndpoint] | List[str] | None = None,
727
747
  ) -> dict[str, Any]:
728
748
  """Makes a live call to the vehicle. This may return cached data if the vehicle is offline. For vehicles running firmware versions 2023.38+, location_data is required to fetch vehicle location. This will result in a location sharing icon to show on the vehicle UI."""
729
- if isinstance(endpoints, list):
730
- endpoints = ";".join(endpoints)
749
+ endpoint_payload = ";".join(endpoints) if endpoints else None
731
750
  return await self._request(
732
751
  Method.GET,
733
752
  f"api/1/vehicles/{vehicle_tag}/vehicle_data",
734
- {"endpoints": endpoints},
753
+ {"endpoints": endpoint_payload},
735
754
  )
736
755
 
737
756
  async def vehicle_subscriptions(
@@ -13,10 +13,14 @@ from .const import (
13
13
  class VehicleSpecific:
14
14
  """Class describing the Tesla Fleet API vehicle endpoints and commands for a specific vehicle."""
15
15
 
16
- def __init__(self, parent, vin: str | None = None):
16
+ def __init__(self, parent, vin: str | int | None = None):
17
17
  self._parent = parent
18
18
  self.vin = vin
19
19
 
20
+ def pre2021(self) -> bool:
21
+ """Checks if a vehicle is pre-2021."""
22
+ return self._parent.pre2021(self.vin)
23
+
20
24
  async def actuate_trunk(self, which_trunk: Trunk | str) -> dict[str, Any]:
21
25
  """Controls the front or rear trunk."""
22
26
  return await self._parent.actuate_trunk(self.vin, which_trunk)
@@ -243,9 +247,27 @@ class VehicleSpecific:
243
247
  """Sets a time at which charging should be completed. The time parameter is minutes after midnight (e.g: time=120 schedules charging for 2:00am vehicle local time)."""
244
248
  return await self._parent.set_scheduled_charging(self.vin, enable, time)
245
249
 
246
- async def set_scheduled_departure(self, enable: bool, time: int) -> dict[str, Any]:
250
+ async def set_scheduled_departure(
251
+ self,
252
+ enable: bool = True,
253
+ preconditioning_enabled: bool = False,
254
+ preconditioning_weekdays_only: bool = False,
255
+ departure_time: int = 0,
256
+ off_peak_charging_enabled: bool = False,
257
+ off_peak_charging_weekdays_only: bool = False,
258
+ end_off_peak_time: int = 0,
259
+ ) -> dict[str, Any]:
247
260
  """Sets a time at which departure should be completed. The time parameter is minutes after midnight (e.g: time=120 schedules departure for 2:00am vehicle local time)."""
248
- return await self._parent.set_scheduled_departure(self.vin, enable, time)
261
+ return await self._parent.set_scheduled_departure(
262
+ self.vin,
263
+ enable,
264
+ preconditioning_enabled,
265
+ preconditioning_weekdays_only,
266
+ departure_time,
267
+ off_peak_charging_enabled,
268
+ off_peak_charging_weekdays_only,
269
+ end_off_peak_time,
270
+ )
249
271
 
250
272
  async def set_sentry_mode(self, on: bool) -> dict[str, Any]:
251
273
  """Enables and disables Sentry Mode. Sentry Mode allows customers to watch the vehicle cameras live from the mobile app, as well as record sentry events."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tesla_fleet_api
3
- Version: 0.5.5
3
+ Version: 0.5.7
4
4
  Summary: Tesla Fleet API library for Python
5
5
  Home-page: https://github.com/Teslemetry/tesla_fleet_api
6
6
  Author: Brett Adams
@@ -0,0 +1,19 @@
1
+ tesla_fleet_api/__init__.py,sha256=0MON9vh3AShIiX16FZ6NU3yZ7kyXFh5GxA0rY8CzVRM,584
2
+ tesla_fleet_api/charging.py,sha256=N_mc8axrXj3iduqLj_jCt4Vx86tHqe3xqQT4R1R7HvU,1689
3
+ tesla_fleet_api/const.py,sha256=cxe_D2pfWT6REocIZEGfC-COOiXZrCcqGGKkYOs6MxM,9277
4
+ tesla_fleet_api/energy.py,sha256=kE-HDupzhgatIsizJoer1MAALP-wH6jjjGliiRQN0Os,5285
5
+ tesla_fleet_api/energyspecific.py,sha256=kICxdeDoWR9JHlgjHvnmjJ1ErLOWJT8bCSESoXo9axU,3732
6
+ tesla_fleet_api/exceptions.py,sha256=Wh9roGPYB9oBGgEEfxMDay5A7RkPy8JFKloKPStGQ2Y,9211
7
+ tesla_fleet_api/partner.py,sha256=1vIBUaxKLIfqcC0X6VXZN0dMAzj_CLNPUMjA6QVqZ1k,1223
8
+ tesla_fleet_api/teslafleetapi.py,sha256=3-gGx-RxOD92Ul0lNCEsCwVBsYunKsO2Sr5rYH0YtIg,5070
9
+ tesla_fleet_api/teslafleetoauth.py,sha256=FfLnuqZMxF2HsZ5miLNtm3pRwKDoQKi2GD-oXgKxZgA,3594
10
+ tesla_fleet_api/teslemetry.py,sha256=XOqm7SaakooJSNXEasJI_tRoCIyiFCD6n_PCx9U_D9g,2107
11
+ tesla_fleet_api/tessie.py,sha256=ZttWuDdQOuTFO4k-BMq7fXKP3Nb4Dsxk3gFJprHHsco,2214
12
+ tesla_fleet_api/user.py,sha256=TZE2oh-n5zrhKXmGRuiNL9voKVODD7rBhGE_IObYVGA,1179
13
+ tesla_fleet_api/vehicle.py,sha256=3MF8KN3BjY2dQxmu6-hrrVxrXxI8iQF-rBS8v89ruUw,32835
14
+ tesla_fleet_api/vehiclespecific.py,sha256=yq1S1rXNUJegG_AIcreoplzznIVDcwviYRvWH2Z5CEI,21492
15
+ tesla_fleet_api-0.5.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
+ tesla_fleet_api-0.5.7.dist-info/METADATA,sha256=YqHUJyTAqgr0WIiXOtOtc3adsNyrBatwTNnjKsyWloc,3961
17
+ tesla_fleet_api-0.5.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
18
+ tesla_fleet_api-0.5.7.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
19
+ tesla_fleet_api-0.5.7.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- tesla_fleet_api/__init__.py,sha256=RL9KGtDjYwbBa5i6Lagzrya-yjvEE1EVfyge2lV49iI,375
2
- tesla_fleet_api/charging.py,sha256=N_mc8axrXj3iduqLj_jCt4Vx86tHqe3xqQT4R1R7HvU,1689
3
- tesla_fleet_api/const.py,sha256=uzb_5f14m5lrcySlHWVL-_JM48HubpWmqL5fXy0kyrw,9277
4
- tesla_fleet_api/energy.py,sha256=Fgg4pdYc226WNOXHUnzBHbZoZ3jYLfN3GgjprazYLZA,5283
5
- tesla_fleet_api/energyspecific.py,sha256=kICxdeDoWR9JHlgjHvnmjJ1ErLOWJT8bCSESoXo9axU,3732
6
- tesla_fleet_api/exceptions.py,sha256=c6i_AegrLzlfrHxht_Z_xLl_kmxcd3DDJaSIcldcUo8,9171
7
- tesla_fleet_api/partner.py,sha256=1vIBUaxKLIfqcC0X6VXZN0dMAzj_CLNPUMjA6QVqZ1k,1223
8
- tesla_fleet_api/teslafleetapi.py,sha256=ErPfOz4M4WERrOlo_a_1ssVPcOIGeiBpbxd4vFJH_x4,4929
9
- tesla_fleet_api/teslafleetoauth.py,sha256=BmRAuwcgFMBo2_3AJzS3QTBm_cP9xt4yoz4vKjwgmsw,3501
10
- tesla_fleet_api/teslemetry.py,sha256=jB2OlYAjjl98mW4p2-VGTVl5lpG1Qox57mXgsdrF1vg,2005
11
- tesla_fleet_api/tessie.py,sha256=3ScOi8RaxHdvp6s5ZdSWYXwHZdey6IkX9SF1oohtSWk,2252
12
- tesla_fleet_api/user.py,sha256=TZE2oh-n5zrhKXmGRuiNL9voKVODD7rBhGE_IObYVGA,1179
13
- tesla_fleet_api/vehicle.py,sha256=wER3UQIccxN-cUxSkOD1oPQrQ33GoZikmE9yQnEJ7Sk,32010
14
- tesla_fleet_api/vehiclespecific.py,sha256=C9gCPGZphzcnDPwyX5HR1ZCEC4IWqdv5ATccHqvFryQ,20817
15
- tesla_fleet_api-0.5.5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
- tesla_fleet_api-0.5.5.dist-info/METADATA,sha256=HMQhlZJBUjSNZUN7LqTggG6b2b_MsN3BBrDxgKAidww,3961
17
- tesla_fleet_api-0.5.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
18
- tesla_fleet_api-0.5.5.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
19
- tesla_fleet_api-0.5.5.dist-info/RECORD,,