Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tesla_fleet_api/teslemetry/vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ async def closure(
json=data,
)

async def open_tonneau(self) -> dict[str, Any]:
"""Opens the tonneau cover."""
return await self.closure(tonneau=ClosureState.OPEN)

async def close_tonneau(self) -> dict[str, Any]:
"""Closes the tonneau cover."""
return await self.closure(tonneau=ClosureState.CLOSE)

async def stop_tonneau(self) -> dict[str, Any]:
"""Stops the tonneau cover."""
return await self.closure(tonneau=ClosureState.STOP)

async def seat_heater(
self,
front_left: SeatHeaterLevel | None = None,
Expand Down
50 changes: 50 additions & 0 deletions tests/test_teslemetry_vehicle_custom_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,53 @@ async def test_trigger_rate_tariff_update(self) -> None:
Method.POST,
f"api/1/vehicles/{VIN}/custom_command/set_rate_tariff",
)


class TonneauTests(IsolatedAsyncioTestCase):
"""Tonneau methods mirror the signed ``Commands`` names via ``closure``."""

async def _assert_tonneau(self, method: str, body: str) -> None:
vehicle, request = _make_vehicle()
result = await getattr(vehicle, method)()
request.assert_awaited_once_with(
Method.POST,
f"api/1/vehicles/{VIN}/custom_command/closure",
json={"tonneau": body},
)
self.assertEqual(result, {"response": {"result": True}})

async def test_open_tonneau(self) -> None:
await self._assert_tonneau("open_tonneau", "open")

async def test_close_tonneau(self) -> None:
await self._assert_tonneau("close_tonneau", "close")

async def test_stop_tonneau(self) -> None:
await self._assert_tonneau("stop_tonneau", "stop")

async def test_router_prefers_ble_and_falls_back_to_cloud(self) -> None:
from tesla_fleet_api.router import VehicleRouter

class _Ble:
vin = VIN

def __init__(self, fail: bool) -> None:
self.fail = fail
self.calls = 0

async def open_tonneau(self) -> dict[str, bool]:
self.calls += 1
if self.fail:
raise ConnectionError("ble down")
return {"ble": True}

cloud, request = _make_vehicle()

ble = _Ble(fail=False)
self.assertEqual(await VehicleRouter(ble, cloud).open_tonneau(), {"ble": True})
request.assert_not_awaited()

ble = _Ble(fail=True)
await VehicleRouter(ble, cloud).open_tonneau()
self.assertEqual(ble.calls, 1)
request.assert_awaited_once()
Loading