tesla-fleet-api 0.3.0 → 0.5.0

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.
Files changed (342) hide show
  1. package/README.md +284 -1
  2. package/dist/_virtual/_rolldown/runtime.cjs +32 -0
  3. package/dist/_virtual/_rolldown/runtime.mjs +12 -0
  4. package/dist/bluetooth/adapters/shared.cjs +38 -0
  5. package/dist/bluetooth/adapters/shared.mjs +36 -0
  6. package/dist/bluetooth/async.cjs +121 -0
  7. package/dist/bluetooth/async.d.cts +10 -0
  8. package/dist/bluetooth/async.d.mts +10 -0
  9. package/dist/bluetooth/async.mjs +116 -0
  10. package/dist/bluetooth/broadcast.cjs +153 -0
  11. package/dist/bluetooth/broadcast.d.cts +59 -0
  12. package/dist/bluetooth/broadcast.d.mts +59 -0
  13. package/dist/bluetooth/broadcast.mjs +151 -0
  14. package/dist/bluetooth/constants.cjs +99 -0
  15. package/dist/bluetooth/constants.d.cts +70 -0
  16. package/dist/bluetooth/constants.d.mts +70 -0
  17. package/dist/bluetooth/constants.mjs +72 -0
  18. package/dist/bluetooth/esphome.cjs +292 -0
  19. package/dist/bluetooth/esphome.d.cts +83 -0
  20. package/dist/bluetooth/esphome.d.mts +83 -0
  21. package/dist/bluetooth/esphome.mjs +291 -0
  22. package/dist/bluetooth/framing.cjs +125 -0
  23. package/dist/bluetooth/framing.d.cts +45 -0
  24. package/dist/bluetooth/framing.d.mts +45 -0
  25. package/dist/bluetooth/framing.mjs +122 -0
  26. package/dist/bluetooth/homey.cjs +155 -0
  27. package/dist/bluetooth/homey.d.cts +75 -0
  28. package/dist/bluetooth/homey.d.mts +75 -0
  29. package/dist/bluetooth/homey.mjs +150 -0
  30. package/dist/bluetooth/names.cjs +24 -0
  31. package/dist/bluetooth/names.d.cts +10 -0
  32. package/dist/bluetooth/names.d.mts +10 -0
  33. package/dist/bluetooth/names.mjs +20 -0
  34. package/dist/bluetooth/noble.cjs +178 -0
  35. package/dist/bluetooth/noble.d.cts +58 -0
  36. package/dist/bluetooth/noble.d.mts +58 -0
  37. package/dist/bluetooth/noble.mjs +177 -0
  38. package/dist/bluetooth/streamglue.cjs +157 -0
  39. package/dist/bluetooth/streamglue.d.cts +37 -0
  40. package/dist/bluetooth/streamglue.d.mts +37 -0
  41. package/dist/bluetooth/streamglue.mjs +154 -0
  42. package/dist/bluetooth/teslabluetooth.cjs +67 -0
  43. package/dist/bluetooth/teslabluetooth.d.cts +41 -0
  44. package/dist/bluetooth/teslabluetooth.d.mts +41 -0
  45. package/dist/bluetooth/teslabluetooth.mjs +66 -0
  46. package/dist/bluetooth/transport.cjs +10 -0
  47. package/dist/bluetooth/transport.d.cts +95 -0
  48. package/dist/bluetooth/transport.d.mts +95 -0
  49. package/dist/bluetooth/transport.mjs +10 -0
  50. package/dist/bluetooth/vehiclebluetooth.cjs +1272 -0
  51. package/dist/bluetooth/vehiclebluetooth.d.cts +495 -0
  52. package/dist/bluetooth/vehiclebluetooth.d.mts +495 -0
  53. package/dist/bluetooth/vehiclebluetooth.mjs +1270 -0
  54. package/dist/bluetooth/verify.cjs +93 -0
  55. package/dist/bluetooth/verify.d.cts +35 -0
  56. package/dist/bluetooth/verify.d.mts +35 -0
  57. package/dist/bluetooth/verify.mjs +91 -0
  58. package/dist/bluetooth.cjs +53 -0
  59. package/dist/bluetooth.d.cts +10 -0
  60. package/dist/bluetooth.d.mts +10 -0
  61. package/dist/bluetooth.mjs +9 -0
  62. package/dist/charging.cjs +53 -0
  63. package/dist/charging.d.cts +31 -0
  64. package/dist/charging.d.mts +30 -0
  65. package/dist/charging.mjs +53 -0
  66. package/dist/commands.cjs +1797 -0
  67. package/dist/commands.d.cts +881 -0
  68. package/dist/commands.d.mts +881 -0
  69. package/dist/commands.mjs +1791 -0
  70. package/dist/const.cjs +322 -0
  71. package/dist/const.d.cts +308 -0
  72. package/dist/const.d.mts +308 -0
  73. package/dist/const.mjs +282 -0
  74. package/dist/energy.cjs +142 -0
  75. package/dist/energy.d.cts +101 -0
  76. package/dist/energy.d.mts +100 -0
  77. package/dist/energy.mjs +142 -0
  78. package/dist/energyisland.cjs +38 -0
  79. package/dist/energyisland.mjs +37 -0
  80. package/dist/energyparsers.cjs +118 -0
  81. package/dist/energyparsers.d.cts +39 -0
  82. package/dist/energyparsers.d.mts +39 -0
  83. package/dist/energyparsers.mjs +116 -0
  84. package/dist/energyspecific.cjs +457 -0
  85. package/dist/energyspecific.d.cts +258 -0
  86. package/dist/energyspecific.d.mts +258 -0
  87. package/dist/energyspecific.mjs +451 -0
  88. package/dist/exceptions.cjs +1488 -0
  89. package/dist/exceptions.d.cts +1143 -0
  90. package/dist/exceptions.d.mts +1143 -0
  91. package/dist/exceptions.mjs +1325 -0
  92. package/dist/funnel.cjs +297 -0
  93. package/dist/funnel.d.cts +118 -0
  94. package/dist/funnel.d.mts +118 -0
  95. package/dist/funnel.mjs +292 -0
  96. package/dist/index.cjs +287 -0
  97. package/dist/index.d.cts +28 -0
  98. package/dist/index.d.mts +28 -0
  99. package/dist/index.mjs +27 -0
  100. package/dist/log.cjs +75 -0
  101. package/dist/log.d.cts +4 -0
  102. package/dist/log.d.mts +4 -0
  103. package/dist/log.mjs +71 -0
  104. package/dist/oauth.cjs +143 -0
  105. package/dist/oauth.d.cts +69 -0
  106. package/dist/oauth.d.mts +69 -0
  107. package/dist/oauth.mjs +143 -0
  108. package/dist/partner.cjs +32 -0
  109. package/dist/partner.d.cts +24 -0
  110. package/dist/partner.d.mts +23 -0
  111. package/dist/partner.mjs +32 -0
  112. package/dist/powerwall/client.cjs +818 -0
  113. package/dist/powerwall/client.d.cts +297 -0
  114. package/dist/powerwall/client.d.mts +297 -0
  115. package/dist/powerwall/client.mjs +807 -0
  116. package/dist/powerwall/components.cjs +188 -0
  117. package/dist/powerwall/components.d.cts +45 -0
  118. package/dist/powerwall/components.d.mts +45 -0
  119. package/dist/powerwall/components.mjs +182 -0
  120. package/dist/powerwall/energysite.cjs +216 -0
  121. package/dist/powerwall/energysite.d.cts +104 -0
  122. package/dist/powerwall/energysite.d.mts +104 -0
  123. package/dist/powerwall/energysite.mjs +214 -0
  124. package/dist/powerwall/exceptions.cjs +59 -0
  125. package/dist/powerwall/exceptions.d.cts +38 -0
  126. package/dist/powerwall/exceptions.d.mts +38 -0
  127. package/dist/powerwall/exceptions.mjs +51 -0
  128. package/dist/powerwall/gateway.cjs +102 -0
  129. package/dist/powerwall/gateway.d.cts +57 -0
  130. package/dist/powerwall/gateway.d.mts +57 -0
  131. package/dist/powerwall/gateway.mjs +101 -0
  132. package/dist/powerwall/merge.cjs +163 -0
  133. package/dist/powerwall/merge.d.cts +63 -0
  134. package/dist/powerwall/merge.d.mts +63 -0
  135. package/dist/powerwall/merge.mjs +159 -0
  136. package/dist/powerwall/models.d.cts +95 -0
  137. package/dist/powerwall/models.d.mts +95 -0
  138. package/dist/powerwall/queries.cjs +17 -0
  139. package/dist/powerwall/queries.mjs +10 -0
  140. package/dist/powerwall/transport.cjs +232 -0
  141. package/dist/powerwall/transport.mjs +227 -0
  142. package/dist/powerwall.cjs +47 -0
  143. package/dist/powerwall.d.cts +9 -0
  144. package/dist/powerwall.d.mts +9 -0
  145. package/dist/powerwall.mjs +8 -0
  146. package/dist/router/base.cjs +203 -0
  147. package/dist/router/base.d.cts +112 -0
  148. package/dist/router/base.d.mts +112 -0
  149. package/dist/router/base.mjs +200 -0
  150. package/dist/router/energysite.cjs +65 -0
  151. package/dist/router/energysite.d.cts +47 -0
  152. package/dist/router/energysite.d.mts +47 -0
  153. package/dist/router/energysite.mjs +60 -0
  154. package/dist/router.cjs +13 -0
  155. package/dist/router.d.cts +3 -0
  156. package/dist/router.d.mts +3 -0
  157. package/dist/router.mjs +3 -0
  158. package/dist/signing/crypto.cjs +59 -0
  159. package/dist/signing/crypto.mjs +52 -0
  160. package/dist/signing/energy.cjs +123 -0
  161. package/dist/signing/energy.d.cts +45 -0
  162. package/dist/signing/energy.d.mts +45 -0
  163. package/dist/signing/energy.mjs +120 -0
  164. package/dist/signing/jws.cjs +229 -0
  165. package/dist/signing/jws.d.cts +45 -0
  166. package/dist/signing/jws.d.mts +45 -0
  167. package/dist/signing/jws.mjs +211 -0
  168. package/dist/signing/keys.cjs +191 -0
  169. package/dist/signing/keys.d.cts +21 -0
  170. package/dist/signing/keys.d.mts +21 -0
  171. package/dist/signing/keys.mjs +182 -0
  172. package/dist/signing/session.cjs +186 -0
  173. package/dist/signing/session.d.cts +106 -0
  174. package/dist/signing/session.d.mts +106 -0
  175. package/dist/signing/session.mjs +184 -0
  176. package/dist/tariff.cjs +319 -0
  177. package/dist/tariff.d.cts +40 -0
  178. package/dist/tariff.d.mts +40 -0
  179. package/dist/tariff.mjs +317 -0
  180. package/dist/teslafleetapi.cjs +326 -0
  181. package/dist/teslafleetapi.d.cts +160 -0
  182. package/dist/teslafleetapi.d.mts +160 -0
  183. package/dist/teslafleetapi.mjs +326 -0
  184. package/dist/teslemetry.cjs +183 -0
  185. package/dist/teslemetry.d.cts +113 -0
  186. package/dist/teslemetry.d.mts +113 -0
  187. package/dist/teslemetry.mjs +181 -0
  188. package/dist/teslemetryenergy.cjs +287 -0
  189. package/dist/teslemetryenergy.d.cts +154 -0
  190. package/dist/teslemetryenergy.d.mts +154 -0
  191. package/dist/teslemetryenergy.mjs +282 -0
  192. package/dist/teslemetryvehicle.cjs +407 -0
  193. package/dist/teslemetryvehicle.d.cts +238 -0
  194. package/dist/teslemetryvehicle.d.mts +238 -0
  195. package/dist/teslemetryvehicle.mjs +405 -0
  196. package/dist/tessie.cjs +71 -0
  197. package/dist/tessie.d.cts +69 -0
  198. package/dist/tessie.d.mts +69 -0
  199. package/dist/tessie.mjs +71 -0
  200. package/dist/tessievehicle.cjs +514 -0
  201. package/dist/tessievehicle.d.cts +333 -0
  202. package/dist/tessievehicle.d.mts +333 -0
  203. package/dist/tessievehicle.mjs +513 -0
  204. package/dist/types/commands.d.cts +28 -0
  205. package/dist/types/commands.d.mts +28 -0
  206. package/dist/types/live_status.d.cts +30 -0
  207. package/dist/types/live_status.d.mts +30 -0
  208. package/dist/types/products.d.cts +58 -0
  209. package/dist/types/products.d.mts +58 -0
  210. package/dist/types/responses.d.cts +13 -0
  211. package/dist/types/responses.d.mts +13 -0
  212. package/dist/types/site_info.d.cts +154 -0
  213. package/dist/types/site_info.d.mts +154 -0
  214. package/dist/types/vehicle.d.cts +33 -0
  215. package/dist/types/vehicle.d.mts +33 -0
  216. package/dist/types/vehicle_data.d.cts +278 -0
  217. package/dist/types/vehicle_data.d.mts +278 -0
  218. package/dist/types.cjs +0 -0
  219. package/dist/types.d.cts +9 -0
  220. package/dist/types.d.mts +9 -0
  221. package/dist/types.mjs +1 -0
  222. package/dist/user.cjs +28 -0
  223. package/dist/user.d.cts +17 -0
  224. package/dist/user.d.mts +16 -0
  225. package/dist/user.mjs +28 -0
  226. package/dist/util.cjs +41 -0
  227. package/dist/util.d.cts +18 -0
  228. package/dist/util.d.mts +18 -0
  229. package/dist/util.mjs +40 -0
  230. package/dist/vehicle.cjs +847 -0
  231. package/dist/vehicle.d.cts +566 -0
  232. package/dist/vehicle.d.mts +565 -0
  233. package/dist/vehicle.mjs +847 -0
  234. package/dist/vehiclesigned.cjs +35 -0
  235. package/dist/vehiclesigned.d.cts +23 -0
  236. package/dist/vehiclesigned.d.mts +22 -0
  237. package/dist/vehiclesigned.mjs +35 -0
  238. package/dist/vehiclespecific.cjs +715 -0
  239. package/dist/vehiclespecific.d.cts +497 -0
  240. package/dist/vehiclespecific.d.mts +496 -0
  241. package/dist/vehiclespecific.mjs +715 -0
  242. package/package.json +178 -38
  243. package/dist/charging.d.ts +0 -30
  244. package/dist/charging.js +0 -51
  245. package/dist/charging.js.map +0 -1
  246. package/dist/commands.d.ts +0 -352
  247. package/dist/commands.js +0 -875
  248. package/dist/commands.js.map +0 -1
  249. package/dist/energy.d.ts +0 -94
  250. package/dist/energy.js +0 -125
  251. package/dist/energy.js.map +0 -1
  252. package/dist/energyspecific.d.ts +0 -77
  253. package/dist/energyspecific.js +0 -97
  254. package/dist/energyspecific.js.map +0 -1
  255. package/dist/helpers.d.ts +0 -2
  256. package/dist/helpers.js +0 -10
  257. package/dist/helpers.js.map +0 -1
  258. package/dist/index.d.ts +0 -15
  259. package/dist/index.js +0 -15
  260. package/dist/index.js.map +0 -1
  261. package/dist/partner.d.ts +0 -23
  262. package/dist/partner.js +0 -31
  263. package/dist/partner.js.map +0 -1
  264. package/dist/signing/crypto.d.ts +0 -10
  265. package/dist/signing/crypto.js +0 -26
  266. package/dist/signing/crypto.js.map +0 -1
  267. package/dist/signing/errors.d.ts +0 -29
  268. package/dist/signing/errors.js +0 -40
  269. package/dist/signing/errors.js.map +0 -1
  270. package/dist/signing/session.d.ts +0 -69
  271. package/dist/signing/session.js +0 -102
  272. package/dist/signing/session.js.map +0 -1
  273. package/dist/tariff.d.ts +0 -29
  274. package/dist/tariff.js +0 -302
  275. package/dist/tariff.js.map +0 -1
  276. package/dist/teslafleetapi.d.ts +0 -58
  277. package/dist/teslafleetapi.js +0 -120
  278. package/dist/teslafleetapi.js.map +0 -1
  279. package/dist/teslemetry.d.ts +0 -29
  280. package/dist/teslemetry.js +0 -39
  281. package/dist/teslemetry.js.map +0 -1
  282. package/dist/tessie.d.ts +0 -23
  283. package/dist/tessie.js +0 -28
  284. package/dist/tessie.js.map +0 -1
  285. package/dist/types/commands.d.ts +0 -44
  286. package/dist/types/commands.js +0 -11
  287. package/dist/types/commands.js.map +0 -1
  288. package/dist/types/live_status.d.ts +0 -26
  289. package/dist/types/live_status.js +0 -2
  290. package/dist/types/live_status.js.map +0 -1
  291. package/dist/types/products.d.ts +0 -54
  292. package/dist/types/products.js +0 -2
  293. package/dist/types/products.js.map +0 -1
  294. package/dist/types/responses.d.ts +0 -5
  295. package/dist/types/responses.js +0 -2
  296. package/dist/types/responses.js.map +0 -1
  297. package/dist/types/site_info.d.ts +0 -150
  298. package/dist/types/site_info.js +0 -2
  299. package/dist/types/site_info.js.map +0 -1
  300. package/dist/types/vehicle.d.ts +0 -23
  301. package/dist/types/vehicle.js +0 -10
  302. package/dist/types/vehicle.js.map +0 -1
  303. package/dist/types/vehicle_data.d.ts +0 -274
  304. package/dist/types/vehicle_data.js +0 -2
  305. package/dist/types/vehicle_data.js.map +0 -1
  306. package/dist/user.d.ts +0 -16
  307. package/dist/user.js +0 -26
  308. package/dist/user.js.map +0 -1
  309. package/dist/vehicle.d.ts +0 -548
  310. package/dist/vehicle.js +0 -774
  311. package/dist/vehicle.js.map +0 -1
  312. package/dist/vehiclesigned.d.ts +0 -13
  313. package/dist/vehiclesigned.js +0 -19
  314. package/dist/vehiclesigned.js.map +0 -1
  315. package/dist/vehiclespecific.d.ts +0 -432
  316. package/dist/vehiclespecific.js +0 -601
  317. package/dist/vehiclespecific.js.map +0 -1
  318. package/src/charging.ts +0 -66
  319. package/src/commands.ts +0 -1134
  320. package/src/energy.ts +0 -217
  321. package/src/energyspecific.ts +0 -116
  322. package/src/helpers.ts +0 -11
  323. package/src/index.ts +0 -21
  324. package/src/partner.ts +0 -37
  325. package/src/signing/crypto.ts +0 -29
  326. package/src/signing/errors.ts +0 -50
  327. package/src/signing/session.ts +0 -132
  328. package/src/tariff.ts +0 -375
  329. package/src/teslafleetapi.ts +0 -182
  330. package/src/teslemetry.ts +0 -54
  331. package/src/tessie.ts +0 -42
  332. package/src/types/commands.ts +0 -62
  333. package/src/types/live_status.ts +0 -27
  334. package/src/types/products.ts +0 -61
  335. package/src/types/responses.ts +0 -1
  336. package/src/types/site_info.ts +0 -159
  337. package/src/types/vehicle.ts +0 -33
  338. package/src/types/vehicle_data.ts +0 -286
  339. package/src/user.ts +0 -35
  340. package/src/vehicle.ts +0 -886
  341. package/src/vehiclesigned.ts +0 -20
  342. package/src/vehiclespecific.ts +0 -818
@@ -0,0 +1,1791 @@
1
+ import { AutoSeat, ClimateModes, PhoneFontSize, Seats } from "./const.mjs";
2
+ import VehicleSpecific from "./vehiclespecific.mjs";
3
+ import { sign_fleet_telemetry_config } from "./signing/jws.mjs";
4
+ import { Session } from "./signing/session.mjs";
5
+ import { logRequestError, logRequestResult } from "./log.mjs";
6
+ import { aesGcmDecrypt, aesGcmEncrypt, deriveSharedKey, publicKeyFor, sha256, uint32BE } from "./signing/crypto.mjs";
7
+ import { InvalidResponse, MESSAGE_FAULTS, NotOnWhitelistFault, SIGNED_MESSAGE_INFORMATION_FAULTS, SessionInfoAuthenticationFault, SignedCommandResponseReplayed, SigningDisabled, TeslaFleetMessageFault, TeslaFleetMessageFaultIncorrectEpoch, TeslaFleetMessageFaultInvalidTokenOrCounter, WHITELIST_OPERATION_STATUS, WhitelistOperationStatus } from "./exceptions.mjs";
8
+ import crypto from "crypto";
9
+ import { Domain, Flags, MessageFaultE, OperationStatusE, RoutableMessage } from "@teslemetry/tesla-protocol/command/universal_message";
10
+ import { KeyIdentity, SessionInfo, SessionInfoStatus, SignatureType, Tag } from "@teslemetry/tesla-protocol/command/signatures";
11
+ import { ClosureMoveRequest, ClosureMoveTypeE, FromVCSECMessage, OperationStatusE as OperationStatusE$1, RKEActionE, UnsignedMessage, operationStatusEToJSON, rKEActionEToJSON, signedMessageInformationEToJSON, whitelistOperationInformationEToJSON } from "@teslemetry/tesla-protocol/command/vcsec";
12
+ import { genericErrorEToJSON } from "@teslemetry/tesla-protocol/command/errors";
13
+ import { Action, AddManagedChargingSiteRequest, AutoSeatClimateAction, AutoSeatClimateAction_AutoSeatPositionE, AutoSeatClimateAction_CarSeat, AutoStwHeatAction, BandwidthTest, BatchRemoveChargeSchedulesAction, BatchRemovePreconditionSchedulesAction, BluetoothClassicPairingRequest, BoomboxAction, CancelSohTestAction, ChargeOnSolarFeature, ChargingSetLimitAction, ChargingStartStopAction, DashcamSaveClipAction, DeleteDashcamClipsAction, DrivingClearSpeedLimitPinAction, DrivingClearSpeedLimitPinAdminAction, DrivingSetSpeedLimitAction, DrivingSpeedLimitAction, EraseUserDataAction, FetchKeysInfoAction, FormatUSBAction, GetChargeOnSolarFeatureRequest, GetLocalProfilesForVaultUuidAction, GetManagedChargingSitesRequest, GetMessagesAction, GetNearbyChargingSites, GetRateTariffRequest, GetVehicleData, GetVehicleImageState, HvacAutoAction, HvacBioweaponModeAction, HvacClimateKeeperAction_ClimateKeeperActionE, HvacRecirculationAction, HvacSeatCoolerActions, HvacSeatCoolerActions_HvacSeatCoolerAction, HvacSeatCoolerActions_HvacSeatCoolerLevelE, HvacSeatCoolerActions_HvacSeatCoolerPositionE, HvacSeatHeaterActions, HvacSeatHeaterActions_HvacSeatHeaterAction, HvacSetPreconditioningMaxAction, HvacSteeringWheelHeaterAction, HvacTemperatureAdjustmentAction, ManagedChargingSite, ManagerType, MediaUpdateVolume, NavigationGpsDestinationRequest, NavigationGpsRequest, NavigationRequest, NavigationRouteAction, NavigationSuperchargerRequest, NavigationWaypointsRequest, OperationStatusE as OperationStatusE$2, ParentalControlsAction, ParentalControlsClearPinAction, ParentalControlsClearPinAdminAction, ParentalControlsEnableSettingsAction, ParentalControlsSetSpeedLimitAction, PhoneUnitPreferences, PiiKeyRequest, Ping, PseudonymSyncRequest, RemoveChargeScheduleAction, RemoveManagedChargingSiteRequest, RemovePreconditionScheduleAction, Response, ScheduledChargingAction, ScheduledDepartureAction, SetCabinOverheatProtectionAction, SetChargingAmpsAction, SetCopTempAction, SetDischargeLimitAction, SetDistanceUnitAction, SetEnergyDisplayFormatAction, SetKeepAccessoryPowerModeAction, SetLightbarBrightnessAction, SetLightbarDitchAction, SetLightbarMiddleAction, SetLowPowerModeAction, SetOutletSocLimitAction, SetOutletTimerAction, SetOutletsOnOffAction, SetPhoneSettingPreferencesAction, SetPowerFeedOnOffAction, SetPowerFeedSocLimitAction, SetPowerFeedTimerAction, SetPowershareDischargeLimitAction, SetPowershareFeatureAction, SetPowershareFeatureAction_PowershareFeatureRequest, SetPowershareRequestAction, SetPowershareRequestAction_PowershareRequest, SetRateTariffRequest, SetSuspensionLevelAction, SetTemperatureUnitAction, SetTentModeRequestAction, SetTimeDisplayFormatAction, SetTirePressureUnitAction, SetTrailerLightTestStartStopAction, SetTruckBedLightAutoStateAction, SetTruckBedLightBrightnessAction, SetVehicleNameAction, SetZoneLightRequestAction, SetupCloudProfileWithLocalProfileUuidAction, SiteController, StartLightShowAction, StopLightShowAction, StwHeatLevelAction, TakeDrivenoteAction, TeslaAuthResponseAction, UiSetUpcomingCalendarEntries, UpdateChargeOnSolarFeatureRequest, VehicleAction, VehicleControlCancelSoftwareUpdateAction, VehicleControlFlashLightsAction, VehicleControlHonkHornAction, VehicleControlResetPinToDriveAction, VehicleControlResetPinToDriveAdminAction, VehicleControlResetValetPinAction, VehicleControlScheduleSoftwareUpdateAction, VehicleControlSetPinToDriveAction, VehicleControlSetSentryModeAction, VehicleControlSetValetModeAction, VehicleControlSunroofOpenCloseAction, VehicleControlTriggerHomelinkAction, VehicleControlWindowAction, VehicleImageDataChunkRequest, VehicleImageRequest, VehicleImageRequest_Type, VideoRequestAction } from "@teslemetry/tesla-protocol/command/car_server";
14
+ import { ChargeSchedule, LatLong, OffPeakChargingTimes, PreconditionSchedule, PreconditioningTimes, StwHeatLevel } from "@teslemetry/tesla-protocol/command/common";
15
+ import { ClimateState_CopActivationTemp, VehicleState_GuestMode } from "@teslemetry/tesla-protocol/command/vehicle";
16
+ // src/commands.ts
17
+ const VOID = {};
18
+ /** Maximum HMAC-personalized (re)send attempts for one logical command, matching the reference implementation. */
19
+ const MAX_ATTEMPTS = 4;
20
+ const TrunkFields = {
21
+ front: "frontTrunk",
22
+ rear: "rearTrunk"
23
+ };
24
+ /** Node's REST `Seats` values mapped onto the seat-heater oneof field they select. */
25
+ const SeatHeaterFields = {
26
+ [Seats.FRONT_LEFT]: "carSeatFrontLeft",
27
+ [Seats.FRONT_RIGHT]: "carSeatFrontRight",
28
+ [Seats.REAR_LEFT]: "carSeatRearLeft",
29
+ [Seats.REAR_LEFT_BACK]: "carSeatRearLeftBack",
30
+ [Seats.REAR_CENTER]: "carSeatRearCenter",
31
+ [Seats.REAR_RIGHT]: "carSeatRearRight",
32
+ [Seats.REAR_RIGHT_BACK]: "carSeatRearRightBack",
33
+ [Seats.THIRD_LEFT]: "carSeatThirdRowLeft",
34
+ [Seats.THIRD_RIGHT]: "carSeatThirdRowRight"
35
+ };
36
+ const SeatHeaterLevels = [
37
+ "seatHeaterOff",
38
+ "seatHeaterLow",
39
+ "seatHeaterMed",
40
+ "seatHeaterHigh"
41
+ ];
42
+ /**
43
+ * Keyed by the REST `seat_position`, which Tesla's vehicle-command proxy reads
44
+ * as the proto enum value (1 front left, 2 front right), not the 0-based `Seats`.
45
+ */
46
+ const SeatCoolerPositions = {
47
+ [AutoSeat.FRONT_LEFT]: HvacSeatCoolerActions_HvacSeatCoolerPositionE.HvacSeatCoolerPosition_FrontLeft,
48
+ [AutoSeat.FRONT_RIGHT]: HvacSeatCoolerActions_HvacSeatCoolerPositionE.HvacSeatCoolerPosition_FrontRight
49
+ };
50
+ const SeatCoolerLevels = [
51
+ HvacSeatCoolerActions_HvacSeatCoolerLevelE.HvacSeatCoolerLevel_Off,
52
+ HvacSeatCoolerActions_HvacSeatCoolerLevelE.HvacSeatCoolerLevel_Low,
53
+ HvacSeatCoolerActions_HvacSeatCoolerLevelE.HvacSeatCoolerLevel_Med,
54
+ HvacSeatCoolerActions_HvacSeatCoolerLevelE.HvacSeatCoolerLevel_High
55
+ ];
56
+ /** Keyed by the 1-indexed `AutoSeat` REST value, which equals the proto enum value. */
57
+ const AutoSeatPositions = {
58
+ [AutoSeat.FRONT_LEFT]: AutoSeatClimateAction_AutoSeatPositionE.AutoSeatPosition_FrontLeft,
59
+ [AutoSeat.FRONT_RIGHT]: AutoSeatClimateAction_AutoSeatPositionE.AutoSeatPosition_FrontRight
60
+ };
61
+ /** Keyed by the REST `Level`, which takes 0, 1 and 3 here: the protocol has no medium steering wheel heat. */
62
+ const StwHeatLevels = {
63
+ 0: StwHeatLevel.StwHeatLevel_Off,
64
+ 1: StwHeatLevel.StwHeatLevel_Low,
65
+ 3: StwHeatLevel.StwHeatLevel_High
66
+ };
67
+ const ClimateKeeperActions = {
68
+ [ClimateModes.Off]: HvacClimateKeeperAction_ClimateKeeperActionE.ClimateKeeperAction_Off,
69
+ [ClimateModes.Keep]: HvacClimateKeeperAction_ClimateKeeperActionE.ClimateKeeperAction_On,
70
+ [ClimateModes.Dog]: HvacClimateKeeperAction_ClimateKeeperActionE.ClimateKeeperAction_Dog,
71
+ [ClimateModes.Camp]: HvacClimateKeeperAction_ClimateKeeperActionE.ClimateKeeperAction_Camp
72
+ };
73
+ /** `set_cop_temp` accepts either the enum index or the Celsius/Fahrenheit value it represents. */
74
+ const CopActivationTemps = {
75
+ 0: ClimateState_CopActivationTemp.CopActivationTempLow,
76
+ 30: ClimateState_CopActivationTemp.CopActivationTempLow,
77
+ 90: ClimateState_CopActivationTemp.CopActivationTempLow,
78
+ 1: ClimateState_CopActivationTemp.CopActivationTempMedium,
79
+ 35: ClimateState_CopActivationTemp.CopActivationTempMedium,
80
+ 95: ClimateState_CopActivationTemp.CopActivationTempMedium,
81
+ 2: ClimateState_CopActivationTemp.CopActivationTempHigh,
82
+ 40: ClimateState_CopActivationTemp.CopActivationTempHigh,
83
+ 100: ClimateState_CopActivationTemp.CopActivationTempHigh
84
+ };
85
+ function sleep(ms) {
86
+ return new Promise((resolve) => setTimeout(resolve, ms));
87
+ }
88
+ /**
89
+ * The name of a message's populated oneof field, as `WhichOneof` gives it in
90
+ * Python. ts-proto leaves unset oneof members `undefined`; `plainFields` names
91
+ * any fields outside the oneof, which always carry a value.
92
+ */
93
+ function populatedField(message, plainFields = []) {
94
+ return Object.entries(message).find(([key, value]) => value !== void 0 && !plainFields.includes(key))?.[0];
95
+ }
96
+ /** A short debug-log name for a VCSEC command: the RKE action name, or the populated field. */
97
+ function vcsec_command_name(command) {
98
+ if (command.RKEAction !== void 0) return rKEActionEToJSON(command.RKEAction);
99
+ return populatedField(command) ?? "unknown";
100
+ }
101
+ /** A short debug-log name for an infotainment command: the populated `VehicleAction` field. */
102
+ function infotainment_command_name(command) {
103
+ return (command.vehicleAction && populatedField(command.vehicleAction, ["dropNominalSuccessResponses"])) ?? "unknown";
104
+ }
105
+ function ok(reason = "") {
106
+ return { response: {
107
+ result: true,
108
+ reason
109
+ } };
110
+ }
111
+ function fail(reason) {
112
+ return { response: {
113
+ result: false,
114
+ reason
115
+ } };
116
+ }
117
+ /**
118
+ * Day names Tesla's vehicle-command proxy accepts for `days_of_week`, which the
119
+ * REST route takes as a comma-joined string rather than the proto bitmask.
120
+ */
121
+ const DAY_OF_WEEK_BITS = {
122
+ SUN: 1,
123
+ SUNDAY: 1,
124
+ MON: 2,
125
+ MONDAY: 2,
126
+ TUES: 4,
127
+ TUESDAY: 4,
128
+ WED: 8,
129
+ WEDNESDAY: 8,
130
+ THURS: 16,
131
+ THURSDAY: 16,
132
+ FRI: 32,
133
+ FRIDAY: 32,
134
+ SAT: 64,
135
+ SATURDAY: 64,
136
+ ALL: 127,
137
+ WEEKDAYS: 62
138
+ };
139
+ /**
140
+ * Convert a bitmask or comma-joined day names (e.g. `"Mon,Wed"`, `"All"`) to the proto bitmask.
141
+ * @throws Error for an unknown day name.
142
+ */
143
+ function days_of_week_mask(days_of_week) {
144
+ if (typeof days_of_week === "number") return Math.trunc(days_of_week);
145
+ if (/^\d+$/.test(days_of_week.trim())) return parseInt(days_of_week.trim(), 10);
146
+ let mask = 0;
147
+ for (const day of days_of_week.split(",")) {
148
+ const bit = DAY_OF_WEEK_BITS[day.trim().toUpperCase()];
149
+ if (bit === void 0) throw new Error(`Invalid day of week: ${day}`);
150
+ mask |= bit;
151
+ }
152
+ return mask;
153
+ }
154
+ /**
155
+ * Transport-agnostic signed-command builder for the Tesla Vehicle Command
156
+ * Protocol: mirrors `python-tesla-fleet-api`'s `Commands` ABC. Every method
157
+ * here builds a `RoutableMessage`, signs it by `authMethod`, and dispatches
158
+ * it through the single abstract seam `_send`. A concrete subclass fills that
159
+ * seam for one transport: the cloud `/signed_command` HTTP endpoint
160
+ * (`VehicleSigned`) today, a BLE GATT link next. The protected members are
161
+ * what such a transport builds on.
162
+ *
163
+ * `"hmac"` signs a plaintext command. `"aes"` encrypts it with AES-GCM and asks
164
+ * the vehicle to encrypt its reply, which firmware before 2024.38 ignores.
165
+ */
166
+ var Commands = class extends VehicleSpecific {
167
+ #privateKey;
168
+ #publicKey;
169
+ /** Delay between WAIT-retries; overridable so tests don't have to wait for real timers. */
170
+ retryDelayMs = 2e3;
171
+ /** Session-info requests sent before a handshake gives up on replies that fail authentication. */
172
+ handshakeAttempts = 3;
173
+ /** Delay between those requests. */
174
+ handshakeRetryDelayMs = 1e3;
175
+ /** How `buildMessage` signs a command. */
176
+ authMethod = "hmac";
177
+ /** One random routing address per instance: replies addressed to it are ours. */
178
+ fromDestination;
179
+ sessions;
180
+ /**
181
+ * @param parent
182
+ * @param vin
183
+ * @param privateKey Raw 32-byte P-256 scalar. `undefined` falls back to the parent's key, and throws if there is none. `false` disables signing, for a passive listener that never sends a command: any handshake then raises `SigningDisabled`.
184
+ * @param publicKey Uncompressed P-256 point. Derived from `privateKey` if omitted.
185
+ */
186
+ constructor(parent, vin, privateKey, publicKey) {
187
+ super(parent, vin);
188
+ if (vin.length !== 17) throw new Error(`Signed commands require a 17-character VIN, got ${vin.length} characters.`);
189
+ if (privateKey === false) this.#privateKey = null;
190
+ else {
191
+ const resolvedPrivateKey = privateKey ?? parent.private_key ?? parent.parent.private_key;
192
+ if (!resolvedPrivateKey) throw new Error("No private key provided for signed commands.");
193
+ this.#privateKey = resolvedPrivateKey;
194
+ }
195
+ this.#publicKey = publicKey ?? (this.#privateKey ? publicKeyFor(this.#privateKey) : Buffer.alloc(0));
196
+ this.fromDestination = crypto.randomBytes(16);
197
+ const deriveKey = (vehiclePublicKey) => this.shared_key(vehiclePublicKey);
198
+ this.sessions = {
199
+ [Domain.DOMAIN_VEHICLE_SECURITY]: new Session(Domain.DOMAIN_VEHICLE_SECURITY, deriveKey),
200
+ [Domain.DOMAIN_INFOTAINMENT]: new Session(Domain.DOMAIN_INFOTAINMENT, deriveKey)
201
+ };
202
+ }
203
+ /** The uncompressed public key this instance signs with. Empty when signing is disabled. */
204
+ get publicKey() {
205
+ return this.#publicKey;
206
+ }
207
+ /** Derive the 16-byte shared key used for signed-command session encryption. */
208
+ shared_key(vehicleKey) {
209
+ if (this.#privateKey === null) throw new SigningDisabled();
210
+ return deriveSharedKey(this.#privateKey, vehicleKey);
211
+ }
212
+ /** A Tesla.SS256 JWS over a Fleet Telemetry config, signed here so the key never leaves this class. */
213
+ signFleetTelemetryConfig(config) {
214
+ if (this.#privateKey === null) throw new SigningDisabled();
215
+ return sign_fleet_telemetry_config(this.#privateKey, config);
216
+ }
217
+ sessionFor(domain) {
218
+ const session = this.sessions[domain];
219
+ if (!session) throw new Error(`No signed-command session configured for domain ${domain}.`);
220
+ return session;
221
+ }
222
+ /**
223
+ * Absorb session info piggy-backed on any signed-command reply and raise
224
+ * on a whitelist rejection or a terminal message fault. Every concrete
225
+ * `_send` must call this on the reply - passing the `uuid` and destination
226
+ * domain of the request it just sent - before returning it. The session comes
227
+ * from that request: a reply's own `fromDestination` is unauthenticated, so it
228
+ * can only be checked against the request, never select a session.
229
+ *
230
+ * A `SessionInfo` is untrusted wire data until its `session_info_tag` is
231
+ * verified: the tag is an HMAC over the exact bytes received, bound to this
232
+ * request's `uuid` as a challenge (so a captured older reply can't be
233
+ * replayed against a newer request). It is keyed by the session's stored
234
+ * key. Only at first contact, when there is none, is that key derived from
235
+ * the public key in the reply, which is trust on first use; see `Session`.
236
+ * Only once that tag checks out do we act on anything the message claims -
237
+ * including its own whitelist-status field - and even then `Session.commit`
238
+ * still refuses a clock time that regresses within the same epoch.
239
+ *
240
+ * The one exception is an empty public key: no shared key can be derived
241
+ * from it to verify a tag. An unpaired key has no session, so
242
+ * key-not-on-whitelist is the only real reply that omits the key, and that
243
+ * one status is accepted unauthenticated. Any other status with no key is
244
+ * malformed.
245
+ */
246
+ validate_msg(resp, requestUuid, requestDomain) {
247
+ if (resp.sessionInfo && resp.sessionInfo.length > 0) {
248
+ const session = requestDomain !== void 0 ? this.sessions[requestDomain] : void 0;
249
+ if (!session || resp.fromDestination?.domain !== requestDomain) throw new SessionInfoAuthenticationFault("Session info reply is not from the domain the request went to; discarded.");
250
+ if (resp.requestUuid && resp.requestUuid.length > 0 && !requestUuid.equals(Buffer.from(resp.requestUuid))) throw new SessionInfoAuthenticationFault("Session info reply does not match an outstanding request; discarded.");
251
+ let info;
252
+ try {
253
+ info = SessionInfo.decode(resp.sessionInfo);
254
+ } catch (cause) {
255
+ throw new SessionInfoAuthenticationFault("Session info reply could not be decoded.", null, { cause });
256
+ }
257
+ if (info.publicKey.length === 0) {
258
+ if (info.status === SessionInfoStatus.SESSION_INFO_STATUS_KEY_NOT_ON_WHITELIST) throw new NotOnWhitelistFault();
259
+ throw new SessionInfoAuthenticationFault("Session info reply has no public key.");
260
+ }
261
+ let keys;
262
+ try {
263
+ keys = session.trustedKeys(Buffer.from(info.publicKey));
264
+ } catch (cause) {
265
+ if (cause instanceof SessionInfoAuthenticationFault || cause instanceof SigningDisabled) throw cause;
266
+ throw new SessionInfoAuthenticationFault("Session info reply has an invalid public key.", null, { cause });
267
+ }
268
+ const tag = resp.signatureData?.sessionInfoTag?.tag;
269
+ if (!tag || tag.length === 0) throw new SessionInfoAuthenticationFault("Session info reply is missing its authentication tag; discarded.");
270
+ const metadata = Buffer.concat([
271
+ Buffer.from([
272
+ Tag.TAG_SIGNATURE_TYPE,
273
+ 1,
274
+ SignatureType.SIGNATURE_TYPE_HMAC
275
+ ]),
276
+ Buffer.from([Tag.TAG_PERSONALIZATION, 17]),
277
+ Buffer.from(this.vin, "ascii"),
278
+ Buffer.from([Tag.TAG_CHALLENGE, requestUuid.length]),
279
+ requestUuid,
280
+ Buffer.from([Tag.TAG_END])
281
+ ]);
282
+ const expectedTag = crypto.createHmac("sha256", keys.sessionInfoKey).update(Buffer.concat([metadata, Buffer.from(resp.sessionInfo)])).digest();
283
+ const receivedTag = Buffer.from(tag);
284
+ if (expectedTag.length !== receivedTag.length || !crypto.timingSafeEqual(expectedTag, receivedTag)) throw new SessionInfoAuthenticationFault("Session info reply failed authentication (invalid tag); discarded.");
285
+ if (info.status === SessionInfoStatus.SESSION_INFO_STATUS_KEY_NOT_ON_WHITELIST) throw new NotOnWhitelistFault();
286
+ if (!session.commit(info, keys)) throw new SessionInfoAuthenticationFault("Session info reply is stale (clock regressed within the same epoch); discarded.");
287
+ }
288
+ const fault = resp.signedMessageStatus?.signedMessageFault;
289
+ if (fault !== void 0 && fault !== MessageFaultE.MESSAGEFAULT_ERROR_NONE) throw new (MESSAGE_FAULTS[fault] ?? TeslaFleetMessageFault)({ fault });
290
+ }
291
+ /** The unsigned session-info request that opens a domain session. */
292
+ sessionInfoRequest(domain) {
293
+ return RoutableMessage.create({
294
+ toDestination: { domain },
295
+ fromDestination: { routingAddress: this.fromDestination },
296
+ sessionInfoRequest: { publicKey: this.#publicKey },
297
+ uuid: crypto.randomBytes(16)
298
+ });
299
+ }
300
+ /**
301
+ * Open or refresh a domain session. A reply that fails authentication is
302
+ * discarded and the unsigned, idempotent request sent again, rather than
303
+ * failing the handshake on one bad reply. Never trusted either way.
304
+ *
305
+ * For VCSEC the caller must hold the session lock; `ensureHandshake` and
306
+ * `handshakeVehicleSecurity` do.
307
+ * @returns Whether the session can now sign.
308
+ * @throws SigningDisabled before anything is sent, when this instance has no key.
309
+ */
310
+ async handshake(domain, options) {
311
+ if (this.#privateKey === null) throw new SigningDisabled();
312
+ for (let attempt = 1;; attempt++) try {
313
+ await this._send(this.sessionInfoRequest(domain), "session_info", options);
314
+ return this.sessionFor(domain).ready;
315
+ } catch (error) {
316
+ if (!(error instanceof SessionInfoAuthenticationFault) || attempt >= this.handshakeAttempts) throw error;
317
+ await sleep(this.handshakeRetryDelayMs);
318
+ }
319
+ }
320
+ /**
321
+ * Open a domain session unless one is ready, for a subclass that must know
322
+ * it can sign before it dispatches. Do not call this from inside the VCSEC
323
+ * session lock, which it takes.
324
+ */
325
+ async ensureHandshake(domain) {
326
+ const session = this.sessionFor(domain);
327
+ if (domain !== Domain.DOMAIN_VEHICLE_SECURITY) {
328
+ if (!session.ready) await this.handshake(domain);
329
+ return;
330
+ }
331
+ await session.withLock(async () => {
332
+ if (!session.ready) await this.handshake(domain);
333
+ });
334
+ }
335
+ /** Perform a handshake with the vehicle security domain, even if a session is already established. */
336
+ async handshakeVehicleSecurity() {
337
+ await this.sessionFor(Domain.DOMAIN_VEHICLE_SECURITY).withLock(() => this.handshake(Domain.DOMAIN_VEHICLE_SECURITY));
338
+ }
339
+ /** Perform a handshake with the infotainment domain, even if a session is already established. */
340
+ async handshakeInfotainment() {
341
+ await this.handshake(Domain.DOMAIN_INFOTAINMENT);
342
+ }
343
+ /** Sign `command` for `session` by `authMethod`. Assigns a counter, so run it under the session lock. */
344
+ buildMessage(session, command) {
345
+ return this.authMethod === "aes" ? this.buildAesMessage(session, command) : this.buildHmacMessage(session, command);
346
+ }
347
+ buildHmacMessage(session, command) {
348
+ const personalized = session.hmacPersonalized();
349
+ if (!session.hmacKey) throw new Error("Session HMAC key is missing.");
350
+ const metadata = Buffer.concat([
351
+ Buffer.from([
352
+ Tag.TAG_SIGNATURE_TYPE,
353
+ 1,
354
+ SignatureType.SIGNATURE_TYPE_HMAC_PERSONALIZED
355
+ ]),
356
+ Buffer.from([
357
+ Tag.TAG_DOMAIN,
358
+ 1,
359
+ session.domain
360
+ ]),
361
+ Buffer.from([Tag.TAG_PERSONALIZATION, 17]),
362
+ Buffer.from(this.vin, "ascii"),
363
+ Buffer.from([Tag.TAG_EPOCH, personalized.epoch.length]),
364
+ Buffer.from(personalized.epoch),
365
+ Buffer.from([Tag.TAG_EXPIRES_AT, 4]),
366
+ uint32BE(personalized.expiresAt),
367
+ Buffer.from([Tag.TAG_COUNTER, 4]),
368
+ uint32BE(personalized.counter),
369
+ Buffer.from([Tag.TAG_END])
370
+ ]);
371
+ const tag = crypto.createHmac("sha256", session.hmacKey).update(Buffer.concat([metadata, command])).digest();
372
+ return RoutableMessage.create({
373
+ toDestination: { domain: session.domain },
374
+ fromDestination: { routingAddress: this.fromDestination },
375
+ protobufMessageAsBytes: command,
376
+ uuid: crypto.randomBytes(16),
377
+ signatureData: {
378
+ signerIdentity: KeyIdentity.create({ publicKey: this.#publicKey }),
379
+ HMACPersonalizedData: {
380
+ ...personalized,
381
+ tag
382
+ }
383
+ }
384
+ });
385
+ }
386
+ buildAesMessage(session, command) {
387
+ const personalized = session.aesGcmPersonalized();
388
+ if (!session.sharedKey) throw new Error("Session shared key is missing.");
389
+ const flags = 1 << Flags.FLAG_ENCRYPT_RESPONSE;
390
+ const metadata = Buffer.concat([
391
+ Buffer.from([
392
+ Tag.TAG_SIGNATURE_TYPE,
393
+ 1,
394
+ SignatureType.SIGNATURE_TYPE_AES_GCM_PERSONALIZED
395
+ ]),
396
+ Buffer.from([
397
+ Tag.TAG_DOMAIN,
398
+ 1,
399
+ session.domain
400
+ ]),
401
+ Buffer.from([Tag.TAG_PERSONALIZATION, 17]),
402
+ Buffer.from(this.vin, "ascii"),
403
+ Buffer.from([Tag.TAG_EPOCH, personalized.epoch.length]),
404
+ Buffer.from(personalized.epoch),
405
+ Buffer.from([Tag.TAG_EXPIRES_AT, 4]),
406
+ uint32BE(personalized.expiresAt),
407
+ Buffer.from([Tag.TAG_COUNTER, 4]),
408
+ uint32BE(personalized.counter),
409
+ Buffer.from([Tag.TAG_FLAGS, 4]),
410
+ uint32BE(flags),
411
+ Buffer.from([Tag.TAG_END])
412
+ ]);
413
+ const { ciphertext, tag } = aesGcmEncrypt(session.sharedKey, personalized.nonce, command, sha256(metadata));
414
+ return RoutableMessage.create({
415
+ toDestination: { domain: session.domain },
416
+ fromDestination: { routingAddress: this.fromDestination },
417
+ protobufMessageAsBytes: ciphertext,
418
+ uuid: crypto.randomBytes(16),
419
+ flags,
420
+ signatureData: {
421
+ signerIdentity: KeyIdentity.create({ publicKey: this.#publicKey }),
422
+ AESGCMPersonalizedData: {
423
+ ...personalized,
424
+ tag
425
+ }
426
+ }
427
+ });
428
+ }
429
+ /** The authentication method of `request` followed by its tag, which a response's metadata binds to. */
430
+ requestHash(session, request) {
431
+ const aes = request.signatureData?.AESGCMPersonalizedData;
432
+ if (aes) return Buffer.concat([Buffer.from([SignatureType.SIGNATURE_TYPE_AES_GCM_PERSONALIZED]), aes.tag]);
433
+ const hmac = request.signatureData?.HMACPersonalizedData;
434
+ if (!hmac) throw new Error("Invalid request signature data.");
435
+ const hash = Buffer.concat([Buffer.from([SignatureType.SIGNATURE_TYPE_HMAC_PERSONALIZED]), hmac.tag]);
436
+ return session.domain === Domain.DOMAIN_VEHICLE_SECURITY ? hash.subarray(0, 17) : hash;
437
+ }
438
+ /**
439
+ * Open an encrypted reply to `request`. A reply with no `AESGCMResponseData`
440
+ * is plaintext and comes back as it is.
441
+ *
442
+ * A reply that fails to open cannot be trusted, and says nothing about
443
+ * whether the command ran.
444
+ * @returns The reply with its payload in the clear.
445
+ * @throws Error when the reply fails to open.
446
+ * @throws SignedCommandResponseReplayed when this request already saw this response counter.
447
+ */
448
+ decryptResponse(session, request, resp) {
449
+ const data = resp.signatureData?.AESGCMResponseData;
450
+ if (!data || resp.protobufMessageAsBytes === void 0) return resp;
451
+ if (!session.sharedKey) throw new Error("Session shared key is missing.");
452
+ const requestHash = this.requestHash(session, request);
453
+ const metadata = Buffer.concat([
454
+ Buffer.from([
455
+ Tag.TAG_SIGNATURE_TYPE,
456
+ 1,
457
+ SignatureType.SIGNATURE_TYPE_AES_GCM_RESPONSE
458
+ ]),
459
+ Buffer.from([
460
+ Tag.TAG_DOMAIN,
461
+ 1,
462
+ resp.fromDestination?.domain ?? Domain.DOMAIN_BROADCAST
463
+ ]),
464
+ Buffer.from([Tag.TAG_PERSONALIZATION, 17]),
465
+ Buffer.from(this.vin, "ascii"),
466
+ Buffer.from([Tag.TAG_COUNTER, 4]),
467
+ uint32BE(data.counter),
468
+ Buffer.from([Tag.TAG_FLAGS, 4]),
469
+ uint32BE(resp.flags),
470
+ Buffer.from([Tag.TAG_REQUEST_HASH, requestHash.length]),
471
+ requestHash,
472
+ Buffer.from([Tag.TAG_FAULT, 4]),
473
+ uint32BE(resp.signedMessageStatus?.signedMessageFault ?? 0),
474
+ Buffer.from([Tag.TAG_END])
475
+ ]);
476
+ const plaintext = aesGcmDecrypt(session.sharedKey, data.nonce, resp.protobufMessageAsBytes, data.tag, sha256(metadata));
477
+ if (!session.record_response_counter(requestHash, data.counter)) throw new SignedCommandResponseReplayed();
478
+ return {
479
+ ...resp,
480
+ protobufMessageAsBytes: plaintext
481
+ };
482
+ }
483
+ /**
484
+ * Build, sign, dispatch (with WAIT/epoch-fault retry), and interpret one
485
+ * domain command.
486
+ *
487
+ * VCSEC requires messages to arrive in strict counter order and warns
488
+ * clients to avoid simultaneous requests to it at all (unlike
489
+ * Infotainment, which tolerates a sliding window) - so for
490
+ * `DOMAIN_VEHICLE_SECURITY` the *entire* dispatch (handshake, build,
491
+ * send, and any retry) runs under the domain's lock, guaranteeing at
492
+ * most one VCSEC message is ever in flight. Infotainment keeps the
493
+ * narrower build-only lock, serializing only counter assignment.
494
+ */
495
+ async dispatch(domain, command, options = {}) {
496
+ const session = this.sessionFor(domain);
497
+ const serializeWholeDispatch = domain === Domain.DOMAIN_VEHICLE_SECURITY;
498
+ const run = async () => {
499
+ if (!session.ready) await this.handshake(domain);
500
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
501
+ const msg = serializeWholeDispatch ? this.buildMessage(session, command) : await session.withLock(() => this.buildMessage(session, command));
502
+ let resp;
503
+ try {
504
+ resp = await this._send(msg, "protobuf_message_as_bytes", options);
505
+ } catch (error) {
506
+ if ((error instanceof TeslaFleetMessageFaultIncorrectEpoch || error instanceof TeslaFleetMessageFaultInvalidTokenOrCounter) && attempt < 3) continue;
507
+ throw error;
508
+ }
509
+ if (resp.signedMessageStatus?.operationStatus === OperationStatusE.OPERATIONSTATUS_WAIT) {
510
+ if (attempt >= 3) return fail("Too many retries");
511
+ await sleep(this.retryDelayMs);
512
+ continue;
513
+ }
514
+ const result = this.interpretResponse(this.decryptResponse(session, msg, resp), options.expectsData ?? true);
515
+ if (result === "wait") {
516
+ if (attempt >= 3) return fail("Too many retries");
517
+ await sleep(this.retryDelayMs);
518
+ continue;
519
+ }
520
+ return result;
521
+ }
522
+ return fail("Too many retries");
523
+ };
524
+ return serializeWholeDispatch ? session.withLock(run) : run();
525
+ }
526
+ interpretResponse(resp, expectsData) {
527
+ if (!resp.protobufMessageAsBytes || resp.protobufMessageAsBytes.length === 0) return ok();
528
+ const domain = resp.fromDestination?.domain;
529
+ if (domain === Domain.DOMAIN_VEHICLE_SECURITY) return this.interpretVcsecResponse(resp.protobufMessageAsBytes, expectsData);
530
+ if (domain === Domain.DOMAIN_INFOTAINMENT) return this.interpretInfotainmentResponse(resp.protobufMessageAsBytes);
531
+ return ok();
532
+ }
533
+ interpretVcsecResponse(bytes, expectsData) {
534
+ const vcsec = FromVCSECMessage.decode(bytes);
535
+ if (vcsec.nominalError) return fail(genericErrorEToJSON(vcsec.nominalError.genericError));
536
+ if (vcsec.vehicleStatus) return expectsData ? { response: vcsec.vehicleStatus } : ok();
537
+ if (vcsec.commandStatus) {
538
+ const status = vcsec.commandStatus;
539
+ if (status.operationStatus === OperationStatusE$1.OPERATIONSTATUS_OK) {
540
+ this.raiseWhitelistFault(status.whitelistOperationStatus?.whitelistOperationInformation);
541
+ return ok();
542
+ }
543
+ if (status.operationStatus === OperationStatusE$1.OPERATIONSTATUS_WAIT) return "wait";
544
+ if (status.operationStatus === OperationStatusE$1.OPERATIONSTATUS_ERROR) {
545
+ if (status.signedMessageStatus) {
546
+ const information = status.signedMessageStatus.signedMessageInformation;
547
+ const cls = SIGNED_MESSAGE_INFORMATION_FAULTS[information];
548
+ if (cls) throw new cls({ information: signedMessageInformationEToJSON(information) });
549
+ } else this.raiseWhitelistFault(status.whitelistOperationStatus?.whitelistOperationInformation);
550
+ return fail(operationStatusEToJSON(status.operationStatus));
551
+ }
552
+ }
553
+ return ok();
554
+ }
555
+ raiseWhitelistFault(information) {
556
+ if (!information) return;
557
+ if (information >= WHITELIST_OPERATION_STATUS.length) throw new WhitelistOperationStatus(`Unknown whitelist operation failure: ${information}`);
558
+ const cls = WHITELIST_OPERATION_STATUS[information];
559
+ if (cls) throw new cls({ information: whitelistOperationInformationEToJSON(information) });
560
+ }
561
+ interpretInfotainmentResponse(bytes) {
562
+ const response = Response.decode(bytes);
563
+ if (response.ping) return ok(response.ping.localTimestamp?.toISOString() ?? "");
564
+ if (response.vehicleData) return { response: response.vehicleData };
565
+ const field = populatedField(response, ["actionStatus"]);
566
+ const data = field ? { [field]: response[field] } : {};
567
+ if (response.actionStatus) return { response: {
568
+ result: response.actionStatus.result === OperationStatusE$2.OPERATIONSTATUS_OK,
569
+ reason: response.actionStatus.resultReason?.plainText ?? "",
570
+ ...data
571
+ } };
572
+ return { response: {
573
+ result: true,
574
+ reason: "",
575
+ ...data
576
+ } };
577
+ }
578
+ /** Dispatch one signed command, logging its name, transport and outcome. */
579
+ async dispatchLogged(name, domain, command, options) {
580
+ const log = (message) => this.parent.parent._log(message);
581
+ let result;
582
+ try {
583
+ result = await this.dispatch(domain, command, options);
584
+ } catch (error) {
585
+ logRequestError(log, name, this._transport_name, error);
586
+ throw error;
587
+ }
588
+ logRequestResult(log, name, this._transport_name, result);
589
+ return result;
590
+ }
591
+ /** The data a read asked for. A reply that only reports an outcome carries none. */
592
+ readData(reply) {
593
+ if ("result" in reply.response) throw new InvalidResponse({
594
+ result: reply.response.result,
595
+ reason: reply.response.reason
596
+ });
597
+ return reply.response;
598
+ }
599
+ /** One `getVehicleImageState` read, with the single image its reply must carry. */
600
+ async readVehicleImage(request) {
601
+ const data = await this._getInfotainment(Action.create({ vehicleAction: VehicleAction.create({ getVehicleData: GetVehicleData.create({ getVehicleImageState: GetVehicleImageState.create({ imageRequests: [VehicleImageRequest.create(request)] }) }) }) }));
602
+ const image = data.vehicleImageState?.vehicleImages[0];
603
+ if (!image) throw new InvalidResponse({ vehicleImageState: data.vehicleImageState ?? null });
604
+ return image;
605
+ }
606
+ /**
607
+ * Fetches a rendered vehicle image and returns its assembled bytes. Unlike
608
+ * any other read it is paged: an `ID` request reports the total size, then
609
+ * `DATA` requests advance by `chunk_size` until the whole range has arrived.
610
+ * @param image_type `VehicleImageType`
611
+ * @param chunk_size Bytes per request. A transport with a small frame needs a smaller value than the default.
612
+ * @throws Error when `chunk_size` is invalid, before anything is sent, or when the chunks do not add up to the reported size.
613
+ * @throws InvalidResponse when a reply carries no image.
614
+ */
615
+ async vehicle_image_state(image_type, chunk_size = 16384) {
616
+ if (!Number.isInteger(chunk_size) || chunk_size <= 0) throw new Error("chunk_size must be a positive integer");
617
+ const { totalImageSize: totalSize } = await this.readVehicleImage({
618
+ dataType: VehicleImageRequest_Type.ID,
619
+ imageType: image_type
620
+ });
621
+ const chunks = [];
622
+ let offset = 0;
623
+ while (offset < totalSize) {
624
+ const { assetData } = await this.readVehicleImage({
625
+ dataType: VehicleImageRequest_Type.DATA,
626
+ imageType: image_type,
627
+ chunkRequest: VehicleImageDataChunkRequest.create({
628
+ chunkOffset: offset,
629
+ chunkSize: Math.min(chunk_size, totalSize - offset)
630
+ })
631
+ });
632
+ const startOffset = assetData?.startOffset ?? 0;
633
+ if (startOffset !== offset) throw new Error(`Unexpected vehicle image chunk offset ${startOffset}; expected ${offset}`);
634
+ const chunk = assetData?.data;
635
+ if (!chunk || chunk.length === 0) throw new Error(`Vehicle image ended after ${offset} of ${totalSize} bytes`);
636
+ chunks.push(chunk);
637
+ offset += chunk.length;
638
+ if (offset > totalSize) throw new Error(`Vehicle image exceeded declared size of ${totalSize} bytes`);
639
+ }
640
+ return Buffer.concat(chunks);
641
+ }
642
+ /** Sign and send an actuation: its reply is a bare terminal ack, so `expectsData` is false. */
643
+ async sendVehicleSecurity(command, options = {}) {
644
+ return await this.dispatchLogged(vcsec_command_name(command), Domain.DOMAIN_VEHICLE_SECURITY, Buffer.from(UnsignedMessage.encode(command).finish()), {
645
+ ...options,
646
+ expectsData: false
647
+ });
648
+ }
649
+ /**
650
+ * Sign and send a read to the Vehicle Security computer.
651
+ * @throws InvalidResponse when the reply carries no `VehicleStatus`.
652
+ */
653
+ async _getVehicleSecurity(command) {
654
+ const reply = await this.dispatchLogged(vcsec_command_name(command), Domain.DOMAIN_VEHICLE_SECURITY, Buffer.from(UnsignedMessage.encode(command).finish()));
655
+ return this.readData(reply);
656
+ }
657
+ /**
658
+ * Sign and send a command to the Infotainment computer. Reads go through
659
+ * `_getInfotainment`. `mutating` is false for a command that cannot change
660
+ * the vehicle, so a transport can give up on it rather than ask whether it
661
+ * ran; `ping` is the only one. The cloud transport has no use for it.
662
+ */
663
+ async sendInfotainment(action, { onSubmitted } = {}) {
664
+ return await this.dispatchLogged(infotainment_command_name(action), Domain.DOMAIN_INFOTAINMENT, Buffer.from(Action.encode(action).finish()), { onSubmitted });
665
+ }
666
+ /**
667
+ * Sign and send a read to the Infotainment computer.
668
+ * @throws InvalidResponse when the reply carries no `VehicleData`.
669
+ */
670
+ async _getInfotainment(action) {
671
+ const reply = await this.dispatchLogged(infotainment_command_name(action), Domain.DOMAIN_INFOTAINMENT, Buffer.from(Action.encode(action).finish()));
672
+ return this.readData(reply);
673
+ }
674
+ vehicleAction(action, options) {
675
+ return this.sendInfotainment(Action.create({ vehicleAction: action }), options);
676
+ }
677
+ moveTonneau(tonneau) {
678
+ return this.sendVehicleSecurity(UnsignedMessage.create({ closureMoveRequest: ClosureMoveRequest.create({ tonneau }) }));
679
+ }
680
+ resolveSeat(seat_position) {
681
+ return typeof seat_position === "string" ? Seats[seat_position] : seat_position;
682
+ }
683
+ /** Pings the vehicle. On success, `reason` is the vehicle's timestamp in ISO 8601. */
684
+ async ping() {
685
+ return this.vehicleAction(VehicleAction.create({ ping: Ping.create({ pingId: 0 }) }), { mutating: false });
686
+ }
687
+ /**
688
+ * Add or modify a charging schedule. At least one of `start_time` or `end_time` is required.
689
+ * @param days_of_week Comma-joined day names (e.g. `"Mon,Wed"`, `"All"`, `"Weekdays"`) or a day bitmask
690
+ * @param enabled `true` or `false`
691
+ * @param lat Latitude of the schedule's location
692
+ * @param lon Longitude of the schedule's location
693
+ * @param start_time Minutes after midnight to start charging
694
+ * @param end_time Minutes after midnight to stop charging
695
+ * @param one_time Run the schedule only once
696
+ * @param id Schedule ID to modify an existing schedule
697
+ * @param name Schedule name
698
+ */
699
+ async add_charge_schedule(days_of_week, enabled, lat, lon, start_time, end_time, one_time, id, name) {
700
+ if (start_time == null && end_time == null) throw new Error("Either start_time or end_time or both must be provided");
701
+ return this.vehicleAction(VehicleAction.create({ addChargeScheduleAction: ChargeSchedule.create({
702
+ daysOfWeek: days_of_week_mask(days_of_week),
703
+ enabled,
704
+ startEnabled: start_time != null,
705
+ endEnabled: end_time != null,
706
+ latitude: lat,
707
+ longitude: lon,
708
+ startTime: start_time,
709
+ endTime: end_time,
710
+ oneTime: one_time,
711
+ id,
712
+ name
713
+ }) }));
714
+ }
715
+ /**
716
+ * Registers a managed charging site, for a utility managed-charging program, on this vehicle.
717
+ * @param public_key The raw EC point string the vehicle expects, not the DER a gateway's `get_signed_commands_public_key` returns
718
+ * @param din The gateway's DIN, which the vehicle matches to the site controller
719
+ * @param lat Latitude
720
+ * @param lon Longitude
721
+ */
722
+ async add_managed_charging_site(public_key, din, lat, lon) {
723
+ return this.vehicleAction(VehicleAction.create({ addManagedChargingSiteRequest: AddManagedChargingSiteRequest.create({ site: ManagedChargingSite.create({
724
+ publicKey: public_key,
725
+ managerType: ManagerType.create({ siteController: SiteController.create({ din }) }),
726
+ latLon: LatLong.create({
727
+ latitude: lat,
728
+ longitude: lon
729
+ })
730
+ }) }) }));
731
+ }
732
+ /**
733
+ * Add or modify a preconditioning schedule.
734
+ * @param days_of_week Comma-joined day names (e.g. `"Mon,Wed"`, `"All"`, `"Weekdays"`) or a day bitmask
735
+ * @param enabled `true` or `false`
736
+ * @param lat Latitude of the schedule's location
737
+ * @param lon Longitude of the schedule's location
738
+ * @param precondition_time Minutes after midnight to be preconditioned by
739
+ * @param id Schedule ID to modify an existing schedule
740
+ * @param one_time Run the schedule only once
741
+ * @param name Schedule name
742
+ */
743
+ async add_precondition_schedule(days_of_week, enabled, lat, lon, precondition_time, id, one_time, name) {
744
+ return this.vehicleAction(VehicleAction.create({ addPreconditionScheduleAction: PreconditionSchedule.create({
745
+ daysOfWeek: days_of_week_mask(days_of_week),
746
+ enabled,
747
+ preconditionTime: precondition_time,
748
+ latitude: lat,
749
+ longitude: lon,
750
+ oneTime: one_time,
751
+ id,
752
+ name
753
+ }) }));
754
+ }
755
+ /**
756
+ * Controls the front (which_trunk: "front") or rear (which_trunk: "rear") trunk.
757
+ * @param which_trunk "front" or "rear"
758
+ */
759
+ async actuate_trunk(which_trunk) {
760
+ const field = TrunkFields[which_trunk];
761
+ if (!field) throw new Error(`Invalid trunk: ${which_trunk}`);
762
+ const closureMoveRequest = {};
763
+ closureMoveRequest[field] = ClosureMoveTypeE.CLOSURE_MOVE_TYPE_MOVE;
764
+ return this.sendVehicleSecurity(UnsignedMessage.create({ closureMoveRequest: ClosureMoveRequest.create(closureMoveRequest) }));
765
+ }
766
+ /**
767
+ * Adjusts vehicle media playback volume.
768
+ * @param volume A floating point number from 0.0 to 11.0.
769
+ */
770
+ async adjust_volume(volume) {
771
+ if (volume < 0 || volume > 11) throw new Error("Volume must a number from 0.0 to 11.0");
772
+ return this.vehicleAction(VehicleAction.create({ mediaUpdateVolume: MediaUpdateVolume.create({ volumeAbsoluteFloat: volume }) }));
773
+ }
774
+ /** Starts climate preconditioning. */
775
+ async auto_conditioning_start() {
776
+ return this.vehicleAction(VehicleAction.create({ hvacAutoAction: HvacAutoAction.create({ powerOn: true }) }));
777
+ }
778
+ /** Stops climate preconditioning. */
779
+ async auto_conditioning_stop() {
780
+ return this.vehicleAction(VehicleAction.create({ hvacAutoAction: HvacAutoAction.create({ powerOn: false }) }));
781
+ }
782
+ /** Auto secures the vehicle: locks it and closes what it can. */
783
+ async auto_secure_vehicle() {
784
+ return this.sendVehicleSecurity(UnsignedMessage.create({ RKEAction: RKEActionE.RKE_ACTION_AUTO_SECURE_VEHICLE }));
785
+ }
786
+ /**
787
+ * Removes charging schedules by location type.
788
+ * @param home Remove schedules at home
789
+ * @param work Remove schedules at work
790
+ * @param other Remove schedules at other locations
791
+ */
792
+ async batch_remove_charge_schedules(home, work, other) {
793
+ return this.vehicleAction(VehicleAction.create({ batchRemoveChargeSchedulesAction: BatchRemoveChargeSchedulesAction.create({
794
+ home,
795
+ work,
796
+ other
797
+ }) }));
798
+ }
799
+ /**
800
+ * Removes preconditioning schedules by location type.
801
+ * @param home Remove schedules at home
802
+ * @param work Remove schedules at work
803
+ * @param other Remove schedules at other locations
804
+ */
805
+ async batch_remove_precondition_schedules(home, work, other) {
806
+ return this.vehicleAction(VehicleAction.create({ batchRemovePreconditionSchedulesAction: BatchRemovePreconditionSchedulesAction.create({
807
+ home,
808
+ work,
809
+ other
810
+ }) }));
811
+ }
812
+ /** Cancels the countdown to install the vehicle software update. */
813
+ async cancel_software_update() {
814
+ return this.vehicleAction(VehicleAction.create({ vehicleControlCancelSoftwareUpdateAction: VehicleControlCancelSoftwareUpdateAction.create({}) }));
815
+ }
816
+ /** Cancels a State of Health test. */
817
+ async cancel_soh_test() {
818
+ return this.vehicleAction(VehicleAction.create({ cancelSohTestAction: CancelSohTestAction.create({}) }));
819
+ }
820
+ /** Charges in max range mode -- we recommend limiting the use of this mode to long trips. */
821
+ async charge_max_range() {
822
+ return this.vehicleAction(VehicleAction.create({ chargingStartStopAction: ChargingStartStopAction.create({ startMaxRange: VOID }) }));
823
+ }
824
+ /** Closes the charge port door. */
825
+ async charge_port_door_close() {
826
+ return this.sendVehicleSecurity(UnsignedMessage.create({ closureMoveRequest: ClosureMoveRequest.create({ chargePort: ClosureMoveTypeE.CLOSURE_MOVE_TYPE_CLOSE }) }));
827
+ }
828
+ /** Opens the charge port door. */
829
+ async charge_port_door_open() {
830
+ return this.sendVehicleSecurity(UnsignedMessage.create({ closureMoveRequest: ClosureMoveRequest.create({ chargePort: ClosureMoveTypeE.CLOSURE_MOVE_TYPE_OPEN }) }));
831
+ }
832
+ /** Charges in Standard mode. */
833
+ async charge_standard() {
834
+ return this.vehicleAction(VehicleAction.create({ chargingStartStopAction: ChargingStartStopAction.create({ startStandard: VOID }) }));
835
+ }
836
+ /** Starts charging the vehicle. */
837
+ async charge_start() {
838
+ return this.vehicleAction(VehicleAction.create({ chargingStartStopAction: ChargingStartStopAction.create({ start: VOID }) }));
839
+ }
840
+ /** Stops charging the vehicle. */
841
+ async charge_stop() {
842
+ return this.vehicleAction(VehicleAction.create({ chargingStartStopAction: ChargingStartStopAction.create({ stop: VOID }) }));
843
+ }
844
+ /**
845
+ * Deactivates PIN to Drive and resets the associated PIN for vehicles running firmware versions 2023.44+. This command is only accessible to fleet managers or owners.
846
+ * @param _pin Accepted for parity with the REST command; the signed action carries no PIN.
847
+ */
848
+ async clear_pin_to_drive_admin(_pin) {
849
+ return this.reset_pin_to_drive_admin();
850
+ }
851
+ /** Closes the Cybertruck tonneau cover. */
852
+ async close_tonneau() {
853
+ return this.moveTonneau(ClosureMoveTypeE.CLOSURE_MOVE_TYPE_CLOSE);
854
+ }
855
+ /** Saves a dashcam clip. */
856
+ async dashcam_save_clip() {
857
+ return this.vehicleAction(VehicleAction.create({ dashcamSaveClipAction: DashcamSaveClipAction.create({}) }));
858
+ }
859
+ /** Locks the vehicle. */
860
+ async door_lock() {
861
+ return this.sendVehicleSecurity(UnsignedMessage.create({ RKEAction: RKEActionE.RKE_ACTION_LOCK }));
862
+ }
863
+ /** Unlocks the vehicle. */
864
+ async door_unlock() {
865
+ return this.sendVehicleSecurity(UnsignedMessage.create({ RKEAction: RKEActionE.RKE_ACTION_UNLOCK }));
866
+ }
867
+ /** Erases user's data from the user interface. Requires the vehicle to be in park. */
868
+ async erase_user_data() {
869
+ return this.vehicleAction(VehicleAction.create({ eraseUserDataAction: EraseUserDataAction.create({}) }));
870
+ }
871
+ /** Briefly flashes the vehicle headlights. Requires the vehicle to be in park. */
872
+ async flash_lights() {
873
+ return this.vehicleAction(VehicleAction.create({ vehicleControlFlashLightsAction: VehicleControlFlashLightsAction.create({}) }));
874
+ }
875
+ /** Gets the charge on solar settings, under `response.getChargeOnSolarFeatureResponse`. */
876
+ async get_charge_on_solar() {
877
+ return this.vehicleAction(VehicleAction.create({ getChargeOnSolarFeatureRequest: GetChargeOnSolarFeatureRequest.create({}) }), { mutating: false });
878
+ }
879
+ /** Gets the registered managed charging sites, under `response.getManagedChargingSitesResponse`. */
880
+ async get_managed_charging_sites() {
881
+ return this.vehicleAction(VehicleAction.create({ getManagedChargingSitesRequest: GetManagedChargingSitesRequest.create({}) }), { mutating: false });
882
+ }
883
+ /** Gets vehicle in-car messages. The reply carries the vehicle's response under `getMessagesResponse`, if it sends one. */
884
+ async get_messages() {
885
+ return this.vehicleAction(VehicleAction.create({ getMessagesAction: GetMessagesAction.create({}) }), { mutating: false });
886
+ }
887
+ /** Gets the current time-of-use rate tariff schedule, under `response.getRateTariffResponse`. */
888
+ async get_rate_tariff() {
889
+ return this.vehicleAction(VehicleAction.create({ getRateTariffRequest: GetRateTariffRequest.create({}) }), { mutating: false });
890
+ }
891
+ /**
892
+ * Restricts certain vehicle UI functionality from guest users
893
+ * @param enable `true` or `false`
894
+ */
895
+ async guest_mode(enable) {
896
+ return this.vehicleAction(VehicleAction.create({ guestModeAction: VehicleState_GuestMode.create({ GuestModeActive: enable }) }));
897
+ }
898
+ /** Honks the vehicle horn. Requires the vehicle to be in park. */
899
+ async honk_horn() {
900
+ return this.vehicleAction(VehicleAction.create({ vehicleControlHonkHornAction: VehicleControlHonkHornAction.create({}) }));
901
+ }
902
+ /** Advances media player to next favorite track. */
903
+ async media_next_fav() {
904
+ return this.vehicleAction(VehicleAction.create({ mediaNextFavorite: {} }));
905
+ }
906
+ /** Advances media player to next track. */
907
+ async media_next_track() {
908
+ return this.vehicleAction(VehicleAction.create({ mediaNextTrack: {} }));
909
+ }
910
+ /** Advances media player to previous favorite track. */
911
+ async media_prev_fav() {
912
+ return this.vehicleAction(VehicleAction.create({ mediaPreviousFavorite: {} }));
913
+ }
914
+ /** Advances media player to previous track. */
915
+ async media_prev_track() {
916
+ return this.vehicleAction(VehicleAction.create({ mediaPreviousTrack: {} }));
917
+ }
918
+ /** Toggles current play/pause state. */
919
+ async media_toggle_playback() {
920
+ return this.vehicleAction(VehicleAction.create({ mediaPlayAction: {} }));
921
+ }
922
+ /** Turns the volume down by one. */
923
+ async media_volume_down() {
924
+ return this.vehicleAction(VehicleAction.create({ mediaUpdateVolume: MediaUpdateVolume.create({ volumeDelta: -1 }) }));
925
+ }
926
+ /** Turns the volume up by one. */
927
+ async media_volume_up() {
928
+ return this.vehicleAction(VehicleAction.create({ mediaUpdateVolume: MediaUpdateVolume.create({ volumeDelta: 1 }) }));
929
+ }
930
+ /**
931
+ * Start navigation to coordinates with a named destination.
932
+ * @param lat Latitude
933
+ * @param lon Longitude
934
+ * @param destination Destination name
935
+ * @param order Trip order: `0` replaces the current trip (default), `1` prepends it as the next stop, `2` appends it as the last stop
936
+ */
937
+ async navigation_gps_destination_request(lat, lon, destination, order = 0) {
938
+ return this.vehicleAction(VehicleAction.create({ navigationGpsDestinationRequest: NavigationGpsDestinationRequest.create({
939
+ lat,
940
+ lon,
941
+ destination,
942
+ order
943
+ }) }));
944
+ }
945
+ /**
946
+ * Start navigation to given coordinates.
947
+ * @param lat Latitude
948
+ * @param lon Longitude
949
+ * @param order Trip order: `0` replaces the current trip (default), `1` prepends it as the next stop, `2` appends it as the last stop
950
+ */
951
+ async navigation_gps_request(lat, lon, order = 0) {
952
+ return this.vehicleAction(VehicleAction.create({ navigationGpsRequest: NavigationGpsRequest.create({
953
+ lat,
954
+ lon,
955
+ order
956
+ }) }));
957
+ }
958
+ /**
959
+ * Sends a location to the in-vehicle navigation system.
960
+ *
961
+ * `type`, `locale` and `timestamp_ms` are REST-only fields with no equivalent
962
+ * in the signed-command protocol, which only carries a destination string
963
+ * and a multi-stop order. They keep REST's positions, so the router's types
964
+ * agree, and are not sent.
965
+ * @param value Destination text
966
+ */
967
+ async navigation_request(value, _type, _locale, _timestamp_ms) {
968
+ return this.vehicleAction(VehicleAction.create({ navigationRequest: NavigationRequest.create({ destination: value }) }));
969
+ }
970
+ /**
971
+ * Start navigation to a supercharger.
972
+ * @param id Supercharger ID
973
+ * @param order Trip order: `0` replaces the current trip (default), `1` prepends it as the next stop, `2` appends it as the last stop
974
+ */
975
+ async navigation_sc_request(id, order) {
976
+ return this.vehicleAction(VehicleAction.create({ navigationSuperchargerRequest: NavigationSuperchargerRequest.create({
977
+ id,
978
+ remoteNavTripOrder: order ?? 0
979
+ }) }));
980
+ }
981
+ /** Triggers vehicle route navigation. */
982
+ async navigation_route() {
983
+ return this.vehicleAction(VehicleAction.create({ navigationRouteAction: NavigationRouteAction.create({}) }));
984
+ }
985
+ /**
986
+ * Sends a list of waypoints to the vehicle's navigation system.
987
+ * @param waypoints Comma-separated Google Maps place IDs, e.g. `"refId:ChIJ...,refId:ChIJ..."`
988
+ */
989
+ async navigation_waypoints_request(waypoints) {
990
+ return this.vehicleAction(VehicleAction.create({ navigationWaypointsRequest: NavigationWaypointsRequest.create({ waypoints }) }));
991
+ }
992
+ /** Opens the Cybertruck tonneau cover. */
993
+ async open_tonneau() {
994
+ return this.moveTonneau(ClosureMoveTypeE.CLOSURE_MOVE_TYPE_OPEN);
995
+ }
996
+ /**
997
+ * Returns the charging sites near the current location of the vehicle.
998
+ * The sites are under `response.getNearbyChargingSites`.
999
+ * @param count Number of sites to return
1000
+ * @param radius Search radius
1001
+ * @param detail Whether to include site metadata
1002
+ */
1003
+ async nearby_charging_sites(count, radius, detail) {
1004
+ return this.vehicleAction(VehicleAction.create({ getNearbyChargingSites: GetNearbyChargingSites.create({
1005
+ count,
1006
+ radius,
1007
+ includeMetaData: detail
1008
+ }) }), { mutating: false });
1009
+ }
1010
+ /**
1011
+ * Sets automatic seat heating and cooling. Only the front seats support this action.
1012
+ * @param auto_seat_position `AutoSeat` position (1-indexed: front left is 1, front right is 2)
1013
+ * @param auto_climate_on `true` or `false`
1014
+ */
1015
+ async remote_auto_seat_climate_request(auto_seat_position, auto_climate_on) {
1016
+ const position = AutoSeatPositions[typeof auto_seat_position === "string" ? AutoSeat[auto_seat_position] : auto_seat_position];
1017
+ if (position === void 0) throw new Error(`Invalid seat position for auto seat climate: ${auto_seat_position}`);
1018
+ return this.vehicleAction(VehicleAction.create({ autoSeatClimateAction: AutoSeatClimateAction.create({ carseat: [AutoSeatClimateAction_CarSeat.create({
1019
+ on: auto_climate_on,
1020
+ seatPosition: position
1021
+ })] }) }));
1022
+ }
1023
+ /**
1024
+ * Sets automatic steering wheel heating on/off.
1025
+ * @param on `true` or `false`
1026
+ */
1027
+ async remote_auto_steering_wheel_heat_climate_request(on) {
1028
+ return this.vehicleAction(VehicleAction.create({ autoStwHeatAction: AutoStwHeatAction.create({ on }) }));
1029
+ }
1030
+ /**
1031
+ * Removes a charging schedule.
1032
+ * @param id Schedule ID
1033
+ */
1034
+ async remove_charge_schedule(id) {
1035
+ return this.vehicleAction(VehicleAction.create({ removeChargeScheduleAction: RemoveChargeScheduleAction.create({ id }) }));
1036
+ }
1037
+ /**
1038
+ * Removes a registered managed charging site.
1039
+ * @param public_key The public key it was registered with
1040
+ */
1041
+ async remove_managed_charging_site(public_key) {
1042
+ return this.vehicleAction(VehicleAction.create({ removeManagedChargingSiteRequest: RemoveManagedChargingSiteRequest.create({ publicKey: public_key }) }));
1043
+ }
1044
+ /**
1045
+ * Removes a preconditioning schedule.
1046
+ * @param id Schedule ID
1047
+ */
1048
+ async remove_precondition_schedule(id) {
1049
+ return this.vehicleAction(VehicleAction.create({ removePreconditionScheduleAction: RemovePreconditionScheduleAction.create({ id }) }));
1050
+ }
1051
+ /**
1052
+ * Plays a sound through the vehicle external speaker.
1053
+ * @param sound Fart is `0`, Locate ping is `2000`
1054
+ */
1055
+ async remote_boombox(sound = 0) {
1056
+ return this.vehicleAction(VehicleAction.create({ boomboxAction: BoomboxAction.create({ sound }) }));
1057
+ }
1058
+ /**
1059
+ * Sets seat cooling. Only the front seats support this action.
1060
+ * @param seat_position `AutoSeat` position (1-indexed: front left is 1, front right is 2), unlike seat heating
1061
+ * @param seat_cooler_level Cooling level
1062
+ */
1063
+ async remote_seat_cooler_request(seat_position, seat_cooler_level) {
1064
+ const position = SeatCoolerPositions[typeof seat_position === "string" ? AutoSeat[seat_position] : seat_position];
1065
+ if (position === void 0) throw new Error(`Invalid seat position for seat cooling: ${seat_position}`);
1066
+ const level = SeatCoolerLevels[seat_cooler_level];
1067
+ if (level === void 0) throw new Error(`Invalid seat cooler level: ${seat_cooler_level}`);
1068
+ return this.vehicleAction(VehicleAction.create({ hvacSeatCoolerActions: HvacSeatCoolerActions.create({ hvacSeatCoolerAction: [HvacSeatCoolerActions_HvacSeatCoolerAction.create({
1069
+ seatCoolerLevel: level,
1070
+ seatPosition: position
1071
+ })] }) }));
1072
+ }
1073
+ /**
1074
+ * Sets seat heating.
1075
+ * @param seat_position Seat position
1076
+ * @param seat_heater_level Heating level
1077
+ */
1078
+ async remote_seat_heater_request(seat_position, seat_heater_level) {
1079
+ const field = SeatHeaterFields[this.resolveSeat(seat_position)];
1080
+ if (!field) throw new Error(`Invalid seat position: ${seat_position}`);
1081
+ const levelField = SeatHeaterLevels[seat_heater_level];
1082
+ if (!levelField) throw new Error(`Invalid seat heater level: ${seat_heater_level}`);
1083
+ const heaterAction = {};
1084
+ heaterAction[field] = VOID;
1085
+ heaterAction[levelField] = VOID;
1086
+ return this.vehicleAction(VehicleAction.create({ hvacSeatHeaterActions: HvacSeatHeaterActions.create({ hvacSeatHeaterAction: [HvacSeatHeaterActions_HvacSeatHeaterAction.create(heaterAction)] }) }));
1087
+ }
1088
+ /** Starts the vehicle remotely. Requires keyless driving to be enabled. */
1089
+ async remote_start_drive() {
1090
+ return this.sendVehicleSecurity(UnsignedMessage.create({ RKEAction: RKEActionE.RKE_ACTION_REMOTE_DRIVE }));
1091
+ }
1092
+ /**
1093
+ * Sets steering wheel heat level.
1094
+ * @param level `Level` OFF, LOW or HIGH (0, 1, 3). There is no medium level.
1095
+ */
1096
+ async remote_steering_wheel_heat_level_request(level) {
1097
+ const stwLevel = StwHeatLevels[level];
1098
+ if (stwLevel === void 0) throw new Error(`Invalid steering wheel heat level ${level}; expected 0, 1 or 3`);
1099
+ return this.vehicleAction(VehicleAction.create({ stwHeatLevelAction: StwHeatLevelAction.create({ stwHeatLevel: stwLevel }) }));
1100
+ }
1101
+ /**
1102
+ * Sets steering wheel heating on/off. For vehicles that do not support auto steering wheel heat.
1103
+ * @param on `true` or `false`
1104
+ */
1105
+ async remote_steering_wheel_heater_request(on) {
1106
+ return this.vehicleAction(VehicleAction.create({ hvacSteeringWheelHeaterAction: HvacSteeringWheelHeaterAction.create({ powerOn: on }) }));
1107
+ }
1108
+ /**
1109
+ * Resets PIN to Drive for fleet managers and owners. Requires firmware 2023.44+.
1110
+ * The vehicle only accepts this with account credentials, which the cloud
1111
+ * transport has and a raw Bluetooth link does not.
1112
+ */
1113
+ async reset_pin_to_drive_admin() {
1114
+ return this.vehicleAction(VehicleAction.create({ vehicleControlResetPinToDriveAdminAction: VehicleControlResetPinToDriveAdminAction.create({}) }));
1115
+ }
1116
+ /** Removes PIN to Drive. Requires the car to be in Pin to Drive mode and not in Valet mode. */
1117
+ async reset_pin_to_drive_pin() {
1118
+ return this.vehicleAction(VehicleAction.create({ vehicleControlResetPinToDriveAction: VehicleControlResetPinToDriveAction.create({}) }));
1119
+ }
1120
+ /** Removes PIN for Valet Mode. */
1121
+ async reset_valet_pin() {
1122
+ return this.vehicleAction(VehicleAction.create({ vehicleControlResetValetPinAction: VehicleControlResetValetPinAction.create({}) }));
1123
+ }
1124
+ /**
1125
+ * Schedules a vehicle software update (over the air "OTA") to be installed in the future.
1126
+ * @param offset_sec Offset in seconds
1127
+ */
1128
+ async schedule_software_update(offset_sec) {
1129
+ return this.vehicleAction(VehicleAction.create({ vehicleControlScheduleSoftwareUpdateAction: VehicleControlScheduleSoftwareUpdateAction.create({ offsetSec: offset_sec }) }));
1130
+ }
1131
+ /**
1132
+ * Turns Bioweapon Defense Mode on and off.
1133
+ * @param on `true` or `false`
1134
+ * @param manual_override `true` or `false`
1135
+ */
1136
+ async set_bioweapon_mode(on, manual_override) {
1137
+ return this.vehicleAction(VehicleAction.create({ hvacBioweaponModeAction: HvacBioweaponModeAction.create({
1138
+ on,
1139
+ manualOverride: manual_override
1140
+ }) }));
1141
+ }
1142
+ /**
1143
+ * Sets the vehicle overheat protection.
1144
+ * @param on `true` or `false`
1145
+ * @param fan_only `true` or `false`
1146
+ */
1147
+ async set_cabin_overheat_protection(on, fan_only) {
1148
+ return this.vehicleAction(VehicleAction.create({ setCabinOverheatProtectionAction: SetCabinOverheatProtectionAction.create({
1149
+ on,
1150
+ fanOnly: fan_only
1151
+ }) }));
1152
+ }
1153
+ /**
1154
+ * Sets the vehicle's charge limit to a custom percentage.
1155
+ * @param percent Charge limit percentage typically between 50-100
1156
+ */
1157
+ async set_charge_limit(percent) {
1158
+ return this.vehicleAction(VehicleAction.create({ chargingSetLimitAction: ChargingSetLimitAction.create({ percent }) }));
1159
+ }
1160
+ /**
1161
+ * Sets the charging amps.
1162
+ * @param charging_amps Current limit in Amps typically between 5-32
1163
+ */
1164
+ async set_charging_amps(charging_amps) {
1165
+ return this.vehicleAction(VehicleAction.create({ setChargingAmpsAction: SetChargingAmpsAction.create({ chargingAmps: charging_amps }) }));
1166
+ }
1167
+ /**
1168
+ * Enables climate keeper mode.
1169
+ * @param climate_keeper_mode `0` is Off, `1` is Keep, `2` is Dog, `3` is Camp
1170
+ */
1171
+ async set_climate_keeper_mode(climate_keeper_mode) {
1172
+ const mode = typeof climate_keeper_mode === "string" ? ClimateModes[climate_keeper_mode] : climate_keeper_mode;
1173
+ const action = ClimateKeeperActions[mode];
1174
+ if (action === void 0) throw new Error(`Invalid climate keeper mode: ${climate_keeper_mode}`);
1175
+ return this.vehicleAction(VehicleAction.create({ hvacClimateKeeperAction: {
1176
+ ClimateKeeperAction: action,
1177
+ manualOverride: false,
1178
+ manualOverrideMode: []
1179
+ } }));
1180
+ }
1181
+ /**
1182
+ * Adjusts the Cabin Overheat Protection temperature (COP).
1183
+ * @param cop_temp Integer representing Low (0/30C/90F), Medium (1/35C/95F), or High (2/40C/100F)
1184
+ */
1185
+ async set_cop_temp(cop_temp) {
1186
+ const copActivationTemp = CopActivationTemps[cop_temp];
1187
+ if (copActivationTemp === void 0) throw new Error(`Invalid cop_temp: ${cop_temp}`);
1188
+ return this.vehicleAction(VehicleAction.create({ setCopTempAction: SetCopTempAction.create({ copActivationTemp }) }));
1189
+ }
1190
+ /**
1191
+ * Sets the vehicle's general discharge limit. This is not `set_powershare_discharge_limit`, which is a separate message.
1192
+ * @param discharge_limit Discharge limit
1193
+ */
1194
+ async set_discharge_limit(discharge_limit) {
1195
+ return this.vehicleAction(VehicleAction.create({ setDischargeLimitAction: SetDischargeLimitAction.create({ dischargeLimit: discharge_limit }) }));
1196
+ }
1197
+ /**
1198
+ * Turns Keep Accessory Power mode on and off, keeping 12V accessory power available while the vehicle is parked.
1199
+ * @param on `true` or `false`
1200
+ */
1201
+ async set_keep_accessory_power_mode(on) {
1202
+ return this.vehicleAction(VehicleAction.create({ setKeepAccessoryPowerModeAction: SetKeepAccessoryPowerModeAction.create({ keepAccessoryPowerMode: on }) }));
1203
+ }
1204
+ /**
1205
+ * Turns Low Power mode on and off, reducing standby power consumption while the vehicle is parked.
1206
+ * @param on `true` or `false`
1207
+ */
1208
+ async set_low_power_mode(on) {
1209
+ return this.vehicleAction(VehicleAction.create({ setLowPowerModeAction: SetLowPowerModeAction.create({ lowPowerMode: on }) }));
1210
+ }
1211
+ /**
1212
+ * Sets a four-digit passcode for PIN to Drive.
1213
+ * @param on `true` or `false`
1214
+ * @param password Four-digit passcode
1215
+ */
1216
+ async set_pin_to_drive(on, password) {
1217
+ return this.vehicleAction(VehicleAction.create({ vehicleControlSetPinToDriveAction: VehicleControlSetPinToDriveAction.create({
1218
+ on,
1219
+ password: String(password)
1220
+ }) }));
1221
+ }
1222
+ /**
1223
+ * Sets an override for preconditioning — it should default to empty if no override is used.
1224
+ * @param on `true` or `false`
1225
+ * @param manual_override `true` or `false`
1226
+ */
1227
+ async set_preconditioning_max(on, manual_override) {
1228
+ return this.vehicleAction(VehicleAction.create({ hvacSetPreconditioningMaxAction: HvacSetPreconditioningMaxAction.create({
1229
+ on,
1230
+ manualOverride: manual_override
1231
+ }) }));
1232
+ }
1233
+ /**
1234
+ * Sets a time-of-use rate tariff schedule. The schedule nests up to five
1235
+ * named seasons of four period types each, so build `seasons` and `tariff`
1236
+ * with the `tesla-protocol` message types.
1237
+ * @param seasons The tariff's seasons
1238
+ * @param tariff The tariff
1239
+ */
1240
+ async set_rate_tariff(seasons, tariff) {
1241
+ return this.vehicleAction(VehicleAction.create({ setRateTariffRequest: SetRateTariffRequest.create({
1242
+ seasons,
1243
+ tariff
1244
+ }) }));
1245
+ }
1246
+ /**
1247
+ * Sets HVAC recirculation mode on and off.
1248
+ * @param on `true` or `false`
1249
+ */
1250
+ async set_recirculation(on) {
1251
+ return this.vehicleAction(VehicleAction.create({ hvacRecirculationAction: HvacRecirculationAction.create({ on }) }));
1252
+ }
1253
+ /**
1254
+ * Sets a time at which charging should be completed.
1255
+ * @param enable `true` or `false`
1256
+ * @param time Minutes after midnight
1257
+ */
1258
+ async set_scheduled_charging(enable, time) {
1259
+ return this.vehicleAction(VehicleAction.create({ scheduledChargingAction: ScheduledChargingAction.create({
1260
+ enabled: enable,
1261
+ chargingTime: time
1262
+ }) }));
1263
+ }
1264
+ /**
1265
+ * Sets a time at which departure should be completed.
1266
+ *
1267
+ * The protocol has no enable flags: a present recurrence block switches its
1268
+ * feature on. So preconditioning and off-peak charging are sent only when
1269
+ * their `*_enabled` or `*_weekdays_only` argument is true, and an absent
1270
+ * block is what turns the feature off.
1271
+ * @param enable `true` or `false`
1272
+ * @param preconditioning_enabled `true` or `false`
1273
+ * @param preconditioning_weekdays_only `true` or `false`
1274
+ * @param departure_time Minutes after midnight
1275
+ * @param off_peak_charging_enabled `true` or `false`
1276
+ * @param off_peak_charging_weekdays_only `true` or `false`
1277
+ * @param end_off_peak_time Minutes after midnight
1278
+ */
1279
+ async set_scheduled_departure(enable = true, preconditioning_enabled = false, preconditioning_weekdays_only = false, departure_time = 0, off_peak_charging_enabled = false, off_peak_charging_weekdays_only = false, end_off_peak_time = 0) {
1280
+ let preconditioningTimes;
1281
+ if (preconditioning_weekdays_only) preconditioningTimes = PreconditioningTimes.create({ weekdays: VOID });
1282
+ else if (preconditioning_enabled) preconditioningTimes = PreconditioningTimes.create({ allWeek: VOID });
1283
+ let offPeakChargingTimes;
1284
+ if (off_peak_charging_weekdays_only) offPeakChargingTimes = OffPeakChargingTimes.create({ weekdays: VOID });
1285
+ else if (off_peak_charging_enabled) offPeakChargingTimes = OffPeakChargingTimes.create({ allWeek: VOID });
1286
+ return this.vehicleAction(VehicleAction.create({ scheduledDepartureAction: ScheduledDepartureAction.create({
1287
+ enabled: enable,
1288
+ departureTime: departure_time,
1289
+ preconditioningTimes,
1290
+ offPeakChargingTimes,
1291
+ offPeakHoursEndTime: end_off_peak_time
1292
+ }) }));
1293
+ }
1294
+ /**
1295
+ * Enables and disables Sentry Mode.
1296
+ * @param on `true` or `false`
1297
+ */
1298
+ async set_sentry_mode(on) {
1299
+ return this.vehicleAction(VehicleAction.create({ vehicleControlSetSentryModeAction: VehicleControlSetSentryModeAction.create({ on }) }));
1300
+ }
1301
+ /**
1302
+ * Sets the vehicle suspension level.
1303
+ * @param level `1` entry, `2` low, `3` medium, `4` high, `5` very high, `6` extract
1304
+ */
1305
+ async set_suspension_level(level) {
1306
+ return this.vehicleAction(VehicleAction.create({ setSuspensionLevelAction: SetSuspensionLevelAction.create({ suspensionLevel: level }) }));
1307
+ }
1308
+ /**
1309
+ * Sets the driver and/or passenger-side cabin temperature (and other zones if sync is enabled).
1310
+ * @param driver_temp Driver temperature
1311
+ * @param passenger_temp Passenger temperature
1312
+ */
1313
+ async set_temps(driver_temp, passenger_temp) {
1314
+ return this.vehicleAction(VehicleAction.create({ hvacTemperatureAdjustmentAction: HvacTemperatureAdjustmentAction.create({
1315
+ driverTempCelsius: driver_temp,
1316
+ passengerTempCelsius: passenger_temp
1317
+ }) }));
1318
+ }
1319
+ /**
1320
+ * Enables or disables tent mode.
1321
+ * @param on `true` or `false`
1322
+ */
1323
+ async set_tent_mode(on) {
1324
+ return this.vehicleAction(VehicleAction.create({ setTentModeRequestAction: SetTentModeRequestAction.create({ on }) }));
1325
+ }
1326
+ /**
1327
+ * Turns on Valet Mode and sets a four-digit passcode.
1328
+ * @param on `true` or `false`
1329
+ * @param password Four-digit passcode
1330
+ */
1331
+ async set_valet_mode(on, password) {
1332
+ return this.vehicleAction(VehicleAction.create({ vehicleControlSetValetModeAction: VehicleControlSetValetModeAction.create({
1333
+ on,
1334
+ password: password == null ? void 0 : String(password)
1335
+ }) }));
1336
+ }
1337
+ /**
1338
+ * Changes the name of a vehicle.
1339
+ * @param vehicle_name New name
1340
+ */
1341
+ async set_vehicle_name(vehicle_name) {
1342
+ return this.vehicleAction(VehicleAction.create({ setVehicleNameAction: SetVehicleNameAction.create({ vehicleName: vehicle_name }) }));
1343
+ }
1344
+ /**
1345
+ * Activates Speed Limit Mode with a four-digit PIN.
1346
+ * @param pin Four-digit PIN
1347
+ */
1348
+ async speed_limit_activate(pin) {
1349
+ return this.vehicleAction(VehicleAction.create({ drivingSpeedLimitAction: DrivingSpeedLimitAction.create({
1350
+ activate: true,
1351
+ pin: String(pin)
1352
+ }) }));
1353
+ }
1354
+ /**
1355
+ * Deactivates Speed Limit Mode and resets the associated PIN.
1356
+ * @param pin Four-digit PIN
1357
+ */
1358
+ async speed_limit_clear_pin(pin) {
1359
+ return this.vehicleAction(VehicleAction.create({ drivingClearSpeedLimitPinAction: DrivingClearSpeedLimitPinAction.create({ pin: String(pin) }) }));
1360
+ }
1361
+ /** Deactivates Speed Limit Mode and resets the associated PIN, for fleet managers or owners. */
1362
+ async speed_limit_clear_pin_admin() {
1363
+ return this.vehicleAction(VehicleAction.create({ drivingClearSpeedLimitPinAdminAction: DrivingClearSpeedLimitPinAdminAction.create({}) }));
1364
+ }
1365
+ /**
1366
+ * Deactivates Speed Limit Mode.
1367
+ * @param pin Four-digit PIN
1368
+ */
1369
+ async speed_limit_deactivate(pin) {
1370
+ return this.vehicleAction(VehicleAction.create({ drivingSpeedLimitAction: DrivingSpeedLimitAction.create({
1371
+ activate: false,
1372
+ pin: String(pin)
1373
+ }) }));
1374
+ }
1375
+ /**
1376
+ * Sets the maximum speed allowed when Speed Limit Mode is active.
1377
+ * @param limit_mph Maximum speed in MPH
1378
+ */
1379
+ async speed_limit_set_limit(limit_mph) {
1380
+ return this.vehicleAction(VehicleAction.create({ drivingSetSpeedLimitAction: DrivingSetSpeedLimitAction.create({ limitMph: limit_mph }) }));
1381
+ }
1382
+ /**
1383
+ * Starts a light show.
1384
+ * @param show_index Index of the show
1385
+ * @param start_time Start time
1386
+ * @param volume Volume
1387
+ * @param dance_moves Whether the vehicle moves during the show
1388
+ */
1389
+ async start_light_show(show_index = 0, start_time = 0, volume = 0, dance_moves = false) {
1390
+ return this.vehicleAction(VehicleAction.create({ startLightShowAction: StartLightShowAction.create({
1391
+ showIndex: show_index,
1392
+ startTime: start_time,
1393
+ volume,
1394
+ danceMoves: dance_moves
1395
+ }) }));
1396
+ }
1397
+ /** Stops the current light show. */
1398
+ async stop_light_show() {
1399
+ return this.vehicleAction(VehicleAction.create({ stopLightShowAction: StopLightShowAction.create({}) }));
1400
+ }
1401
+ /** Stops the Cybertruck tonneau cover. */
1402
+ async stop_tonneau() {
1403
+ return this.moveTonneau(ClosureMoveTypeE.CLOSURE_MOVE_TYPE_STOP);
1404
+ }
1405
+ /**
1406
+ * Controls the panoramic sunroof on the Model S.
1407
+ *
1408
+ * "stop" has no corresponding field in the signed-command protobuf (only
1409
+ * vent/close/open), so it is rejected rather than guessed at.
1410
+ * @param state "open", "close" or "vent"
1411
+ */
1412
+ async sun_roof_control(state) {
1413
+ let action;
1414
+ if (state === "vent") action = VehicleControlSunroofOpenCloseAction.create({ vent: VOID });
1415
+ else if (state === "open") action = VehicleControlSunroofOpenCloseAction.create({ open: VOID });
1416
+ else if (state === "close") action = VehicleControlSunroofOpenCloseAction.create({ close: VOID });
1417
+ else throw new Error("sun_roof_control: \"stop\" is not representable in a signed command.");
1418
+ return this.vehicleAction(VehicleAction.create({ vehicleControlSunroofOpenCloseAction: action }));
1419
+ }
1420
+ /**
1421
+ * Records a drive note. Overrides the inherited plaintext command so it is
1422
+ * signed and dispatched over the vehicle-command protocol rather than
1423
+ * silently falling through to the unsigned REST endpoint on vehicles that
1424
+ * require signing.
1425
+ * @param note Drive note
1426
+ */
1427
+ async take_drivenote(note) {
1428
+ return this.vehicleAction(VehicleAction.create({ takeDrivenoteAction: TakeDrivenoteAction.create({ note }) }));
1429
+ }
1430
+ /**
1431
+ * Turns on HomeLink (used to open and close garage doors).
1432
+ * @param token
1433
+ * @param lat Latitude. `0` is a coordinate; the location is sent when both are given.
1434
+ * @param lon Longitude
1435
+ */
1436
+ async trigger_homelink(token, lat, lon) {
1437
+ return this.vehicleAction(VehicleAction.create({ vehicleControlTriggerHomelinkAction: VehicleControlTriggerHomelinkAction.create({
1438
+ location: lat != null && lon != null ? LatLong.create({
1439
+ latitude: lat,
1440
+ longitude: lon
1441
+ }) : void 0,
1442
+ token
1443
+ }) }));
1444
+ }
1445
+ /**
1446
+ * Updates the charge on solar settings.
1447
+ * @param enabled `true` or `false`
1448
+ * @param lower_charge_limit Lower charge limit
1449
+ * @param upper_charge_limit Upper charge limit
1450
+ */
1451
+ async update_charge_on_solar(enabled, lower_charge_limit, upper_charge_limit) {
1452
+ return this.vehicleAction(VehicleAction.create({ updateChargeOnSolarFeatureRequest: UpdateChargeOnSolarFeatureRequest.create({ chargeOnSolar: ChargeOnSolarFeature.create({
1453
+ enabled,
1454
+ lowerChargeLimit: lower_charge_limit,
1455
+ upperChargeLimit: upper_charge_limit
1456
+ }) }) }));
1457
+ }
1458
+ /**
1459
+ * Sends upcoming calendar entries to the vehicle. Overrides the inherited
1460
+ * plaintext command so it is signed and dispatched over the vehicle-command
1461
+ * protocol rather than silently falling through to the unsigned REST
1462
+ * endpoint on vehicles that require signing.
1463
+ * @param calendar_data Calendar data
1464
+ */
1465
+ async upcoming_calendar_entries(calendar_data) {
1466
+ return this.vehicleAction(VehicleAction.create({ uiSetUpcomingCalendarEntries: UiSetUpcomingCalendarEntries.create({ calendarData: calendar_data }) }));
1467
+ }
1468
+ /**
1469
+ * Asks the vehicle to open a video stream.
1470
+ * @param url Video URL
1471
+ */
1472
+ async video_request(url) {
1473
+ return this.vehicleAction(VehicleAction.create({ videoRequestAction: VideoRequestAction.create({ url }) }));
1474
+ }
1475
+ /**
1476
+ * Control the windows of a parked vehicle. Supported commands: vent and close.
1477
+ * @param command "vent" or "close"
1478
+ * @param lat Latitude
1479
+ * @param lon Longitude
1480
+ */
1481
+ async window_control(command, _lat, _lon) {
1482
+ let action;
1483
+ if (command === "vent") action = VehicleControlWindowAction.create({ vent: VOID });
1484
+ else if (command === "close") action = VehicleControlWindowAction.create({ close: VOID });
1485
+ else throw new Error(`Invalid window command: ${command}`);
1486
+ return this.vehicleAction(VehicleAction.create({ vehicleControlWindowAction: action }));
1487
+ }
1488
+ /**
1489
+ * Requests a PII key, for privacy and telemetry pseudonymization.
1490
+ * @param subscriber_public_key Subscriber public key
1491
+ * @param pii_key_expiration Expiry as a Unix timestamp in seconds
1492
+ */
1493
+ async pii_key_request(subscriber_public_key, pii_key_expiration) {
1494
+ return this.vehicleAction(VehicleAction.create({ piiKeyRequest: PiiKeyRequest.create({
1495
+ subscriberPublicKey: subscriber_public_key,
1496
+ piiKeyExpiration: /* @__PURE__ */ new Date(pii_key_expiration * 1e3)
1497
+ }) }));
1498
+ }
1499
+ /**
1500
+ * Syncs the vehicle's privacy and telemetry pseudonym with a previously known hashed value.
1501
+ * @param last_known_pseudonym_hashed The hashed pseudonym
1502
+ */
1503
+ async pseudonym_sync_request(last_known_pseudonym_hashed) {
1504
+ return this.vehicleAction(VehicleAction.create({ pseudonymSyncRequest: PseudonymSyncRequest.create({ lastKnownPseudonymHashed: last_known_pseudonym_hashed }) }));
1505
+ }
1506
+ /**
1507
+ * Passes a completed "Sign in with Tesla" OAuth response to the vehicle
1508
+ * screen. The caller must already hold that response from its own auth flow.
1509
+ * @param client_id OAuth client ID
1510
+ * @param scope OAuth scope
1511
+ * @param access_token Access token
1512
+ * @param refresh_token Refresh token
1513
+ * @param expiry_timestamp Token expiry
1514
+ * @param error OAuth error, if any
1515
+ * @param scoped_token Scoped token
1516
+ */
1517
+ async tesla_auth_response(client_id, scope, access_token, refresh_token, expiry_timestamp, error = "", scoped_token = "") {
1518
+ return this.vehicleAction(VehicleAction.create({ teslaAuthResponseAction: TeslaAuthResponseAction.create({
1519
+ clientId: client_id,
1520
+ scope,
1521
+ accessToken: access_token,
1522
+ refreshToken: refresh_token,
1523
+ expiryTimestamp: expiry_timestamp,
1524
+ error,
1525
+ scopedToken: scoped_token
1526
+ }) }));
1527
+ }
1528
+ /**
1529
+ * Links a local Tesla profile to a cloud vault profile.
1530
+ * @param cloud_vault_uuid Cloud vault UUID
1531
+ * @param local_profile_uuid Local profile UUID
1532
+ * @param delete_local_profile_after_setup Whether to delete the local profile afterwards
1533
+ */
1534
+ async setup_cloud_profile_with_local_profile_uuid(cloud_vault_uuid, local_profile_uuid, delete_local_profile_after_setup = false) {
1535
+ return this.vehicleAction(VehicleAction.create({ setupCloudProfileWithLocalProfileUuidAction: SetupCloudProfileWithLocalProfileUuidAction.create({
1536
+ cloudVaultUuid: cloud_vault_uuid,
1537
+ localProfileUuid: local_profile_uuid,
1538
+ deleteLocalProfileAfterSetup: delete_local_profile_after_setup
1539
+ }) }));
1540
+ }
1541
+ /**
1542
+ * Gets the local Tesla profiles of a cloud vault, under `response.getLocalProfilesResponse`.
1543
+ * @param vault_uuid Cloud vault UUID
1544
+ */
1545
+ async get_local_profiles_for_vault_uuid(vault_uuid) {
1546
+ return this.vehicleAction(VehicleAction.create({ getLocalProfilesForVaultUuidAction: GetLocalProfilesForVaultUuidAction.create({ vaultUuid: vault_uuid }) }), { mutating: false });
1547
+ }
1548
+ /**
1549
+ * Requests Bluetooth Classic, not BLE, pairing with a phone for calls and audio.
1550
+ * @param name Device name
1551
+ * @param mac_address Device MAC address
1552
+ */
1553
+ async bluetooth_classic_pairing_request(name, mac_address) {
1554
+ return this.vehicleAction(VehicleAction.create({ bluetoothClassicPairingRequest: BluetoothClassicPairingRequest.create({
1555
+ utf8Name: name,
1556
+ macAddress: mac_address
1557
+ }) }));
1558
+ }
1559
+ /**
1560
+ * Runs a diagnostic bandwidth test, with its result under `response.bandwidthTestResponse`.
1561
+ * @param requested_size Size in bytes
1562
+ */
1563
+ async bandwidth_test(requested_size) {
1564
+ return this.vehicleAction(VehicleAction.create({ bandwidthTest: BandwidthTest.create({ requestedSize: requested_size }) }));
1565
+ }
1566
+ /** Gets information about keys paired with the vehicle, under `response.keysInfoResponse`. */
1567
+ async fetch_keys_info() {
1568
+ return this.vehicleAction(VehicleAction.create({ fetchKeysInfoAction: FetchKeysInfoAction.create({}) }), { mutating: false });
1569
+ }
1570
+ /** Formats the USB drive connected to the vehicle, erasing all files on it. Irreversible. */
1571
+ async format_usb() {
1572
+ return this.vehicleAction(VehicleAction.create({ formatUsbAction: FormatUSBAction.create({ formatUsb: true }) }));
1573
+ }
1574
+ /** Deletes all dashcam clips stored on the vehicle. Irreversible. */
1575
+ async delete_dashcam_clips() {
1576
+ return this.vehicleAction(VehicleAction.create({ deleteDashcamClipsAction: DeleteDashcamClipsAction.create({ deleteClips: true }) }));
1577
+ }
1578
+ /**
1579
+ * Activates or deactivates parental controls.
1580
+ * @param activate `true` or `false`
1581
+ * @param pin Four-digit PIN
1582
+ */
1583
+ async parental_controls(activate, pin) {
1584
+ return this.vehicleAction(VehicleAction.create({ parentalControlsAction: ParentalControlsAction.create({
1585
+ activate,
1586
+ pin: String(pin)
1587
+ }) }));
1588
+ }
1589
+ /**
1590
+ * Clears the parental controls PIN.
1591
+ * @param pin Four-digit PIN
1592
+ */
1593
+ async parental_controls_clear_pin(pin) {
1594
+ return this.vehicleAction(VehicleAction.create({ parentalControlsClearPinAction: ParentalControlsClearPinAction.create({ pin: String(pin) }) }));
1595
+ }
1596
+ /** Clears the parental controls PIN, for fleet managers and owners. */
1597
+ async parental_controls_clear_pin_admin() {
1598
+ return this.vehicleAction(VehicleAction.create({ parentalControlsClearPinAdminAction: ParentalControlsClearPinAdminAction.create({}) }));
1599
+ }
1600
+ /**
1601
+ * Enables or disables a parental controls setting.
1602
+ * @param setting `0` speed limit, `1` acceleration, `2` safety features, `3` curfew, `4` browser blocked, `5` theater blocked, `6` arcade blocked
1603
+ * @param enable `true` or `false`
1604
+ */
1605
+ async parental_controls_enable_setting(setting, enable) {
1606
+ return this.vehicleAction(VehicleAction.create({ parentalControlsEnableSettingsAction: ParentalControlsEnableSettingsAction.create({
1607
+ setting,
1608
+ enable
1609
+ }) }));
1610
+ }
1611
+ /**
1612
+ * Sets the parental controls speed limit.
1613
+ * @param limit_mph Maximum speed in MPH
1614
+ */
1615
+ async parental_controls_set_speed_limit(limit_mph) {
1616
+ return this.vehicleAction(VehicleAction.create({ parentalControlsSetSpeedLimitAction: ParentalControlsSetSpeedLimitAction.create({ limitMph: limit_mph }) }));
1617
+ }
1618
+ /**
1619
+ * Sets the displayed temperature unit.
1620
+ * @param unit `TemperatureUnit`
1621
+ */
1622
+ async set_temperature_unit(unit) {
1623
+ return this.vehicleAction(VehicleAction.create({ setTemperatureUnitAction: SetTemperatureUnitAction.create({ unit }) }));
1624
+ }
1625
+ /**
1626
+ * Sets the displayed distance unit.
1627
+ * @param unit `DistanceUnit`
1628
+ */
1629
+ async set_distance_unit(unit) {
1630
+ return this.vehicleAction(VehicleAction.create({ setDistanceUnitAction: SetDistanceUnitAction.create({ unit }) }));
1631
+ }
1632
+ /**
1633
+ * Sets the displayed clock format.
1634
+ * @param format `TimeDisplayFormat`
1635
+ */
1636
+ async set_time_display_format(format) {
1637
+ return this.vehicleAction(VehicleAction.create({ setTimeDisplayFormatAction: SetTimeDisplayFormatAction.create({ format }) }));
1638
+ }
1639
+ /**
1640
+ * Sets the displayed tire pressure unit.
1641
+ * @param unit `TirePressureUnit`
1642
+ */
1643
+ async set_tire_pressure_unit(unit) {
1644
+ return this.vehicleAction(VehicleAction.create({ setTirePressureUnitAction: SetTirePressureUnitAction.create({ unit }) }));
1645
+ }
1646
+ /**
1647
+ * Sets the displayed energy or range unit.
1648
+ * @param format `EnergyDisplayFormat`
1649
+ */
1650
+ async set_energy_display_format(format) {
1651
+ return this.vehicleAction(VehicleAction.create({ setEnergyDisplayFormatAction: SetEnergyDisplayFormatAction.create({ format }) }));
1652
+ }
1653
+ /**
1654
+ * Sets paired-phone display preferences.
1655
+ * @param font_size `PhoneFontSize`
1656
+ * @param options.distance_unit `DistanceUnit`
1657
+ * @param options.temperature_unit `TemperatureUnit`
1658
+ */
1659
+ async set_phone_setting_preferences(font_size = PhoneFontSize.STANDARD, { distance_unit, temperature_unit } = {}) {
1660
+ const unitPreferences = distance_unit != null || temperature_unit != null ? PhoneUnitPreferences.create({
1661
+ distanceUnit: distance_unit,
1662
+ temperatureUnit: temperature_unit
1663
+ }) : void 0;
1664
+ return this.vehicleAction(VehicleAction.create({ setPhoneSettingPreferencesAction: SetPhoneSettingPreferencesAction.create({
1665
+ fontSize: font_size,
1666
+ unitPreferences
1667
+ }) }));
1668
+ }
1669
+ /**
1670
+ * Enables or disables the Powershare feature.
1671
+ * @param on `true` or `false`
1672
+ */
1673
+ async set_powershare_feature(on) {
1674
+ const powershareFeatureRequest = on ? SetPowershareFeatureAction_PowershareFeatureRequest.POWERSHARE_FEATURE_REQUEST_ON : SetPowershareFeatureAction_PowershareFeatureRequest.POWERSHARE_FEATURE_REQUEST_OFF;
1675
+ return this.vehicleAction(VehicleAction.create({ setPowershareFeatureAction: SetPowershareFeatureAction.create({ powershareFeatureRequest }) }));
1676
+ }
1677
+ /**
1678
+ * Enables or disables powershare.
1679
+ * @param on `true` or `false`
1680
+ */
1681
+ async set_powershare_request(on) {
1682
+ const powershareRequest = on ? SetPowershareRequestAction_PowershareRequest.POWERSHARE_REQUEST_ON : SetPowershareRequestAction_PowershareRequest.POWERSHARE_REQUEST_OFF;
1683
+ return this.vehicleAction(VehicleAction.create({ setPowershareRequestAction: SetPowershareRequestAction.create({ powershareRequest }) }));
1684
+ }
1685
+ /**
1686
+ * Sets the Powershare discharge limit. This is not `set_discharge_limit`, which is a separate message.
1687
+ * @param percent Discharge limit percentage
1688
+ */
1689
+ async set_powershare_discharge_limit(percent) {
1690
+ return this.vehicleAction(VehicleAction.create({ setPowershareDischargeLimitAction: SetPowershareDischargeLimitAction.create({ powershareDischargeLimit: percent }) }));
1691
+ }
1692
+ /**
1693
+ * Sets the outlets on or off.
1694
+ * @param request `0` off, `1` cabin and bed, `2` cabin
1695
+ */
1696
+ async set_outlets(request) {
1697
+ return this.vehicleAction(VehicleAction.create({ setOutletsOnOffAction: SetOutletsOnOffAction.create({ outletRequest: request }) }));
1698
+ }
1699
+ /**
1700
+ * Sets the outlet timer.
1701
+ * @param num_minutes Minutes
1702
+ */
1703
+ async set_outlet_timer(num_minutes) {
1704
+ return this.vehicleAction(VehicleAction.create({ setOutletTimerAction: SetOutletTimerAction.create({ numMinutes: num_minutes }) }));
1705
+ }
1706
+ /**
1707
+ * Sets the outlet state of charge limit.
1708
+ * @param percent State of charge percentage
1709
+ */
1710
+ async set_outlet_soc_limit(percent) {
1711
+ return this.vehicleAction(VehicleAction.create({ setOutletSocLimitAction: SetOutletSocLimitAction.create({ percent }) }));
1712
+ }
1713
+ /**
1714
+ * Sets the power feed on or off.
1715
+ * @param request `0` off, `1` feed 1, `2` feed 2, `3` both
1716
+ */
1717
+ async set_power_feed(request) {
1718
+ return this.vehicleAction(VehicleAction.create({ setPowerFeedOnOffAction: SetPowerFeedOnOffAction.create({ powerFeedRequest: request }) }));
1719
+ }
1720
+ /**
1721
+ * Sets the power feed timer.
1722
+ * @param num_minutes Minutes
1723
+ */
1724
+ async set_power_feed_timer(num_minutes) {
1725
+ return this.vehicleAction(VehicleAction.create({ setPowerFeedTimerAction: SetPowerFeedTimerAction.create({ numMinutes: num_minutes }) }));
1726
+ }
1727
+ /**
1728
+ * Sets the power feed state of charge limit.
1729
+ * @param percent State of charge percentage
1730
+ */
1731
+ async set_power_feed_soc_limit(percent) {
1732
+ return this.vehicleAction(VehicleAction.create({ setPowerFeedSocLimitAction: SetPowerFeedSocLimitAction.create({ percent }) }));
1733
+ }
1734
+ /**
1735
+ * Sets the lightbar brightness.
1736
+ * @param brightness Brightness
1737
+ */
1738
+ async set_lightbar_brightness(brightness) {
1739
+ return this.vehicleAction(VehicleAction.create({ setLightbarBrightnessAction: SetLightbarBrightnessAction.create({ brightnessRequest: brightness }) }));
1740
+ }
1741
+ /**
1742
+ * Turns the lightbar middle light on or off.
1743
+ * @param on `true` or `false`
1744
+ */
1745
+ async set_lightbar_middle(on) {
1746
+ return this.vehicleAction(VehicleAction.create({ setLightbarMiddleAction: SetLightbarMiddleAction.create({ middleLightRequest: on }) }));
1747
+ }
1748
+ /**
1749
+ * Turns the ditch lights on or off.
1750
+ * @param on `true` or `false`
1751
+ */
1752
+ async set_lightbar_ditch(on) {
1753
+ return this.vehicleAction(VehicleAction.create({ setLightbarDitchAction: SetLightbarDitchAction.create({ ditchLightsRequest: on }) }));
1754
+ }
1755
+ /**
1756
+ * Sets the front zone light level.
1757
+ * @param level `0` off, `1` low, `2` medium, `3` high
1758
+ */
1759
+ async set_front_zone_lights(level) {
1760
+ return this.vehicleAction(VehicleAction.create({ setFrontZoneLightRequestAction: SetZoneLightRequestAction.create({ zoneLightRequest: level }) }));
1761
+ }
1762
+ /**
1763
+ * Sets the rear zone light level.
1764
+ * @param level `0` off, `1` low, `2` medium, `3` high
1765
+ */
1766
+ async set_rear_zone_lights(level) {
1767
+ return this.vehicleAction(VehicleAction.create({ setRearZoneLightRequestAction: SetZoneLightRequestAction.create({ zoneLightRequest: level }) }));
1768
+ }
1769
+ /**
1770
+ * Starts or stops the trailer light test.
1771
+ * @param on `true` or `false`
1772
+ */
1773
+ async set_trailer_light_test(on) {
1774
+ return this.vehicleAction(VehicleAction.create({ setTrailerLightTestStartStopAction: SetTrailerLightTestStartStopAction.create({ startStop: on }) }));
1775
+ }
1776
+ /**
1777
+ * Sets the truck bed light's auto state.
1778
+ * @param on `true` or `false`
1779
+ */
1780
+ async set_truck_bed_light_auto(on) {
1781
+ return this.vehicleAction(VehicleAction.create({ setTruckBedLightAutoStateAction: SetTruckBedLightAutoStateAction.create({ powerState: on }) }));
1782
+ }
1783
+ /**
1784
+ * Sets the truck bed light brightness.
1785
+ * @param brightness Brightness
1786
+ */
1787
+ async set_truck_bed_light_brightness(brightness) {
1788
+ return this.vehicleAction(VehicleAction.create({ setTruckBedLightBrightnessAction: SetTruckBedLightBrightnessAction.create({ brightness }) }));
1789
+ }
1790
+ };
1791
+ export { DAY_OF_WEEK_BITS, days_of_week_mask, Commands as default, infotainment_command_name, vcsec_command_name };