tesla-fleet-api 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +284 -1
- package/dist/_virtual/_rolldown/runtime.cjs +32 -0
- package/dist/_virtual/_rolldown/runtime.mjs +12 -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/charging.cjs +53 -0
- package/dist/charging.d.cts +31 -0
- package/dist/charging.d.mts +30 -0
- package/dist/charging.mjs +53 -0
- package/dist/commands.cjs +1797 -0
- package/dist/commands.d.cts +881 -0
- package/dist/commands.d.mts +881 -0
- package/dist/commands.mjs +1791 -0
- package/dist/const.cjs +322 -0
- package/dist/const.d.cts +308 -0
- package/dist/const.d.mts +308 -0
- package/dist/const.mjs +282 -0
- package/dist/energy.cjs +142 -0
- package/dist/energy.d.cts +101 -0
- package/dist/energy.d.mts +100 -0
- package/dist/energy.mjs +142 -0
- 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 +457 -0
- package/dist/energyspecific.d.cts +258 -0
- package/dist/energyspecific.d.mts +258 -0
- package/dist/energyspecific.mjs +451 -0
- package/dist/exceptions.cjs +1488 -0
- package/dist/exceptions.d.cts +1143 -0
- package/dist/exceptions.d.mts +1143 -0
- package/dist/exceptions.mjs +1325 -0
- 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 +287 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.mjs +27 -0
- 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/partner.cjs +32 -0
- package/dist/partner.d.cts +24 -0
- package/dist/partner.d.mts +23 -0
- package/dist/partner.mjs +32 -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 -0
- package/dist/router.d.mts +3 -0
- package/dist/router.mjs +3 -0
- package/dist/signing/crypto.cjs +59 -0
- package/dist/signing/crypto.mjs +52 -0
- 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 +186 -0
- package/dist/signing/session.d.cts +106 -0
- package/dist/signing/session.d.mts +106 -0
- package/dist/signing/session.mjs +184 -0
- package/dist/tariff.cjs +319 -0
- package/dist/tariff.d.cts +40 -0
- package/dist/tariff.d.mts +40 -0
- package/dist/tariff.mjs +317 -0
- package/dist/teslafleetapi.cjs +326 -0
- package/dist/teslafleetapi.d.cts +160 -0
- package/dist/teslafleetapi.d.mts +160 -0
- package/dist/teslafleetapi.mjs +326 -0
- package/dist/teslemetry.cjs +183 -0
- package/dist/teslemetry.d.cts +113 -0
- package/dist/teslemetry.d.mts +113 -0
- package/dist/teslemetry.mjs +181 -0
- 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 +71 -0
- package/dist/tessie.d.cts +69 -0
- package/dist/tessie.d.mts +69 -0
- package/dist/tessie.mjs +71 -0
- 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/commands.d.cts +28 -0
- package/dist/types/commands.d.mts +28 -0
- package/dist/types/live_status.d.cts +30 -0
- package/dist/types/live_status.d.mts +30 -0
- package/dist/types/products.d.cts +58 -0
- package/dist/types/products.d.mts +58 -0
- package/dist/types/responses.d.cts +13 -0
- package/dist/types/responses.d.mts +13 -0
- package/dist/types/site_info.d.cts +154 -0
- package/dist/types/site_info.d.mts +154 -0
- package/dist/types/vehicle.d.cts +33 -0
- package/dist/types/vehicle.d.mts +33 -0
- package/dist/types/vehicle_data.d.cts +278 -0
- package/dist/types/vehicle_data.d.mts +278 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.cts +9 -0
- package/dist/types.d.mts +9 -0
- package/dist/types.mjs +1 -0
- package/dist/user.cjs +28 -0
- package/dist/user.d.cts +17 -0
- package/dist/user.d.mts +16 -0
- package/dist/user.mjs +28 -0
- 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 +847 -0
- package/dist/vehicle.d.cts +566 -0
- package/dist/vehicle.d.mts +565 -0
- package/dist/vehicle.mjs +847 -0
- package/dist/vehiclesigned.cjs +35 -0
- package/dist/vehiclesigned.d.cts +23 -0
- package/dist/vehiclesigned.d.mts +22 -0
- package/dist/vehiclesigned.mjs +35 -0
- package/dist/vehiclespecific.cjs +715 -0
- package/dist/vehiclespecific.d.cts +497 -0
- package/dist/vehiclespecific.d.mts +496 -0
- package/dist/vehiclespecific.mjs +715 -0
- package/package.json +178 -38
- package/dist/charging.d.ts +0 -30
- package/dist/charging.js +0 -51
- package/dist/charging.js.map +0 -1
- package/dist/commands.d.ts +0 -352
- package/dist/commands.js +0 -875
- package/dist/commands.js.map +0 -1
- package/dist/energy.d.ts +0 -94
- package/dist/energy.js +0 -125
- package/dist/energy.js.map +0 -1
- package/dist/energyspecific.d.ts +0 -77
- package/dist/energyspecific.js +0 -97
- package/dist/energyspecific.js.map +0 -1
- package/dist/helpers.d.ts +0 -2
- package/dist/helpers.js +0 -10
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -15
- package/dist/index.js.map +0 -1
- package/dist/partner.d.ts +0 -23
- package/dist/partner.js +0 -31
- package/dist/partner.js.map +0 -1
- package/dist/signing/crypto.d.ts +0 -10
- package/dist/signing/crypto.js +0 -26
- package/dist/signing/crypto.js.map +0 -1
- package/dist/signing/errors.d.ts +0 -29
- package/dist/signing/errors.js +0 -40
- package/dist/signing/errors.js.map +0 -1
- package/dist/signing/session.d.ts +0 -69
- package/dist/signing/session.js +0 -102
- package/dist/signing/session.js.map +0 -1
- package/dist/tariff.d.ts +0 -29
- package/dist/tariff.js +0 -302
- package/dist/tariff.js.map +0 -1
- package/dist/teslafleetapi.d.ts +0 -58
- package/dist/teslafleetapi.js +0 -120
- package/dist/teslafleetapi.js.map +0 -1
- package/dist/teslemetry.d.ts +0 -29
- package/dist/teslemetry.js +0 -39
- package/dist/teslemetry.js.map +0 -1
- package/dist/tessie.d.ts +0 -23
- package/dist/tessie.js +0 -28
- package/dist/tessie.js.map +0 -1
- package/dist/types/commands.d.ts +0 -44
- package/dist/types/commands.js +0 -11
- package/dist/types/commands.js.map +0 -1
- package/dist/types/live_status.d.ts +0 -26
- package/dist/types/live_status.js +0 -2
- package/dist/types/live_status.js.map +0 -1
- package/dist/types/products.d.ts +0 -54
- package/dist/types/products.js +0 -2
- package/dist/types/products.js.map +0 -1
- package/dist/types/responses.d.ts +0 -5
- package/dist/types/responses.js +0 -2
- package/dist/types/responses.js.map +0 -1
- package/dist/types/site_info.d.ts +0 -150
- package/dist/types/site_info.js +0 -2
- package/dist/types/site_info.js.map +0 -1
- package/dist/types/vehicle.d.ts +0 -23
- package/dist/types/vehicle.js +0 -10
- package/dist/types/vehicle.js.map +0 -1
- package/dist/types/vehicle_data.d.ts +0 -274
- package/dist/types/vehicle_data.js +0 -2
- package/dist/types/vehicle_data.js.map +0 -1
- package/dist/user.d.ts +0 -16
- package/dist/user.js +0 -26
- package/dist/user.js.map +0 -1
- package/dist/vehicle.d.ts +0 -548
- package/dist/vehicle.js +0 -774
- package/dist/vehicle.js.map +0 -1
- package/dist/vehiclesigned.d.ts +0 -13
- package/dist/vehiclesigned.js +0 -19
- package/dist/vehiclesigned.js.map +0 -1
- package/dist/vehiclespecific.d.ts +0 -432
- package/dist/vehiclespecific.js +0 -601
- package/dist/vehiclespecific.js.map +0 -1
- package/src/charging.ts +0 -66
- package/src/commands.ts +0 -1134
- package/src/energy.ts +0 -217
- package/src/energyspecific.ts +0 -116
- package/src/helpers.ts +0 -11
- package/src/index.ts +0 -21
- package/src/partner.ts +0 -37
- package/src/signing/crypto.ts +0 -29
- package/src/signing/errors.ts +0 -50
- package/src/signing/session.ts +0 -132
- package/src/tariff.ts +0 -375
- package/src/teslafleetapi.ts +0 -182
- package/src/teslemetry.ts +0 -54
- package/src/tessie.ts +0 -42
- package/src/types/commands.ts +0 -62
- package/src/types/live_status.ts +0 -27
- package/src/types/products.ts +0 -61
- package/src/types/responses.ts +0 -1
- package/src/types/site_info.ts +0 -159
- package/src/types/vehicle.ts +0 -33
- package/src/types/vehicle_data.ts +0 -286
- package/src/user.ts +0 -35
- package/src/vehicle.ts +0 -886
- package/src/vehiclesigned.ts +0 -20
- package/src/vehiclespecific.ts +0 -818
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_async = require("./async.cjs");
|
|
3
|
+
const require_constants = require("./constants.cjs");
|
|
4
|
+
const require_transport = require("./transport.cjs");
|
|
5
|
+
const require_shared = require("./adapters/shared.cjs");
|
|
6
|
+
// src/bluetooth/adapters/homey.ts
|
|
7
|
+
/**
|
|
8
|
+
* Bytes per write. Homey hides the MTU, so this is the ATT minimum, the one size
|
|
9
|
+
* sure to work. BLE-00 step 6: if a whole 114-byte frame gets a reply, this can
|
|
10
|
+
* become `null`. Otherwise step 7 keeps it, or the MTU estimate less 3 if larger.
|
|
11
|
+
*/
|
|
12
|
+
const HOMEY_MAX_WRITE_SIZE = 20;
|
|
13
|
+
/**
|
|
14
|
+
* For `connect_timeout_ms` and `max_connect_attempts`, not applied by this
|
|
15
|
+
* adapter: `discover()` caches for 30 s, so a fast retry sees old data, and
|
|
16
|
+
* these fit Homey's 9 s action window. BLE-00 step 11 sets both, against its
|
|
17
|
+
* target of a connect under 4 s in 9 of 10. A flow with no such window should
|
|
18
|
+
* keep the library's defaults until then, as a link slower than this never lands.
|
|
19
|
+
*/
|
|
20
|
+
const HOMEY_VEHICLE_OPTIONS = {
|
|
21
|
+
connect_timeout_ms: 4e3,
|
|
22
|
+
max_connect_attempts: 1
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Bound on discovery and subscribing once a link is up. Homey has no timeout of
|
|
26
|
+
* its own, and if these hang, nothing else could release the vehicle's slot.
|
|
27
|
+
* BLE-00 steps 3 and 4 show what a slow link takes.
|
|
28
|
+
*/
|
|
29
|
+
const HOMEY_SETUP_TIMEOUT_MS = require_constants.DEFAULT_CONNECT_TIMEOUT_MS;
|
|
30
|
+
/** Bound on unsubscribing, which must not keep `disconnect` from running on a dead link. BLE-00 step 10. */
|
|
31
|
+
const HOMEY_UNSUBSCRIBE_TIMEOUT_MS = 1e3;
|
|
32
|
+
function find(characteristics, uuid) {
|
|
33
|
+
return characteristics.find((characteristic) => require_shared.compactUuid(characteristic.uuid) === require_shared.compactUuid(uuid));
|
|
34
|
+
}
|
|
35
|
+
var HomeyConnection = class {
|
|
36
|
+
id;
|
|
37
|
+
handlers;
|
|
38
|
+
maxWriteSize;
|
|
39
|
+
claims;
|
|
40
|
+
lost = false;
|
|
41
|
+
closed = false;
|
|
42
|
+
closing;
|
|
43
|
+
peripheral;
|
|
44
|
+
characteristics = [];
|
|
45
|
+
genericAccess;
|
|
46
|
+
subscribed = false;
|
|
47
|
+
onDisconnect = () => {
|
|
48
|
+
this.lost = true;
|
|
49
|
+
if (!this.closed) this.handlers.onDisconnect();
|
|
50
|
+
};
|
|
51
|
+
constructor(id, handlers, maxWriteSize, claims) {
|
|
52
|
+
this.id = id;
|
|
53
|
+
this.handlers = handlers;
|
|
54
|
+
this.maxWriteSize = maxWriteSize;
|
|
55
|
+
this.claims = claims;
|
|
56
|
+
}
|
|
57
|
+
/** Stale after a silent drop. The library's timeouts are what find a dead link. */
|
|
58
|
+
get isConnected() {
|
|
59
|
+
return !this.lost && !this.closed && this.peripheral?.isConnected === true;
|
|
60
|
+
}
|
|
61
|
+
/** Discover, then subscribe: the link is live only once this resolves. */
|
|
62
|
+
async attach(peripheral) {
|
|
63
|
+
this.peripheral = peripheral;
|
|
64
|
+
this.assertCurrent();
|
|
65
|
+
peripheral.once("disconnect", this.onDisconnect);
|
|
66
|
+
const characteristics = await (await peripheral.getService(require_shared.compactUuid(require_constants.SERVICE_UUID))).discoverCharacteristics();
|
|
67
|
+
const notify = find(characteristics, require_constants.VEHICLE_NOTIFY_UUID);
|
|
68
|
+
if (!notify || !find(characteristics, "00000212-b2d1-43f0-9b88-960cebf8b91e")) throw new Error("The vehicle's write or notify characteristic was not found.");
|
|
69
|
+
this.assertCurrent();
|
|
70
|
+
this.characteristics = characteristics;
|
|
71
|
+
await notify.subscribeToNotifications((data) => this.handlers.onNotify(data));
|
|
72
|
+
this.subscribed = true;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Homey hands every attempt the same link, and one subscription per
|
|
76
|
+
* characteristic. A superseded attempt stops here, before it changes either.
|
|
77
|
+
*/
|
|
78
|
+
assertCurrent() {
|
|
79
|
+
if (this.claims.superseded(this.id, this)) throw new Error("A newer connect attempt took over this link.");
|
|
80
|
+
}
|
|
81
|
+
async write(data) {
|
|
82
|
+
const characteristic = find(this.characteristics, require_constants.VEHICLE_WRITE_UUID);
|
|
83
|
+
if (!characteristic) throw new require_transport.BleNotSubmittedError("The vehicle write characteristic was not found.");
|
|
84
|
+
if (!this.isConnected) throw new require_transport.BleNotSubmittedError("The link is down.");
|
|
85
|
+
await characteristic.write(Buffer.from(data));
|
|
86
|
+
}
|
|
87
|
+
async read(characteristic) {
|
|
88
|
+
const target = characteristic === "version" ? find(this.characteristics, require_constants.VERSION_UUID) : find(await this.discoverGenericAccess(), characteristic === "deviceName" ? require_constants.NAME_UUID : require_constants.APPEARANCE_UUID);
|
|
89
|
+
if (!target) throw new require_transport.BleNotSubmittedError(`The ${characteristic} characteristic was not found.`);
|
|
90
|
+
return target.read();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Homey's stack may hide this service, which BLE-00 step 8 settles. A failed
|
|
94
|
+
* lookup leaves a characteristic unresolved on a healthy link, so it must not
|
|
95
|
+
* read as a lost one.
|
|
96
|
+
*/
|
|
97
|
+
discoverGenericAccess() {
|
|
98
|
+
const { peripheral } = this;
|
|
99
|
+
if (!peripheral) return Promise.reject(new require_transport.BleNotSubmittedError("The link is down."));
|
|
100
|
+
this.genericAccess ??= peripheral.getService(require_shared.compactUuid(require_constants.GENERIC_ACCESS_UUID)).then((service) => service.discoverCharacteristics()).catch((cause) => {
|
|
101
|
+
this.genericAccess = void 0;
|
|
102
|
+
throw new require_transport.BleNotSubmittedError("Generic Access could not be resolved.", { cause });
|
|
103
|
+
});
|
|
104
|
+
return this.genericAccess;
|
|
105
|
+
}
|
|
106
|
+
disconnect() {
|
|
107
|
+
this.closing ??= (async () => {
|
|
108
|
+
this.closed = true;
|
|
109
|
+
const { peripheral, claims, id } = this;
|
|
110
|
+
peripheral?.removeListener("disconnect", this.onDisconnect);
|
|
111
|
+
const superseded = claims.superseded(id, this);
|
|
112
|
+
claims.release(id, this);
|
|
113
|
+
if (superseded || !peripheral) return;
|
|
114
|
+
if (this.subscribed) await require_shared.quietly(() => require_async.withTimeout(() => find(this.characteristics, require_constants.VEHICLE_NOTIFY_UUID).unsubscribeFromNotifications(), HOMEY_UNSUBSCRIBE_TIMEOUT_MS));
|
|
115
|
+
await require_shared.quietly(() => peripheral.disconnect());
|
|
116
|
+
})();
|
|
117
|
+
return this.closing;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var HomeyBleTransport = class {
|
|
121
|
+
ble;
|
|
122
|
+
maxWriteSize;
|
|
123
|
+
claims = new require_shared.LinkClaims();
|
|
124
|
+
/** @param ble `this.homey.ble`. The app needs the `homey:wireless:ble` permission. */
|
|
125
|
+
constructor(ble, options = {}) {
|
|
126
|
+
this.ble = ble;
|
|
127
|
+
this.maxWriteSize = options.maxWriteSize === void 0 ? 20 : options.maxWriteSize;
|
|
128
|
+
}
|
|
129
|
+
/** Takes Homey's fixed window, whatever `timeoutMs` says. Never pass `discover` a filter. */
|
|
130
|
+
async scan({ matches }) {
|
|
131
|
+
return (await this.ble.discover()).filter((advertisement) => !matches || advertisement.localName !== void 0 && matches(advertisement.localName)).map((advertisement) => ({
|
|
132
|
+
id: advertisement.uuid,
|
|
133
|
+
name: advertisement.localName,
|
|
134
|
+
rssi: advertisement.rssi,
|
|
135
|
+
connectable: advertisement.connectable
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
async connect(device, handlers) {
|
|
139
|
+
const connection = new HomeyConnection(device.id, handlers, this.maxWriteSize, this.claims);
|
|
140
|
+
this.claims.claim(device.id, connection);
|
|
141
|
+
try {
|
|
142
|
+
const peripheral = await (await this.ble.find(device.id)).connect();
|
|
143
|
+
await require_async.withTimeout(() => connection.attach(peripheral), HOMEY_SETUP_TIMEOUT_MS);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
await connection.disconnect();
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
return connection;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
exports.HOMEY_MAX_WRITE_SIZE = HOMEY_MAX_WRITE_SIZE;
|
|
152
|
+
exports.HOMEY_SETUP_TIMEOUT_MS = HOMEY_SETUP_TIMEOUT_MS;
|
|
153
|
+
exports.HOMEY_UNSUBSCRIBE_TIMEOUT_MS = HOMEY_UNSUBSCRIBE_TIMEOUT_MS;
|
|
154
|
+
exports.HOMEY_VEHICLE_OPTIONS = HOMEY_VEHICLE_OPTIONS;
|
|
155
|
+
exports.HomeyBleTransport = HomeyBleTransport;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { BleConnection, BleDeviceRef, BleLinkHandlers, BleScanOptions, BleTransport } from "./transport.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* Bytes per write. Homey hides the MTU, so this is the ATT minimum, the one size
|
|
4
|
+
* sure to work. BLE-00 step 6: if a whole 114-byte frame gets a reply, this can
|
|
5
|
+
* become `null`. Otherwise step 7 keeps it, or the MTU estimate less 3 if larger.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HOMEY_MAX_WRITE_SIZE = 20;
|
|
8
|
+
/**
|
|
9
|
+
* For `connect_timeout_ms` and `max_connect_attempts`, not applied by this
|
|
10
|
+
* adapter: `discover()` caches for 30 s, so a fast retry sees old data, and
|
|
11
|
+
* these fit Homey's 9 s action window. BLE-00 step 11 sets both, against its
|
|
12
|
+
* target of a connect under 4 s in 9 of 10. A flow with no such window should
|
|
13
|
+
* keep the library's defaults until then, as a link slower than this never lands.
|
|
14
|
+
*/
|
|
15
|
+
export declare const HOMEY_VEHICLE_OPTIONS: {
|
|
16
|
+
readonly connect_timeout_ms: 4000;
|
|
17
|
+
readonly max_connect_attempts: 1;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Bound on discovery and subscribing once a link is up. Homey has no timeout of
|
|
21
|
+
* its own, and if these hang, nothing else could release the vehicle's slot.
|
|
22
|
+
* BLE-00 steps 3 and 4 show what a slow link takes.
|
|
23
|
+
*/
|
|
24
|
+
export declare const HOMEY_SETUP_TIMEOUT_MS = 20000;
|
|
25
|
+
/** Bound on unsubscribing, which must not keep `disconnect` from running on a dead link. BLE-00 step 10. */
|
|
26
|
+
export declare const HOMEY_UNSUBSCRIBE_TIMEOUT_MS = 1000;
|
|
27
|
+
export interface HomeyCharacteristicLike {
|
|
28
|
+
uuid: string;
|
|
29
|
+
read(): Promise<Buffer>;
|
|
30
|
+
/** Always a write with response: the only kind Homey offers. */
|
|
31
|
+
write(data: Buffer): Promise<unknown>;
|
|
32
|
+
subscribeToNotifications(callback: (data: Buffer) => void): Promise<void>;
|
|
33
|
+
unsubscribeFromNotifications(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface HomeyServiceLike {
|
|
36
|
+
discoverCharacteristics(): Promise<HomeyCharacteristicLike[]>;
|
|
37
|
+
}
|
|
38
|
+
export interface HomeyPeripheralLike {
|
|
39
|
+
/** Can stay true after a silent drop, so it is only ever a faster signal. BLE-00 step 9 measures it. */
|
|
40
|
+
readonly isConnected: boolean;
|
|
41
|
+
getService(uuid: string): Promise<HomeyServiceLike>;
|
|
42
|
+
disconnect(): Promise<void>;
|
|
43
|
+
/** Not guaranteed on every drop, but if it fires, the link is gone. BLE-00 step 9 measures it. */
|
|
44
|
+
once(event: "disconnect", listener: () => void): unknown;
|
|
45
|
+
removeListener(event: "disconnect", listener: () => void): unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface HomeyAdvertisementLike {
|
|
48
|
+
uuid: string;
|
|
49
|
+
/** Typed as a string, but Homey's guide says it is optional. BLE-00 step 2 measures how often it is there. */
|
|
50
|
+
localName?: string;
|
|
51
|
+
rssi?: number;
|
|
52
|
+
connectable?: boolean;
|
|
53
|
+
/** If already connected, returns the existing connection. It has no timeout: the library bounds it. */
|
|
54
|
+
connect(): Promise<HomeyPeripheralLike>;
|
|
55
|
+
}
|
|
56
|
+
/** What this adapter needs of `this.homey.ble`. */
|
|
57
|
+
export interface HomeyBleManagerLike {
|
|
58
|
+
/** About 5 s, fixed. Called with no filter, because the vehicle advertises no service. */
|
|
59
|
+
discover(): Promise<HomeyAdvertisementLike[]>;
|
|
60
|
+
find(uuid: string): Promise<HomeyAdvertisementLike>;
|
|
61
|
+
}
|
|
62
|
+
export interface HomeyBleTransportOptions {
|
|
63
|
+
/** Bytes per write, or `null` for a whole frame in one write. Defaults to `HOMEY_MAX_WRITE_SIZE`. */
|
|
64
|
+
maxWriteSize?: number | null;
|
|
65
|
+
}
|
|
66
|
+
export declare class HomeyBleTransport implements BleTransport {
|
|
67
|
+
private readonly ble;
|
|
68
|
+
private readonly maxWriteSize;
|
|
69
|
+
private readonly claims;
|
|
70
|
+
/** @param ble `this.homey.ble`. The app needs the `homey:wireless:ble` permission. */
|
|
71
|
+
constructor(ble: HomeyBleManagerLike, options?: HomeyBleTransportOptions);
|
|
72
|
+
/** Takes Homey's fixed window, whatever `timeoutMs` says. Never pass `discover` a filter. */
|
|
73
|
+
scan({ matches }: BleScanOptions): Promise<BleDeviceRef[]>;
|
|
74
|
+
connect(device: BleDeviceRef, handlers: BleLinkHandlers): Promise<BleConnection>;
|
|
75
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { BleConnection, BleDeviceRef, BleLinkHandlers, BleScanOptions, BleTransport } from "./transport.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Bytes per write. Homey hides the MTU, so this is the ATT minimum, the one size
|
|
4
|
+
* sure to work. BLE-00 step 6: if a whole 114-byte frame gets a reply, this can
|
|
5
|
+
* become `null`. Otherwise step 7 keeps it, or the MTU estimate less 3 if larger.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HOMEY_MAX_WRITE_SIZE = 20;
|
|
8
|
+
/**
|
|
9
|
+
* For `connect_timeout_ms` and `max_connect_attempts`, not applied by this
|
|
10
|
+
* adapter: `discover()` caches for 30 s, so a fast retry sees old data, and
|
|
11
|
+
* these fit Homey's 9 s action window. BLE-00 step 11 sets both, against its
|
|
12
|
+
* target of a connect under 4 s in 9 of 10. A flow with no such window should
|
|
13
|
+
* keep the library's defaults until then, as a link slower than this never lands.
|
|
14
|
+
*/
|
|
15
|
+
export declare const HOMEY_VEHICLE_OPTIONS: {
|
|
16
|
+
readonly connect_timeout_ms: 4000;
|
|
17
|
+
readonly max_connect_attempts: 1;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Bound on discovery and subscribing once a link is up. Homey has no timeout of
|
|
21
|
+
* its own, and if these hang, nothing else could release the vehicle's slot.
|
|
22
|
+
* BLE-00 steps 3 and 4 show what a slow link takes.
|
|
23
|
+
*/
|
|
24
|
+
export declare const HOMEY_SETUP_TIMEOUT_MS = 20000;
|
|
25
|
+
/** Bound on unsubscribing, which must not keep `disconnect` from running on a dead link. BLE-00 step 10. */
|
|
26
|
+
export declare const HOMEY_UNSUBSCRIBE_TIMEOUT_MS = 1000;
|
|
27
|
+
export interface HomeyCharacteristicLike {
|
|
28
|
+
uuid: string;
|
|
29
|
+
read(): Promise<Buffer>;
|
|
30
|
+
/** Always a write with response: the only kind Homey offers. */
|
|
31
|
+
write(data: Buffer): Promise<unknown>;
|
|
32
|
+
subscribeToNotifications(callback: (data: Buffer) => void): Promise<void>;
|
|
33
|
+
unsubscribeFromNotifications(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface HomeyServiceLike {
|
|
36
|
+
discoverCharacteristics(): Promise<HomeyCharacteristicLike[]>;
|
|
37
|
+
}
|
|
38
|
+
export interface HomeyPeripheralLike {
|
|
39
|
+
/** Can stay true after a silent drop, so it is only ever a faster signal. BLE-00 step 9 measures it. */
|
|
40
|
+
readonly isConnected: boolean;
|
|
41
|
+
getService(uuid: string): Promise<HomeyServiceLike>;
|
|
42
|
+
disconnect(): Promise<void>;
|
|
43
|
+
/** Not guaranteed on every drop, but if it fires, the link is gone. BLE-00 step 9 measures it. */
|
|
44
|
+
once(event: "disconnect", listener: () => void): unknown;
|
|
45
|
+
removeListener(event: "disconnect", listener: () => void): unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface HomeyAdvertisementLike {
|
|
48
|
+
uuid: string;
|
|
49
|
+
/** Typed as a string, but Homey's guide says it is optional. BLE-00 step 2 measures how often it is there. */
|
|
50
|
+
localName?: string;
|
|
51
|
+
rssi?: number;
|
|
52
|
+
connectable?: boolean;
|
|
53
|
+
/** If already connected, returns the existing connection. It has no timeout: the library bounds it. */
|
|
54
|
+
connect(): Promise<HomeyPeripheralLike>;
|
|
55
|
+
}
|
|
56
|
+
/** What this adapter needs of `this.homey.ble`. */
|
|
57
|
+
export interface HomeyBleManagerLike {
|
|
58
|
+
/** About 5 s, fixed. Called with no filter, because the vehicle advertises no service. */
|
|
59
|
+
discover(): Promise<HomeyAdvertisementLike[]>;
|
|
60
|
+
find(uuid: string): Promise<HomeyAdvertisementLike>;
|
|
61
|
+
}
|
|
62
|
+
export interface HomeyBleTransportOptions {
|
|
63
|
+
/** Bytes per write, or `null` for a whole frame in one write. Defaults to `HOMEY_MAX_WRITE_SIZE`. */
|
|
64
|
+
maxWriteSize?: number | null;
|
|
65
|
+
}
|
|
66
|
+
export declare class HomeyBleTransport implements BleTransport {
|
|
67
|
+
private readonly ble;
|
|
68
|
+
private readonly maxWriteSize;
|
|
69
|
+
private readonly claims;
|
|
70
|
+
/** @param ble `this.homey.ble`. The app needs the `homey:wireless:ble` permission. */
|
|
71
|
+
constructor(ble: HomeyBleManagerLike, options?: HomeyBleTransportOptions);
|
|
72
|
+
/** Takes Homey's fixed window, whatever `timeoutMs` says. Never pass `discover` a filter. */
|
|
73
|
+
scan({ matches }: BleScanOptions): Promise<BleDeviceRef[]>;
|
|
74
|
+
connect(device: BleDeviceRef, handlers: BleLinkHandlers): Promise<BleConnection>;
|
|
75
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { withTimeout } from "./async.mjs";
|
|
2
|
+
import { APPEARANCE_UUID, DEFAULT_CONNECT_TIMEOUT_MS, GENERIC_ACCESS_UUID, NAME_UUID, SERVICE_UUID, VEHICLE_NOTIFY_UUID, VEHICLE_WRITE_UUID, VERSION_UUID } from "./constants.mjs";
|
|
3
|
+
import { BleNotSubmittedError } from "./transport.mjs";
|
|
4
|
+
import { LinkClaims, compactUuid, quietly } from "./adapters/shared.mjs";
|
|
5
|
+
// src/bluetooth/adapters/homey.ts
|
|
6
|
+
/**
|
|
7
|
+
* Bytes per write. Homey hides the MTU, so this is the ATT minimum, the one size
|
|
8
|
+
* sure to work. BLE-00 step 6: if a whole 114-byte frame gets a reply, this can
|
|
9
|
+
* become `null`. Otherwise step 7 keeps it, or the MTU estimate less 3 if larger.
|
|
10
|
+
*/
|
|
11
|
+
const HOMEY_MAX_WRITE_SIZE = 20;
|
|
12
|
+
/**
|
|
13
|
+
* For `connect_timeout_ms` and `max_connect_attempts`, not applied by this
|
|
14
|
+
* adapter: `discover()` caches for 30 s, so a fast retry sees old data, and
|
|
15
|
+
* these fit Homey's 9 s action window. BLE-00 step 11 sets both, against its
|
|
16
|
+
* target of a connect under 4 s in 9 of 10. A flow with no such window should
|
|
17
|
+
* keep the library's defaults until then, as a link slower than this never lands.
|
|
18
|
+
*/
|
|
19
|
+
const HOMEY_VEHICLE_OPTIONS = {
|
|
20
|
+
connect_timeout_ms: 4e3,
|
|
21
|
+
max_connect_attempts: 1
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Bound on discovery and subscribing once a link is up. Homey has no timeout of
|
|
25
|
+
* its own, and if these hang, nothing else could release the vehicle's slot.
|
|
26
|
+
* BLE-00 steps 3 and 4 show what a slow link takes.
|
|
27
|
+
*/
|
|
28
|
+
const HOMEY_SETUP_TIMEOUT_MS = DEFAULT_CONNECT_TIMEOUT_MS;
|
|
29
|
+
/** Bound on unsubscribing, which must not keep `disconnect` from running on a dead link. BLE-00 step 10. */
|
|
30
|
+
const HOMEY_UNSUBSCRIBE_TIMEOUT_MS = 1e3;
|
|
31
|
+
function find(characteristics, uuid) {
|
|
32
|
+
return characteristics.find((characteristic) => compactUuid(characteristic.uuid) === compactUuid(uuid));
|
|
33
|
+
}
|
|
34
|
+
var HomeyConnection = class {
|
|
35
|
+
id;
|
|
36
|
+
handlers;
|
|
37
|
+
maxWriteSize;
|
|
38
|
+
claims;
|
|
39
|
+
lost = false;
|
|
40
|
+
closed = false;
|
|
41
|
+
closing;
|
|
42
|
+
peripheral;
|
|
43
|
+
characteristics = [];
|
|
44
|
+
genericAccess;
|
|
45
|
+
subscribed = false;
|
|
46
|
+
onDisconnect = () => {
|
|
47
|
+
this.lost = true;
|
|
48
|
+
if (!this.closed) this.handlers.onDisconnect();
|
|
49
|
+
};
|
|
50
|
+
constructor(id, handlers, maxWriteSize, claims) {
|
|
51
|
+
this.id = id;
|
|
52
|
+
this.handlers = handlers;
|
|
53
|
+
this.maxWriteSize = maxWriteSize;
|
|
54
|
+
this.claims = claims;
|
|
55
|
+
}
|
|
56
|
+
/** Stale after a silent drop. The library's timeouts are what find a dead link. */
|
|
57
|
+
get isConnected() {
|
|
58
|
+
return !this.lost && !this.closed && this.peripheral?.isConnected === true;
|
|
59
|
+
}
|
|
60
|
+
/** Discover, then subscribe: the link is live only once this resolves. */
|
|
61
|
+
async attach(peripheral) {
|
|
62
|
+
this.peripheral = peripheral;
|
|
63
|
+
this.assertCurrent();
|
|
64
|
+
peripheral.once("disconnect", this.onDisconnect);
|
|
65
|
+
const characteristics = await (await peripheral.getService(compactUuid(SERVICE_UUID))).discoverCharacteristics();
|
|
66
|
+
const notify = find(characteristics, VEHICLE_NOTIFY_UUID);
|
|
67
|
+
if (!notify || !find(characteristics, "00000212-b2d1-43f0-9b88-960cebf8b91e")) throw new Error("The vehicle's write or notify characteristic was not found.");
|
|
68
|
+
this.assertCurrent();
|
|
69
|
+
this.characteristics = characteristics;
|
|
70
|
+
await notify.subscribeToNotifications((data) => this.handlers.onNotify(data));
|
|
71
|
+
this.subscribed = true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Homey hands every attempt the same link, and one subscription per
|
|
75
|
+
* characteristic. A superseded attempt stops here, before it changes either.
|
|
76
|
+
*/
|
|
77
|
+
assertCurrent() {
|
|
78
|
+
if (this.claims.superseded(this.id, this)) throw new Error("A newer connect attempt took over this link.");
|
|
79
|
+
}
|
|
80
|
+
async write(data) {
|
|
81
|
+
const characteristic = find(this.characteristics, VEHICLE_WRITE_UUID);
|
|
82
|
+
if (!characteristic) throw new BleNotSubmittedError("The vehicle write characteristic was not found.");
|
|
83
|
+
if (!this.isConnected) throw new BleNotSubmittedError("The link is down.");
|
|
84
|
+
await characteristic.write(Buffer.from(data));
|
|
85
|
+
}
|
|
86
|
+
async read(characteristic) {
|
|
87
|
+
const target = characteristic === "version" ? find(this.characteristics, VERSION_UUID) : find(await this.discoverGenericAccess(), characteristic === "deviceName" ? NAME_UUID : APPEARANCE_UUID);
|
|
88
|
+
if (!target) throw new BleNotSubmittedError(`The ${characteristic} characteristic was not found.`);
|
|
89
|
+
return target.read();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Homey's stack may hide this service, which BLE-00 step 8 settles. A failed
|
|
93
|
+
* lookup leaves a characteristic unresolved on a healthy link, so it must not
|
|
94
|
+
* read as a lost one.
|
|
95
|
+
*/
|
|
96
|
+
discoverGenericAccess() {
|
|
97
|
+
const { peripheral } = this;
|
|
98
|
+
if (!peripheral) return Promise.reject(new BleNotSubmittedError("The link is down."));
|
|
99
|
+
this.genericAccess ??= peripheral.getService(compactUuid(GENERIC_ACCESS_UUID)).then((service) => service.discoverCharacteristics()).catch((cause) => {
|
|
100
|
+
this.genericAccess = void 0;
|
|
101
|
+
throw new BleNotSubmittedError("Generic Access could not be resolved.", { cause });
|
|
102
|
+
});
|
|
103
|
+
return this.genericAccess;
|
|
104
|
+
}
|
|
105
|
+
disconnect() {
|
|
106
|
+
this.closing ??= (async () => {
|
|
107
|
+
this.closed = true;
|
|
108
|
+
const { peripheral, claims, id } = this;
|
|
109
|
+
peripheral?.removeListener("disconnect", this.onDisconnect);
|
|
110
|
+
const superseded = claims.superseded(id, this);
|
|
111
|
+
claims.release(id, this);
|
|
112
|
+
if (superseded || !peripheral) return;
|
|
113
|
+
if (this.subscribed) await quietly(() => withTimeout(() => find(this.characteristics, VEHICLE_NOTIFY_UUID).unsubscribeFromNotifications(), HOMEY_UNSUBSCRIBE_TIMEOUT_MS));
|
|
114
|
+
await quietly(() => peripheral.disconnect());
|
|
115
|
+
})();
|
|
116
|
+
return this.closing;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var HomeyBleTransport = class {
|
|
120
|
+
ble;
|
|
121
|
+
maxWriteSize;
|
|
122
|
+
claims = new LinkClaims();
|
|
123
|
+
/** @param ble `this.homey.ble`. The app needs the `homey:wireless:ble` permission. */
|
|
124
|
+
constructor(ble, options = {}) {
|
|
125
|
+
this.ble = ble;
|
|
126
|
+
this.maxWriteSize = options.maxWriteSize === void 0 ? 20 : options.maxWriteSize;
|
|
127
|
+
}
|
|
128
|
+
/** Takes Homey's fixed window, whatever `timeoutMs` says. Never pass `discover` a filter. */
|
|
129
|
+
async scan({ matches }) {
|
|
130
|
+
return (await this.ble.discover()).filter((advertisement) => !matches || advertisement.localName !== void 0 && matches(advertisement.localName)).map((advertisement) => ({
|
|
131
|
+
id: advertisement.uuid,
|
|
132
|
+
name: advertisement.localName,
|
|
133
|
+
rssi: advertisement.rssi,
|
|
134
|
+
connectable: advertisement.connectable
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
async connect(device, handlers) {
|
|
138
|
+
const connection = new HomeyConnection(device.id, handlers, this.maxWriteSize, this.claims);
|
|
139
|
+
this.claims.claim(device.id, connection);
|
|
140
|
+
try {
|
|
141
|
+
const peripheral = await (await this.ble.find(device.id)).connect();
|
|
142
|
+
await withTimeout(() => connection.attach(peripheral), HOMEY_SETUP_TIMEOUT_MS);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
await connection.disconnect();
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
return connection;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
export { HOMEY_MAX_WRITE_SIZE, HOMEY_SETUP_TIMEOUT_MS, HOMEY_UNSUBSCRIBE_TIMEOUT_MS, HOMEY_VEHICLE_OPTIONS, HomeyBleTransport };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let crypto = require("crypto");
|
|
3
|
+
crypto = require_runtime.__toESM(crypto, 1);
|
|
4
|
+
// src/bluetooth/names.ts
|
|
5
|
+
const VALID_NAME = /^S[a-f0-9]{16}[CDRP]$/;
|
|
6
|
+
/** Whether a BLE device name is a valid Tesla vehicle's. */
|
|
7
|
+
function valid_name(name) {
|
|
8
|
+
return VALID_NAME.test(name);
|
|
9
|
+
}
|
|
10
|
+
/** The BLE device name of a vehicle. */
|
|
11
|
+
function get_name(vin) {
|
|
12
|
+
return `S${crypto.default.createHash("sha1").update(vin, "utf8").digest("hex").slice(0, 16)}C`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether an advertised name belongs to this VIN. The hash matches, with any of
|
|
16
|
+
* the four suffixes `valid_name` allows, which is wider than Python's exact
|
|
17
|
+
* match on `C`.
|
|
18
|
+
*/
|
|
19
|
+
function name_matches_vin(advertised, vin) {
|
|
20
|
+
return valid_name(advertised) && advertised.slice(0, 17) === get_name(vin).slice(0, 17);
|
|
21
|
+
}
|
|
22
|
+
exports.get_name = get_name;
|
|
23
|
+
exports.name_matches_vin = name_matches_vin;
|
|
24
|
+
exports.valid_name = valid_name;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Whether a BLE device name is a valid Tesla vehicle's. */
|
|
2
|
+
export declare function valid_name(name: string): boolean;
|
|
3
|
+
/** The BLE device name of a vehicle. */
|
|
4
|
+
export declare function get_name(vin: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Whether an advertised name belongs to this VIN. The hash matches, with any of
|
|
7
|
+
* the four suffixes `valid_name` allows, which is wider than Python's exact
|
|
8
|
+
* match on `C`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function name_matches_vin(advertised: string, vin: string): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Whether a BLE device name is a valid Tesla vehicle's. */
|
|
2
|
+
export declare function valid_name(name: string): boolean;
|
|
3
|
+
/** The BLE device name of a vehicle. */
|
|
4
|
+
export declare function get_name(vin: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Whether an advertised name belongs to this VIN. The hash matches, with any of
|
|
7
|
+
* the four suffixes `valid_name` allows, which is wider than Python's exact
|
|
8
|
+
* match on `C`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function name_matches_vin(advertised: string, vin: string): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
// src/bluetooth/names.ts
|
|
3
|
+
const VALID_NAME = /^S[a-f0-9]{16}[CDRP]$/;
|
|
4
|
+
/** Whether a BLE device name is a valid Tesla vehicle's. */
|
|
5
|
+
function valid_name(name) {
|
|
6
|
+
return VALID_NAME.test(name);
|
|
7
|
+
}
|
|
8
|
+
/** The BLE device name of a vehicle. */
|
|
9
|
+
function get_name(vin) {
|
|
10
|
+
return `S${crypto.createHash("sha1").update(vin, "utf8").digest("hex").slice(0, 16)}C`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Whether an advertised name belongs to this VIN. The hash matches, with any of
|
|
14
|
+
* the four suffixes `valid_name` allows, which is wider than Python's exact
|
|
15
|
+
* match on `C`.
|
|
16
|
+
*/
|
|
17
|
+
function name_matches_vin(advertised, vin) {
|
|
18
|
+
return valid_name(advertised) && advertised.slice(0, 17) === get_name(vin).slice(0, 17);
|
|
19
|
+
}
|
|
20
|
+
export { get_name, name_matches_vin, valid_name };
|