tesla-fleet-api 0.9.9__tar.gz → 1.0.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. {tesla_fleet_api-0.9.9/tesla_fleet_api.egg-info → tesla_fleet_api-1.0.0}/PKG-INFO +3 -2
  2. tesla_fleet_api-1.0.0/pyproject.toml +2 -0
  3. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/setup.py +3 -3
  4. tesla_fleet_api-1.0.0/tesla_fleet_api/__init__.py +15 -0
  5. tesla_fleet_api-1.0.0/tesla_fleet_api/const.py +161 -0
  6. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/tesla_fleet_api/exceptions.py +117 -0
  7. tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/__init__.py +11 -0
  8. tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/bluetooth.py +33 -0
  9. {tesla_fleet_api-0.9.9/tesla_fleet_api → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla}/charging.py +1 -1
  10. tesla_fleet_api-0.9.9/tesla_fleet_api/energy.py → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/energysite.py +41 -33
  11. tesla_fleet_api-0.9.9/tesla_fleet_api/teslafleetapi.py → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/fleet.py +8 -53
  12. tesla_fleet_api-0.9.9/tesla_fleet_api/teslafleetoauth.py → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/oauth.py +3 -4
  13. {tesla_fleet_api-0.9.9/tesla_fleet_api → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla}/partner.py +1 -1
  14. tesla_fleet_api-1.0.0/tesla_fleet_api/tesla/tesla.py +52 -0
  15. {tesla_fleet_api-0.9.9/tesla_fleet_api → tesla_fleet_api-1.0.0/tesla_fleet_api/tesla}/user.py +1 -1
  16. tesla_fleet_api-1.0.0/tesla_fleet_api/teslemetry/__init__.py +5 -0
  17. {tesla_fleet_api-0.9.9/tesla_fleet_api → tesla_fleet_api-1.0.0/tesla_fleet_api/teslemetry}/teslemetry.py +16 -25
  18. tesla_fleet_api-1.0.0/tesla_fleet_api/teslemetry/vehicle.py +73 -0
  19. tesla_fleet_api-1.0.0/tesla_fleet_api/tessie/__init__.py +5 -0
  20. {tesla_fleet_api-0.9.9/tesla_fleet_api → tesla_fleet_api-1.0.0/tesla_fleet_api/tessie}/tessie.py +17 -9
  21. tesla_fleet_api-1.0.0/tesla_fleet_api/tessie/vehicle.py +41 -0
  22. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0/tesla_fleet_api.egg-info}/PKG-INFO +3 -2
  23. tesla_fleet_api-1.0.0/tesla_fleet_api.egg-info/SOURCES.txt +28 -0
  24. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/tesla_fleet_api.egg-info/requires.txt +1 -0
  25. tesla_fleet_api-0.9.9/tesla_fleet_api/__init__.py +0 -30
  26. tesla_fleet_api-0.9.9/tesla_fleet_api/const.py +0 -385
  27. tesla_fleet_api-0.9.9/tesla_fleet_api/energyspecific.py +0 -125
  28. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/__init__.py +0 -0
  29. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/__init__.pyi +0 -9
  30. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/car_server_pb2.py +0 -175
  31. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/car_server_pb2.pyi +0 -904
  32. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/common_pb2.py +0 -33
  33. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/common_pb2.pyi +0 -130
  34. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/errors_pb2.py +0 -17
  35. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/errors_pb2.pyi +0 -32
  36. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/keys_pb2.py +0 -15
  37. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/keys_pb2.pyi +0 -21
  38. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/managed_charging_pb2.py +0 -15
  39. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/managed_charging_pb2.pyi +0 -17
  40. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/signatures_pb2.py +0 -35
  41. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/signatures_pb2.pyi +0 -152
  42. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/universal_message_pb2.py +0 -30
  43. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/universal_message_pb2.pyi +0 -148
  44. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/vcsec_pb2.py +0 -79
  45. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/vcsec_pb2.pyi +0 -482
  46. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/vehicle_pb2.py +0 -125
  47. tesla_fleet_api-0.9.9/tesla_fleet_api/pb2/vehicle_pb2.pyi +0 -1183
  48. tesla_fleet_api-0.9.9/tesla_fleet_api/teslafleetopensource.py +0 -61
  49. tesla_fleet_api-0.9.9/tesla_fleet_api/vehicle.py +0 -878
  50. tesla_fleet_api-0.9.9/tesla_fleet_api/vehiclesigned.py +0 -1127
  51. tesla_fleet_api-0.9.9/tesla_fleet_api/vehiclespecific.py +0 -505
  52. tesla_fleet_api-0.9.9/tesla_fleet_api.egg-info/SOURCES.txt +0 -45
  53. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/LICENSE +0 -0
  54. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/README.md +0 -0
  55. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/setup.cfg +0 -0
  56. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/tesla_fleet_api/ratecalculator.py +0 -0
  57. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/tesla_fleet_api.egg-info/dependency_links.txt +0 -0
  58. {tesla_fleet_api-0.9.9 → tesla_fleet_api-1.0.0}/tesla_fleet_api.egg-info/top_level.txt +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tesla_fleet_api
3
- Version: 0.9.9
3
+ Version: 1.0.0
4
4
  Summary: Tesla Fleet API library for Python
5
5
  Home-page: https://github.com/Teslemetry/python-tesla-fleet-api
6
6
  Author: Brett Adams
7
7
  Author-email: hello@teslemetry.com
8
- Classifier: Development Status :: 4 - Beta
8
+ Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Operating System :: OS Independent
@@ -17,6 +17,7 @@ Requires-Dist: aiofiles
17
17
  Requires-Dist: aiolimiter
18
18
  Requires-Dist: cryptography
19
19
  Requires-Dist: protobuf
20
+ Requires-Dist: bleak
20
21
  Dynamic: author
21
22
  Dynamic: author-email
22
23
  Dynamic: classifier
@@ -0,0 +1,2 @@
1
+ [tool.ruff]
2
+ exclude = ["tesla_fleet_api/tesla/vehicle/proto/*"]
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="tesla_fleet_api",
8
- version="0.9.9",
8
+ version="1.0.0",
9
9
  author="Brett Adams",
10
10
  author_email="hello@teslemetry.com",
11
11
  description="Tesla Fleet API library for Python",
@@ -14,11 +14,11 @@ setuptools.setup(
14
14
  url="https://github.com/Teslemetry/python-tesla-fleet-api",
15
15
  packages=setuptools.find_packages(),
16
16
  classifiers=[
17
- "Development Status :: 4 - Beta",
17
+ "Development Status :: 5 - Production/Stable",
18
18
  "Programming Language :: Python :: 3",
19
19
  "License :: OSI Approved :: Apache Software License",
20
20
  "Operating System :: OS Independent",
21
21
  ],
22
22
  python_requires=">=3.10",
23
- install_requires=["aiohttp", "aiofiles", "aiolimiter", "cryptography", "protobuf"],
23
+ install_requires=["aiohttp", "aiofiles", "aiolimiter", "cryptography", "protobuf", "bleak"],
24
24
  )
@@ -0,0 +1,15 @@
1
+ from .tesla.fleet import TeslaFleetApi
2
+ from .tesla.bluetooth import TeslaBluetooth
3
+ from .tesla.oauth import TeslaFleetOAuth
4
+ from .tesla.opensource import TeslaFleetOpenSource
5
+ from .teslemetry.teslemetry import Teslemetry
6
+ from .tessie.tessie import Tessie
7
+
8
+ __all__ = [
9
+ "TeslaFleetApi",
10
+ "TeslaBluetooth",
11
+ "TeslaFleetOAuth",
12
+ "TeslaFleetOpenSource",
13
+ "Teslemetry",
14
+ "Tessie",
15
+ ]
@@ -0,0 +1,161 @@
1
+ """Tesla Fleet API constants."""
2
+
3
+ from enum import Enum
4
+ import logging
5
+
6
+ VERSION = "1.0.0"
7
+ LOGGER = logging.getLogger(__package__)
8
+ SERVERS = {
9
+ "na": "https://fleet-api.prd.na.vn.cloud.tesla.com",
10
+ "eu": "https://fleet-api.prd.eu.vn.cloud.tesla.com",
11
+ "cn": "https://fleet-api.prd.cn.vn.cloud.tesla.cn",
12
+ }
13
+
14
+
15
+ class IntEnum(int, Enum):
16
+ """Integer Enum."""
17
+
18
+ def __str__(self) -> str:
19
+ return str(self.value)
20
+
21
+
22
+ class StrEnum(str, Enum):
23
+ """String Enum."""
24
+
25
+ def __str__(self) -> str:
26
+ return self.value
27
+
28
+
29
+ class Method(StrEnum):
30
+ """HTTP Methods."""
31
+
32
+ GET = "GET"
33
+ POST = "POST"
34
+ DELETE = "DELETE"
35
+
36
+
37
+ class Trunk(StrEnum):
38
+ """Trunk options"""
39
+
40
+ FRONT = "front"
41
+ REAR = "rear"
42
+
43
+
44
+ class Seat(IntEnum):
45
+ """Seat positions"""
46
+
47
+ FRONT_LEFT = 0
48
+ FRONT_RIGHT = 1
49
+ REAR_LEFT = 2
50
+ REAR_CENTER = 4
51
+ REAR_RIGHT = 5
52
+ THIRD_LEFT = 6
53
+ THIRD_RIGHT = 7
54
+
55
+
56
+ class Level(IntEnum):
57
+ """Level options"""
58
+
59
+ OFF = 0
60
+ LOW = 1
61
+ MEDIUM = 2
62
+ HIGH = 3
63
+
64
+
65
+ class ClimateKeeperMode(IntEnum):
66
+ """Climate Keeper Mode options"""
67
+
68
+ OFF = 0
69
+ KEEP_MODE = 1
70
+ DOG_MODE = 2
71
+ CAMP_MODE = 3
72
+
73
+
74
+ class CabinOverheatProtectionTemp(IntEnum):
75
+ """COP Temp options"""
76
+
77
+ LOW = 0 # 30C 90F
78
+ MEDIUM = 1 # 35C 95F
79
+ HIGH = 2 # 40C 100F
80
+
81
+
82
+ class VehicleDataEndpoint(StrEnum):
83
+ """Endpoints options"""
84
+
85
+ CHARGE_STATE = "charge_state"
86
+ CLIMATE_STATE = "climate_state"
87
+ CLOSURES_STATE = "closures_state"
88
+ DRIVE_STATE = "drive_state"
89
+ GUI_SETTINGS = "gui_settings"
90
+ LOCATION_DATA = "location_data"
91
+ CHARGE_SCHEDULE_DATA = "charge_schedule_data"
92
+ PRECONDITIONING_SCHEDULE_DATA = "preconditioning_schedule_data"
93
+ VEHICLE_CONFIG = "vehicle_config"
94
+ VEHICLE_STATE = "vehicle_state"
95
+ VEHICLE_DATA_COMBO = "vehicle_data_combo"
96
+
97
+
98
+
99
+ class SunRoofCommand(StrEnum):
100
+ """Sunroof options"""
101
+
102
+ STOP = "stop"
103
+ CLOSE = "close"
104
+ VENT = "vent"
105
+
106
+
107
+ class WindowCommand(StrEnum):
108
+ """Window Control options"""
109
+
110
+ VENT = "vent"
111
+ CLOSE = "close"
112
+
113
+
114
+ class DeviceType(StrEnum):
115
+ """Device Type options"""
116
+
117
+ ANDROID = "android"
118
+ IOS_DEVELOPMENT = "ios-development"
119
+ IOS_ENTERPRISE = "ios-enterprise"
120
+ IOS_BETA = "ios-beta"
121
+ IOS_PRODUCTION = "ios-production"
122
+
123
+
124
+ class Scope(StrEnum):
125
+ """Fleet API Scope"""
126
+
127
+ OPENID = "openid"
128
+ OFFLINE_ACCESS = "offline_access"
129
+ USER_DATA = "user_data"
130
+ VEHICLE_DEVICE_DATA = "vehicle_device_data"
131
+ VEHICLE_LOCATION = "vehicle_location"
132
+ VEHICLE_CMDS = "vehicle_cmds"
133
+ VEHICLE_CHARGING_CMDS = "vehicle_charging_cmds"
134
+ ENERGY_DEVICE_DATA = "energy_device_data"
135
+ ENERGY_CMDS = "energy_cmds"
136
+
137
+
138
+ class EnergyOperationMode(StrEnum):
139
+ """Energy Operation Mode options"""
140
+
141
+ AUTONOMOUS = "autonomous"
142
+ SELF_CONSUMPTION = "self_consumption"
143
+ BACKUP = "backup"
144
+
145
+
146
+ class EnergyExportMode(StrEnum):
147
+ """Energy Export Mode options"""
148
+
149
+ BATTERY_OK = "battery_ok"
150
+ PV_ONLY = "pv_only"
151
+ NEVER = "never"
152
+
153
+
154
+ class TeslaEnergyPeriod(StrEnum):
155
+ """Period for history for energy sites"""
156
+
157
+ DAY = "day"
158
+ WEEK = "week"
159
+ MONTH = "month"
160
+ YEAR = "year"
161
+ LIFETIME = "lifetime"
@@ -853,6 +853,123 @@ SIGNED_MESSAGE_INFORMATION_FAULTS = [
853
853
  SignedMessageInformationFaultCouldNotHashMetadata,
854
854
  ]
855
855
 
856
+ class WhitelistOperationStatus(TeslaFleetError):
857
+ message = "Whitelist operation failed"
858
+
859
+ class WhitelistOperationUndocumentedError(WhitelistOperationStatus):
860
+ message = "Undocumented whitelist operation error"
861
+ code = 1
862
+
863
+ class WhitelistOperationNoPermissionToRemoveOneself(WhitelistOperationStatus):
864
+ message = "No permission to remove oneself from whitelist"
865
+ code = 2
866
+
867
+ class WhitelistOperationKeyfobSlotsFull(WhitelistOperationStatus):
868
+ message = "Keyfob slots are full"
869
+ code = 3
870
+
871
+ class WhitelistOperationWhitelistFull(WhitelistOperationStatus):
872
+ message = "Whitelist is full"
873
+ code = 4
874
+
875
+ class WhitelistOperationNoPermissionToAdd(WhitelistOperationStatus):
876
+ message = "No permission to add to whitelist"
877
+ code = 5
878
+
879
+ class WhitelistOperationInvalidPublicKey(WhitelistOperationStatus):
880
+ message = "Invalid public key"
881
+ code = 6
882
+
883
+ class WhitelistOperationNoPermissionToRemove(WhitelistOperationStatus):
884
+ message = "No permission to remove from whitelist"
885
+ code = 7
886
+
887
+ class WhitelistOperationNoPermissionToChangePermissions(WhitelistOperationStatus):
888
+ message = "No permission to change permissions"
889
+ code = 8
890
+
891
+ class WhitelistOperationAttemptingToElevateOthersAboveOneself(WhitelistOperationStatus):
892
+ message = "Attempting to elevate others above oneself"
893
+ code = 9
894
+
895
+ class WhitelistOperationAttemptingToDemoteSuperiorToOneself(WhitelistOperationStatus):
896
+ message = "Attempting to demote superior to oneself"
897
+ code = 10
898
+
899
+ class WhitelistOperationAttemptingToRemoveOwnPermissions(WhitelistOperationStatus):
900
+ message = "Attempting to remove own permissions"
901
+ code = 11
902
+
903
+ class WhitelistOperationPublicKeyNotOnWhitelist(WhitelistOperationStatus):
904
+ message = "Public key not on whitelist"
905
+ code = 12
906
+
907
+ class WhitelistOperationAttemptingToAddExistingKey(WhitelistOperationStatus):
908
+ message = "Attempting to add key that is already on the whitelist"
909
+ code = 13
910
+
911
+ class WhitelistOperationNotAllowedToAddUnlessOnReader(WhitelistOperationStatus):
912
+ message = "Not allowed to add unless on reader"
913
+ code = 14
914
+
915
+ class WhitelistOperationFMModifyingOutsideOfFMode(WhitelistOperationStatus):
916
+ message = "FM modifying outside of F mode"
917
+ code = 15
918
+
919
+ class WhitelistOperationFMAttemptingToAddPermanentKey(WhitelistOperationStatus):
920
+ message = "FM attempting to add permanent key"
921
+ code = 16
922
+
923
+ class WhitelistOperationFMAttemptingToRemovePermanentKey(WhitelistOperationStatus):
924
+ message = "FM attempting to remove permanent key"
925
+ code = 17
926
+
927
+ class WhitelistOperationKeychainWhileFSFull(WhitelistOperationStatus):
928
+ message = "Keychain while FS full"
929
+ code = 18
930
+
931
+ class WhitelistOperationAttemptingToAddKeyWithoutRole(WhitelistOperationStatus):
932
+ message = "Attempting to add key without role"
933
+ code = 19
934
+
935
+ class WhitelistOperationAttemptingToAddKeyWithServiceRole(WhitelistOperationStatus):
936
+ message = "Attempting to add key with service role"
937
+ code = 20
938
+
939
+ class WhitelistOperationNonServiceKeyAttemptingToAddServiceTech(WhitelistOperationStatus):
940
+ message = "Non-service key attempting to add service tech"
941
+ code = 21
942
+
943
+ class WhitelistOperationServiceKeyAttemptingToAddServiceTechOutsideServiceMode(WhitelistOperationStatus):
944
+ message = "Service key attempting to add service tech outside service mode"
945
+ code = 22
946
+
947
+ WHITELIST_OPERATION_STATUS = [
948
+ None,
949
+ WhitelistOperationUndocumentedError,
950
+ WhitelistOperationNoPermissionToRemoveOneself,
951
+ WhitelistOperationKeyfobSlotsFull,
952
+ WhitelistOperationWhitelistFull,
953
+ WhitelistOperationNoPermissionToAdd,
954
+ WhitelistOperationInvalidPublicKey,
955
+ WhitelistOperationNoPermissionToRemove,
956
+ WhitelistOperationNoPermissionToChangePermissions,
957
+ WhitelistOperationAttemptingToElevateOthersAboveOneself,
958
+ WhitelistOperationAttemptingToDemoteSuperiorToOneself,
959
+ WhitelistOperationAttemptingToRemoveOwnPermissions,
960
+ WhitelistOperationPublicKeyNotOnWhitelist,
961
+ WhitelistOperationAttemptingToAddExistingKey,
962
+ WhitelistOperationNotAllowedToAddUnlessOnReader,
963
+ WhitelistOperationFMModifyingOutsideOfFMode,
964
+ WhitelistOperationFMAttemptingToAddPermanentKey,
965
+ WhitelistOperationFMAttemptingToRemovePermanentKey,
966
+ WhitelistOperationKeychainWhileFSFull,
967
+ WhitelistOperationAttemptingToAddKeyWithoutRole,
968
+ WhitelistOperationAttemptingToAddKeyWithServiceRole,
969
+ WhitelistOperationNonServiceKeyAttemptingToAddServiceTech,
970
+ WhitelistOperationServiceKeyAttemptingToAddServiceTechOutsideServiceMode
971
+ ]
972
+
856
973
 
857
974
  async def raise_for_status(resp: aiohttp.ClientResponse) -> None:
858
975
  """Raise an exception if the response status code is >=400."""
@@ -0,0 +1,11 @@
1
+ """Tesla Fleet API classes."""
2
+
3
+ from .fleet import TeslaFleetApi
4
+ from .bluetooth import TeslaBluetooth
5
+ from .oauth import TeslaFleetOAuth
6
+
7
+ __all__ = [
8
+ "TeslaFleetApi",
9
+ "TeslaBluetooth",
10
+ "TeslaFleetOAuth",
11
+ ]
@@ -0,0 +1,33 @@
1
+ """Bluetooth only interface."""
2
+
3
+ import re
4
+ from .tesla import Tesla
5
+ from .vehicle.bluetooth import VehicleBluetooth
6
+
7
+ class TeslaBluetooth(Tesla):
8
+ """Class describing a Tesla Bluetooth connection."""
9
+
10
+ def __init__(
11
+ self,
12
+ ):
13
+ """Initialize the Tesla Fleet API."""
14
+
15
+ self.vehicles = Vehicles(self)
16
+
17
+ def valid_name(self, name: str) -> bool:
18
+ """Check if a BLE device name is a valid Tesla vehicle."""
19
+ return bool(re.match("^S[a-f0-9]{16}[A-F]$", name))
20
+
21
+ class Vehicles(dict[str, VehicleBluetooth]):
22
+ """Class containing and creating vehicles."""
23
+
24
+ _parent: TeslaBluetooth
25
+
26
+ def __init__(self, parent: TeslaBluetooth):
27
+ self._parent = parent
28
+
29
+ def createBluetooth(self, vin: str) -> VehicleBluetooth:
30
+ """Creates a specific vehicle."""
31
+ vehicle = VehicleBluetooth(self._parent, vin)
32
+ self[vin] = vehicle
33
+ return vehicle
@@ -1,5 +1,5 @@
1
1
  from typing import Any
2
- from .const import Method
2
+ from ..const import Method
3
3
 
4
4
 
5
5
  class Charging:
@@ -1,37 +1,35 @@
1
1
  from __future__ import annotations
2
2
  from typing import Any, TYPE_CHECKING
3
- from .const import Method, EnergyOperationMode, EnergyExportMode, TeslaEnergyPeriod
4
- from .energyspecific import EnergySpecific
3
+ from ..const import Method, EnergyOperationMode, EnergyExportMode, TeslaEnergyPeriod
5
4
 
6
5
  if TYPE_CHECKING:
7
- from .teslafleetapi import TeslaFleetApi
6
+ from . import TeslaFleetApi
8
7
 
9
-
10
- class Energy:
8
+ class EnergySite:
11
9
  """Class describing the Tesla Fleet API partner endpoints"""
12
10
 
13
- parent: TeslaFleetApi
11
+ energy_site_id: int
14
12
 
15
- def __init__(self, parent):
13
+ def __init__(
14
+ self,
15
+ parent: TeslaFleetApi,
16
+ energy_site_id: int
17
+ ):
16
18
  self._request = parent._request
17
-
18
- def specific(self, energy_site_id: int) -> EnergySpecific:
19
- """Create a specific energy site."""
20
- return EnergySpecific(self, energy_site_id)
19
+ self.energy_site_id = energy_site_id
21
20
 
22
21
  async def backup(
23
- self, energy_site_id: int, backup_reserve_percent: int
22
+ self, backup_reserve_percent: int
24
23
  ) -> dict[str, Any]:
25
24
  """Adjust the site's backup reserve."""
26
25
  return await self._request(
27
26
  Method.POST,
28
- f"api/1/energy_sites/{energy_site_id}/backup",
27
+ f"api/1/energy_sites/{self.energy_site_id}/backup",
29
28
  json={"backup_reserve_percent": backup_reserve_percent},
30
29
  )
31
30
 
32
31
  async def backup_history(
33
32
  self,
34
- energy_site_id: int,
35
33
  period: TeslaEnergyPeriod | str | None,
36
34
  start_date: str | None = None,
37
35
  end_date: str | None = None,
@@ -40,7 +38,7 @@ class Energy:
40
38
  """Returns the backup (off-grid) event history of the site in duration of seconds."""
41
39
  return await self._request(
42
40
  Method.GET,
43
- f"api/1/energy_sites/{energy_site_id}/calendar_history",
41
+ f"api/1/energy_sites/{self.energy_site_id}/calendar_history",
44
42
  params={
45
43
  "kind": "backup",
46
44
  "start_date": start_date,
@@ -52,7 +50,6 @@ class Energy:
52
50
 
53
51
  async def charge_history(
54
52
  self,
55
- energy_site_id: int,
56
53
  start_date: str,
57
54
  end_date: str,
58
55
  time_zone: str | None = None,
@@ -60,7 +57,7 @@ class Energy:
60
57
  """Returns the charging history of a wall connector."""
61
58
  return await self._request(
62
59
  Method.GET,
63
- f"api/1/energy_sites/{energy_site_id}/telemetry_history",
60
+ f"api/1/energy_sites/{self.energy_site_id}/telemetry_history",
64
61
  params={
65
62
  "kind": "charge",
66
63
  "start_date": start_date,
@@ -71,7 +68,6 @@ class Energy:
71
68
 
72
69
  async def energy_history(
73
70
  self,
74
- energy_site_id: int,
75
71
  period: TeslaEnergyPeriod | str | None,
76
72
  start_date: str | None = None,
77
73
  end_date: str | None = None,
@@ -80,7 +76,7 @@ class Energy:
80
76
  """Returns the energy measurements of the site, aggregated to the requested period."""
81
77
  return await self._request(
82
78
  Method.GET,
83
- f"api/1/energy_sites/{energy_site_id}/calendar_history",
79
+ f"api/1/energy_sites/{self.energy_site_id}/calendar_history",
84
80
  params={
85
81
  "kind": "energy",
86
82
  "start_date": start_date,
@@ -92,70 +88,82 @@ class Energy:
92
88
 
93
89
  async def grid_import_export(
94
90
  self,
95
- energy_site_id: int,
96
91
  disallow_charge_from_grid_with_solar_installed: bool | None = None,
97
92
  customer_preferred_export_rule: EnergyExportMode | str | None = None,
98
93
  ) -> dict[str, Any]:
99
94
  """Allow/disallow charging from the grid and exporting energy to the grid."""
100
95
  return await self._request(
101
96
  Method.POST,
102
- f"api/1/energy_sites/{energy_site_id}/grid_import_export",
97
+ f"api/1/energy_sites/{self.energy_site_id}/grid_import_export",
103
98
  json={
104
99
  "disallow_charge_from_grid_with_solar_installed": disallow_charge_from_grid_with_solar_installed,
105
100
  "customer_preferred_export_rule": customer_preferred_export_rule,
106
101
  },
107
102
  )
108
103
 
109
- async def live_status(self, energy_site_id: int) -> dict[str, Any]:
104
+ async def live_status(self) -> dict[str, Any]:
110
105
  """Returns the live status of the site (power, state of energy, grid status, storm mode)."""
111
106
  return await self._request(
112
107
  Method.GET,
113
- f"api/1/energy_sites/{energy_site_id}/live_status",
108
+ f"api/1/energy_sites/{self.energy_site_id}/live_status",
114
109
  )
115
110
 
116
111
  async def off_grid_vehicle_charging_reserve(
117
- self, energy_site_id: int, off_grid_vehicle_charging_reserve_percent: int
112
+ self, off_grid_vehicle_charging_reserve_percent: int
118
113
  ) -> dict[str, Any]:
119
114
  """Adjust the site's off-grid vehicle charging backup reserve."""
120
115
  return await self._request(
121
116
  Method.POST,
122
- f"api/1/energy_sites/{energy_site_id}/off_grid_vehicle_charging_reserve",
117
+ f"api/1/energy_sites/{self.energy_site_id}/off_grid_vehicle_charging_reserve",
123
118
  json={
124
119
  "off_grid_vehicle_charging_reserve_percent": off_grid_vehicle_charging_reserve_percent
125
120
  },
126
121
  )
127
122
 
128
123
  async def operation(
129
- self, energy_site_id: int, default_real_mode: EnergyOperationMode | str
124
+ self, default_real_mode: EnergyOperationMode | str
130
125
  ) -> dict[str, Any]:
131
126
  """Set the site's mode."""
132
127
  return await self._request(
133
128
  Method.POST,
134
- f"api/1/energy_sites/{energy_site_id}/operation",
129
+ f"api/1/energy_sites/{self.energy_site_id}/operation",
135
130
  json={"default_real_mode": default_real_mode},
136
131
  )
137
132
 
138
- async def site_info(self, energy_site_id: int) -> dict[str, Any]:
133
+ async def site_info(self) -> dict[str, Any]:
139
134
  """Returns information about the site. Things like assets (has solar, etc), settings (backup reserve, etc), and features (storm_mode_capable, etc)."""
140
135
  return await self._request(
141
136
  Method.GET,
142
- f"api/1/energy_sites/{energy_site_id}/site_info",
137
+ f"api/1/energy_sites/{self.energy_site_id}/site_info",
143
138
  )
144
139
 
145
- async def storm_mode(self, energy_site_id: int, enabled: bool) -> dict[str, Any]:
140
+ async def storm_mode(self, enabled: bool) -> dict[str, Any]:
146
141
  """Update storm watch participation."""
147
142
  return await self._request(
148
143
  Method.POST,
149
- f"api/1/energy_sites/{energy_site_id}/storm_mode",
144
+ f"api/1/energy_sites/{self.energy_site_id}/storm_mode",
150
145
  json={"enabled": enabled},
151
146
  )
152
147
 
153
148
  async def time_of_use_settings(
154
- self, energy_site_id: int, settings: dict[str, Any]
149
+ self, settings: dict[str, Any]
155
150
  ) -> dict[str, Any]:
156
151
  """Update the time of use settings for the energy site."""
157
152
  return await self._request(
158
153
  Method.POST,
159
- f"api/1/energy_sites/{energy_site_id}/time_of_use_settings",
154
+ f"api/1/energy_sites/{self.energy_site_id}/time_of_use_settings",
160
155
  json={"tou_settings": {"tariff_content_v2": settings}},
161
156
  )
157
+
158
+ class EnergySites(dict[int, EnergySite]):
159
+ """Class describing the Tesla Fleet API partner endpoints"""
160
+
161
+ _parent: TeslaFleetApi
162
+
163
+ def __init__(self, parent: TeslaFleetApi):
164
+ self._parent = parent
165
+
166
+ def create(self, energy_site_id: int) -> EnergySite:
167
+ """Create a specific energy site."""
168
+ self[energy_site_id] = EnergySite(self._parent, energy_site_id)
169
+ return self[energy_site_id]