tesla-fleet-api 0.9.10__py3-none-any.whl → 1.0.1__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.
- tesla_fleet_api/__init__.py +7 -22
- tesla_fleet_api/const.py +1 -225
- tesla_fleet_api/exceptions.py +117 -0
- tesla_fleet_api/tesla/__init__.py +11 -0
- tesla_fleet_api/tesla/bluetooth.py +38 -0
- tesla_fleet_api/{charging.py → tesla/charging.py} +1 -1
- tesla_fleet_api/{energy.py → tesla/energysite.py} +41 -33
- tesla_fleet_api/{teslafleetapi.py → tesla/fleet.py} +8 -53
- tesla_fleet_api/{teslafleetoauth.py → tesla/oauth.py} +3 -4
- tesla_fleet_api/{partner.py → tesla/partner.py} +1 -1
- tesla_fleet_api/tesla/tesla.py +52 -0
- tesla_fleet_api/{user.py → tesla/user.py} +1 -1
- tesla_fleet_api/tesla/vehicle/__init__.py +13 -0
- tesla_fleet_api/tesla/vehicle/bluetooth.py +219 -0
- tesla_fleet_api/{vehiclesigned.py → tesla/vehicle/commands.py} +321 -164
- tesla_fleet_api/{vehicle.py → tesla/vehicle/fleet.py} +173 -206
- tesla_fleet_api/tesla/vehicle/signed.py +56 -0
- tesla_fleet_api/tesla/vehicle/vehicle.py +19 -0
- tesla_fleet_api/tesla/vehicle/vehicles.py +46 -0
- tesla_fleet_api/teslemetry/__init__.py +5 -0
- tesla_fleet_api/{teslemetry.py → teslemetry/teslemetry.py} +16 -25
- tesla_fleet_api/teslemetry/vehicle.py +73 -0
- tesla_fleet_api/tessie/__init__.py +5 -0
- tesla_fleet_api/{tessie.py → tessie/tessie.py} +17 -9
- tesla_fleet_api/tessie/vehicle.py +41 -0
- {tesla_fleet_api-0.9.10.dist-info → tesla_fleet_api-1.0.1.dist-info}/METADATA +3 -2
- tesla_fleet_api-1.0.1.dist-info/RECORD +51 -0
- tesla_fleet_api/energyspecific.py +0 -125
- tesla_fleet_api/teslafleetopensource.py +0 -61
- tesla_fleet_api/vehiclespecific.py +0 -509
- tesla_fleet_api-0.9.10.dist-info/RECORD +0 -42
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/__init__.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/__init__.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/car_server_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/car_server_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/common_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/common_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/errors_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/errors_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/keys_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/keys_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/managed_charging_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/managed_charging_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/signatures_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/signatures_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/universal_message_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/universal_message_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/vcsec_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/vcsec_pb2.pyi +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/vehicle_pb2.py +0 -0
- /tesla_fleet_api/{pb2 → tesla/vehicle/proto}/vehicle_pb2.pyi +0 -0
- {tesla_fleet_api-0.9.10.dist-info → tesla_fleet_api-1.0.1.dist-info}/LICENSE +0 -0
- {tesla_fleet_api-0.9.10.dist-info → tesla_fleet_api-1.0.1.dist-info}/WHEEL +0 -0
- {tesla_fleet_api-0.9.10.dist-info → tesla_fleet_api-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import base64
|
4
|
+
from typing import TYPE_CHECKING
|
5
|
+
|
6
|
+
from .fleet import VehicleFleet
|
7
|
+
from .commands import Commands
|
8
|
+
|
9
|
+
from ...exceptions import (
|
10
|
+
MESSAGE_FAULTS,
|
11
|
+
)
|
12
|
+
from .proto.signatures_pb2 import (
|
13
|
+
SessionInfo,
|
14
|
+
)
|
15
|
+
from .proto.universal_message_pb2 import (
|
16
|
+
RoutableMessage,
|
17
|
+
)
|
18
|
+
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from ..fleet import TeslaFleetApi
|
21
|
+
|
22
|
+
|
23
|
+
class VehicleSigned(VehicleFleet, Commands):
|
24
|
+
"""Class describing the Tesla Fleet API vehicle endpoints and commands for a specific vehicle with command signing."""
|
25
|
+
|
26
|
+
|
27
|
+
_auth_method = "hmac"
|
28
|
+
|
29
|
+
def __init__(self, parent: TeslaFleetApi, vin: str):
|
30
|
+
"""Initialize the VehicleSigned class."""
|
31
|
+
super().__init__(parent, vin)
|
32
|
+
super(Commands, self).__init__(parent, vin)
|
33
|
+
|
34
|
+
|
35
|
+
async def _send(self, msg: RoutableMessage) -> RoutableMessage:
|
36
|
+
"""Serialize a message and send to the signed command endpoint."""
|
37
|
+
|
38
|
+
async with self._sessions[msg.to_destination.domain].lock:
|
39
|
+
resp = await self.signed_command(
|
40
|
+
base64.b64encode(msg.SerializeToString()).decode()
|
41
|
+
)
|
42
|
+
|
43
|
+
resp_msg = RoutableMessage.FromString(base64.b64decode(resp["response"]))
|
44
|
+
|
45
|
+
# Check UUID?
|
46
|
+
# Check RoutingAdress?
|
47
|
+
|
48
|
+
if resp_msg.session_info:
|
49
|
+
self._sessions[resp_msg.from_destination.domain].update(
|
50
|
+
SessionInfo.FromString(resp_msg.session_info), self.private_key
|
51
|
+
)
|
52
|
+
|
53
|
+
if resp_msg.signedMessageStatus.signed_message_fault:
|
54
|
+
raise MESSAGE_FAULTS[resp_msg.signedMessageStatus.signed_message_fault]
|
55
|
+
|
56
|
+
return resp_msg
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from ..tesla import Tesla
|
7
|
+
|
8
|
+
|
9
|
+
class Vehicle:
|
10
|
+
"""Base class describing a Tesla vehicle."""
|
11
|
+
|
12
|
+
vin: str
|
13
|
+
|
14
|
+
def __init__(self, parent: Tesla, vin: str):
|
15
|
+
self.vin = vin
|
16
|
+
|
17
|
+
def pre2021(self, vin: str) -> bool:
|
18
|
+
"""Checks if a vehicle is a pre-2021 model S or X."""
|
19
|
+
return vin[3] in ["S", "X"] and (vin[9] <= "L" or (vin[9] == "M" and vin[7] in ['1', '2', '3', '4']))
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from .signed import VehicleSigned
|
5
|
+
from .bluetooth import VehicleBluetooth
|
6
|
+
from .fleet import VehicleFleet
|
7
|
+
from .vehicle import Vehicle
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from ..fleet import TeslaFleetApi
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
class Vehicles(dict[str, Vehicle]):
|
15
|
+
"""Class containing and creating vehicles."""
|
16
|
+
|
17
|
+
_parent: TeslaFleetApi
|
18
|
+
|
19
|
+
def __init__(self, parent: TeslaFleetApi):
|
20
|
+
self._parent = parent
|
21
|
+
|
22
|
+
def createFleet(self, vin: str) -> VehicleFleet:
|
23
|
+
"""Creates a Fleet API vehicle."""
|
24
|
+
vehicle = VehicleFleet(self._parent, vin)
|
25
|
+
self[vin] = vehicle
|
26
|
+
return vehicle
|
27
|
+
|
28
|
+
def createSigned(self, vin: str) -> VehicleSigned:
|
29
|
+
"""Creates a Fleet API vehicle that uses command protocol."""
|
30
|
+
vehicle = VehicleSigned(self._parent, vin)
|
31
|
+
self[vin] = vehicle
|
32
|
+
return vehicle
|
33
|
+
|
34
|
+
def createBluetooth(self, vin: str) -> VehicleBluetooth:
|
35
|
+
"""Creates a bluetooth vehicle that uses command protocol."""
|
36
|
+
vehicle = VehicleBluetooth(self._parent, vin)
|
37
|
+
self[vin] = vehicle
|
38
|
+
return vehicle
|
39
|
+
|
40
|
+
def specific(self, vin: str) -> Vehicle:
|
41
|
+
"""Legacy method for creating a Fleet API vehicle."""
|
42
|
+
return self.createFleet(vin)
|
43
|
+
|
44
|
+
def specificSigned(self, vin: str) -> VehicleSigned:
|
45
|
+
"""Legacy method for creating a Fleet API vehicle that uses command protocol."""
|
46
|
+
return self.createSigned(vin)
|
@@ -1,30 +1,32 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
3
|
import aiohttp
|
4
|
-
from aiolimiter import AsyncLimiter
|
5
4
|
|
6
|
-
from .
|
7
|
-
from .
|
5
|
+
from ..tesla.charging import Charging
|
6
|
+
from ..tesla.energysite import EnergySites
|
7
|
+
from ..tesla.user import User
|
8
|
+
from .vehicle import TeslemetryVehicles
|
9
|
+
from ..const import LOGGER, Method
|
10
|
+
from ..tesla import TeslaFleetApi
|
8
11
|
|
9
|
-
|
10
|
-
rate_limit = AsyncLimiter(5, 10)
|
12
|
+
class Teslemetry(TeslaFleetApi):
|
11
13
|
|
14
|
+
server = "https://api.teslemetry.com"
|
12
15
|
|
13
|
-
class Teslemetry(TeslaFleetApi):
|
14
16
|
def __init__(
|
15
17
|
self,
|
16
18
|
session: aiohttp.ClientSession,
|
17
19
|
access_token: str,
|
18
20
|
):
|
19
21
|
"""Initialize the Teslemetry API."""
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
)
|
27
|
-
self.
|
22
|
+
|
23
|
+
self.session = session
|
24
|
+
self.access_token = access_token
|
25
|
+
|
26
|
+
self.charging = Charging(self)
|
27
|
+
self.energySites = EnergySites(self)
|
28
|
+
self.user = User(self)
|
29
|
+
self.vehicle = TeslemetryVehicles(self)
|
28
30
|
|
29
31
|
async def ping(self) -> dict[str, bool]:
|
30
32
|
"""Send a ping."""
|
@@ -102,14 +104,3 @@ class Teslemetry(TeslaFleetApi):
|
|
102
104
|
Method.GET,
|
103
105
|
f"api/refresh/{vin}",
|
104
106
|
)
|
105
|
-
|
106
|
-
async def _request(
|
107
|
-
self,
|
108
|
-
method: Method,
|
109
|
-
path: str,
|
110
|
-
params: dict[str, Any] | None = None,
|
111
|
-
json: dict[str, Any] | None = None,
|
112
|
-
) -> dict[str, Any]:
|
113
|
-
"""Send a request to the Teslemetry API."""
|
114
|
-
async with rate_limit:
|
115
|
-
return await super()._request(method, path, params, json)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING, Any
|
3
|
+
|
4
|
+
from ..const import Method
|
5
|
+
from ..tesla.vehicle.proto.universal_message_pb2 import Domain
|
6
|
+
from ..tesla.vehicle.vehicle import Vehicle
|
7
|
+
from ..tesla.vehicle.vehicles import Vehicles
|
8
|
+
from ..tesla.vehicle.bluetooth import VehicleBluetooth
|
9
|
+
from ..tesla.vehicle.fleet import VehicleFleet
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from .teslemetry import Teslemetry
|
13
|
+
|
14
|
+
class TeslemetryVehicle(Vehicle):
|
15
|
+
"""Teslemetry specific base vehicle."""
|
16
|
+
pass
|
17
|
+
|
18
|
+
class TeslemetryVehicleFleet(VehicleFleet):
|
19
|
+
"""Teslemetry specific API vehicle."""
|
20
|
+
|
21
|
+
async def server_side_polling(
|
22
|
+
self, value: bool | None = None
|
23
|
+
) -> bool | None:
|
24
|
+
"""Get or set Auto mode."""
|
25
|
+
if value is True:
|
26
|
+
return (
|
27
|
+
await self._request(
|
28
|
+
Method.POST,
|
29
|
+
f"api/auto/{self.vin}",
|
30
|
+
)
|
31
|
+
).get("response")
|
32
|
+
if value is False:
|
33
|
+
return (
|
34
|
+
await self._request(
|
35
|
+
Method.DELETE,
|
36
|
+
f"api/auto/{self.vin}",
|
37
|
+
)
|
38
|
+
).get("response")
|
39
|
+
return (
|
40
|
+
await self._request(
|
41
|
+
Method.GET,
|
42
|
+
f"api/auto/{self.vin}",
|
43
|
+
)
|
44
|
+
).get("response")
|
45
|
+
|
46
|
+
async def data_refresh(self) -> dict[str, Any]:
|
47
|
+
"""Force a refresh of the vehicle data."""
|
48
|
+
return await self._request(
|
49
|
+
Method.GET,
|
50
|
+
f"api/refresh/{self.vin}",
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
class TeslemetryVehicles(Vehicles):
|
55
|
+
"""Class containing and creating vehicles."""
|
56
|
+
|
57
|
+
def create(self, vin: str) -> TeslemetryVehicleFleet:
|
58
|
+
"""Creates a specific vehicle."""
|
59
|
+
return self.createFleet(vin)
|
60
|
+
|
61
|
+
def createFleet(self, vin: str) -> TeslemetryVehicleFleet:
|
62
|
+
"""Creates a specific vehicle."""
|
63
|
+
vehicle = TeslemetryVehicleFleet(self._parent, vin)
|
64
|
+
self[vin] = vehicle
|
65
|
+
return vehicle
|
66
|
+
|
67
|
+
def createSigned(self, vin: str):
|
68
|
+
"""Creates a specific vehicle."""
|
69
|
+
raise NotImplementedError("Signing is handled by Teslemetry server-side")
|
70
|
+
|
71
|
+
def createBluetooth(self, vin: str):
|
72
|
+
"""Creates a specific vehicle."""
|
73
|
+
raise NotImplementedError("Bluetooth is only handled locally")
|
@@ -1,23 +1,31 @@
|
|
1
1
|
import aiohttp
|
2
2
|
from typing import Any
|
3
|
-
from .teslafleetapi import TeslaFleetApi
|
4
|
-
from .const import Method
|
5
3
|
|
4
|
+
from ..tesla.charging import Charging
|
5
|
+
from ..tesla.energysite import EnergySites
|
6
|
+
from ..tesla.user import User
|
7
|
+
from ..tesla import TeslaFleetApi
|
8
|
+
from ..const import Method
|
9
|
+
from .vehicle import TessieVehicles
|
6
10
|
|
7
11
|
class Tessie(TeslaFleetApi):
|
12
|
+
|
13
|
+
server="https://api.tessie.com"
|
14
|
+
|
8
15
|
def __init__(
|
9
16
|
self,
|
10
17
|
session: aiohttp.ClientSession,
|
11
18
|
access_token: str,
|
12
19
|
):
|
13
20
|
"""Initialize the Tessie API."""
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
)
|
21
|
+
|
22
|
+
self.session = session
|
23
|
+
self.access_token = access_token
|
24
|
+
|
25
|
+
self.charging = Charging(self)
|
26
|
+
self.energySites = EnergySites(self)
|
27
|
+
self.user = User(self)
|
28
|
+
self.vehicle = TessieVehicles(self)
|
21
29
|
|
22
30
|
async def scopes(self) -> list[str]:
|
23
31
|
"""Get user scopes."""
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING, Any
|
3
|
+
|
4
|
+
from ..const import Method
|
5
|
+
from ..tesla.vehicle.proto.universal_message_pb2 import Domain
|
6
|
+
from ..tesla.vehicle.vehicle import Vehicle
|
7
|
+
from ..tesla.vehicle.vehicles import Vehicles
|
8
|
+
from ..tesla.vehicle.bluetooth import VehicleBluetooth
|
9
|
+
from ..tesla.vehicle.fleet import VehicleFleet
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from .tessie import Tessie
|
13
|
+
|
14
|
+
class TessieVehicle(Vehicle):
|
15
|
+
"""Tessie specific base vehicle."""
|
16
|
+
pass
|
17
|
+
|
18
|
+
class TessieVehicleFleet(VehicleFleet):
|
19
|
+
"""Tessie specific API vehicle."""
|
20
|
+
pass
|
21
|
+
|
22
|
+
class TessieVehicles(Vehicles):
|
23
|
+
"""Class containing and creating vehicles."""
|
24
|
+
|
25
|
+
def create(self, vin: str) -> TessieVehicleFleet:
|
26
|
+
"""Creates a specific vehicle."""
|
27
|
+
return self.createFleet(vin)
|
28
|
+
|
29
|
+
def createFleet(self, vin: str) -> TessieVehicleFleet:
|
30
|
+
"""Creates a specific vehicle."""
|
31
|
+
vehicle = TessieVehicleFleet(self._parent, vin)
|
32
|
+
self[vin] = vehicle
|
33
|
+
return vehicle
|
34
|
+
|
35
|
+
def createSigned(self, vin: str):
|
36
|
+
"""Creates a specific vehicle."""
|
37
|
+
raise NotImplementedError("Signing is handled by Tessie server-side")
|
38
|
+
|
39
|
+
def createBluetooth(self, vin: str):
|
40
|
+
"""Creates a specific vehicle."""
|
41
|
+
raise NotImplementedError("Bluetooth is only handled locally")
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: tesla_fleet_api
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.1
|
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 ::
|
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,51 @@
|
|
1
|
+
tesla_fleet_api/__init__.py,sha256=FewtEncMLxOZa3dVA3SsT3tY--RMNF9-GXIpOTkbXvk,396
|
2
|
+
tesla_fleet_api/const.py,sha256=8KPO_bQbwwspp1Gm-DrHt4EsuQQSFsp1n9yMk0b2hZA,3158
|
3
|
+
tesla_fleet_api/exceptions.py,sha256=nTo9MIJrAxL-UxzbrMrr00QhSvrLaSc6ee00Ko9pB1Q,34213
|
4
|
+
tesla_fleet_api/ratecalculator.py,sha256=4lz8yruUeouHXh_3ezsXX-CTpIegp1T1J4VuRV_qdHA,1791
|
5
|
+
tesla_fleet_api/tesla/__init__.py,sha256=sWIkVh4lesdp5eGQPC9Hjk_eoyN1_g9zz7vpMsJzTgo,219
|
6
|
+
tesla_fleet_api/tesla/bluetooth.py,sha256=7L6U8_xr2JiAX2YJOCLcsCOD7NkGdLLSf3-qnopHQtg,1092
|
7
|
+
tesla_fleet_api/tesla/charging.py,sha256=9zNSFi9vo8v03KQRKyosO5me49_tDrg3_25BRZibfQ0,1690
|
8
|
+
tesla_fleet_api/tesla/energysite.py,sha256=jauUrh14LL-EaMruxhye1YsNHjtTMmgCl1HCf_8mBeI,6070
|
9
|
+
tesla_fleet_api/tesla/fleet.py,sha256=NCkHLd-ddpa0wkSu_CEOG7ru9ea5HTLXud4lvkh3DWM,5516
|
10
|
+
tesla_fleet_api/tesla/oauth.py,sha256=pFGtIcERjsNKrO5VUEHm8WsNo1xF4DVbx3Yt2MhlGPQ,4070
|
11
|
+
tesla_fleet_api/tesla/partner.py,sha256=TU3Xg18x2w3PHv6Dy3Mo40pb417pp5lqnF0c1vDCt6g,1224
|
12
|
+
tesla_fleet_api/tesla/tesla.py,sha256=Jlz90-fM0nJbhnQN0k3ukNv59-9KqZZbyQ91IiLIbfo,2010
|
13
|
+
tesla_fleet_api/tesla/user.py,sha256=1LVwarEU-wmkqkPw0LGvNiPRy6uGRZkYL-vr17sz51M,1180
|
14
|
+
tesla_fleet_api/tesla/vehicle/__init__.py,sha256=luJKFuTGxmo4ef4tURaZgYwdkmWqCQrjxKogQzlFBtI,265
|
15
|
+
tesla_fleet_api/tesla/vehicle/bluetooth.py,sha256=QjnFT4UYNsS4UWD_Spq-2T6Qlh4HnVCX_1ZCS18XjT8,8153
|
16
|
+
tesla_fleet_api/tesla/vehicle/commands.py,sha256=INHps_29kPjblFSFJdQCrf2Ob3tURy6J9pO85NbGDVU,46874
|
17
|
+
tesla_fleet_api/tesla/vehicle/fleet.py,sha256=j9jGE6kGUnmlO6kvB2CBJcwaEPaJ-CGxP7Cgv2AI9AU,32018
|
18
|
+
tesla_fleet_api/tesla/vehicle/signed.py,sha256=lhf_zzMc9xL9P2S8GC7IQC-CEVkQNUIrT_gR8AvODCc,1659
|
19
|
+
tesla_fleet_api/tesla/vehicle/vehicle.py,sha256=kbL6o-doro5wD-pMBbFcphfSUz1jNApfAUDEZmleKNs,485
|
20
|
+
tesla_fleet_api/tesla/vehicle/vehicles.py,sha256=gG7I9tCr3-fag5DSLK2lXayBpjbgEpE61DeDzJZs4f8,1449
|
21
|
+
tesla_fleet_api/tesla/vehicle/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
+
tesla_fleet_api/tesla/vehicle/proto/__init__.pyi,sha256=qFXWNIgl71wB260u-XPzaAwWAHL6krw21q-aXnBtop0,252
|
23
|
+
tesla_fleet_api/tesla/vehicle/proto/car_server_pb2.py,sha256=v_eb4NDIkx_ZYPYW29_EFRky5vQ4b2q14gwuQSbouYw,29202
|
24
|
+
tesla_fleet_api/tesla/vehicle/proto/car_server_pb2.pyi,sha256=qkig9HEsOE4Dk2-r38BAWOyALqt7CtUnlirgSVt_oa8,46334
|
25
|
+
tesla_fleet_api/tesla/vehicle/proto/common_pb2.py,sha256=C5O6BBTckU3F-XItLfivaPG_XVCnzF_JX4mpVfM_jFk,3931
|
26
|
+
tesla_fleet_api/tesla/vehicle/proto/common_pb2.pyi,sha256=8aZiigp74MfSOMpHtMw0D9Jj0kwPz1zV_BIZfVWhh_0,5012
|
27
|
+
tesla_fleet_api/tesla/vehicle/proto/errors_pb2.py,sha256=nfOvriyjVgVxnJZIAYNRHiBa1_14dOXhC9Pokc5anV8,1631
|
28
|
+
tesla_fleet_api/tesla/vehicle/proto/errors_pb2.pyi,sha256=CNsAR7Oe6wavnqjzhInEyAFxMio6TtXfaNT0DUztn6o,1478
|
29
|
+
tesla_fleet_api/tesla/vehicle/proto/keys_pb2.py,sha256=-hyVP9-W1DypTYLaWwkOSUzgia6l9R3M9wUIgvNs-T0,1252
|
30
|
+
tesla_fleet_api/tesla/vehicle/proto/keys_pb2.pyi,sha256=HH-TfhE5ihwmoPCGdiVnZ5B7KkaMJglEpusgLc1J02M,676
|
31
|
+
tesla_fleet_api/tesla/vehicle/proto/managed_charging_pb2.py,sha256=4crkLo6uC0YPkgw90jRjAqlGMFnRze_koUt2-pw14m4,1430
|
32
|
+
tesla_fleet_api/tesla/vehicle/proto/managed_charging_pb2.pyi,sha256=SqEmrfknTfzYTUYHtsoCpt1Fw2YpU3OyQllX247UfyQ,1227
|
33
|
+
tesla_fleet_api/tesla/vehicle/proto/signatures_pb2.py,sha256=TRaJ6lzmJtryhhmBC_PbYzftc-pqCmwC6wuBCXHeuTg,4734
|
34
|
+
tesla_fleet_api/tesla/vehicle/proto/signatures_pb2.pyi,sha256=-OGm9ctBnEJiXk-3nkFCPRTxKgFiqFgMbKeq3x2zGGM,6101
|
35
|
+
tesla_fleet_api/tesla/vehicle/proto/universal_message_pb2.py,sha256=UklH73qoYsqxylie6IK8iIcw2tmykSqDiaBKSWz66OQ,5093
|
36
|
+
tesla_fleet_api/tesla/vehicle/proto/universal_message_pb2.pyi,sha256=a_RygTJL26v0rA7QuUwsxiG1_ZBcliwXCqOAqTIJ6UE,7647
|
37
|
+
tesla_fleet_api/tesla/vehicle/proto/vcsec_pb2.py,sha256=PDv9TfiXnNs6sQ0D5vBrsSSPinSqu3eBUwvTcG8xMWo,15919
|
38
|
+
tesla_fleet_api/tesla/vehicle/proto/vcsec_pb2.pyi,sha256=cyK1uyRtDjRVqVlyl5uRQYY1RhFlWSJheLg3PGfs-_s,28524
|
39
|
+
tesla_fleet_api/tesla/vehicle/proto/vehicle_pb2.py,sha256=bqyFJM-1qZ7W9XKREINhYZx8yXAudmq6W8_Pdfkhbkk,44711
|
40
|
+
tesla_fleet_api/tesla/vehicle/proto/vehicle_pb2.pyi,sha256=sAUW_9aVB8NqJCnhZjXMLfqfePLVZv_7PfSKZKEBaQA,74251
|
41
|
+
tesla_fleet_api/teslemetry/__init__.py,sha256=OnHrZEkPGVFrziwMA-vArvh5vgBn6vT_nMbIhjN49V0,68
|
42
|
+
tesla_fleet_api/teslemetry/teslemetry.py,sha256=BtV__OSenTg_dwM0aovbL--mv3HhIIWtoWHQp58sViQ,2990
|
43
|
+
tesla_fleet_api/teslemetry/vehicle.py,sha256=aCe4Vhs4WHd6OQ-gzdxsPubKF_C5aLBoHrDvzyVgucI,2277
|
44
|
+
tesla_fleet_api/tessie/__init__.py,sha256=UNsWgx5w0DJSIFcMd7jBBdSxklF3Vhubq9tSL8vfegg,56
|
45
|
+
tesla_fleet_api/tessie/tessie.py,sha256=Z6t-ulDL7zfBIAJ6L7EBUMux2iawWjR1cR4jvYIhVFg,2523
|
46
|
+
tesla_fleet_api/tessie/vehicle.py,sha256=C2Q0en3Uo3xtI2sU9jSHXUtYhgBrNJYYhl8gP2zVmfQ,1315
|
47
|
+
tesla_fleet_api-1.0.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
48
|
+
tesla_fleet_api-1.0.1.dist-info/METADATA,sha256=6wVdb-DMTVaAa9hKPrYQNjphXXMbE6Rabxf003sDSB8,4056
|
49
|
+
tesla_fleet_api-1.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
50
|
+
tesla_fleet_api-1.0.1.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
|
51
|
+
tesla_fleet_api-1.0.1.dist-info/RECORD,,
|
@@ -1,125 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from typing import Any, TYPE_CHECKING
|
3
|
-
from .const import EnergyExportMode, EnergyOperationMode, TeslaEnergyPeriod
|
4
|
-
|
5
|
-
if TYPE_CHECKING:
|
6
|
-
from .energy import Energy
|
7
|
-
|
8
|
-
|
9
|
-
class EnergySpecific:
|
10
|
-
"""Class describing the Tesla Fleet API partner endpoints"""
|
11
|
-
|
12
|
-
_parent: Energy
|
13
|
-
energy_site_id: int
|
14
|
-
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
parent: Energy,
|
18
|
-
energy_site_id: int,
|
19
|
-
):
|
20
|
-
self._parent = parent
|
21
|
-
self.energy_site_id = energy_site_id
|
22
|
-
|
23
|
-
async def backup(self, backup_reserve_percent: int) -> dict[str, Any]:
|
24
|
-
"""Adjust the site's backup reserve."""
|
25
|
-
return await self._parent.backup(
|
26
|
-
self.energy_site_id,
|
27
|
-
backup_reserve_percent,
|
28
|
-
)
|
29
|
-
|
30
|
-
async def backup_history(
|
31
|
-
self,
|
32
|
-
period: TeslaEnergyPeriod | str,
|
33
|
-
start_date: str | None = None,
|
34
|
-
end_date: str | None = None,
|
35
|
-
time_zone: str | None = None,
|
36
|
-
) -> dict[str, Any]:
|
37
|
-
"""Returns the backup (off-grid) event history of the site in duration of seconds."""
|
38
|
-
return await self._parent.backup_history(
|
39
|
-
self.energy_site_id,
|
40
|
-
period,
|
41
|
-
start_date,
|
42
|
-
end_date,
|
43
|
-
time_zone,
|
44
|
-
)
|
45
|
-
|
46
|
-
async def charge_history(
|
47
|
-
self,
|
48
|
-
start_date: str,
|
49
|
-
end_date: str,
|
50
|
-
time_zone: str | None = None,
|
51
|
-
) -> dict[str, Any]:
|
52
|
-
"""Returns the charging history of a wall connector."""
|
53
|
-
return await self._parent.charge_history(
|
54
|
-
self.energy_site_id,
|
55
|
-
start_date,
|
56
|
-
end_date,
|
57
|
-
time_zone,
|
58
|
-
)
|
59
|
-
|
60
|
-
async def energy_history(
|
61
|
-
self,
|
62
|
-
period: TeslaEnergyPeriod | str,
|
63
|
-
start_date: str | None = None,
|
64
|
-
end_date: str | None = None,
|
65
|
-
time_zone: str | None = None,
|
66
|
-
) -> dict[str, Any]:
|
67
|
-
"""Returns the energy measurements of the site, aggregated to the requested period."""
|
68
|
-
return await self._parent.energy_history(
|
69
|
-
self.energy_site_id,
|
70
|
-
period,
|
71
|
-
start_date,
|
72
|
-
end_date,
|
73
|
-
time_zone,
|
74
|
-
)
|
75
|
-
|
76
|
-
async def grid_import_export(
|
77
|
-
self,
|
78
|
-
disallow_charge_from_grid_with_solar_installed: bool | None = None,
|
79
|
-
customer_preferred_export_rule: EnergyExportMode | str | None = None,
|
80
|
-
) -> dict[str, Any]:
|
81
|
-
"""Allow/disallow charging from the grid and exporting energy to the grid."""
|
82
|
-
return await self._parent.grid_import_export(
|
83
|
-
self.energy_site_id,
|
84
|
-
disallow_charge_from_grid_with_solar_installed,
|
85
|
-
customer_preferred_export_rule,
|
86
|
-
)
|
87
|
-
|
88
|
-
async def live_status(self) -> dict[str, Any]:
|
89
|
-
"""Returns the live status of the site (power, state of energy, grid status, storm mode)."""
|
90
|
-
return await self._parent.live_status(self.energy_site_id)
|
91
|
-
|
92
|
-
async def off_grid_vehicle_charging_reserve(
|
93
|
-
self, off_grid_vehicle_charging_reserve_percent: int
|
94
|
-
) -> dict[str, Any]:
|
95
|
-
"""Adjust the site's off-grid vehicle charging backup reserve."""
|
96
|
-
return await self._parent.off_grid_vehicle_charging_reserve(
|
97
|
-
self.energy_site_id, off_grid_vehicle_charging_reserve_percent
|
98
|
-
)
|
99
|
-
|
100
|
-
async def operation(
|
101
|
-
self, default_real_mode: EnergyOperationMode | str
|
102
|
-
) -> dict[str, Any]:
|
103
|
-
"""Set the site's mode."""
|
104
|
-
return await self._parent.operation(
|
105
|
-
self.energy_site_id,
|
106
|
-
default_real_mode,
|
107
|
-
)
|
108
|
-
|
109
|
-
async def site_info(self) -> dict[str, Any]:
|
110
|
-
"""Returns information about the site. Things like assets (has solar, etc), settings (backup reserve, etc), and features (storm_mode_capable, etc)."""
|
111
|
-
return await self._parent.site_info(self.energy_site_id)
|
112
|
-
|
113
|
-
async def storm_mode(self, enabled: bool) -> dict[str, Any]:
|
114
|
-
"""Update storm watch participation."""
|
115
|
-
return await self._parent.storm_mode(
|
116
|
-
self.energy_site_id,
|
117
|
-
enabled,
|
118
|
-
)
|
119
|
-
|
120
|
-
async def time_of_use_settings(self, settings: dict[str, Any]) -> dict[str, Any]:
|
121
|
-
"""Update the site's time of use settings."""
|
122
|
-
return await self._parent.time_of_use_settings(
|
123
|
-
self.energy_site_id,
|
124
|
-
settings,
|
125
|
-
)
|
@@ -1,61 +0,0 @@
|
|
1
|
-
import aiohttp
|
2
|
-
import time
|
3
|
-
import secrets
|
4
|
-
import hashlib
|
5
|
-
import base64
|
6
|
-
|
7
|
-
from .teslafleetoauth import TeslaFleetOAuth
|
8
|
-
from .const import Scope, SERVERS
|
9
|
-
|
10
|
-
|
11
|
-
class TeslaFleetOpenSource(TeslaFleetOAuth):
|
12
|
-
"""Tesla Fleet Open Source OAuth API."""
|
13
|
-
|
14
|
-
code_verifier: str
|
15
|
-
code_challenge: str
|
16
|
-
|
17
|
-
def __init__(
|
18
|
-
self,
|
19
|
-
session: aiohttp.ClientSession,
|
20
|
-
client_id: str,
|
21
|
-
redirect_uri: str,
|
22
|
-
):
|
23
|
-
self.code_verifier = secrets.token_urlsafe(32)
|
24
|
-
|
25
|
-
# Hash the code_verifier using SHA-256
|
26
|
-
hashed_verifier = hashlib.sha256(self.code_verifier.encode()).digest()
|
27
|
-
# Encode the hash using URL-safe Base64 encoding, without padding
|
28
|
-
self.code_challenge = (
|
29
|
-
base64.urlsafe_b64encode(hashed_verifier).decode().replace("=", "")
|
30
|
-
)
|
31
|
-
|
32
|
-
super().__init__(session, client_id, redirect_uri=redirect_uri)
|
33
|
-
|
34
|
-
def get_login_url(self, scopes: list[Scope], state: str = "login") -> str:
|
35
|
-
"""Get the login URL without a client secret."""
|
36
|
-
|
37
|
-
return (
|
38
|
-
super().get_login_url(scopes, state)
|
39
|
-
+ f"&code_challenge={self.code_challenge}"
|
40
|
-
)
|
41
|
-
|
42
|
-
async def get_refresh_token(self, code: str) -> None:
|
43
|
-
"""Get the refresh token."""
|
44
|
-
async with self.session.post(
|
45
|
-
"https://auth.tesla.com/oauth2/v3/token",
|
46
|
-
data={
|
47
|
-
"grant_type": "authorization_code",
|
48
|
-
"client_id": self.client_id,
|
49
|
-
"code": code,
|
50
|
-
"audience": self.server,
|
51
|
-
"redirect_uri": self.redirect_uri,
|
52
|
-
"code_verifier": self.code_verifier,
|
53
|
-
},
|
54
|
-
) as resp:
|
55
|
-
if resp.ok:
|
56
|
-
data = await resp.json()
|
57
|
-
self.refresh_token = data["refresh_token"]
|
58
|
-
self.access_token = data["access_token"]
|
59
|
-
self.expires = int(time.time()) + data["expires_in"]
|
60
|
-
region = code.split("_")[0].lower()
|
61
|
-
self.server = SERVERS.get(region)
|