zwave-js 8.6.0 → 8.7.2
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/build/Utils.d.ts +2 -2
- package/build/Utils.d.ts.map +1 -1
- package/build/Utils.js +3 -1
- package/build/Utils.js.map +1 -1
- package/build/lib/commandclass/AssociationCC.d.ts.map +1 -1
- package/build/lib/commandclass/AssociationCC.js +2 -4
- package/build/lib/commandclass/AssociationCC.js.map +1 -1
- package/build/lib/commandclass/ManufacturerProprietaryCC.d.ts.map +1 -1
- package/build/lib/commandclass/ManufacturerProprietaryCC.js +15 -8
- package/build/lib/commandclass/ManufacturerProprietaryCC.js.map +1 -1
- package/build/lib/commandclass/MultiChannelAssociationCC.d.ts.map +1 -1
- package/build/lib/commandclass/MultiChannelAssociationCC.js +2 -4
- package/build/lib/commandclass/MultiChannelAssociationCC.js.map +1 -1
- package/build/lib/controller/AddNodeToNetworkRequest.d.ts +36 -8
- package/build/lib/controller/AddNodeToNetworkRequest.d.ts.map +1 -1
- package/build/lib/controller/AddNodeToNetworkRequest.js +111 -41
- package/build/lib/controller/AddNodeToNetworkRequest.js.map +1 -1
- package/build/lib/controller/ApplicationUpdateRequest.d.ts +16 -4
- package/build/lib/controller/ApplicationUpdateRequest.d.ts.map +1 -1
- package/build/lib/controller/ApplicationUpdateRequest.js +56 -15
- package/build/lib/controller/ApplicationUpdateRequest.js.map +1 -1
- package/build/lib/controller/Controller.d.ts +65 -20
- package/build/lib/controller/Controller.d.ts.map +1 -1
- package/build/lib/controller/Controller.js +651 -265
- package/build/lib/controller/Controller.js.map +1 -1
- package/build/lib/controller/Inclusion.d.ts +31 -4
- package/build/lib/controller/Inclusion.d.ts.map +1 -1
- package/build/lib/controller/Inclusion.js +15 -3
- package/build/lib/controller/Inclusion.js.map +1 -1
- package/build/lib/controller/RemoveNodeFromNetworkRequest.d.ts +15 -9
- package/build/lib/controller/RemoveNodeFromNetworkRequest.d.ts.map +1 -1
- package/build/lib/controller/RemoveNodeFromNetworkRequest.js +70 -41
- package/build/lib/controller/RemoveNodeFromNetworkRequest.js.map +1 -1
- package/build/lib/driver/Driver.d.ts +5 -1
- package/build/lib/driver/Driver.d.ts.map +1 -1
- package/build/lib/driver/Driver.js +246 -59
- package/build/lib/driver/Driver.js.map +1 -1
- package/build/lib/node/Node.d.ts +6 -0
- package/build/lib/node/Node.d.ts.map +1 -1
- package/build/lib/node/Node.js +22 -9
- package/build/lib/node/Node.js.map +1 -1
- package/package.json +10 -10
|
@@ -56,6 +56,7 @@ const ApplicationUpdateRequest_1 = require("../controller/ApplicationUpdateReque
|
|
|
56
56
|
const BridgeApplicationCommandRequest_1 = require("../controller/BridgeApplicationCommandRequest");
|
|
57
57
|
const Controller_1 = require("../controller/Controller");
|
|
58
58
|
const GetControllerVersionMessages_1 = require("../controller/GetControllerVersionMessages");
|
|
59
|
+
const Inclusion_1 = require("../controller/Inclusion");
|
|
59
60
|
const SendDataBridgeMessages_1 = require("../controller/SendDataBridgeMessages");
|
|
60
61
|
const SendDataMessages_1 = require("../controller/SendDataMessages");
|
|
61
62
|
const SendDataShared_1 = require("../controller/SendDataShared");
|
|
@@ -232,6 +233,7 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
232
233
|
this._controllerLog = new Controller_2.ControllerLogger(this._logContainer);
|
|
233
234
|
// Initialize the cache
|
|
234
235
|
this.cacheDir = this.options.storage.cacheDir;
|
|
236
|
+
// TODO: Load provisioning list
|
|
235
237
|
// Initialize config manager
|
|
236
238
|
this.configManager = new config_1.ConfigManager({
|
|
237
239
|
logContainer: this._logContainer,
|
|
@@ -452,7 +454,9 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
452
454
|
spOpenPromise.resolve();
|
|
453
455
|
// Perform initialization sequence
|
|
454
456
|
await this.writeHeader(serial_1.MessageHeaders.NAK);
|
|
455
|
-
|
|
457
|
+
// Per the specs, this should be followed by a soft-reset but we need to be able
|
|
458
|
+
// to handle sticks that don't support the soft reset command. Therefore we do it
|
|
459
|
+
// after opening the value DBs
|
|
456
460
|
// Try to create the cache directory. This can fail, in which case we should expose a good error message
|
|
457
461
|
try {
|
|
458
462
|
await this.options.storage.driver.ensureDir(this.cacheDir);
|
|
@@ -534,6 +538,32 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
534
538
|
get allNodesReady() {
|
|
535
539
|
return this._nodesReadyEventEmitted;
|
|
536
540
|
}
|
|
541
|
+
async initValueDBs(homeId) {
|
|
542
|
+
// Always start the value and metadata databases
|
|
543
|
+
const options = {
|
|
544
|
+
ignoreReadErrors: true,
|
|
545
|
+
...ThrottlePresets_1.throttlePresets[this.options.storage.throttle],
|
|
546
|
+
};
|
|
547
|
+
if (this.options.storage.lockDir) {
|
|
548
|
+
options.lockfileDirectory = this.options.storage.lockDir;
|
|
549
|
+
}
|
|
550
|
+
const valueDBFile = path_1.default.join(this.cacheDir, `${homeId.toString(16)}.values.jsonl`);
|
|
551
|
+
this._valueDB = new jsonl_db_1.JsonlDB(valueDBFile, {
|
|
552
|
+
...options,
|
|
553
|
+
reviver: (key, value) => (0, core_1.deserializeCacheValue)(value),
|
|
554
|
+
serializer: (key, value) => (0, core_1.serializeCacheValue)(value),
|
|
555
|
+
});
|
|
556
|
+
await this._valueDB.open();
|
|
557
|
+
const metadataDBFile = path_1.default.join(this.cacheDir, `${homeId.toString(16)}.metadata.jsonl`);
|
|
558
|
+
this._metadataDB = new jsonl_db_1.JsonlDB(metadataDBFile, options);
|
|
559
|
+
await this._metadataDB.open();
|
|
560
|
+
if (process.env.NO_CACHE === "true") {
|
|
561
|
+
// Since value/metadata DBs are append-only, we need to clear them
|
|
562
|
+
// if the cache should be ignored
|
|
563
|
+
this._valueDB.clear();
|
|
564
|
+
this._metadataDB.clear();
|
|
565
|
+
}
|
|
566
|
+
}
|
|
537
567
|
/**
|
|
538
568
|
* Initializes the variables for controller and nodes,
|
|
539
569
|
* adds event handlers and starts the interview process.
|
|
@@ -546,42 +576,56 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
546
576
|
.on("node added", this.onNodeAdded.bind(this))
|
|
547
577
|
.on("node removed", this.onNodeRemoved.bind(this));
|
|
548
578
|
}
|
|
549
|
-
const initValueDBs = async () => {
|
|
550
|
-
// Always start the value and metadata databases
|
|
551
|
-
const options = {
|
|
552
|
-
ignoreReadErrors: true,
|
|
553
|
-
...ThrottlePresets_1.throttlePresets[this.options.storage.throttle],
|
|
554
|
-
};
|
|
555
|
-
if (this.options.storage.lockDir) {
|
|
556
|
-
options.lockfileDirectory = this.options.storage.lockDir;
|
|
557
|
-
}
|
|
558
|
-
const valueDBFile = path_1.default.join(this.cacheDir, `${this._controller.homeId.toString(16)}.values.jsonl`);
|
|
559
|
-
this._valueDB = new jsonl_db_1.JsonlDB(valueDBFile, {
|
|
560
|
-
...options,
|
|
561
|
-
reviver: (key, value) => (0, core_1.deserializeCacheValue)(value),
|
|
562
|
-
serializer: (key, value) => (0, core_1.serializeCacheValue)(value),
|
|
563
|
-
});
|
|
564
|
-
await this._valueDB.open();
|
|
565
|
-
const metadataDBFile = path_1.default.join(this.cacheDir, `${this._controller.homeId.toString(16)}.metadata.jsonl`);
|
|
566
|
-
this._metadataDB = new jsonl_db_1.JsonlDB(metadataDBFile, options);
|
|
567
|
-
await this._metadataDB.open();
|
|
568
|
-
if (process.env.NO_CACHE === "true") {
|
|
569
|
-
// Since value/metadata DBs are append-only, we need to clear them
|
|
570
|
-
// if the cache should be ignored
|
|
571
|
-
this._valueDB.clear();
|
|
572
|
-
this._metadataDB.clear();
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
579
|
if (!this.options.interview.skipInterview) {
|
|
580
|
+
// Determine controller IDs to open the Value DBs
|
|
581
|
+
// We need to do this first because some older controllers, especially the UZB1 and
|
|
582
|
+
// some 500-series sticks in virtualized environments don't respond after a soft reset
|
|
583
|
+
// No need to initialize databases if skipInterview is true, because it is only used in some
|
|
584
|
+
// Driver unit tests that don't need access to them
|
|
585
|
+
// Identify the controller and determine if it supports soft reset
|
|
586
|
+
await this.controller.identify();
|
|
587
|
+
if (this.options.enableSoftReset && !(await this.maySoftReset())) {
|
|
588
|
+
this.driverLog.print(`Soft reset is enabled through config, but this stick does not support it.`, "warn");
|
|
589
|
+
this.options.enableSoftReset = false;
|
|
590
|
+
}
|
|
591
|
+
if (this.options.enableSoftReset) {
|
|
592
|
+
try {
|
|
593
|
+
await this.softResetInternal(false);
|
|
594
|
+
}
|
|
595
|
+
catch (e) {
|
|
596
|
+
if ((0, core_1.isZWaveError)(e) &&
|
|
597
|
+
e.code === core_1.ZWaveErrorCodes.Driver_Failed) {
|
|
598
|
+
// Remember that soft reset is not supported by this stick
|
|
599
|
+
await this.rememberNoSoftReset();
|
|
600
|
+
// Then fail the driver
|
|
601
|
+
await this.destroy();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// There are situations where a controller claims it has the ID 0,
|
|
607
|
+
// which isn't valid. In this case try again after having soft-reset the stick
|
|
608
|
+
if (this.controller.ownNodeId === 0 &&
|
|
609
|
+
this.options.enableSoftReset) {
|
|
610
|
+
this.driverLog.print(`Controller identification returned invalid node ID 0 - trying again...`, "warn");
|
|
611
|
+
await this.controller.identify();
|
|
612
|
+
}
|
|
613
|
+
if (this.controller.ownNodeId === 0) {
|
|
614
|
+
this.driverLog.print(`Controller identification returned invalid node ID 0`, "error");
|
|
615
|
+
await this.destroy();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
// now that we know the home ID, we can open the databases
|
|
619
|
+
await this.initValueDBs(this.controller.homeId);
|
|
576
620
|
// Interview the controller.
|
|
577
|
-
await this._controller.interview(
|
|
621
|
+
await this._controller.interview(async () => {
|
|
578
622
|
// Try to restore the network information from the cache
|
|
579
623
|
if (process.env.NO_CACHE !== "true") {
|
|
580
624
|
await this.restoreNetworkStructureFromCache();
|
|
581
625
|
}
|
|
582
626
|
});
|
|
583
|
-
//
|
|
584
|
-
|
|
627
|
+
// Auto-enable smart start inclusion
|
|
628
|
+
this._controller.autoProvisionSmartStart();
|
|
585
629
|
}
|
|
586
630
|
// Set up the S0 security manager. We can only do that after the controller
|
|
587
631
|
// interview because we need to know the controller node id.
|
|
@@ -1058,6 +1102,76 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1058
1102
|
throw new core_1.ZWaveError("Cannot retrieve the version of a CC that is not implemented", core_1.ZWaveErrorCodes.CC_NotSupported);
|
|
1059
1103
|
}
|
|
1060
1104
|
}
|
|
1105
|
+
async maySoftReset() {
|
|
1106
|
+
var _a;
|
|
1107
|
+
// If we've previously determined a stick not to support soft reset, don't bother trying again
|
|
1108
|
+
let supportsSoftReset;
|
|
1109
|
+
if (this._controllerInterviewed) {
|
|
1110
|
+
supportsSoftReset = this.controller.supportsSoftReset;
|
|
1111
|
+
}
|
|
1112
|
+
else {
|
|
1113
|
+
// The controller wasn't interviewed yet, read the json file manually
|
|
1114
|
+
const fs = this.options.storage.driver;
|
|
1115
|
+
const cacheFile = path_1.default.join(this.cacheDir, this.controller.homeId.toString(16) + ".json");
|
|
1116
|
+
// Read it if it exists
|
|
1117
|
+
let json;
|
|
1118
|
+
if (await fs.pathExists(cacheFile)) {
|
|
1119
|
+
try {
|
|
1120
|
+
json = JSON.parse(await fs.readFile(cacheFile, "utf8"));
|
|
1121
|
+
}
|
|
1122
|
+
catch { }
|
|
1123
|
+
}
|
|
1124
|
+
supportsSoftReset = (_a = json === null || json === void 0 ? void 0 : json.controller) === null || _a === void 0 ? void 0 : _a.supportsSoftReset;
|
|
1125
|
+
}
|
|
1126
|
+
if (supportsSoftReset === false)
|
|
1127
|
+
return false;
|
|
1128
|
+
// Blacklist some sticks that are known to not support soft reset
|
|
1129
|
+
const { manufacturerId, productType, productId } = this.controller;
|
|
1130
|
+
// Z-Wave.me UZB1
|
|
1131
|
+
if (manufacturerId === 0x0115 &&
|
|
1132
|
+
productType === 0x0000 &&
|
|
1133
|
+
productId === 0x0000) {
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
// Z-Wave.me UZB
|
|
1137
|
+
if (manufacturerId === 0x0115 &&
|
|
1138
|
+
productType === 0x0400 &&
|
|
1139
|
+
productId === 0x0001) {
|
|
1140
|
+
return false;
|
|
1141
|
+
}
|
|
1142
|
+
return true;
|
|
1143
|
+
}
|
|
1144
|
+
async rememberNoSoftReset() {
|
|
1145
|
+
var _a;
|
|
1146
|
+
this.driverLog.print("Soft reset seems not to be supported by this stick, disabling it.", "warn");
|
|
1147
|
+
this.controller.supportsSoftReset = false;
|
|
1148
|
+
if (this._controllerInterviewed) {
|
|
1149
|
+
// We can use the normal method for this
|
|
1150
|
+
await this.saveNetworkToCacheInternal();
|
|
1151
|
+
}
|
|
1152
|
+
else {
|
|
1153
|
+
// saveNetworkToCache won't write anything, just edit the file "manually"
|
|
1154
|
+
// TODO: This is ugly, rework this when changing how the network data is saved
|
|
1155
|
+
const fs = this.options.storage.driver;
|
|
1156
|
+
await fs.ensureDir(this.cacheDir);
|
|
1157
|
+
const cacheFile = path_1.default.join(this.cacheDir, this.controller.homeId.toString(16) + ".json");
|
|
1158
|
+
// Read it if it exists
|
|
1159
|
+
let json;
|
|
1160
|
+
if (await fs.pathExists(cacheFile)) {
|
|
1161
|
+
try {
|
|
1162
|
+
json = JSON.parse(await fs.readFile(cacheFile, "utf8"));
|
|
1163
|
+
}
|
|
1164
|
+
catch { }
|
|
1165
|
+
}
|
|
1166
|
+
// Change the supportsSoftReset flag
|
|
1167
|
+
json !== null && json !== void 0 ? json : (json = {});
|
|
1168
|
+
(_a = json.controller) !== null && _a !== void 0 ? _a : (json.controller = {});
|
|
1169
|
+
json.controller.supportsSoftReset = false;
|
|
1170
|
+
// And save it again
|
|
1171
|
+
const jsonString = (0, shared_1.stringify)(json);
|
|
1172
|
+
await this.options.storage.driver.writeFile(cacheFile, jsonString, "utf8");
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1061
1175
|
/**
|
|
1062
1176
|
* Soft-resets the controller if the feature is enabled
|
|
1063
1177
|
*/
|
|
@@ -1083,6 +1197,9 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1083
1197
|
this.controllerLog.print(message, "error");
|
|
1084
1198
|
throw new core_1.ZWaveError(message, core_1.ZWaveErrorCodes.Driver_FeatureDisabled);
|
|
1085
1199
|
}
|
|
1200
|
+
return this.softResetInternal(true);
|
|
1201
|
+
}
|
|
1202
|
+
async softResetInternal(destroyOnError) {
|
|
1086
1203
|
this.controllerLog.print("Performing soft reset...");
|
|
1087
1204
|
try {
|
|
1088
1205
|
this.isSoftResetting = true;
|
|
@@ -1095,7 +1212,14 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1095
1212
|
this.controllerLog.print(`Soft reset failed: ${(0, shared_1.getErrorMessage)(e)}`, "error");
|
|
1096
1213
|
}
|
|
1097
1214
|
// Make sure we're able to communicate with the controller again
|
|
1098
|
-
await this.ensureSerialAPI()
|
|
1215
|
+
if (!(await this.ensureSerialAPI())) {
|
|
1216
|
+
if (destroyOnError) {
|
|
1217
|
+
await this.destroy();
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
throw new core_1.ZWaveError("The Serial API did not respond after soft-reset", core_1.ZWaveErrorCodes.Driver_Failed);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1099
1223
|
this.isSoftResetting = false;
|
|
1100
1224
|
// And resume sending
|
|
1101
1225
|
this.unpauseSendThread();
|
|
@@ -1109,7 +1233,7 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1109
1233
|
if (waitResult) {
|
|
1110
1234
|
// Serial API did start, maybe do something with the information?
|
|
1111
1235
|
this.controllerLog.print("reconnected and restarted");
|
|
1112
|
-
return;
|
|
1236
|
+
return true;
|
|
1113
1237
|
}
|
|
1114
1238
|
// If the controller disconnected the serial port during the soft reset, we need to re-open it
|
|
1115
1239
|
if (!this.serial.isOpen) {
|
|
@@ -1122,7 +1246,7 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1122
1246
|
if (waitResult) {
|
|
1123
1247
|
// Serial API did start, maybe do something with the information?
|
|
1124
1248
|
this.controllerLog.print("Serial API started");
|
|
1125
|
-
return;
|
|
1249
|
+
return true;
|
|
1126
1250
|
}
|
|
1127
1251
|
this.controllerLog.print("Did not receive notification that Serial API has started, checking if it responds...");
|
|
1128
1252
|
// We don't need to use any specific command here. However we're going to use this one in the interview
|
|
@@ -1144,21 +1268,15 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1144
1268
|
};
|
|
1145
1269
|
// Poll the controller with increasing backoff delay
|
|
1146
1270
|
if (await pollController())
|
|
1147
|
-
return;
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
if (await pollController())
|
|
1155
|
-
return;
|
|
1156
|
-
this.controllerLog.print("Serial API did not respond, trying again in 10 seconds...");
|
|
1157
|
-
await (0, async_1.wait)(10000, true);
|
|
1158
|
-
if (await pollController())
|
|
1159
|
-
return;
|
|
1271
|
+
return true;
|
|
1272
|
+
for (const backoff of [2, 5, 10, 15]) {
|
|
1273
|
+
this.controllerLog.print(`Serial API did not respond, trying again in ${backoff} seconds...`);
|
|
1274
|
+
await (0, async_1.wait)(backoff * 1000, true);
|
|
1275
|
+
if (await pollController())
|
|
1276
|
+
return true;
|
|
1277
|
+
}
|
|
1160
1278
|
this.controllerLog.print("Serial API did not respond, giving up", "error");
|
|
1161
|
-
|
|
1279
|
+
return false;
|
|
1162
1280
|
}
|
|
1163
1281
|
/**
|
|
1164
1282
|
* Performs a hard reset on the controller. This wipes out all configuration!
|
|
@@ -1206,12 +1324,27 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1206
1324
|
* Must be called under any circumstances.
|
|
1207
1325
|
*/
|
|
1208
1326
|
async destroy() {
|
|
1209
|
-
var _a, _b, _c;
|
|
1327
|
+
var _a, _b, _c, _d;
|
|
1210
1328
|
// Ensure this is only called once and all subsequent calls block
|
|
1211
1329
|
if (this._destroyPromise)
|
|
1212
1330
|
return this._destroyPromise;
|
|
1213
1331
|
this._destroyPromise = (0, deferred_promise_1.createDeferredPromise)();
|
|
1214
1332
|
this.driverLog.print("destroying driver instance...");
|
|
1333
|
+
// Disable inclusion before shutting down
|
|
1334
|
+
try {
|
|
1335
|
+
switch ((_a = this._controller) === null || _a === void 0 ? void 0 : _a.inclusionState) {
|
|
1336
|
+
case Inclusion_1.InclusionState.SmartStart:
|
|
1337
|
+
case Inclusion_1.InclusionState.Including:
|
|
1338
|
+
await this._controller.stopInclusionNoCallback();
|
|
1339
|
+
break;
|
|
1340
|
+
case Inclusion_1.InclusionState.Excluding:
|
|
1341
|
+
await this._controller.stopExclusionNoCallback();
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
catch {
|
|
1346
|
+
// ignore
|
|
1347
|
+
}
|
|
1215
1348
|
// First stop the send thread machine and close the serial port, so nothing happens anymore
|
|
1216
1349
|
if (this.sendThread.initialized)
|
|
1217
1350
|
this.sendThread.stop();
|
|
@@ -1231,8 +1364,8 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1231
1364
|
}
|
|
1232
1365
|
try {
|
|
1233
1366
|
// Attempt to close the value DBs
|
|
1234
|
-
await ((
|
|
1235
|
-
await ((
|
|
1367
|
+
await ((_b = this._valueDB) === null || _b === void 0 ? void 0 : _b.close());
|
|
1368
|
+
await ((_c = this._metadataDB) === null || _c === void 0 ? void 0 : _c.close());
|
|
1236
1369
|
}
|
|
1237
1370
|
catch (e) {
|
|
1238
1371
|
this.driverLog.print(`Closing the value DBs failed: ${(0, shared_1.getErrorMessage)(e)}`, "error");
|
|
@@ -1248,7 +1381,7 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1248
1381
|
clearTimeout(timeout);
|
|
1249
1382
|
}
|
|
1250
1383
|
// Destroy all nodes
|
|
1251
|
-
(
|
|
1384
|
+
(_d = this._controller) === null || _d === void 0 ? void 0 : _d.nodes.forEach((n) => n.destroy());
|
|
1252
1385
|
process.removeListener("exit", this._cleanupHandler);
|
|
1253
1386
|
process.removeListener("SIGINT", this._cleanupHandler);
|
|
1254
1387
|
process.removeListener("uncaughtException", this._cleanupHandler);
|
|
@@ -1461,7 +1594,7 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1461
1594
|
throw e;
|
|
1462
1595
|
}
|
|
1463
1596
|
async handleSecurityS2DecodeError(e, msg) {
|
|
1464
|
-
var _a;
|
|
1597
|
+
var _a, _b;
|
|
1465
1598
|
if (!(0, core_1.isZWaveError)(e))
|
|
1466
1599
|
return false;
|
|
1467
1600
|
if ((e.code === core_1.ZWaveErrorCodes.Security2CC_NoSPAN ||
|
|
@@ -1493,13 +1626,42 @@ class Driver extends shared_1.TypedEventEmitter {
|
|
|
1493
1626
|
? "Message authentication failed"
|
|
1494
1627
|
: "No SPAN is established yet";
|
|
1495
1628
|
if (this.controller.bootstrappingS2NodeId === nodeId) {
|
|
1496
|
-
// The node is currently being bootstrapped.
|
|
1497
|
-
this.
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1629
|
+
// The node is currently being bootstrapped.
|
|
1630
|
+
if ((_b = this.securityManager2) === null || _b === void 0 ? void 0 : _b.tempKeys.has(nodeId)) {
|
|
1631
|
+
// The DSK has been verified, so we should be able to decode this command.
|
|
1632
|
+
// If this is the first attempt, we need to request a nonce first
|
|
1633
|
+
if (this.securityManager2.getSPANState(nodeId).type ===
|
|
1634
|
+
core_1.SPANState.None) {
|
|
1635
|
+
this.controllerLog.logNode(nodeId, {
|
|
1636
|
+
message: `${message}, cannot decode command. Requesting a nonce...`,
|
|
1637
|
+
level: "verbose",
|
|
1638
|
+
direction: "outbound",
|
|
1639
|
+
});
|
|
1640
|
+
// Send the node our nonce
|
|
1641
|
+
node.commandClasses["Security 2"]
|
|
1642
|
+
.sendNonce()
|
|
1643
|
+
.catch(() => {
|
|
1644
|
+
// Ignore errors
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
else {
|
|
1648
|
+
// Us repeatedly not being able to decode the command means we need to abort the bootstrapping process
|
|
1649
|
+
// because the PIN is wrong
|
|
1650
|
+
this.controllerLog.logNode(nodeId, {
|
|
1651
|
+
message: `${message}, cannot decode command. Aborting the S2 bootstrapping process...`,
|
|
1652
|
+
level: "error",
|
|
1653
|
+
direction: "inbound",
|
|
1654
|
+
});
|
|
1655
|
+
this.controller.cancelSecureBootstrapS2(shared_2.KEXFailType.BootstrappingCanceled);
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
this.controllerLog.logNode(nodeId, {
|
|
1660
|
+
message: `Ignoring KEXSet because the DSK has not been verified yet`,
|
|
1661
|
+
level: "verbose",
|
|
1662
|
+
direction: "inbound",
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1503
1665
|
}
|
|
1504
1666
|
else if (!this.hasPendingTransactions(isS2NonceReport)) {
|
|
1505
1667
|
this.controllerLog.logNode(nodeId, {
|
|
@@ -1999,6 +2161,31 @@ ${handlers.length} left`);
|
|
|
1999
2161
|
return;
|
|
2000
2162
|
}
|
|
2001
2163
|
}
|
|
2164
|
+
else if (msg instanceof ApplicationUpdateRequest_1.ApplicationUpdateRequestSmartStartHomeIDReceived) {
|
|
2165
|
+
// the controller is in Smart Start learn mode and a node requests inclusion via Smart Start
|
|
2166
|
+
this.controllerLog.print("Received Smart Start inclusion request");
|
|
2167
|
+
if (this.controller.inclusionState !== Inclusion_1.InclusionState.Idle &&
|
|
2168
|
+
this.controller.inclusionState !== Inclusion_1.InclusionState.SmartStart) {
|
|
2169
|
+
this.controllerLog.print("Controller is busy and cannot handle this inclusion request right now...");
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
// Check if the node is on the provisioning list
|
|
2173
|
+
const provisioningEntry = this.controller.provisioningList.find((entry) => (0, core_1.nwiHomeIdFromDSK)((0, core_1.dskFromString)(entry.dsk)).equals(msg.nwiHomeId));
|
|
2174
|
+
if (!provisioningEntry) {
|
|
2175
|
+
this.controllerLog.print("NWI Home ID not found in provisioning list, ignoring request...");
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
this.controllerLog.print("NWI Home ID found in provisioning list, including node...");
|
|
2179
|
+
try {
|
|
2180
|
+
const result = await this.controller.beginInclusionSmartStart(provisioningEntry);
|
|
2181
|
+
if (!result) {
|
|
2182
|
+
this.controllerLog.print("Smart Start inclusion could not be started", "error");
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
catch (e) {
|
|
2186
|
+
this.controllerLog.print(`Smart Start inclusion could not be started: ${(0, shared_1.getErrorMessage)(e)}`, "error");
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2002
2189
|
}
|
|
2003
2190
|
else {
|
|
2004
2191
|
// Check if we have a dynamic handler waiting for this message
|