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,41 @@
1
+ import { Logger } from "../log.mjs";
2
+ import TeslaFleetApi from "../teslafleetapi.mjs";
3
+ import Vehicle from "../vehicle.mjs";
4
+ import VehicleBluetooth, { VehicleBluetoothOptions } from "./vehiclebluetooth.mjs";
5
+ /**
6
+ * The vehicles of a `TeslaBluetooth`. `createBluetooth` lives here, not on the
7
+ * root `Vehicle`, so the root entry never loads Bluetooth code.
8
+ */
9
+ export declare class VehiclesBluetooth extends Vehicle {
10
+ /** Class `createBluetooth` instantiates; a subclass overrides it to supply its own vehicle type. */
11
+ static Bluetooth: new (parent: Vehicle, vin: string, options: VehicleBluetoothOptions) => VehicleBluetooth;
12
+ /** Same as `createBluetooth`, under Python's other name. */
13
+ create(vin: string, options: VehicleBluetoothOptions): VehicleBluetooth;
14
+ /** Creates a vehicle reached over Bluetooth through `options.transport`. */
15
+ createBluetooth(vin: string, options: VehicleBluetoothOptions): VehicleBluetooth;
16
+ }
17
+ /**
18
+ * A client with no cloud behind it, for vehicles reached only over Bluetooth.
19
+ * Every REST path raises `BluetoothCloudUnavailableError` before any I/O, so a
20
+ * REST method a vehicle inherits fails clearly, sends nothing, and is safe for
21
+ * a router to fail over on. A cloud client that wants the same key on both
22
+ * paths uses `new VehicleBluetooth(client.vehicles, vin, options)` instead.
23
+ */
24
+ export default class TeslaBluetooth extends TeslaFleetApi {
25
+ static Vehicles: new (parent: TeslaFleetApi) => Vehicle;
26
+ vehicles: VehiclesBluetooth;
27
+ readonly _transport_name: string;
28
+ constructor(options?: {
29
+ privateKey?: Buffer;
30
+ debug?: boolean;
31
+ logger?: Logger;
32
+ });
33
+ _request(): Promise<never>;
34
+ protected _fetch(): Promise<never>;
35
+ /** Whether a BLE device name is a valid Tesla vehicle's. */
36
+ valid_name(name: string): boolean;
37
+ /** The BLE device name of a vehicle. */
38
+ get_name(vin: string): string;
39
+ /** Whether an advertised name belongs to this VIN, with any valid suffix. */
40
+ name_matches_vin(advertised: string, vin: string): boolean;
41
+ }
@@ -0,0 +1,66 @@
1
+ import { BluetoothCloudUnavailableError } from "../exceptions.mjs";
2
+ import TeslaFleetApi from "../teslafleetapi.mjs";
3
+ import Vehicle from "../vehicle.mjs";
4
+ import { get_name, name_matches_vin, valid_name } from "./names.mjs";
5
+ import VehicleBluetooth from "./vehiclebluetooth.mjs";
6
+ // src/bluetooth/teslabluetooth.ts
7
+ /**
8
+ * The vehicles of a `TeslaBluetooth`. `createBluetooth` lives here, not on the
9
+ * root `Vehicle`, so the root entry never loads Bluetooth code.
10
+ */
11
+ var VehiclesBluetooth = class extends Vehicle {
12
+ /** Class `createBluetooth` instantiates; a subclass overrides it to supply its own vehicle type. */
13
+ static Bluetooth = VehicleBluetooth;
14
+ /** Same as `createBluetooth`, under Python's other name. */
15
+ create(vin, options) {
16
+ return this.createBluetooth(vin, options);
17
+ }
18
+ /** Creates a vehicle reached over Bluetooth through `options.transport`. */
19
+ createBluetooth(vin, options) {
20
+ const vehicle = new this.constructor.Bluetooth(this, vin, options);
21
+ this.byVin.set(vin, vehicle);
22
+ return vehicle;
23
+ }
24
+ };
25
+ /**
26
+ * A client with no cloud behind it, for vehicles reached only over Bluetooth.
27
+ * Every REST path raises `BluetoothCloudUnavailableError` before any I/O, so a
28
+ * REST method a vehicle inherits fails clearly, sends nothing, and is safe for
29
+ * a router to fail over on. A cloud client that wants the same key on both
30
+ * paths uses `new VehicleBluetooth(client.vehicles, vin, options)` instead.
31
+ */
32
+ var TeslaBluetooth = class extends TeslaFleetApi {
33
+ static Vehicles = VehiclesBluetooth;
34
+ _transport_name = "bluetooth";
35
+ constructor(options = {}) {
36
+ super({
37
+ server: "bluetooth://local",
38
+ chargingScope: false,
39
+ energyScope: false,
40
+ partnerScope: false,
41
+ userScope: false,
42
+ debug: options.debug,
43
+ logger: options.logger
44
+ });
45
+ this.private_key = options.privateKey ?? null;
46
+ }
47
+ async _request() {
48
+ throw new BluetoothCloudUnavailableError();
49
+ }
50
+ async _fetch() {
51
+ throw new BluetoothCloudUnavailableError();
52
+ }
53
+ /** Whether a BLE device name is a valid Tesla vehicle's. */
54
+ valid_name(name) {
55
+ return valid_name(name);
56
+ }
57
+ /** The BLE device name of a vehicle. */
58
+ get_name(vin) {
59
+ return get_name(vin);
60
+ }
61
+ /** Whether an advertised name belongs to this VIN, with any valid suffix. */
62
+ name_matches_vin(advertised, vin) {
63
+ return name_matches_vin(advertised, vin);
64
+ }
65
+ };
66
+ export { VehiclesBluetooth, TeslaBluetooth as default };
@@ -0,0 +1,10 @@
1
+ // src/bluetooth/transport.ts
2
+ /**
3
+ * Thrown by an adapter only when bytes provably never entered the BLE stack,
4
+ * such as an unresolved characteristic, or a link the backend reports down
5
+ * before the call. A router can then safely replay the command elsewhere.
6
+ */
7
+ var BleNotSubmittedError = class extends Error {
8
+ name = "BleNotSubmittedError";
9
+ };
10
+ exports.BleNotSubmittedError = BleNotSubmittedError;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The seam between the library and a Bluetooth backend.
3
+ *
4
+ * The library owns framing, reassembly, signing, sessions, retries, keepalive
5
+ * and confirmation. An adapter owns raw GATT and holds no Tesla logic but the
6
+ * UUIDs, which it imports. Around every adapter the library adds one call at a
7
+ * time per connection, a timeout on every call, frame chunking and link-loss
8
+ * handling, so an adapter needs none of them. This file imports no backend,
9
+ * and neither does anything else in `./bluetooth`.
10
+ *
11
+ * The contract asks only for what the weakest backend, Homey, can do:
12
+ *
13
+ * - `scan` may take a fixed window and ignore `timeoutMs`. Homey's `discover()`
14
+ * takes no filter and scans for about 5 s, whatever it is asked. The library
15
+ * filters what comes back, so an adapter may return all it saw.
16
+ * - `connect` needs no timeout of its own, and Homey has none. The library
17
+ * abandons a hung attempt, and closes the connection if it arrives later.
18
+ * - `write` is always with response, the only mode Homey offers and the only
19
+ * one the vehicle takes.
20
+ * - `maxWriteSize` may be left out when the backend hides its MTU. The library
21
+ * then writes `DEFAULT_MAX_WRITE_SIZE` bytes at a time.
22
+ * - `isConnected` and `onDisconnect` may both lie: Homey's state goes stale on
23
+ * a silent drop, and its event is not guaranteed. Neither has to be right,
24
+ * since a failed or timed-out operation is what the library treats as a dead
25
+ * link. A rejection with `BleNotSubmittedError` is the exception.
26
+ *
27
+ * Adapter rules, each worth a test in the adapter's own suite:
28
+ *
29
+ * 1. Never scan with a service filter, because the vehicle advertises none.
30
+ * Scan actively where the backend has a choice: the name is in the scan
31
+ * response.
32
+ * 2. `connect` resolves only once the notify subscription is confirmed, as a
33
+ * reply sent before that is lost.
34
+ * 3. `connect` closes a half-open link before it rejects. The vehicle has
35
+ * three connection slots.
36
+ * 4. Subscribe again on every connect. Subscriptions end with the link.
37
+ * 5. `write` is always with response.
38
+ * 6. Throw `BleNotSubmittedError` only when the failure is provably before any
39
+ * radio I/O, as a read of a characteristic that was never resolved is on a
40
+ * stack that hides Generic Access. It leaves the link up. All other failures
41
+ * stay plain errors, and the library treats them as a lost link.
42
+ * 7. Pass notifications unchanged and in order. The library copies them, so a
43
+ * reused backend buffer is safe once the handler returns.
44
+ * 8. Do not retry writes. A retry can run a command twice.
45
+ * 9. `disconnect` is safe to call twice, and on a dead link.
46
+ */
47
+ /** Named characteristics, so an adapter resolves service and UUID its own way. */
48
+ export type BleCharacteristic = "version" | "deviceName" | "appearance";
49
+ /** A found vehicle. `id` is opaque: a Homey peripheral uuid, a MAC, a browser device id. */
50
+ export interface BleDeviceRef {
51
+ id: string;
52
+ name?: string;
53
+ rssi?: number;
54
+ /** `false` means the vehicle already holds its maximum BLE connections. */
55
+ connectable?: boolean;
56
+ }
57
+ export interface BleLinkHandlers {
58
+ /** One notification, unchanged and in arrival order. */
59
+ onNotify(chunk: Uint8Array): void;
60
+ /** Best effort, and a faster signal only. The library also treats a failed operation as a lost link. */
61
+ onDisconnect(): void;
62
+ }
63
+ export interface BleConnection {
64
+ /** The adapter's best knowledge. It may be stale. */
65
+ readonly isConnected: boolean;
66
+ /**
67
+ * Largest bytes per write. `null` means the backend accepts a full frame.
68
+ * Left out, the library uses `DEFAULT_MAX_WRITE_SIZE`.
69
+ */
70
+ readonly maxWriteSize?: number | null;
71
+ /** One write-with-response to the vehicle write characteristic. Resolves on the ATT response. */
72
+ write(data: Uint8Array): Promise<void>;
73
+ read(characteristic: BleCharacteristic): Promise<Uint8Array>;
74
+ disconnect(): Promise<void>;
75
+ }
76
+ export interface BleScanOptions {
77
+ /** How long the library will wait. A backend with a fixed scan window may ignore it. */
78
+ timeoutMs: number;
79
+ /** Tells an adapter which name it can stop scanning for. */
80
+ matches?: (name: string) => boolean;
81
+ }
82
+ export interface BleTransport {
83
+ /** How long one scan needs, for a backend with a fixed window. `scan_timeout_ms` overrides it. */
84
+ readonly scanTimeoutMs?: number;
85
+ /** Active, unfiltered scan. Resolves once a match is found, or when the scan ends with what was seen. */
86
+ scan(options: BleScanOptions): Promise<BleDeviceRef[]>;
87
+ /** Connect, discover, subscribe to notify. Resolves only when notifications are live. */
88
+ connect(device: BleDeviceRef, handlers: BleLinkHandlers): Promise<BleConnection>;
89
+ }
90
+ /**
91
+ * Thrown by an adapter only when bytes provably never entered the BLE stack,
92
+ * such as an unresolved characteristic, or a link the backend reports down
93
+ * before the call. A router can then safely replay the command elsewhere.
94
+ */
95
+ export declare class BleNotSubmittedError extends Error {
96
+ readonly name = "BleNotSubmittedError";
97
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The seam between the library and a Bluetooth backend.
3
+ *
4
+ * The library owns framing, reassembly, signing, sessions, retries, keepalive
5
+ * and confirmation. An adapter owns raw GATT and holds no Tesla logic but the
6
+ * UUIDs, which it imports. Around every adapter the library adds one call at a
7
+ * time per connection, a timeout on every call, frame chunking and link-loss
8
+ * handling, so an adapter needs none of them. This file imports no backend,
9
+ * and neither does anything else in `./bluetooth`.
10
+ *
11
+ * The contract asks only for what the weakest backend, Homey, can do:
12
+ *
13
+ * - `scan` may take a fixed window and ignore `timeoutMs`. Homey's `discover()`
14
+ * takes no filter and scans for about 5 s, whatever it is asked. The library
15
+ * filters what comes back, so an adapter may return all it saw.
16
+ * - `connect` needs no timeout of its own, and Homey has none. The library
17
+ * abandons a hung attempt, and closes the connection if it arrives later.
18
+ * - `write` is always with response, the only mode Homey offers and the only
19
+ * one the vehicle takes.
20
+ * - `maxWriteSize` may be left out when the backend hides its MTU. The library
21
+ * then writes `DEFAULT_MAX_WRITE_SIZE` bytes at a time.
22
+ * - `isConnected` and `onDisconnect` may both lie: Homey's state goes stale on
23
+ * a silent drop, and its event is not guaranteed. Neither has to be right,
24
+ * since a failed or timed-out operation is what the library treats as a dead
25
+ * link. A rejection with `BleNotSubmittedError` is the exception.
26
+ *
27
+ * Adapter rules, each worth a test in the adapter's own suite:
28
+ *
29
+ * 1. Never scan with a service filter, because the vehicle advertises none.
30
+ * Scan actively where the backend has a choice: the name is in the scan
31
+ * response.
32
+ * 2. `connect` resolves only once the notify subscription is confirmed, as a
33
+ * reply sent before that is lost.
34
+ * 3. `connect` closes a half-open link before it rejects. The vehicle has
35
+ * three connection slots.
36
+ * 4. Subscribe again on every connect. Subscriptions end with the link.
37
+ * 5. `write` is always with response.
38
+ * 6. Throw `BleNotSubmittedError` only when the failure is provably before any
39
+ * radio I/O, as a read of a characteristic that was never resolved is on a
40
+ * stack that hides Generic Access. It leaves the link up. All other failures
41
+ * stay plain errors, and the library treats them as a lost link.
42
+ * 7. Pass notifications unchanged and in order. The library copies them, so a
43
+ * reused backend buffer is safe once the handler returns.
44
+ * 8. Do not retry writes. A retry can run a command twice.
45
+ * 9. `disconnect` is safe to call twice, and on a dead link.
46
+ */
47
+ /** Named characteristics, so an adapter resolves service and UUID its own way. */
48
+ export type BleCharacteristic = "version" | "deviceName" | "appearance";
49
+ /** A found vehicle. `id` is opaque: a Homey peripheral uuid, a MAC, a browser device id. */
50
+ export interface BleDeviceRef {
51
+ id: string;
52
+ name?: string;
53
+ rssi?: number;
54
+ /** `false` means the vehicle already holds its maximum BLE connections. */
55
+ connectable?: boolean;
56
+ }
57
+ export interface BleLinkHandlers {
58
+ /** One notification, unchanged and in arrival order. */
59
+ onNotify(chunk: Uint8Array): void;
60
+ /** Best effort, and a faster signal only. The library also treats a failed operation as a lost link. */
61
+ onDisconnect(): void;
62
+ }
63
+ export interface BleConnection {
64
+ /** The adapter's best knowledge. It may be stale. */
65
+ readonly isConnected: boolean;
66
+ /**
67
+ * Largest bytes per write. `null` means the backend accepts a full frame.
68
+ * Left out, the library uses `DEFAULT_MAX_WRITE_SIZE`.
69
+ */
70
+ readonly maxWriteSize?: number | null;
71
+ /** One write-with-response to the vehicle write characteristic. Resolves on the ATT response. */
72
+ write(data: Uint8Array): Promise<void>;
73
+ read(characteristic: BleCharacteristic): Promise<Uint8Array>;
74
+ disconnect(): Promise<void>;
75
+ }
76
+ export interface BleScanOptions {
77
+ /** How long the library will wait. A backend with a fixed scan window may ignore it. */
78
+ timeoutMs: number;
79
+ /** Tells an adapter which name it can stop scanning for. */
80
+ matches?: (name: string) => boolean;
81
+ }
82
+ export interface BleTransport {
83
+ /** How long one scan needs, for a backend with a fixed window. `scan_timeout_ms` overrides it. */
84
+ readonly scanTimeoutMs?: number;
85
+ /** Active, unfiltered scan. Resolves once a match is found, or when the scan ends with what was seen. */
86
+ scan(options: BleScanOptions): Promise<BleDeviceRef[]>;
87
+ /** Connect, discover, subscribe to notify. Resolves only when notifications are live. */
88
+ connect(device: BleDeviceRef, handlers: BleLinkHandlers): Promise<BleConnection>;
89
+ }
90
+ /**
91
+ * Thrown by an adapter only when bytes provably never entered the BLE stack,
92
+ * such as an unresolved characteristic, or a link the backend reports down
93
+ * before the call. A router can then safely replay the command elsewhere.
94
+ */
95
+ export declare class BleNotSubmittedError extends Error {
96
+ readonly name = "BleNotSubmittedError";
97
+ }
@@ -0,0 +1,10 @@
1
+ // src/bluetooth/transport.ts
2
+ /**
3
+ * Thrown by an adapter only when bytes provably never entered the BLE stack,
4
+ * such as an unresolved characteristic, or a link the backend reports down
5
+ * before the call. A router can then safely replay the command elsewhere.
6
+ */
7
+ var BleNotSubmittedError = class extends Error {
8
+ name = "BleNotSubmittedError";
9
+ };
10
+ export { BleNotSubmittedError };