tesla-fleet-api 0.4.0 → 0.6.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 (215) hide show
  1. package/README.md +269 -1
  2. package/dist/_virtual/_rolldown/runtime.cjs +10 -0
  3. package/dist/bluetooth/adapters/shared.cjs +38 -0
  4. package/dist/bluetooth/adapters/shared.mjs +36 -0
  5. package/dist/bluetooth/async.cjs +121 -0
  6. package/dist/bluetooth/async.d.cts +10 -0
  7. package/dist/bluetooth/async.d.mts +10 -0
  8. package/dist/bluetooth/async.mjs +116 -0
  9. package/dist/bluetooth/broadcast.cjs +153 -0
  10. package/dist/bluetooth/broadcast.d.cts +59 -0
  11. package/dist/bluetooth/broadcast.d.mts +59 -0
  12. package/dist/bluetooth/broadcast.mjs +151 -0
  13. package/dist/bluetooth/constants.cjs +96 -0
  14. package/dist/bluetooth/constants.d.cts +68 -0
  15. package/dist/bluetooth/constants.d.mts +68 -0
  16. package/dist/bluetooth/constants.mjs +70 -0
  17. package/dist/bluetooth/framing.cjs +125 -0
  18. package/dist/bluetooth/framing.d.cts +45 -0
  19. package/dist/bluetooth/framing.d.mts +45 -0
  20. package/dist/bluetooth/framing.mjs +122 -0
  21. package/dist/bluetooth/homey.cjs +165 -0
  22. package/dist/bluetooth/homey.d.cts +84 -0
  23. package/dist/bluetooth/homey.d.mts +84 -0
  24. package/dist/bluetooth/homey.mjs +159 -0
  25. package/dist/bluetooth/names.cjs +24 -0
  26. package/dist/bluetooth/names.d.cts +10 -0
  27. package/dist/bluetooth/names.d.mts +10 -0
  28. package/dist/bluetooth/names.mjs +20 -0
  29. package/dist/bluetooth/noble.cjs +178 -0
  30. package/dist/bluetooth/noble.d.cts +58 -0
  31. package/dist/bluetooth/noble.d.mts +58 -0
  32. package/dist/bluetooth/noble.mjs +177 -0
  33. package/dist/bluetooth/streamglue.cjs +157 -0
  34. package/dist/bluetooth/streamglue.d.cts +37 -0
  35. package/dist/bluetooth/streamglue.d.mts +37 -0
  36. package/dist/bluetooth/streamglue.mjs +154 -0
  37. package/dist/bluetooth/teslabluetooth.cjs +67 -0
  38. package/dist/bluetooth/teslabluetooth.d.cts +41 -0
  39. package/dist/bluetooth/teslabluetooth.d.mts +41 -0
  40. package/dist/bluetooth/teslabluetooth.mjs +66 -0
  41. package/dist/bluetooth/transport.cjs +10 -0
  42. package/dist/bluetooth/transport.d.cts +97 -0
  43. package/dist/bluetooth/transport.d.mts +97 -0
  44. package/dist/bluetooth/transport.mjs +10 -0
  45. package/dist/bluetooth/vehiclebluetooth.cjs +1272 -0
  46. package/dist/bluetooth/vehiclebluetooth.d.cts +495 -0
  47. package/dist/bluetooth/vehiclebluetooth.d.mts +495 -0
  48. package/dist/bluetooth/vehiclebluetooth.mjs +1270 -0
  49. package/dist/bluetooth/verify.cjs +93 -0
  50. package/dist/bluetooth/verify.d.cts +35 -0
  51. package/dist/bluetooth/verify.d.mts +35 -0
  52. package/dist/bluetooth/verify.mjs +91 -0
  53. package/dist/bluetooth.cjs +52 -0
  54. package/dist/bluetooth.d.cts +10 -0
  55. package/dist/bluetooth.d.mts +10 -0
  56. package/dist/bluetooth.mjs +9 -0
  57. package/dist/commands.cjs +1080 -85
  58. package/dist/commands.d.cts +585 -54
  59. package/dist/commands.d.mts +583 -51
  60. package/dist/commands.mjs +1084 -93
  61. package/dist/const.cjs +22 -0
  62. package/dist/const.d.cts +21 -0
  63. package/dist/const.d.mts +21 -0
  64. package/dist/const.mjs +20 -1
  65. package/dist/energy.cjs +24 -19
  66. package/dist/energy.d.cts +21 -15
  67. package/dist/energy.d.mts +21 -15
  68. package/dist/energy.mjs +24 -19
  69. package/dist/energyisland.cjs +38 -0
  70. package/dist/energyisland.mjs +37 -0
  71. package/dist/energyparsers.cjs +118 -0
  72. package/dist/energyparsers.d.cts +39 -0
  73. package/dist/energyparsers.d.mts +39 -0
  74. package/dist/energyparsers.mjs +116 -0
  75. package/dist/energyspecific.cjs +375 -17
  76. package/dist/energyspecific.d.cts +199 -19
  77. package/dist/energyspecific.d.mts +197 -16
  78. package/dist/energyspecific.mjs +370 -18
  79. package/dist/exceptions.cjs +3 -2
  80. package/dist/exceptions.d.cts +3 -2
  81. package/dist/exceptions.d.mts +3 -2
  82. package/dist/exceptions.mjs +3 -2
  83. package/dist/funnel.cjs +297 -0
  84. package/dist/funnel.d.cts +118 -0
  85. package/dist/funnel.d.mts +118 -0
  86. package/dist/funnel.mjs +292 -0
  87. package/dist/index.cjs +61 -0
  88. package/dist/index.d.cts +22 -8
  89. package/dist/index.d.mts +22 -8
  90. package/dist/index.mjs +19 -6
  91. package/dist/log.cjs +75 -0
  92. package/dist/log.d.cts +4 -0
  93. package/dist/log.d.mts +4 -0
  94. package/dist/log.mjs +71 -0
  95. package/dist/oauth.cjs +143 -0
  96. package/dist/oauth.d.cts +69 -0
  97. package/dist/oauth.d.mts +69 -0
  98. package/dist/oauth.mjs +143 -0
  99. package/dist/powerwall/client.cjs +818 -0
  100. package/dist/powerwall/client.d.cts +297 -0
  101. package/dist/powerwall/client.d.mts +297 -0
  102. package/dist/powerwall/client.mjs +807 -0
  103. package/dist/powerwall/components.cjs +188 -0
  104. package/dist/powerwall/components.d.cts +45 -0
  105. package/dist/powerwall/components.d.mts +45 -0
  106. package/dist/powerwall/components.mjs +182 -0
  107. package/dist/powerwall/energysite.cjs +216 -0
  108. package/dist/powerwall/energysite.d.cts +104 -0
  109. package/dist/powerwall/energysite.d.mts +104 -0
  110. package/dist/powerwall/energysite.mjs +214 -0
  111. package/dist/powerwall/exceptions.cjs +59 -0
  112. package/dist/powerwall/exceptions.d.cts +38 -0
  113. package/dist/powerwall/exceptions.d.mts +38 -0
  114. package/dist/powerwall/exceptions.mjs +51 -0
  115. package/dist/powerwall/gateway.cjs +102 -0
  116. package/dist/powerwall/gateway.d.cts +57 -0
  117. package/dist/powerwall/gateway.d.mts +57 -0
  118. package/dist/powerwall/gateway.mjs +101 -0
  119. package/dist/powerwall/merge.cjs +163 -0
  120. package/dist/powerwall/merge.d.cts +63 -0
  121. package/dist/powerwall/merge.d.mts +63 -0
  122. package/dist/powerwall/merge.mjs +159 -0
  123. package/dist/powerwall/models.d.cts +95 -0
  124. package/dist/powerwall/models.d.mts +95 -0
  125. package/dist/powerwall/queries.cjs +17 -0
  126. package/dist/powerwall/queries.mjs +10 -0
  127. package/dist/powerwall/transport.cjs +232 -0
  128. package/dist/powerwall/transport.mjs +227 -0
  129. package/dist/powerwall.cjs +47 -0
  130. package/dist/powerwall.d.cts +9 -0
  131. package/dist/powerwall.d.mts +9 -0
  132. package/dist/powerwall.mjs +8 -0
  133. package/dist/router/base.cjs +203 -0
  134. package/dist/router/base.d.cts +112 -0
  135. package/dist/router/base.d.mts +112 -0
  136. package/dist/router/base.mjs +200 -0
  137. package/dist/router/energysite.cjs +65 -0
  138. package/dist/router/energysite.d.cts +47 -0
  139. package/dist/router/energysite.d.mts +47 -0
  140. package/dist/router/energysite.mjs +60 -0
  141. package/dist/router.cjs +13 -0
  142. package/dist/router.d.cts +3 -1
  143. package/dist/router.d.mts +3 -1
  144. package/dist/router.mjs +3 -1
  145. package/dist/signing/crypto.cjs +28 -0
  146. package/dist/signing/crypto.mjs +26 -1
  147. package/dist/signing/energy.cjs +123 -0
  148. package/dist/signing/energy.d.cts +45 -0
  149. package/dist/signing/energy.d.mts +45 -0
  150. package/dist/signing/energy.mjs +120 -0
  151. package/dist/signing/jws.cjs +229 -0
  152. package/dist/signing/jws.d.cts +45 -0
  153. package/dist/signing/jws.d.mts +45 -0
  154. package/dist/signing/jws.mjs +211 -0
  155. package/dist/signing/keys.cjs +191 -0
  156. package/dist/signing/keys.d.cts +21 -0
  157. package/dist/signing/keys.d.mts +21 -0
  158. package/dist/signing/keys.mjs +182 -0
  159. package/dist/signing/session.cjs +104 -30
  160. package/dist/signing/session.d.cts +60 -23
  161. package/dist/signing/session.d.mts +60 -23
  162. package/dist/signing/session.mjs +105 -31
  163. package/dist/tariff.cjs +27 -0
  164. package/dist/tariff.d.cts +11 -0
  165. package/dist/tariff.d.mts +11 -0
  166. package/dist/tariff.mjs +27 -1
  167. package/dist/teslafleetapi.cjs +256 -55
  168. package/dist/teslafleetapi.d.cts +110 -14
  169. package/dist/teslafleetapi.d.mts +110 -14
  170. package/dist/teslafleetapi.mjs +258 -57
  171. package/dist/teslemetry.cjs +152 -5
  172. package/dist/teslemetry.d.cts +95 -5
  173. package/dist/teslemetry.d.mts +93 -3
  174. package/dist/teslemetry.mjs +151 -6
  175. package/dist/teslemetryenergy.cjs +287 -0
  176. package/dist/teslemetryenergy.d.cts +154 -0
  177. package/dist/teslemetryenergy.d.mts +154 -0
  178. package/dist/teslemetryenergy.mjs +282 -0
  179. package/dist/teslemetryvehicle.cjs +407 -0
  180. package/dist/teslemetryvehicle.d.cts +238 -0
  181. package/dist/teslemetryvehicle.d.mts +238 -0
  182. package/dist/teslemetryvehicle.mjs +405 -0
  183. package/dist/tessie.cjs +42 -5
  184. package/dist/tessie.d.cts +51 -5
  185. package/dist/tessie.d.mts +49 -3
  186. package/dist/tessie.mjs +42 -5
  187. package/dist/tessievehicle.cjs +514 -0
  188. package/dist/tessievehicle.d.cts +333 -0
  189. package/dist/tessievehicle.d.mts +333 -0
  190. package/dist/tessievehicle.mjs +513 -0
  191. package/dist/types/live_status.d.cts +16 -16
  192. package/dist/types/live_status.d.mts +16 -16
  193. package/dist/types/responses.d.cts +5 -1
  194. package/dist/types/responses.d.mts +5 -1
  195. package/dist/types/vehicle.d.cts +7 -1
  196. package/dist/types/vehicle.d.mts +7 -1
  197. package/dist/types.d.cts +3 -3
  198. package/dist/types.d.mts +3 -3
  199. package/dist/util.cjs +41 -0
  200. package/dist/util.d.cts +18 -0
  201. package/dist/util.d.mts +18 -0
  202. package/dist/util.mjs +40 -0
  203. package/dist/vehicle.cjs +79 -36
  204. package/dist/vehicle.d.cts +42 -26
  205. package/dist/vehicle.d.mts +42 -26
  206. package/dist/vehicle.mjs +80 -37
  207. package/dist/vehiclesigned.cjs +20 -5
  208. package/dist/vehiclesigned.d.cts +14 -5
  209. package/dist/vehiclesigned.d.mts +14 -5
  210. package/dist/vehiclesigned.mjs +20 -5
  211. package/dist/vehiclespecific.cjs +126 -15
  212. package/dist/vehiclespecific.d.cts +82 -18
  213. package/dist/vehiclespecific.d.mts +82 -18
  214. package/dist/vehiclespecific.mjs +126 -15
  215. package/package.json +56 -3
@@ -0,0 +1,495 @@
1
+ import { BluetoothVehicleData, VehicleDataEndpoint } from "../const.cjs";
2
+ import { SendOptions, SendRequires, SignedCommandResponse } from "../commands.cjs";
3
+ import { CommandResponse } from "../types/commands.cjs";
4
+ import { WakeUpOptions } from "../types/vehicle.cjs";
5
+ import Vehicle from "../vehicle.cjs";
6
+ import { BluetoothTimeout } from "../exceptions.cjs";
7
+ import { ReplyQueue } from "./async.cjs";
8
+ import { BroadcastListeners, Unsubscribe } from "./broadcast.cjs";
9
+ import { BleCharacteristic, BleDeviceRef, BleTransport } from "./transport.cjs";
10
+ import { BluetoothConfirmation } from "./verify.cjs";
11
+ import { Domain, RoutableMessage } from "@teslemetry/tesla-protocol/command/universal_message";
12
+ import { KeyFormFactor, UnsignedMessage, VehicleSleepStatusE, VehicleStatus } from "@teslemetry/tesla-protocol/command/vcsec";
13
+ import { Action } from "@teslemetry/tesla-protocol/command/car_server";
14
+ import { AlertState, ChargeScheduleState, ChargeState, ChildPresenceDetectionState, ClimateState, ClosuresState, CurrentVehicleState, DisplayState, DriveState, GuiSettings, LightShowState, LocationState, MediaDetailState, MediaState, ParentalControlsState, ParkedAccessoryState, PreconditioningScheduleState, SoftwareUpdateState, SohState, SuspensionState, TirePressureState, VehicleConfig, VehicleDetailState, VehicleState } from "@teslemetry/tesla-protocol/command/vehicle";
15
+ import { Role } from "@teslemetry/tesla-protocol/command/keys";
16
+ export interface VehicleBluetoothOptions {
17
+ transport: BleTransport;
18
+ /** Raw 32-byte P-256 scalar. `undefined` uses the parent's key. `false` disables signing, for a passive listener. */
19
+ privateKey?: Buffer | false;
20
+ /** Skip the scan and connect to this device. */
21
+ device?: BleDeviceRef;
22
+ /** How hard a mutating command confirms itself. Defaults to `"ack"`. */
23
+ confirmation?: BluetoothConfirmation;
24
+ /**
25
+ * What to do when nothing resolved a command's outcome. `false`, the default,
26
+ * reports best-effort success. `true` raises `BluetoothUnconfirmedCommand`.
27
+ */
28
+ raise_unconfirmed?: boolean;
29
+ /**
30
+ * After this long with no GATT traffic, read a characteristic to hold the
31
+ * link open. Defaults to 20000. `null` or `0` disables it. The reads delay
32
+ * an awake car's sleep, so a consumer that wants it to sleep disables them.
33
+ */
34
+ keepalive_interval_ms?: number | null;
35
+ /** Wakes a sleeping vehicle for an infotainment command, instead of raising. Defaults to `true`. */
36
+ wake_if_asleep?: boolean;
37
+ /** Connect attempts per connect. Defaults to 3. */
38
+ max_connect_attempts?: number;
39
+ /** One connect attempt. Defaults to 20000. */
40
+ connect_timeout_ms?: number;
41
+ /** One scan, which must outlast the backend's scan window. Defaults to 10000. */
42
+ scan_timeout_ms?: number;
43
+ /**
44
+ * The reply wait of one infotainment readiness probe. Defaults to 1000, which
45
+ * a ready car beats by 0.6 s. It starts after the last write, so a slow link
46
+ * loses none of it to writing, but a link with slow replies needs more.
47
+ */
48
+ wake_probe_timeout_ms?: number;
49
+ }
50
+ export interface FindVehicleOptions {
51
+ /** Match this name exactly, instead of this vehicle's. */
52
+ name?: string;
53
+ /** Match this `BleDeviceRef.id`, instead of a name. */
54
+ address?: string;
55
+ timeoutMs?: number;
56
+ }
57
+ export interface PairOptions {
58
+ /** The role the key gets. Defaults to `ROLE_OWNER`. */
59
+ role?: Role;
60
+ /** The form factor the vehicle lists the key under. Defaults to `KEY_FORM_FACTOR_CLOUD_KEY`. */
61
+ form?: KeyFormFactor;
62
+ /** How long to wait for the key card tap. Defaults to 300000. */
63
+ timeoutMs?: number;
64
+ /** Between checks of whether the key was accepted. Defaults to 5000. */
65
+ pollIntervalMs?: number;
66
+ /** Stops the wait, for a user who walked away. Nothing is written after it aborts. */
67
+ signal?: AbortSignal;
68
+ }
69
+ /**
70
+ * A vehicle reached directly over Bluetooth, with commands signed by AES-GCM.
71
+ *
72
+ * All Tesla protocol logic lives here and in `Commands`. A `BleTransport`
73
+ * supplies raw GATT only, so the same class runs on any backend, Homey's
74
+ * included. Backends may hang and may misreport their link, so every backend
75
+ * call is bounded, and a failed or timed-out operation is what counts as a dead
76
+ * link.
77
+ *
78
+ * `Commands.dispatch` holds a VCSEC session's lock across `_send`, and that lock
79
+ * is not reentrant, so `_send` serializes on its own `domainSendLock` and must
80
+ * never take `Session.withLock`.
81
+ *
82
+ * Sessions survive a reconnect, and the vehicle key they pinned at first contact
83
+ * survives with them: a new link may re-handshake, but nothing here clears a
84
+ * session or lets a new link trust a new key.
85
+ *
86
+ * A mutating command that times out is unresolved, not failed: in field data 2
87
+ * of 3 failed writes had executed anyway. So a timed-out command is never sent
88
+ * again. The outcomes a caller can see:
89
+ *
90
+ * - `BluetoothTransportError`: provably never reached the radio. Safe to replay.
91
+ * - `BluetoothCommandFailed`: state proved it did not apply. Safe to replay.
92
+ * - `BluetoothUnconfirmedCommand`: it may have run. Never replay it.
93
+ * - A plain `BluetoothTimeout`: a read, or a step before any write.
94
+ * - Best-effort success, when `raise_unconfirmed` is off and nothing resolved it.
95
+ * `charge_port_door_open` under `"verify"` is the exception, and raises.
96
+ */
97
+ export default class VehicleBluetooth extends BroadcastListeners {
98
+ readonly _transport_name: string;
99
+ protected authMethod: "hmac" | "aes";
100
+ /** Reply wait with data. */
101
+ protected defaultTimeoutMs: number;
102
+ /** Reply wait for a VCSEC actuation. A lost ack is inconclusive, so a shorter wait loses nothing. */
103
+ protected actuationTimeoutMs: number;
104
+ /** Wait for data after a bare ack. */
105
+ protected ackFollowupTimeoutMs: number;
106
+ /** How long a command woken by `wake_if_asleep` waits for infotainment. */
107
+ protected wakeTimeoutMs: number;
108
+ /** How often a wake is resent while infotainment stays silent. */
109
+ protected wakeResendIntervalMs: number;
110
+ /** How long an awake car's infotainment may take to finish booting. */
111
+ protected infotainmentBootTimeoutMs: number;
112
+ /** How long a charge-port opening has to show in charge state. */
113
+ protected chargePortVerifyTimeoutMs: number;
114
+ /** Between charge-state polls. */
115
+ protected chargePortVerifyIntervalMs: number;
116
+ /** Bound on one keepalive read. */
117
+ protected keepaliveTimeoutMs: number;
118
+ /** The vehicle's BLE name, with the usual `C` suffix. */
119
+ readonly ble_name: string;
120
+ readonly confirmation: BluetoothConfirmation;
121
+ readonly raise_unconfirmed: boolean;
122
+ wake_if_asleep: boolean;
123
+ readonly keepalive_interval_ms: number | null;
124
+ protected readonly transport: BleTransport;
125
+ protected readonly queues: Partial<Record<Domain, ReplyQueue<RoutableMessage>>>;
126
+ private readonly maxConnectAttempts;
127
+ private readonly connectTimeoutMs;
128
+ private readonly scanTimeoutMs;
129
+ private readonly wakeProbeTimeoutMs;
130
+ private readonly domainSendLock;
131
+ private readonly connectLock;
132
+ private readonly broadcastWatchers;
133
+ private device;
134
+ private link;
135
+ /** Closing a lost link. A new connect waits for it: a late disconnect could end the new link. */
136
+ private teardown;
137
+ private keepaliveTimer;
138
+ /** When GATT traffic last moved, on the monotonic clock. */
139
+ private lastActivity;
140
+ private connected;
141
+ private readonly connectionListeners;
142
+ constructor(parent: Vehicle, vin: string, options: VehicleBluetoothOptions);
143
+ /** Whether `confirmation` is `"optimistic"`. */
144
+ get optimistic(): boolean;
145
+ /** Whether `confirmation` is `"verify"`. */
146
+ get verify_commands(): boolean;
147
+ /**
148
+ * Find this vehicle. Never filters by service, because the vehicle advertises
149
+ * none. A device with free connection slots wins, then the strongest signal.
150
+ * @throws BluetoothTransportError when the scan fails or finds nothing.
151
+ */
152
+ find_vehicle({ name, address, timeoutMs }?: FindVehicleOptions): Promise<BleDeviceRef>;
153
+ /** Assign the device later connections use. */
154
+ set_device(device: BleDeviceRef): void;
155
+ /** The device later connections use, if one has been found or set. */
156
+ get_device(): BleDeviceRef | undefined;
157
+ /**
158
+ * Connect, unless a link is up. Scans first if no device is known. Python
159
+ * raises there instead, but a Homey app has no scan of its own to run.
160
+ * @throws BluetoothTransportError when every attempt fails, with the last failure as `cause`.
161
+ */
162
+ connect(maxAttempts?: number): Promise<void>;
163
+ /** Connect if the link is down, as every send does. */
164
+ connect_if_needed(maxAttempts?: number): Promise<void>;
165
+ private connectOnce;
166
+ /** Close a connection, bounded and never throwing: the failure behind it is what gets reported. */
167
+ private closeConnection;
168
+ /**
169
+ * Mark a link lost and start closing it. Only the current link has state to
170
+ * clear, so a late event from an old link or an abandoned attempt ends there.
171
+ */
172
+ private loseLink;
173
+ /** Tear down the link and wait for it. The next send reconnects. */
174
+ protected dropLink(reason: string): Promise<void>;
175
+ /** Drop the link after a failed session setup, unless the failure never touched it. */
176
+ protected dropLinkOnFailure(reason: string, error: unknown): Promise<void>;
177
+ /**
178
+ * Disconnect, waiting out any connect in progress.
179
+ * @returns Whether there was a connection.
180
+ */
181
+ disconnect(): Promise<boolean>;
182
+ /**
183
+ * Listen for the link coming up and going down. `true` fires once
184
+ * notifications are live, and `false` once the link is lost, for any reason
185
+ * and however it was noticed. Only real changes fire. A backend that drops
186
+ * silently makes `false` as late as the next operation to time out.
187
+ */
188
+ listen_connection_status(callback: (connected: boolean) => void): Unsubscribe;
189
+ private setConnected;
190
+ private startKeepalive;
191
+ private stopKeepalive;
192
+ private scheduleKeepalive;
193
+ /** Idle-triggered, so an active link pays nothing. It never raises, never reconnects and never wakes the car. */
194
+ private keepaliveTick;
195
+ /**
196
+ * One bounded read, with every failure swallowed. A read that times out
197
+ * still marks the link lost, as any read does here: on a backend that
198
+ * misreports its link, that is how a dead idle link is found before the next
199
+ * command writes to it. Python only drops the read.
200
+ */
201
+ private keepaliveRead;
202
+ /** A backend calls this, so it must never throw. */
203
+ private onNotify;
204
+ /** Route one whole message: replies to their domain's queue, the rest to whoever listens. */
205
+ private onMessage;
206
+ /** Write one frame, with its chunks together, each bounded. */
207
+ private writeFrame;
208
+ /**
209
+ * Read a characteristic, bounded. A rejected or timed-out read marks the link
210
+ * lost, whatever `isConnected` says, as that is how a dead link is found on a
211
+ * backend that misreports it. The exception is `BleNotSubmittedError` with the
212
+ * link reported up: no radio I/O happened, and a stack that hides Generic
213
+ * Access rejects those reads that way on a healthy link.
214
+ * @throws BluetoothTransportError when there is no link.
215
+ */
216
+ protected gattRead(characteristic: BleCharacteristic, timeoutMs?: number): Promise<Uint8Array>;
217
+ protected _send(msg: RoutableMessage, requires: SendRequires, options?: SendOptions): Promise<RoutableMessage>;
218
+ /**
219
+ * Watch for broadcasts showing the requested state. A lost ack does not stop
220
+ * the car broadcasting the change it caused. Only a status after the write
221
+ * counts, as one from before it says nothing.
222
+ */
223
+ private armBroadcastWatcher;
224
+ /**
225
+ * Race the addressed reply against a matching broadcast. A mismatch does not
226
+ * fail fast, because it may predate the actuation and a later broadcast can
227
+ * still confirm it. Only a mismatch still standing when the whole window has
228
+ * run out proves the command did not apply, and a lost link cuts the window
229
+ * short, so it proves nothing then.
230
+ */
231
+ private awaitReplyOrBroadcast;
232
+ /**
233
+ * Wait for the reply carrying `requires`, or a bare ack of this request.
234
+ * @param signal Ends the wait early, as a timeout does.
235
+ */
236
+ private awaitReply;
237
+ /**
238
+ * Whether a reply must be ignored rather than acted on. The link is shared, so
239
+ * an addressed reply can be a late answer to an earlier request, and acting on
240
+ * one can resend a command or report one that never ran.
241
+ *
242
+ * A reply naming another request is never ours. One naming no request must
243
+ * still be heard, because real VCSEC leaves `request_uuid` empty, but nothing
244
+ * ties it to this request unless its session-info tag or its encryption does,
245
+ * and both of those are checked later. So it may ack a command or answer a
246
+ * read, and it may not make anything happen: not a resend or a fault, and a
247
+ * status does not stand in for an actuation's ack.
248
+ */
249
+ private isForeignReply;
250
+ /** A session that a reply left unready cannot sign, and that reply proved nothing. */
251
+ protected ensureHandshake(domain: Domain): Promise<void>;
252
+ /** A failed handshake drops the link, so a retry starts on a fresh one. */
253
+ handshakeVehicleSecurity(): Promise<void>;
254
+ /**
255
+ * A failed handshake drops the link, unless VCSEC reports the car asleep:
256
+ * its infotainment is meant to be silent then, and that read proves the link.
257
+ */
258
+ handshakeInfotainment(): Promise<void>;
259
+ /**
260
+ * Sign and write a mutating command, with no reply wait. A write that fails
261
+ * provably before submission still raises. One that entered the backend may
262
+ * have reached the car, so even here it must not let a router replay it, and
263
+ * it follows `raise_unconfirmed`.
264
+ */
265
+ private sendOptimistic;
266
+ /** End a ladder that could not determine what happened. */
267
+ private unconfirmedOutcome;
268
+ /**
269
+ * Confirm a timed-out command by state, when `"verify"` asks for it.
270
+ * @returns Success, or `null` if the state could not be read. An unreadable car is never woken to verify.
271
+ * @throws BluetoothCommandFailed when the state shows it did not apply, whatever `raise_unconfirmed` says.
272
+ */
273
+ private verifyTimeout;
274
+ /**
275
+ * Open the flap or release a cable. Under `"verify"`, the charging subsystem
276
+ * is made ready first, and only physical state counts as success afterwards:
277
+ * an opening has been reported waking a sleeping car without releasing the
278
+ * latch. No readiness failure has sent anything, so a router may fail over on
279
+ * any of them. Once the one opening write has gone, an unresolved result always
280
+ * raises `BluetoothUnconfirmedCommand`, whatever `raise_unconfirmed` says, and
281
+ * it is never sent again: a best-effort success would hide a latch that never
282
+ * released, and a replay could release a cable the caller had plugged back in.
283
+ * Other modes keep the ordinary VCSEC ladder.
284
+ * @throws BluetoothCommandFailed when the car is asleep with `wake_if_asleep` off, or the cable state is unknown.
285
+ * @throws BluetoothTimeout when the car is not ready in time.
286
+ * @throws BluetoothUnconfirmedCommand when physical state never showed the opening.
287
+ */
288
+ charge_port_door_open(): Promise<CommandResponse>;
289
+ /**
290
+ * Everything before the opening, under one `wakeTimeoutMs` deadline.
291
+ * @returns Whether a cable is connected, which picks the proof of success.
292
+ */
293
+ private chargePortPreflight;
294
+ private chargePortReadiness;
295
+ /**
296
+ * Poll for the physical result, holding to the goal set before the opening:
297
+ * an open flap must never stand in for a latch that did not release. Nothing
298
+ * here may send the opening again, and no failed read may reach a router as
299
+ * anything but unconfirmed.
300
+ */
301
+ private verifyChargePortOpened;
302
+ /**
303
+ * Send a VCSEC actuation through the confirmation ladder. A plan's check also
304
+ * races the ack, so `options` is ignored: the plan is the only source of it.
305
+ */
306
+ protected sendVehicleSecurity(command: UnsignedMessage, _options?: Pick<SendOptions, "confirmBroadcast">): Promise<CommandResponse>;
307
+ /**
308
+ * Send an infotainment command through the confirmation ladder. `mutating:
309
+ * false` is exempt: `ping` always waits for its real reply.
310
+ */
311
+ protected sendInfotainment(action: Action, { mutating }?: {
312
+ mutating?: boolean;
313
+ }): Promise<SignedCommandResponse>;
314
+ private infotainmentLadder;
315
+ /**
316
+ * Wake a sleeping car until infotainment can take a command.
317
+ * @throws BluetoothCommandFailed when it cannot: the command provably never ran.
318
+ */
319
+ protected wakeForCommand(timeout: BluetoothTimeout): Promise<void>;
320
+ /** VCSEC's sleep status, or `null` if unreadable. */
321
+ protected sleepStatus(): Promise<VehicleSleepStatusE | null>;
322
+ /** Whether VCSEC reports the car asleep; `false` if unreadable. */
323
+ protected vehicleAsleep(): Promise<boolean>;
324
+ /** The vehicle security computer's `VehicleStatus`. It answers while the car sleeps. */
325
+ vehicle_state(): Promise<VehicleStatus>;
326
+ private readVehicleData;
327
+ /** The charging state. */
328
+ charge_state(): Promise<ChargeState>;
329
+ /** The HVAC and cabin climate state. */
330
+ climate_state(): Promise<ClimateState>;
331
+ /** The driving state, including speed and power. */
332
+ drive_state(): Promise<DriveState>;
333
+ /** The vehicle's location. */
334
+ location_state(): Promise<LocationState>;
335
+ /** The doors, windows, trunks and locks, as infotainment reports them. */
336
+ closures_state(): Promise<ClosuresState>;
337
+ /** The charge schedules. */
338
+ charge_schedule_state(): Promise<ChargeScheduleState>;
339
+ /** The preconditioning schedules. */
340
+ preconditioning_schedule_state(): Promise<PreconditioningScheduleState>;
341
+ /** The tire pressures. */
342
+ tire_pressure_state(): Promise<TirePressureState>;
343
+ /** The media playback state. */
344
+ media_state(): Promise<MediaState>;
345
+ /** Detail on the media playing now. */
346
+ media_detail_state(): Promise<MediaDetailState>;
347
+ /** The software update state. */
348
+ software_update_state(): Promise<SoftwareUpdateState>;
349
+ /** The parental controls state. */
350
+ parental_controls_state(): Promise<ParentalControlsState>;
351
+ /** The display units and formats. */
352
+ gui_settings(): Promise<GuiSettings>;
353
+ /** The state of parked accessories, such as a tent. */
354
+ parked_accessory_state(): Promise<ParkedAccessoryState>;
355
+ /**
356
+ * The older infotainment vehicle state, tag 6, for older firmware. Not `current_vehicle_state`, nor VCSEC's `vehicle_state`.
357
+ */
358
+ legacy_vehicle_state(): Promise<VehicleState>;
359
+ /**
360
+ * The infotainment vehicle state, tag 18, on current firmware. Not `legacy_vehicle_state`, nor VCSEC's `vehicle_state`.
361
+ */
362
+ current_vehicle_state(): Promise<CurrentVehicleState>;
363
+ /** The vehicle's fixed configuration. */
364
+ vehicle_config(): Promise<VehicleConfig>;
365
+ /** The battery state of health. */
366
+ soh_state(): Promise<SohState>;
367
+ /** The vehicle's name and software details. */
368
+ vehicle_detail_state(): Promise<VehicleDetailState>;
369
+ /** The display state. */
370
+ display_state(): Promise<DisplayState>;
371
+ /** The active alerts. */
372
+ alert_state(): Promise<AlertState>;
373
+ /** The light show state. */
374
+ light_show_state(): Promise<LightShowState>;
375
+ /** The suspension state. */
376
+ suspension_state(): Promise<SuspensionState>;
377
+ /** The child presence detection state. */
378
+ child_presence_detection_state(): Promise<ChildPresenceDetectionState>;
379
+ /**
380
+ * Several sub-states in one signed read. This is not the cloud method: it
381
+ * takes `BluetoothVehicleData` values, not `VehicleDataEndpoint`, and resolves
382
+ * to `VehicleData`, not a REST envelope. There is no default of every endpoint,
383
+ * because as few as two together have exceeded the response size limit, which
384
+ * raises `TeslaFleetMessageFaultResponseSizeExceedsMTU`. Prefer one reader each.
385
+ * @param endpoints An explicit list. `[]` asks for nothing.
386
+ * @throws BluetoothCloudUnavailableError for anything else, sending nothing: no argument and REST endpoint names are the cloud call, which a router can fail over to.
387
+ */
388
+ vehicle_data(endpoints?: BluetoothVehicleData[] | VehicleDataEndpoint[] | string): Promise<any>;
389
+ /**
390
+ * The name set in the vehicle, read from GATT Device Name. It is not advertised.
391
+ * The vehicle prefixes it with a key emoji once it is available.
392
+ * @returns The name, or `null` if it never appeared: a backend may hide Generic Access.
393
+ */
394
+ query_display_name(max_attempts?: number): Promise<string | null>;
395
+ /** GATT Appearance, or `null` if it cannot be read. */
396
+ query_appearance(): Promise<Uint8Array | null>;
397
+ /** The version characteristic as a big-endian integer, or `null` if it cannot be read. */
398
+ query_version(): Promise<number | null>;
399
+ private moveClosure;
400
+ /** Opens the front driver door. */
401
+ open_front_driver_door(): Promise<CommandResponse>;
402
+ /** Closes the front driver door. Doors have no reliable powered close on a Model 3. */
403
+ close_front_driver_door(): Promise<CommandResponse>;
404
+ /** Opens the front passenger door. */
405
+ open_front_passenger_door(): Promise<CommandResponse>;
406
+ /** Closes the front passenger door. Doors have no reliable powered close on a Model 3. */
407
+ close_front_passenger_door(): Promise<CommandResponse>;
408
+ /** Opens the rear driver door. */
409
+ open_rear_driver_door(): Promise<CommandResponse>;
410
+ /** Closes the rear driver door. Doors have no reliable powered close on a Model 3. */
411
+ close_rear_driver_door(): Promise<CommandResponse>;
412
+ /** Opens the rear passenger door. */
413
+ open_rear_passenger_door(): Promise<CommandResponse>;
414
+ /** Closes the rear passenger door. Doors have no reliable powered close on a Model 3. */
415
+ close_rear_passenger_door(): Promise<CommandResponse>;
416
+ /** Opens the rear trunk. */
417
+ open_rear_trunk(): Promise<CommandResponse>;
418
+ /** Closes the rear trunk. */
419
+ close_rear_trunk(): Promise<CommandResponse>;
420
+ /**
421
+ * Ask the vehicle to add this instance's key, which someone confirms by tapping
422
+ * a key card on the console. Resolves once the key is on the whitelist.
423
+ *
424
+ * The whitelist operation is written exactly once, because a resend prompts
425
+ * the user again. Its reply is one frame, which a link that cycles during the
426
+ * walk to the car can lose, so completion is also proved by polling: a VCSEC
427
+ * handshake only succeeds once this key is whitelisted, and it reconnects, so
428
+ * the wait survives a dropped link.
429
+ *
430
+ * Success needs positive evidence: an explicit success reply, or an
431
+ * authenticated handshake with this key. Python takes any reply without a
432
+ * whitelist fault, which a WAIT or a bare ack satisfies before the tap.
433
+ *
434
+ * Tesla's Go SDK sends a bare `ToVCSECMessage` here. This wraps the
435
+ * `UnsignedMessage` in a `RoutableMessage`, as Python does, and that has paired
436
+ * a real car. If pairing fails on another vehicle, look there first.
437
+ * @throws RangeError when `pollIntervalMs` is not positive, before anything is sent.
438
+ * @throws SigningDisabled when this instance has no key, before anything is sent.
439
+ * @throws BluetoothTimeout when nothing confirmed it by `timeoutMs`, with the link dropped.
440
+ * @throws WhitelistOperationStatus or a subclass when the vehicle refused the key.
441
+ * @throws The reason of `signal`, once it aborts. The link is kept.
442
+ */
443
+ pair({ role, form, timeoutMs, pollIntervalMs, signal }?: PairOptions): Promise<void>;
444
+ private confirmPairing;
445
+ /**
446
+ * Whether this key is on the whitelist: a VCSEC handshake only completes once
447
+ * it is. Any failure means "not yet", so polling carries on across a dropped
448
+ * link. It sends one request, unlike `handshake`, because the next poll is the
449
+ * retry, and nothing may be written after a `pair` is aborted.
450
+ */
451
+ private pairProbe;
452
+ /**
453
+ * Look for a whitelist reply that arrived after `_send` stopped waiting. This
454
+ * must run before a probe, whose `_send` discards what is queued. Anything else
455
+ * in the queue stays there.
456
+ * @returns Whether one was there and explicitly reported success.
457
+ * @throws WhitelistOperationStatus or a subclass when it reported a refusal.
458
+ */
459
+ private consumeLateWhitelistReply;
460
+ /**
461
+ * Whether a reply to the whitelist operation says the key was added. Only an
462
+ * OK with a whitelist status and no failure does. A WAIT means the car is
463
+ * still waiting for the tap, and a bare ack, a status or anything else says
464
+ * nothing, so `pair` goes on polling.
465
+ * @throws WhitelistOperationStatus or a subclass when the reply is a refusal.
466
+ */
467
+ private whitelistReplyConfirms;
468
+ /**
469
+ * Wake the vehicle. Takes `VehicleSpecific`'s options, but resolves to a
470
+ * `CommandResponse`, not the REST `VehicleResponse`.
471
+ *
472
+ * Without `wait`, this sends the RKE wake to the vehicle security computer,
473
+ * which acks well before infotainment can answer, so an infotainment command
474
+ * sent straight after can still time out.
475
+ *
476
+ * With `wait`, it blocks until infotainment completes a fresh handshake, the
477
+ * only proof it can take commands: VCSEC reports awake seconds before that.
478
+ * The wake is idempotent, so it is resent every 3 s until then.
479
+ * @param options.timeoutMs Deadline for `wait`, in milliseconds. Defaults to 30000.
480
+ * @throws BluetoothTimeout at the deadline, with the link dropped.
481
+ */
482
+ wake_up({ wait, timeoutMs }?: WakeUpOptions): Promise<any>;
483
+ /**
484
+ * Probe infotainment until it answers. With `wake`, the RKE wake is sent
485
+ * first and resent every `wakeResendIntervalMs`.
486
+ * @param over Stops the probing, for a caller that has stopped waiting.
487
+ * @throws BluetoothTimeout at the deadline.
488
+ */
489
+ protected awaitInfotainment(timeoutMs: number, wake: boolean, over?: AbortSignal): Promise<void>;
490
+ /**
491
+ * Handshake with infotainment, always with a fresh request: only a live reply
492
+ * proves it is awake, so a cached session counts for nothing.
493
+ */
494
+ private probeInfotainment;
495
+ }