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
26 changes: 26 additions & 0 deletions tesla_fleet_api/tesla/vehicle/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
TeslaAuthResponseAction,
SetupCloudProfileWithLocalProfileUuidAction,
GetLocalProfilesForVaultUuidAction,
DeleteDashcamClipsAction,
FormatUSBAction,
)
from google.protobuf.timestamp_pb2 import Timestamp
from tesla_protocol.command.vehicle_pb2 import (
Expand Down Expand Up @@ -2515,3 +2517,27 @@ async def get_local_profiles_for_vault_uuid(
),
mutating=False,
)

# No confirmation guard, matching the existing erase_user_data()
# precedent: this library exposes the signed command as-is and leaves
# any confirmation UX to the caller.

async def format_usb(self) -> dict[str, Any]:
"""Formats the USB drive connected to the vehicle, erasing all files on it. Irreversible."""
return await self._sendInfotainment(
Action(
vehicleAction=VehicleAction(
formatUsbAction=FormatUSBAction(format_usb=True)
)
)
)

async def delete_dashcam_clips(self) -> dict[str, Any]:
"""Deletes all dashcam clips stored on the vehicle. Irreversible."""
return await self._sendInfotainment(
Action(
vehicleAction=VehicleAction(
deleteDashcamClipsAction=DeleteDashcamClipsAction(delete_clips=True)
)
)
)
47 changes: 47 additions & 0 deletions tests/test_ble_destructive_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Destructive data-clearing commands over the mocked BLE transport.

``format_usb``/``delete_dashcam_clips`` are unguarded no-confirmation
wrappers, matching the existing ``erase_user_data()`` precedent
(``tests/test_ble_mocked_commands.py`` has no dedicated test for that one
either - it is exercised indirectly via the cross-transport suite).
"""

from tesla_protocol.command.car_server_pb2 import Action
from tesla_protocol.command.universal_message_pb2 import Domain

from ble_mocked_transport import (
MockedBleTransportTestCase,
decrypt_sent_command,
infotainment_action_ok_reply,
)


def _decode_vehicle_action(vehicle, sent_msg):
plaintext = decrypt_sent_command(vehicle, sent_msg)
action = Action.FromString(plaintext)
assert sent_msg.to_destination.domain == Domain.DOMAIN_INFOTAINMENT
return action.vehicleAction


class FormatUsbTests(MockedBleTransportTestCase):
async def test_sends_format_usb_true(self) -> None:
vehicle, send = self.make_vehicle()
send.return_value = infotainment_action_ok_reply()

result = await vehicle.format_usb()

self.assertEqual(result, {"response": {"result": True, "reason": ""}})
vehicle_action = _decode_vehicle_action(vehicle, send.await_args.args[0])
self.assertTrue(vehicle_action.formatUsbAction.format_usb)


class DeleteDashcamClipsTests(MockedBleTransportTestCase):
async def test_sends_delete_clips_true(self) -> None:
vehicle, send = self.make_vehicle()
send.return_value = infotainment_action_ok_reply()

result = await vehicle.delete_dashcam_clips()

self.assertEqual(result, {"response": {"result": True, "reason": ""}})
vehicle_action = _decode_vehicle_action(vehicle, send.await_args.args[0])
self.assertTrue(vehicle_action.deleteDashcamClipsAction.delete_clips)
Loading