tesla-fleet-api 0.4.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.
- package/README.md +284 -1
- package/dist/_virtual/_rolldown/runtime.cjs +10 -0
- package/dist/bluetooth/adapters/shared.cjs +38 -0
- package/dist/bluetooth/adapters/shared.mjs +36 -0
- package/dist/bluetooth/async.cjs +121 -0
- package/dist/bluetooth/async.d.cts +10 -0
- package/dist/bluetooth/async.d.mts +10 -0
- package/dist/bluetooth/async.mjs +116 -0
- package/dist/bluetooth/broadcast.cjs +153 -0
- package/dist/bluetooth/broadcast.d.cts +59 -0
- package/dist/bluetooth/broadcast.d.mts +59 -0
- package/dist/bluetooth/broadcast.mjs +151 -0
- package/dist/bluetooth/constants.cjs +99 -0
- package/dist/bluetooth/constants.d.cts +70 -0
- package/dist/bluetooth/constants.d.mts +70 -0
- package/dist/bluetooth/constants.mjs +72 -0
- package/dist/bluetooth/esphome.cjs +292 -0
- package/dist/bluetooth/esphome.d.cts +83 -0
- package/dist/bluetooth/esphome.d.mts +83 -0
- package/dist/bluetooth/esphome.mjs +291 -0
- package/dist/bluetooth/framing.cjs +125 -0
- package/dist/bluetooth/framing.d.cts +45 -0
- package/dist/bluetooth/framing.d.mts +45 -0
- package/dist/bluetooth/framing.mjs +122 -0
- package/dist/bluetooth/homey.cjs +155 -0
- package/dist/bluetooth/homey.d.cts +75 -0
- package/dist/bluetooth/homey.d.mts +75 -0
- package/dist/bluetooth/homey.mjs +150 -0
- package/dist/bluetooth/names.cjs +24 -0
- package/dist/bluetooth/names.d.cts +10 -0
- package/dist/bluetooth/names.d.mts +10 -0
- package/dist/bluetooth/names.mjs +20 -0
- package/dist/bluetooth/noble.cjs +178 -0
- package/dist/bluetooth/noble.d.cts +58 -0
- package/dist/bluetooth/noble.d.mts +58 -0
- package/dist/bluetooth/noble.mjs +177 -0
- package/dist/bluetooth/streamglue.cjs +157 -0
- package/dist/bluetooth/streamglue.d.cts +37 -0
- package/dist/bluetooth/streamglue.d.mts +37 -0
- package/dist/bluetooth/streamglue.mjs +154 -0
- package/dist/bluetooth/teslabluetooth.cjs +67 -0
- package/dist/bluetooth/teslabluetooth.d.cts +41 -0
- package/dist/bluetooth/teslabluetooth.d.mts +41 -0
- package/dist/bluetooth/teslabluetooth.mjs +66 -0
- package/dist/bluetooth/transport.cjs +10 -0
- package/dist/bluetooth/transport.d.cts +95 -0
- package/dist/bluetooth/transport.d.mts +95 -0
- package/dist/bluetooth/transport.mjs +10 -0
- package/dist/bluetooth/vehiclebluetooth.cjs +1272 -0
- package/dist/bluetooth/vehiclebluetooth.d.cts +495 -0
- package/dist/bluetooth/vehiclebluetooth.d.mts +495 -0
- package/dist/bluetooth/vehiclebluetooth.mjs +1270 -0
- package/dist/bluetooth/verify.cjs +93 -0
- package/dist/bluetooth/verify.d.cts +35 -0
- package/dist/bluetooth/verify.d.mts +35 -0
- package/dist/bluetooth/verify.mjs +91 -0
- package/dist/bluetooth.cjs +53 -0
- package/dist/bluetooth.d.cts +10 -0
- package/dist/bluetooth.d.mts +10 -0
- package/dist/bluetooth.mjs +9 -0
- package/dist/commands.cjs +1080 -85
- package/dist/commands.d.cts +585 -54
- package/dist/commands.d.mts +583 -51
- package/dist/commands.mjs +1084 -93
- package/dist/const.cjs +22 -0
- package/dist/const.d.cts +21 -0
- package/dist/const.d.mts +21 -0
- package/dist/const.mjs +20 -1
- package/dist/energy.cjs +24 -19
- package/dist/energy.d.cts +21 -15
- package/dist/energy.d.mts +21 -15
- package/dist/energy.mjs +24 -19
- package/dist/energyisland.cjs +38 -0
- package/dist/energyisland.mjs +37 -0
- package/dist/energyparsers.cjs +118 -0
- package/dist/energyparsers.d.cts +39 -0
- package/dist/energyparsers.d.mts +39 -0
- package/dist/energyparsers.mjs +116 -0
- package/dist/energyspecific.cjs +375 -17
- package/dist/energyspecific.d.cts +199 -19
- package/dist/energyspecific.d.mts +197 -16
- package/dist/energyspecific.mjs +370 -18
- package/dist/exceptions.cjs +3 -2
- package/dist/exceptions.d.cts +3 -2
- package/dist/exceptions.d.mts +3 -2
- package/dist/exceptions.mjs +3 -2
- package/dist/funnel.cjs +297 -0
- package/dist/funnel.d.cts +118 -0
- package/dist/funnel.d.mts +118 -0
- package/dist/funnel.mjs +292 -0
- package/dist/index.cjs +61 -0
- package/dist/index.d.cts +22 -8
- package/dist/index.d.mts +22 -8
- package/dist/index.mjs +19 -6
- package/dist/log.cjs +75 -0
- package/dist/log.d.cts +4 -0
- package/dist/log.d.mts +4 -0
- package/dist/log.mjs +71 -0
- package/dist/oauth.cjs +143 -0
- package/dist/oauth.d.cts +69 -0
- package/dist/oauth.d.mts +69 -0
- package/dist/oauth.mjs +143 -0
- package/dist/powerwall/client.cjs +818 -0
- package/dist/powerwall/client.d.cts +297 -0
- package/dist/powerwall/client.d.mts +297 -0
- package/dist/powerwall/client.mjs +807 -0
- package/dist/powerwall/components.cjs +188 -0
- package/dist/powerwall/components.d.cts +45 -0
- package/dist/powerwall/components.d.mts +45 -0
- package/dist/powerwall/components.mjs +182 -0
- package/dist/powerwall/energysite.cjs +216 -0
- package/dist/powerwall/energysite.d.cts +104 -0
- package/dist/powerwall/energysite.d.mts +104 -0
- package/dist/powerwall/energysite.mjs +214 -0
- package/dist/powerwall/exceptions.cjs +59 -0
- package/dist/powerwall/exceptions.d.cts +38 -0
- package/dist/powerwall/exceptions.d.mts +38 -0
- package/dist/powerwall/exceptions.mjs +51 -0
- package/dist/powerwall/gateway.cjs +102 -0
- package/dist/powerwall/gateway.d.cts +57 -0
- package/dist/powerwall/gateway.d.mts +57 -0
- package/dist/powerwall/gateway.mjs +101 -0
- package/dist/powerwall/merge.cjs +163 -0
- package/dist/powerwall/merge.d.cts +63 -0
- package/dist/powerwall/merge.d.mts +63 -0
- package/dist/powerwall/merge.mjs +159 -0
- package/dist/powerwall/models.d.cts +95 -0
- package/dist/powerwall/models.d.mts +95 -0
- package/dist/powerwall/queries.cjs +17 -0
- package/dist/powerwall/queries.mjs +10 -0
- package/dist/powerwall/transport.cjs +232 -0
- package/dist/powerwall/transport.mjs +227 -0
- package/dist/powerwall.cjs +47 -0
- package/dist/powerwall.d.cts +9 -0
- package/dist/powerwall.d.mts +9 -0
- package/dist/powerwall.mjs +8 -0
- package/dist/router/base.cjs +203 -0
- package/dist/router/base.d.cts +112 -0
- package/dist/router/base.d.mts +112 -0
- package/dist/router/base.mjs +200 -0
- package/dist/router/energysite.cjs +65 -0
- package/dist/router/energysite.d.cts +47 -0
- package/dist/router/energysite.d.mts +47 -0
- package/dist/router/energysite.mjs +60 -0
- package/dist/router.cjs +13 -0
- package/dist/router.d.cts +3 -1
- package/dist/router.d.mts +3 -1
- package/dist/router.mjs +3 -1
- package/dist/signing/crypto.cjs +28 -0
- package/dist/signing/crypto.mjs +26 -1
- package/dist/signing/energy.cjs +123 -0
- package/dist/signing/energy.d.cts +45 -0
- package/dist/signing/energy.d.mts +45 -0
- package/dist/signing/energy.mjs +120 -0
- package/dist/signing/jws.cjs +229 -0
- package/dist/signing/jws.d.cts +45 -0
- package/dist/signing/jws.d.mts +45 -0
- package/dist/signing/jws.mjs +211 -0
- package/dist/signing/keys.cjs +191 -0
- package/dist/signing/keys.d.cts +21 -0
- package/dist/signing/keys.d.mts +21 -0
- package/dist/signing/keys.mjs +182 -0
- package/dist/signing/session.cjs +104 -30
- package/dist/signing/session.d.cts +60 -23
- package/dist/signing/session.d.mts +60 -23
- package/dist/signing/session.mjs +105 -31
- package/dist/tariff.cjs +27 -0
- package/dist/tariff.d.cts +11 -0
- package/dist/tariff.d.mts +11 -0
- package/dist/tariff.mjs +27 -1
- package/dist/teslafleetapi.cjs +256 -55
- package/dist/teslafleetapi.d.cts +110 -14
- package/dist/teslafleetapi.d.mts +110 -14
- package/dist/teslafleetapi.mjs +258 -57
- package/dist/teslemetry.cjs +152 -5
- package/dist/teslemetry.d.cts +95 -5
- package/dist/teslemetry.d.mts +93 -3
- package/dist/teslemetry.mjs +151 -6
- package/dist/teslemetryenergy.cjs +287 -0
- package/dist/teslemetryenergy.d.cts +154 -0
- package/dist/teslemetryenergy.d.mts +154 -0
- package/dist/teslemetryenergy.mjs +282 -0
- package/dist/teslemetryvehicle.cjs +407 -0
- package/dist/teslemetryvehicle.d.cts +238 -0
- package/dist/teslemetryvehicle.d.mts +238 -0
- package/dist/teslemetryvehicle.mjs +405 -0
- package/dist/tessie.cjs +42 -5
- package/dist/tessie.d.cts +51 -5
- package/dist/tessie.d.mts +49 -3
- package/dist/tessie.mjs +42 -5
- package/dist/tessievehicle.cjs +514 -0
- package/dist/tessievehicle.d.cts +333 -0
- package/dist/tessievehicle.d.mts +333 -0
- package/dist/tessievehicle.mjs +513 -0
- package/dist/types/live_status.d.cts +16 -16
- package/dist/types/live_status.d.mts +16 -16
- package/dist/types/responses.d.cts +5 -1
- package/dist/types/responses.d.mts +5 -1
- package/dist/types/vehicle.d.cts +7 -1
- package/dist/types/vehicle.d.mts +7 -1
- package/dist/types.d.cts +3 -3
- package/dist/types.d.mts +3 -3
- package/dist/util.cjs +41 -0
- package/dist/util.d.cts +18 -0
- package/dist/util.d.mts +18 -0
- package/dist/util.mjs +40 -0
- package/dist/vehicle.cjs +79 -36
- package/dist/vehicle.d.cts +42 -26
- package/dist/vehicle.d.mts +42 -26
- package/dist/vehicle.mjs +80 -37
- package/dist/vehiclesigned.cjs +20 -5
- package/dist/vehiclesigned.d.cts +14 -5
- package/dist/vehiclesigned.d.mts +14 -5
- package/dist/vehiclesigned.mjs +20 -5
- package/dist/vehiclespecific.cjs +126 -15
- package/dist/vehiclespecific.d.cts +82 -18
- package/dist/vehiclespecific.d.mts +82 -18
- package/dist/vehiclespecific.mjs +126 -15
- package/package.json +70 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const require_commands = require("../commands.cjs");
|
|
2
|
+
let _teslemetry_tesla_protocol_command_universal_message = require("@teslemetry/tesla-protocol/command/universal_message");
|
|
3
|
+
let _teslemetry_tesla_protocol_command_vcsec = require("@teslemetry/tesla-protocol/command/vcsec");
|
|
4
|
+
// src/bluetooth/broadcast.ts
|
|
5
|
+
/**
|
|
6
|
+
* Local callbacks, not tied to a connection, so they live as long as the
|
|
7
|
+
* vehicle and survive reconnects. A callback that throws is logged, and neither
|
|
8
|
+
* later callbacks nor message routing see it.
|
|
9
|
+
*/
|
|
10
|
+
var ListenerRegistry = class {
|
|
11
|
+
log;
|
|
12
|
+
entries = [];
|
|
13
|
+
constructor(log) {
|
|
14
|
+
this.log = log;
|
|
15
|
+
}
|
|
16
|
+
get size() {
|
|
17
|
+
return this.entries.length;
|
|
18
|
+
}
|
|
19
|
+
add(callback) {
|
|
20
|
+
const entry = { callback };
|
|
21
|
+
this.entries.push(entry);
|
|
22
|
+
return () => {
|
|
23
|
+
this.entries = this.entries.filter((other) => other !== entry);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
emit(value) {
|
|
27
|
+
for (const { callback } of this.entries) try {
|
|
28
|
+
callback(value);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
this.log(`BLE listener failed: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A broadcast's VCSEC status, if it carries one. Broadcasts are unsigned, so
|
|
36
|
+
* they need no session and prove nothing about who sent them.
|
|
37
|
+
*/
|
|
38
|
+
function decodeVcsecStatus(message) {
|
|
39
|
+
if (message.protobufMessageAsBytes === void 0) return null;
|
|
40
|
+
try {
|
|
41
|
+
return _teslemetry_tesla_protocol_command_vcsec.FromVCSECMessage.decode(message.protobufMessageAsBytes).vehicleStatus ?? null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Persistent listeners for unsolicited broadcasts, which arrive on the same
|
|
48
|
+
* notifications as command replies. Each `VehicleStatus` leaf has a typed
|
|
49
|
+
* `listen_*`, and `listen_broadcast` takes every raw broadcast on a domain,
|
|
50
|
+
* including payloads with no typed listener.
|
|
51
|
+
*
|
|
52
|
+
* The scalar listeners fire on every status broadcast with whatever value it
|
|
53
|
+
* holds, because proto3 has no presence on them, so a lock-only broadcast also
|
|
54
|
+
* reports `GEAR_UNKNOWN`. The closure listeners fire only when the broadcast
|
|
55
|
+
* carries the block they read.
|
|
56
|
+
*/
|
|
57
|
+
var BroadcastListeners = class extends require_commands.default {
|
|
58
|
+
statusListeners = new ListenerRegistry((message) => this.log(message));
|
|
59
|
+
domainListeners = /* @__PURE__ */ new Map();
|
|
60
|
+
log(message) {
|
|
61
|
+
this.parent.parent._log(message);
|
|
62
|
+
}
|
|
63
|
+
/** Hand one unaddressed message to everything listening. */
|
|
64
|
+
dispatchBroadcast(domain, message) {
|
|
65
|
+
this.domainListeners.get(domain)?.emit(message);
|
|
66
|
+
if (domain === _teslemetry_tesla_protocol_command_universal_message.Domain.DOMAIN_VEHICLE_SECURITY && this.statusListeners.size > 0) {
|
|
67
|
+
const status = decodeVcsecStatus(message);
|
|
68
|
+
if (status) this.statusListeners.emit(status);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
listenClosure(callback) {
|
|
72
|
+
return this.statusListeners.add((status) => {
|
|
73
|
+
if (status.closureStatuses) callback(status.closureStatuses);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** Listen for every unsolicited broadcast on `domain`, including `VehicleStatus`. */
|
|
77
|
+
listen_broadcast(domain, callback) {
|
|
78
|
+
let registry = this.domainListeners.get(domain);
|
|
79
|
+
if (!registry) {
|
|
80
|
+
registry = new ListenerRegistry((message) => this.log(message));
|
|
81
|
+
this.domainListeners.set(domain, registry);
|
|
82
|
+
}
|
|
83
|
+
return registry.add(callback);
|
|
84
|
+
}
|
|
85
|
+
/** Listen for the vehicle's overall lock state. */
|
|
86
|
+
listen_vehicle_lock_state(callback) {
|
|
87
|
+
return this.statusListeners.add((status) => callback(status.vehicleLockState));
|
|
88
|
+
}
|
|
89
|
+
/** Listen for the vehicle's sleep status. */
|
|
90
|
+
listen_vehicle_sleep_status(callback) {
|
|
91
|
+
return this.statusListeners.add((status) => callback(status.vehicleSleepStatus));
|
|
92
|
+
}
|
|
93
|
+
/** Listen for driver presence. */
|
|
94
|
+
listen_user_presence(callback) {
|
|
95
|
+
return this.statusListeners.add((status) => callback(status.userPresence));
|
|
96
|
+
}
|
|
97
|
+
/** Listen for the gear selection. */
|
|
98
|
+
listen_gear(callback) {
|
|
99
|
+
return this.statusListeners.add((status) => callback(status.gear));
|
|
100
|
+
}
|
|
101
|
+
/** Listen for the UI desire state. */
|
|
102
|
+
listen_ui_desire(callback) {
|
|
103
|
+
return this.statusListeners.add((status) => callback(status.UIDesire));
|
|
104
|
+
}
|
|
105
|
+
/** Listen for the tonneau's open percentage, on broadcasts that carry it. */
|
|
106
|
+
listen_tonneau_percent_open(callback) {
|
|
107
|
+
return this.statusListeners.add((status) => {
|
|
108
|
+
if (status.detailedClosureStatus) callback(status.detailedClosureStatus.tonneauPercentOpen);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Listen for a broadcast's whole closure block in one call. The listeners
|
|
113
|
+
* below each fire separately for the same broadcast.
|
|
114
|
+
*/
|
|
115
|
+
listen_closure_statuses(callback) {
|
|
116
|
+
return this.listenClosure(callback);
|
|
117
|
+
}
|
|
118
|
+
/** Listen for the front driver door. */
|
|
119
|
+
listen_front_driver_door(callback) {
|
|
120
|
+
return this.listenClosure((closures) => callback(closures.frontDriverDoor));
|
|
121
|
+
}
|
|
122
|
+
/** Listen for the front passenger door. */
|
|
123
|
+
listen_front_passenger_door(callback) {
|
|
124
|
+
return this.listenClosure((closures) => callback(closures.frontPassengerDoor));
|
|
125
|
+
}
|
|
126
|
+
/** Listen for the rear driver door. */
|
|
127
|
+
listen_rear_driver_door(callback) {
|
|
128
|
+
return this.listenClosure((closures) => callback(closures.rearDriverDoor));
|
|
129
|
+
}
|
|
130
|
+
/** Listen for the rear passenger door. */
|
|
131
|
+
listen_rear_passenger_door(callback) {
|
|
132
|
+
return this.listenClosure((closures) => callback(closures.rearPassengerDoor));
|
|
133
|
+
}
|
|
134
|
+
/** Listen for the front trunk. */
|
|
135
|
+
listen_front_trunk(callback) {
|
|
136
|
+
return this.listenClosure((closures) => callback(closures.frontTrunk));
|
|
137
|
+
}
|
|
138
|
+
/** Listen for the rear trunk. */
|
|
139
|
+
listen_rear_trunk(callback) {
|
|
140
|
+
return this.listenClosure((closures) => callback(closures.rearTrunk));
|
|
141
|
+
}
|
|
142
|
+
/** Listen for the charge port. */
|
|
143
|
+
listen_charge_port(callback) {
|
|
144
|
+
return this.listenClosure((closures) => callback(closures.chargePort));
|
|
145
|
+
}
|
|
146
|
+
/** Listen for the tonneau. */
|
|
147
|
+
listen_tonneau(callback) {
|
|
148
|
+
return this.listenClosure((closures) => callback(closures.tonneau));
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
exports.BroadcastListeners = BroadcastListeners;
|
|
152
|
+
exports.ListenerRegistry = ListenerRegistry;
|
|
153
|
+
exports.decodeVcsecStatus = decodeVcsecStatus;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Commands from "../commands.cjs";
|
|
2
|
+
import { Domain, RoutableMessage } from "@teslemetry/tesla-protocol/command/universal_message";
|
|
3
|
+
import { ClosureStateE, ClosureStatuses, GearE, UIDesireE, UserPresenceE, VehicleLockStateE, VehicleSleepStatusE, VehicleStatus } from "@teslemetry/tesla-protocol/command/vcsec";
|
|
4
|
+
/** Removes a listener. Safe to call twice. */
|
|
5
|
+
export type Unsubscribe = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Persistent listeners for unsolicited broadcasts, which arrive on the same
|
|
8
|
+
* notifications as command replies. Each `VehicleStatus` leaf has a typed
|
|
9
|
+
* `listen_*`, and `listen_broadcast` takes every raw broadcast on a domain,
|
|
10
|
+
* including payloads with no typed listener.
|
|
11
|
+
*
|
|
12
|
+
* The scalar listeners fire on every status broadcast with whatever value it
|
|
13
|
+
* holds, because proto3 has no presence on them, so a lock-only broadcast also
|
|
14
|
+
* reports `GEAR_UNKNOWN`. The closure listeners fire only when the broadcast
|
|
15
|
+
* carries the block they read.
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class BroadcastListeners extends Commands {
|
|
18
|
+
private readonly statusListeners;
|
|
19
|
+
private readonly domainListeners;
|
|
20
|
+
protected log(message: string): void;
|
|
21
|
+
/** Hand one unaddressed message to everything listening. */
|
|
22
|
+
protected dispatchBroadcast(domain: Domain, message: RoutableMessage): void;
|
|
23
|
+
private listenClosure;
|
|
24
|
+
/** Listen for every unsolicited broadcast on `domain`, including `VehicleStatus`. */
|
|
25
|
+
listen_broadcast(domain: Domain, callback: (message: RoutableMessage) => void): Unsubscribe;
|
|
26
|
+
/** Listen for the vehicle's overall lock state. */
|
|
27
|
+
listen_vehicle_lock_state(callback: (state: VehicleLockStateE) => void): Unsubscribe;
|
|
28
|
+
/** Listen for the vehicle's sleep status. */
|
|
29
|
+
listen_vehicle_sleep_status(callback: (status: VehicleSleepStatusE) => void): Unsubscribe;
|
|
30
|
+
/** Listen for driver presence. */
|
|
31
|
+
listen_user_presence(callback: (presence: UserPresenceE) => void): Unsubscribe;
|
|
32
|
+
/** Listen for the gear selection. */
|
|
33
|
+
listen_gear(callback: (gear: GearE) => void): Unsubscribe;
|
|
34
|
+
/** Listen for the UI desire state. */
|
|
35
|
+
listen_ui_desire(callback: (desire: UIDesireE) => void): Unsubscribe;
|
|
36
|
+
/** Listen for the tonneau's open percentage, on broadcasts that carry it. */
|
|
37
|
+
listen_tonneau_percent_open(callback: (percent: number) => void): Unsubscribe;
|
|
38
|
+
/**
|
|
39
|
+
* Listen for a broadcast's whole closure block in one call. The listeners
|
|
40
|
+
* below each fire separately for the same broadcast.
|
|
41
|
+
*/
|
|
42
|
+
listen_closure_statuses(callback: (closures: ClosureStatuses) => void): Unsubscribe;
|
|
43
|
+
/** Listen for the front driver door. */
|
|
44
|
+
listen_front_driver_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
45
|
+
/** Listen for the front passenger door. */
|
|
46
|
+
listen_front_passenger_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
47
|
+
/** Listen for the rear driver door. */
|
|
48
|
+
listen_rear_driver_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
49
|
+
/** Listen for the rear passenger door. */
|
|
50
|
+
listen_rear_passenger_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
51
|
+
/** Listen for the front trunk. */
|
|
52
|
+
listen_front_trunk(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
53
|
+
/** Listen for the rear trunk. */
|
|
54
|
+
listen_rear_trunk(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
55
|
+
/** Listen for the charge port. */
|
|
56
|
+
listen_charge_port(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
57
|
+
/** Listen for the tonneau. */
|
|
58
|
+
listen_tonneau(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
59
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Commands from "../commands.mjs";
|
|
2
|
+
import { Domain, RoutableMessage } from "@teslemetry/tesla-protocol/command/universal_message";
|
|
3
|
+
import { ClosureStateE, ClosureStatuses, GearE, UIDesireE, UserPresenceE, VehicleLockStateE, VehicleSleepStatusE, VehicleStatus } from "@teslemetry/tesla-protocol/command/vcsec";
|
|
4
|
+
/** Removes a listener. Safe to call twice. */
|
|
5
|
+
export type Unsubscribe = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Persistent listeners for unsolicited broadcasts, which arrive on the same
|
|
8
|
+
* notifications as command replies. Each `VehicleStatus` leaf has a typed
|
|
9
|
+
* `listen_*`, and `listen_broadcast` takes every raw broadcast on a domain,
|
|
10
|
+
* including payloads with no typed listener.
|
|
11
|
+
*
|
|
12
|
+
* The scalar listeners fire on every status broadcast with whatever value it
|
|
13
|
+
* holds, because proto3 has no presence on them, so a lock-only broadcast also
|
|
14
|
+
* reports `GEAR_UNKNOWN`. The closure listeners fire only when the broadcast
|
|
15
|
+
* carries the block they read.
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class BroadcastListeners extends Commands {
|
|
18
|
+
private readonly statusListeners;
|
|
19
|
+
private readonly domainListeners;
|
|
20
|
+
protected log(message: string): void;
|
|
21
|
+
/** Hand one unaddressed message to everything listening. */
|
|
22
|
+
protected dispatchBroadcast(domain: Domain, message: RoutableMessage): void;
|
|
23
|
+
private listenClosure;
|
|
24
|
+
/** Listen for every unsolicited broadcast on `domain`, including `VehicleStatus`. */
|
|
25
|
+
listen_broadcast(domain: Domain, callback: (message: RoutableMessage) => void): Unsubscribe;
|
|
26
|
+
/** Listen for the vehicle's overall lock state. */
|
|
27
|
+
listen_vehicle_lock_state(callback: (state: VehicleLockStateE) => void): Unsubscribe;
|
|
28
|
+
/** Listen for the vehicle's sleep status. */
|
|
29
|
+
listen_vehicle_sleep_status(callback: (status: VehicleSleepStatusE) => void): Unsubscribe;
|
|
30
|
+
/** Listen for driver presence. */
|
|
31
|
+
listen_user_presence(callback: (presence: UserPresenceE) => void): Unsubscribe;
|
|
32
|
+
/** Listen for the gear selection. */
|
|
33
|
+
listen_gear(callback: (gear: GearE) => void): Unsubscribe;
|
|
34
|
+
/** Listen for the UI desire state. */
|
|
35
|
+
listen_ui_desire(callback: (desire: UIDesireE) => void): Unsubscribe;
|
|
36
|
+
/** Listen for the tonneau's open percentage, on broadcasts that carry it. */
|
|
37
|
+
listen_tonneau_percent_open(callback: (percent: number) => void): Unsubscribe;
|
|
38
|
+
/**
|
|
39
|
+
* Listen for a broadcast's whole closure block in one call. The listeners
|
|
40
|
+
* below each fire separately for the same broadcast.
|
|
41
|
+
*/
|
|
42
|
+
listen_closure_statuses(callback: (closures: ClosureStatuses) => void): Unsubscribe;
|
|
43
|
+
/** Listen for the front driver door. */
|
|
44
|
+
listen_front_driver_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
45
|
+
/** Listen for the front passenger door. */
|
|
46
|
+
listen_front_passenger_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
47
|
+
/** Listen for the rear driver door. */
|
|
48
|
+
listen_rear_driver_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
49
|
+
/** Listen for the rear passenger door. */
|
|
50
|
+
listen_rear_passenger_door(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
51
|
+
/** Listen for the front trunk. */
|
|
52
|
+
listen_front_trunk(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
53
|
+
/** Listen for the rear trunk. */
|
|
54
|
+
listen_rear_trunk(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
55
|
+
/** Listen for the charge port. */
|
|
56
|
+
listen_charge_port(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
57
|
+
/** Listen for the tonneau. */
|
|
58
|
+
listen_tonneau(callback: (state: ClosureStateE) => void): Unsubscribe;
|
|
59
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import Commands from "../commands.mjs";
|
|
2
|
+
import { Domain } from "@teslemetry/tesla-protocol/command/universal_message";
|
|
3
|
+
import { FromVCSECMessage } from "@teslemetry/tesla-protocol/command/vcsec";
|
|
4
|
+
// src/bluetooth/broadcast.ts
|
|
5
|
+
/**
|
|
6
|
+
* Local callbacks, not tied to a connection, so they live as long as the
|
|
7
|
+
* vehicle and survive reconnects. A callback that throws is logged, and neither
|
|
8
|
+
* later callbacks nor message routing see it.
|
|
9
|
+
*/
|
|
10
|
+
var ListenerRegistry = class {
|
|
11
|
+
log;
|
|
12
|
+
entries = [];
|
|
13
|
+
constructor(log) {
|
|
14
|
+
this.log = log;
|
|
15
|
+
}
|
|
16
|
+
get size() {
|
|
17
|
+
return this.entries.length;
|
|
18
|
+
}
|
|
19
|
+
add(callback) {
|
|
20
|
+
const entry = { callback };
|
|
21
|
+
this.entries.push(entry);
|
|
22
|
+
return () => {
|
|
23
|
+
this.entries = this.entries.filter((other) => other !== entry);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
emit(value) {
|
|
27
|
+
for (const { callback } of this.entries) try {
|
|
28
|
+
callback(value);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
this.log(`BLE listener failed: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A broadcast's VCSEC status, if it carries one. Broadcasts are unsigned, so
|
|
36
|
+
* they need no session and prove nothing about who sent them.
|
|
37
|
+
*/
|
|
38
|
+
function decodeVcsecStatus(message) {
|
|
39
|
+
if (message.protobufMessageAsBytes === void 0) return null;
|
|
40
|
+
try {
|
|
41
|
+
return FromVCSECMessage.decode(message.protobufMessageAsBytes).vehicleStatus ?? null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Persistent listeners for unsolicited broadcasts, which arrive on the same
|
|
48
|
+
* notifications as command replies. Each `VehicleStatus` leaf has a typed
|
|
49
|
+
* `listen_*`, and `listen_broadcast` takes every raw broadcast on a domain,
|
|
50
|
+
* including payloads with no typed listener.
|
|
51
|
+
*
|
|
52
|
+
* The scalar listeners fire on every status broadcast with whatever value it
|
|
53
|
+
* holds, because proto3 has no presence on them, so a lock-only broadcast also
|
|
54
|
+
* reports `GEAR_UNKNOWN`. The closure listeners fire only when the broadcast
|
|
55
|
+
* carries the block they read.
|
|
56
|
+
*/
|
|
57
|
+
var BroadcastListeners = class extends Commands {
|
|
58
|
+
statusListeners = new ListenerRegistry((message) => this.log(message));
|
|
59
|
+
domainListeners = /* @__PURE__ */ new Map();
|
|
60
|
+
log(message) {
|
|
61
|
+
this.parent.parent._log(message);
|
|
62
|
+
}
|
|
63
|
+
/** Hand one unaddressed message to everything listening. */
|
|
64
|
+
dispatchBroadcast(domain, message) {
|
|
65
|
+
this.domainListeners.get(domain)?.emit(message);
|
|
66
|
+
if (domain === Domain.DOMAIN_VEHICLE_SECURITY && this.statusListeners.size > 0) {
|
|
67
|
+
const status = decodeVcsecStatus(message);
|
|
68
|
+
if (status) this.statusListeners.emit(status);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
listenClosure(callback) {
|
|
72
|
+
return this.statusListeners.add((status) => {
|
|
73
|
+
if (status.closureStatuses) callback(status.closureStatuses);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** Listen for every unsolicited broadcast on `domain`, including `VehicleStatus`. */
|
|
77
|
+
listen_broadcast(domain, callback) {
|
|
78
|
+
let registry = this.domainListeners.get(domain);
|
|
79
|
+
if (!registry) {
|
|
80
|
+
registry = new ListenerRegistry((message) => this.log(message));
|
|
81
|
+
this.domainListeners.set(domain, registry);
|
|
82
|
+
}
|
|
83
|
+
return registry.add(callback);
|
|
84
|
+
}
|
|
85
|
+
/** Listen for the vehicle's overall lock state. */
|
|
86
|
+
listen_vehicle_lock_state(callback) {
|
|
87
|
+
return this.statusListeners.add((status) => callback(status.vehicleLockState));
|
|
88
|
+
}
|
|
89
|
+
/** Listen for the vehicle's sleep status. */
|
|
90
|
+
listen_vehicle_sleep_status(callback) {
|
|
91
|
+
return this.statusListeners.add((status) => callback(status.vehicleSleepStatus));
|
|
92
|
+
}
|
|
93
|
+
/** Listen for driver presence. */
|
|
94
|
+
listen_user_presence(callback) {
|
|
95
|
+
return this.statusListeners.add((status) => callback(status.userPresence));
|
|
96
|
+
}
|
|
97
|
+
/** Listen for the gear selection. */
|
|
98
|
+
listen_gear(callback) {
|
|
99
|
+
return this.statusListeners.add((status) => callback(status.gear));
|
|
100
|
+
}
|
|
101
|
+
/** Listen for the UI desire state. */
|
|
102
|
+
listen_ui_desire(callback) {
|
|
103
|
+
return this.statusListeners.add((status) => callback(status.UIDesire));
|
|
104
|
+
}
|
|
105
|
+
/** Listen for the tonneau's open percentage, on broadcasts that carry it. */
|
|
106
|
+
listen_tonneau_percent_open(callback) {
|
|
107
|
+
return this.statusListeners.add((status) => {
|
|
108
|
+
if (status.detailedClosureStatus) callback(status.detailedClosureStatus.tonneauPercentOpen);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Listen for a broadcast's whole closure block in one call. The listeners
|
|
113
|
+
* below each fire separately for the same broadcast.
|
|
114
|
+
*/
|
|
115
|
+
listen_closure_statuses(callback) {
|
|
116
|
+
return this.listenClosure(callback);
|
|
117
|
+
}
|
|
118
|
+
/** Listen for the front driver door. */
|
|
119
|
+
listen_front_driver_door(callback) {
|
|
120
|
+
return this.listenClosure((closures) => callback(closures.frontDriverDoor));
|
|
121
|
+
}
|
|
122
|
+
/** Listen for the front passenger door. */
|
|
123
|
+
listen_front_passenger_door(callback) {
|
|
124
|
+
return this.listenClosure((closures) => callback(closures.frontPassengerDoor));
|
|
125
|
+
}
|
|
126
|
+
/** Listen for the rear driver door. */
|
|
127
|
+
listen_rear_driver_door(callback) {
|
|
128
|
+
return this.listenClosure((closures) => callback(closures.rearDriverDoor));
|
|
129
|
+
}
|
|
130
|
+
/** Listen for the rear passenger door. */
|
|
131
|
+
listen_rear_passenger_door(callback) {
|
|
132
|
+
return this.listenClosure((closures) => callback(closures.rearPassengerDoor));
|
|
133
|
+
}
|
|
134
|
+
/** Listen for the front trunk. */
|
|
135
|
+
listen_front_trunk(callback) {
|
|
136
|
+
return this.listenClosure((closures) => callback(closures.frontTrunk));
|
|
137
|
+
}
|
|
138
|
+
/** Listen for the rear trunk. */
|
|
139
|
+
listen_rear_trunk(callback) {
|
|
140
|
+
return this.listenClosure((closures) => callback(closures.rearTrunk));
|
|
141
|
+
}
|
|
142
|
+
/** Listen for the charge port. */
|
|
143
|
+
listen_charge_port(callback) {
|
|
144
|
+
return this.listenClosure((closures) => callback(closures.chargePort));
|
|
145
|
+
}
|
|
146
|
+
/** Listen for the tonneau. */
|
|
147
|
+
listen_tonneau(callback) {
|
|
148
|
+
return this.listenClosure((closures) => callback(closures.tonneau));
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
export { BroadcastListeners, ListenerRegistry, decodeVcsecStatus };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// src/bluetooth/constants.ts
|
|
2
|
+
/** The vehicle's GATT service. It is never advertised, so never scan for it. */
|
|
3
|
+
const SERVICE_UUID = "00000211-b2d1-43f0-9b88-960cebf8b91e";
|
|
4
|
+
/** Client to car. Tesla's Go SDK names the two by the opposite view, hence these names. */
|
|
5
|
+
const VEHICLE_WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e";
|
|
6
|
+
/** Car to client. */
|
|
7
|
+
const VEHICLE_NOTIFY_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e";
|
|
8
|
+
/** Python's name for `VEHICLE_WRITE_UUID`. */
|
|
9
|
+
const WRITE_UUID = VEHICLE_WRITE_UUID;
|
|
10
|
+
/** Python's name for `VEHICLE_NOTIFY_UUID`. */
|
|
11
|
+
const READ_UUID = VEHICLE_NOTIFY_UUID;
|
|
12
|
+
/** The keepalive read target. */
|
|
13
|
+
const VERSION_UUID = "00000214-b2d1-43f0-9b88-960cebf8b91e";
|
|
14
|
+
/** GATT Device Name. */
|
|
15
|
+
const NAME_UUID = "00002a00-0000-1000-8000-00805f9b34fb";
|
|
16
|
+
/** GATT Appearance. */
|
|
17
|
+
const APPEARANCE_UUID = "00002a01-0000-1000-8000-00805f9b34fb";
|
|
18
|
+
/** Generic Access, for a backend that needs a service UUID to reach the two above. */
|
|
19
|
+
const GENERIC_ACCESS_UUID = "00001800-0000-1000-8000-00805f9b34fb";
|
|
20
|
+
/** Client Characteristic Configuration. Only an ESPHome proxy needs it written by hand. */
|
|
21
|
+
const CCCD_UUID = "00002902-0000-1000-8000-00805f9b34fb";
|
|
22
|
+
/** Largest frame accepted, length prefix included. Tesla's Go SDK allows 2 more bytes. */
|
|
23
|
+
const MAX_FRAME_SIZE = 1024;
|
|
24
|
+
/**
|
|
25
|
+
* Bytes per write when a connection does not say: the ATT default MTU of 23,
|
|
26
|
+
* less 3 of header. Safe on any link, and all Homey offers, as it hides the MTU.
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_MAX_WRITE_SIZE = 20;
|
|
29
|
+
/** A chunk after this much silence means the partial frame before it was abandoned. */
|
|
30
|
+
const STALE_CHUNK_TIMEOUT_MS = 1e3;
|
|
31
|
+
/** An idle held link drops at about 42 s on average; a read this often keeps it about 10 times longer. */
|
|
32
|
+
const DEFAULT_KEEPALIVE_INTERVAL_MS = 2e4;
|
|
33
|
+
/** Infotainment answers a handshake 4 to 16 s after an RKE wake. */
|
|
34
|
+
const DEFAULT_WAKE_TIMEOUT_MS = 3e4;
|
|
35
|
+
/**
|
|
36
|
+
* One infotainment readiness probe. A ready infotainment answers in 0.26 to 0.39 s.
|
|
37
|
+
* The window opens once the request is fully written, so a slow 20-byte link
|
|
38
|
+
* spends none of it writing. Raise it with `wake_probe_timeout_ms` if a link's
|
|
39
|
+
* replies are slower than this, as a probe that keeps timing out never proves
|
|
40
|
+
* the car is ready.
|
|
41
|
+
*/
|
|
42
|
+
const DEFAULT_WAKE_PROBE_TIMEOUT_MS = 1e3;
|
|
43
|
+
/** How often a wake is resent while infotainment stays silent: a first wake can be missed after a long sleep. */
|
|
44
|
+
const WAKE_RESEND_INTERVAL_MS = 3e3;
|
|
45
|
+
/** How long an awake car's infotainment may take to finish booting. */
|
|
46
|
+
const INFOTAINMENT_BOOT_TIMEOUT_MS = 2e4;
|
|
47
|
+
/** How long a charge-port opening has to show in charge state. It took about 1.4 s in live trials. */
|
|
48
|
+
const CHARGE_PORT_VERIFY_TIMEOUT_MS = 5e3;
|
|
49
|
+
/** Between charge-state polls, while waiting for readiness or for the latch. */
|
|
50
|
+
const CHARGE_PORT_VERIFY_INTERVAL_MS = 250;
|
|
51
|
+
/** How long `pair` waits for someone to tap a key card. */
|
|
52
|
+
const DEFAULT_PAIR_TIMEOUT_MS = 3e5;
|
|
53
|
+
/** Between `pair`'s checks of whether the key was accepted. */
|
|
54
|
+
const DEFAULT_PAIR_POLL_INTERVAL_MS = 5e3;
|
|
55
|
+
/** Connect attempts. Each is bounded by `DEFAULT_CONNECT_TIMEOUT_MS`. */
|
|
56
|
+
const DEFAULT_CONNECT_ATTEMPTS = 3;
|
|
57
|
+
/** One connect attempt. Python takes the same figure from `bleak-retry-connector`. */
|
|
58
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 2e4;
|
|
59
|
+
/** One scan. It must outlast the backend's window, which Homey fixes at about 5 s. */
|
|
60
|
+
const DEFAULT_SCAN_TIMEOUT_MS = 1e4;
|
|
61
|
+
/** Bound on tearing down a link: the failure behind it is what gets reported. */
|
|
62
|
+
const LINK_TEARDOWN_TIMEOUT_MS = 5e3;
|
|
63
|
+
/**
|
|
64
|
+
* One write call. Not in Python, whose backends bound their own writes. Homey's
|
|
65
|
+
* have no timeout and its link state can be stale, so a hung write must end
|
|
66
|
+
* here. A design choice. BLE-00 step 10 measures how long a failing write takes
|
|
67
|
+
* on Homey, which sets it.
|
|
68
|
+
*/
|
|
69
|
+
const GATT_WRITE_TIMEOUT_MS = 5e3;
|
|
70
|
+
/** One read call, other than a keepalive's. */
|
|
71
|
+
const GATT_READ_TIMEOUT_MS = 5e3;
|
|
72
|
+
exports.APPEARANCE_UUID = APPEARANCE_UUID;
|
|
73
|
+
exports.CCCD_UUID = CCCD_UUID;
|
|
74
|
+
exports.CHARGE_PORT_VERIFY_INTERVAL_MS = CHARGE_PORT_VERIFY_INTERVAL_MS;
|
|
75
|
+
exports.CHARGE_PORT_VERIFY_TIMEOUT_MS = CHARGE_PORT_VERIFY_TIMEOUT_MS;
|
|
76
|
+
exports.DEFAULT_CONNECT_ATTEMPTS = DEFAULT_CONNECT_ATTEMPTS;
|
|
77
|
+
exports.DEFAULT_CONNECT_TIMEOUT_MS = DEFAULT_CONNECT_TIMEOUT_MS;
|
|
78
|
+
exports.DEFAULT_KEEPALIVE_INTERVAL_MS = DEFAULT_KEEPALIVE_INTERVAL_MS;
|
|
79
|
+
exports.DEFAULT_MAX_WRITE_SIZE = DEFAULT_MAX_WRITE_SIZE;
|
|
80
|
+
exports.DEFAULT_PAIR_POLL_INTERVAL_MS = DEFAULT_PAIR_POLL_INTERVAL_MS;
|
|
81
|
+
exports.DEFAULT_PAIR_TIMEOUT_MS = DEFAULT_PAIR_TIMEOUT_MS;
|
|
82
|
+
exports.DEFAULT_SCAN_TIMEOUT_MS = DEFAULT_SCAN_TIMEOUT_MS;
|
|
83
|
+
exports.DEFAULT_WAKE_PROBE_TIMEOUT_MS = DEFAULT_WAKE_PROBE_TIMEOUT_MS;
|
|
84
|
+
exports.DEFAULT_WAKE_TIMEOUT_MS = DEFAULT_WAKE_TIMEOUT_MS;
|
|
85
|
+
exports.GATT_READ_TIMEOUT_MS = GATT_READ_TIMEOUT_MS;
|
|
86
|
+
exports.GATT_WRITE_TIMEOUT_MS = GATT_WRITE_TIMEOUT_MS;
|
|
87
|
+
exports.GENERIC_ACCESS_UUID = GENERIC_ACCESS_UUID;
|
|
88
|
+
exports.INFOTAINMENT_BOOT_TIMEOUT_MS = INFOTAINMENT_BOOT_TIMEOUT_MS;
|
|
89
|
+
exports.LINK_TEARDOWN_TIMEOUT_MS = LINK_TEARDOWN_TIMEOUT_MS;
|
|
90
|
+
exports.MAX_FRAME_SIZE = MAX_FRAME_SIZE;
|
|
91
|
+
exports.NAME_UUID = NAME_UUID;
|
|
92
|
+
exports.READ_UUID = READ_UUID;
|
|
93
|
+
exports.SERVICE_UUID = SERVICE_UUID;
|
|
94
|
+
exports.STALE_CHUNK_TIMEOUT_MS = STALE_CHUNK_TIMEOUT_MS;
|
|
95
|
+
exports.VEHICLE_NOTIFY_UUID = VEHICLE_NOTIFY_UUID;
|
|
96
|
+
exports.VEHICLE_WRITE_UUID = VEHICLE_WRITE_UUID;
|
|
97
|
+
exports.VERSION_UUID = VERSION_UUID;
|
|
98
|
+
exports.WAKE_RESEND_INTERVAL_MS = WAKE_RESEND_INTERVAL_MS;
|
|
99
|
+
exports.WRITE_UUID = WRITE_UUID;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** The vehicle's GATT service. It is never advertised, so never scan for it. */
|
|
2
|
+
export declare const SERVICE_UUID = "00000211-b2d1-43f0-9b88-960cebf8b91e";
|
|
3
|
+
/** Client to car. Tesla's Go SDK names the two by the opposite view, hence these names. */
|
|
4
|
+
export declare const VEHICLE_WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e";
|
|
5
|
+
/** Car to client. */
|
|
6
|
+
export declare const VEHICLE_NOTIFY_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e";
|
|
7
|
+
/** Python's name for `VEHICLE_WRITE_UUID`. */
|
|
8
|
+
export declare const WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e";
|
|
9
|
+
/** Python's name for `VEHICLE_NOTIFY_UUID`. */
|
|
10
|
+
export declare const READ_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e";
|
|
11
|
+
/** The keepalive read target. */
|
|
12
|
+
export declare const VERSION_UUID = "00000214-b2d1-43f0-9b88-960cebf8b91e";
|
|
13
|
+
/** GATT Device Name. */
|
|
14
|
+
export declare const NAME_UUID = "00002a00-0000-1000-8000-00805f9b34fb";
|
|
15
|
+
/** GATT Appearance. */
|
|
16
|
+
export declare const APPEARANCE_UUID = "00002a01-0000-1000-8000-00805f9b34fb";
|
|
17
|
+
/** Generic Access, for a backend that needs a service UUID to reach the two above. */
|
|
18
|
+
export declare const GENERIC_ACCESS_UUID = "00001800-0000-1000-8000-00805f9b34fb";
|
|
19
|
+
/** Client Characteristic Configuration. Only an ESPHome proxy needs it written by hand. */
|
|
20
|
+
export declare const CCCD_UUID = "00002902-0000-1000-8000-00805f9b34fb";
|
|
21
|
+
/** Largest frame accepted, length prefix included. Tesla's Go SDK allows 2 more bytes. */
|
|
22
|
+
export declare const MAX_FRAME_SIZE = 1024;
|
|
23
|
+
/**
|
|
24
|
+
* Bytes per write when a connection does not say: the ATT default MTU of 23,
|
|
25
|
+
* less 3 of header. Safe on any link, and all Homey offers, as it hides the MTU.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_MAX_WRITE_SIZE = 20;
|
|
28
|
+
/** A chunk after this much silence means the partial frame before it was abandoned. */
|
|
29
|
+
export declare const STALE_CHUNK_TIMEOUT_MS = 1000;
|
|
30
|
+
/** An idle held link drops at about 42 s on average; a read this often keeps it about 10 times longer. */
|
|
31
|
+
export declare const DEFAULT_KEEPALIVE_INTERVAL_MS = 20000;
|
|
32
|
+
/** Infotainment answers a handshake 4 to 16 s after an RKE wake. */
|
|
33
|
+
export declare const DEFAULT_WAKE_TIMEOUT_MS = 30000;
|
|
34
|
+
/**
|
|
35
|
+
* One infotainment readiness probe. A ready infotainment answers in 0.26 to 0.39 s.
|
|
36
|
+
* The window opens once the request is fully written, so a slow 20-byte link
|
|
37
|
+
* spends none of it writing. Raise it with `wake_probe_timeout_ms` if a link's
|
|
38
|
+
* replies are slower than this, as a probe that keeps timing out never proves
|
|
39
|
+
* the car is ready.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEFAULT_WAKE_PROBE_TIMEOUT_MS = 1000;
|
|
42
|
+
/** How often a wake is resent while infotainment stays silent: a first wake can be missed after a long sleep. */
|
|
43
|
+
export declare const WAKE_RESEND_INTERVAL_MS = 3000;
|
|
44
|
+
/** How long an awake car's infotainment may take to finish booting. */
|
|
45
|
+
export declare const INFOTAINMENT_BOOT_TIMEOUT_MS = 20000;
|
|
46
|
+
/** How long a charge-port opening has to show in charge state. It took about 1.4 s in live trials. */
|
|
47
|
+
export declare const CHARGE_PORT_VERIFY_TIMEOUT_MS = 5000;
|
|
48
|
+
/** Between charge-state polls, while waiting for readiness or for the latch. */
|
|
49
|
+
export declare const CHARGE_PORT_VERIFY_INTERVAL_MS = 250;
|
|
50
|
+
/** How long `pair` waits for someone to tap a key card. */
|
|
51
|
+
export declare const DEFAULT_PAIR_TIMEOUT_MS = 300000;
|
|
52
|
+
/** Between `pair`'s checks of whether the key was accepted. */
|
|
53
|
+
export declare const DEFAULT_PAIR_POLL_INTERVAL_MS = 5000;
|
|
54
|
+
/** Connect attempts. Each is bounded by `DEFAULT_CONNECT_TIMEOUT_MS`. */
|
|
55
|
+
export declare const DEFAULT_CONNECT_ATTEMPTS = 3;
|
|
56
|
+
/** One connect attempt. Python takes the same figure from `bleak-retry-connector`. */
|
|
57
|
+
export declare const DEFAULT_CONNECT_TIMEOUT_MS = 20000;
|
|
58
|
+
/** One scan. It must outlast the backend's window, which Homey fixes at about 5 s. */
|
|
59
|
+
export declare const DEFAULT_SCAN_TIMEOUT_MS = 10000;
|
|
60
|
+
/** Bound on tearing down a link: the failure behind it is what gets reported. */
|
|
61
|
+
export declare const LINK_TEARDOWN_TIMEOUT_MS = 5000;
|
|
62
|
+
/**
|
|
63
|
+
* One write call. Not in Python, whose backends bound their own writes. Homey's
|
|
64
|
+
* have no timeout and its link state can be stale, so a hung write must end
|
|
65
|
+
* here. A design choice. BLE-00 step 10 measures how long a failing write takes
|
|
66
|
+
* on Homey, which sets it.
|
|
67
|
+
*/
|
|
68
|
+
export declare const GATT_WRITE_TIMEOUT_MS = 5000;
|
|
69
|
+
/** One read call, other than a keepalive's. */
|
|
70
|
+
export declare const GATT_READ_TIMEOUT_MS = 5000;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** The vehicle's GATT service. It is never advertised, so never scan for it. */
|
|
2
|
+
export declare const SERVICE_UUID = "00000211-b2d1-43f0-9b88-960cebf8b91e";
|
|
3
|
+
/** Client to car. Tesla's Go SDK names the two by the opposite view, hence these names. */
|
|
4
|
+
export declare const VEHICLE_WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e";
|
|
5
|
+
/** Car to client. */
|
|
6
|
+
export declare const VEHICLE_NOTIFY_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e";
|
|
7
|
+
/** Python's name for `VEHICLE_WRITE_UUID`. */
|
|
8
|
+
export declare const WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e";
|
|
9
|
+
/** Python's name for `VEHICLE_NOTIFY_UUID`. */
|
|
10
|
+
export declare const READ_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e";
|
|
11
|
+
/** The keepalive read target. */
|
|
12
|
+
export declare const VERSION_UUID = "00000214-b2d1-43f0-9b88-960cebf8b91e";
|
|
13
|
+
/** GATT Device Name. */
|
|
14
|
+
export declare const NAME_UUID = "00002a00-0000-1000-8000-00805f9b34fb";
|
|
15
|
+
/** GATT Appearance. */
|
|
16
|
+
export declare const APPEARANCE_UUID = "00002a01-0000-1000-8000-00805f9b34fb";
|
|
17
|
+
/** Generic Access, for a backend that needs a service UUID to reach the two above. */
|
|
18
|
+
export declare const GENERIC_ACCESS_UUID = "00001800-0000-1000-8000-00805f9b34fb";
|
|
19
|
+
/** Client Characteristic Configuration. Only an ESPHome proxy needs it written by hand. */
|
|
20
|
+
export declare const CCCD_UUID = "00002902-0000-1000-8000-00805f9b34fb";
|
|
21
|
+
/** Largest frame accepted, length prefix included. Tesla's Go SDK allows 2 more bytes. */
|
|
22
|
+
export declare const MAX_FRAME_SIZE = 1024;
|
|
23
|
+
/**
|
|
24
|
+
* Bytes per write when a connection does not say: the ATT default MTU of 23,
|
|
25
|
+
* less 3 of header. Safe on any link, and all Homey offers, as it hides the MTU.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_MAX_WRITE_SIZE = 20;
|
|
28
|
+
/** A chunk after this much silence means the partial frame before it was abandoned. */
|
|
29
|
+
export declare const STALE_CHUNK_TIMEOUT_MS = 1000;
|
|
30
|
+
/** An idle held link drops at about 42 s on average; a read this often keeps it about 10 times longer. */
|
|
31
|
+
export declare const DEFAULT_KEEPALIVE_INTERVAL_MS = 20000;
|
|
32
|
+
/** Infotainment answers a handshake 4 to 16 s after an RKE wake. */
|
|
33
|
+
export declare const DEFAULT_WAKE_TIMEOUT_MS = 30000;
|
|
34
|
+
/**
|
|
35
|
+
* One infotainment readiness probe. A ready infotainment answers in 0.26 to 0.39 s.
|
|
36
|
+
* The window opens once the request is fully written, so a slow 20-byte link
|
|
37
|
+
* spends none of it writing. Raise it with `wake_probe_timeout_ms` if a link's
|
|
38
|
+
* replies are slower than this, as a probe that keeps timing out never proves
|
|
39
|
+
* the car is ready.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEFAULT_WAKE_PROBE_TIMEOUT_MS = 1000;
|
|
42
|
+
/** How often a wake is resent while infotainment stays silent: a first wake can be missed after a long sleep. */
|
|
43
|
+
export declare const WAKE_RESEND_INTERVAL_MS = 3000;
|
|
44
|
+
/** How long an awake car's infotainment may take to finish booting. */
|
|
45
|
+
export declare const INFOTAINMENT_BOOT_TIMEOUT_MS = 20000;
|
|
46
|
+
/** How long a charge-port opening has to show in charge state. It took about 1.4 s in live trials. */
|
|
47
|
+
export declare const CHARGE_PORT_VERIFY_TIMEOUT_MS = 5000;
|
|
48
|
+
/** Between charge-state polls, while waiting for readiness or for the latch. */
|
|
49
|
+
export declare const CHARGE_PORT_VERIFY_INTERVAL_MS = 250;
|
|
50
|
+
/** How long `pair` waits for someone to tap a key card. */
|
|
51
|
+
export declare const DEFAULT_PAIR_TIMEOUT_MS = 300000;
|
|
52
|
+
/** Between `pair`'s checks of whether the key was accepted. */
|
|
53
|
+
export declare const DEFAULT_PAIR_POLL_INTERVAL_MS = 5000;
|
|
54
|
+
/** Connect attempts. Each is bounded by `DEFAULT_CONNECT_TIMEOUT_MS`. */
|
|
55
|
+
export declare const DEFAULT_CONNECT_ATTEMPTS = 3;
|
|
56
|
+
/** One connect attempt. Python takes the same figure from `bleak-retry-connector`. */
|
|
57
|
+
export declare const DEFAULT_CONNECT_TIMEOUT_MS = 20000;
|
|
58
|
+
/** One scan. It must outlast the backend's window, which Homey fixes at about 5 s. */
|
|
59
|
+
export declare const DEFAULT_SCAN_TIMEOUT_MS = 10000;
|
|
60
|
+
/** Bound on tearing down a link: the failure behind it is what gets reported. */
|
|
61
|
+
export declare const LINK_TEARDOWN_TIMEOUT_MS = 5000;
|
|
62
|
+
/**
|
|
63
|
+
* One write call. Not in Python, whose backends bound their own writes. Homey's
|
|
64
|
+
* have no timeout and its link state can be stale, so a hung write must end
|
|
65
|
+
* here. A design choice. BLE-00 step 10 measures how long a failing write takes
|
|
66
|
+
* on Homey, which sets it.
|
|
67
|
+
*/
|
|
68
|
+
export declare const GATT_WRITE_TIMEOUT_MS = 5000;
|
|
69
|
+
/** One read call, other than a keepalive's. */
|
|
70
|
+
export declare const GATT_READ_TIMEOUT_MS = 5000;
|