zwave-js 15.24.2 → 15.25.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/build/cjs/lib/_version.d.ts +1 -1
- package/build/cjs/lib/_version.js +1 -1
- package/build/cjs/lib/_version.js.map +1 -1
- package/build/cjs/lib/driver/Driver.d.ts +9 -1
- package/build/cjs/lib/driver/Driver.js +223 -132
- package/build/cjs/lib/driver/Driver.js.map +3 -3
- package/build/cjs/lib/driver/DriverMock.d.ts +10 -1
- package/build/cjs/lib/driver/DriverMock.js +54 -5
- package/build/cjs/lib/driver/DriverMock.js.map +3 -3
- package/build/cjs/lib/driver/PartialCCSessionManager.d.ts +69 -0
- package/build/cjs/lib/driver/PartialCCSessionManager.js +161 -0
- package/build/cjs/lib/driver/PartialCCSessionManager.js.map +7 -0
- package/build/cjs/lib/driver/ZWaveOptions.d.ts +5 -0
- package/build/cjs/lib/driver/ZWaveOptions.js.map +2 -2
- package/build/cjs/lib/node/MockNodeBehaviors.js +2 -1
- package/build/cjs/lib/node/MockNodeBehaviors.js.map +2 -2
- package/build/cjs/lib/node/Node.d.ts +0 -1
- package/build/cjs/lib/node/Node.js +51 -12
- package/build/cjs/lib/node/Node.js.map +2 -2
- package/build/cjs/lib/node/VirtualNode.js +4 -4
- package/build/cjs/lib/node/VirtualNode.js.map +2 -2
- package/build/cjs/lib/node/_Types.d.ts +5 -3
- package/build/cjs/lib/node/_Types.js +1 -0
- package/build/cjs/lib/node/_Types.js.map +2 -2
- package/build/cjs/lib/node/feature-apis/AccessControl.js +44 -18
- package/build/cjs/lib/node/feature-apis/AccessControl.js.map +2 -2
- package/build/cjs/lib/node/mixins/90_InterviewProgress.d.ts +94 -0
- package/build/cjs/lib/node/mixins/90_InterviewProgress.js +280 -0
- package/build/cjs/lib/node/mixins/90_InterviewProgress.js.map +7 -0
- package/build/cjs/lib/node/mixins/index.d.ts +2 -2
- package/build/cjs/lib/node/mixins/index.js +2 -2
- package/build/cjs/lib/node/mixins/index.js.map +2 -2
- package/build/cjs/lib/test/integrationTestSuite.d.ts +8 -1
- package/build/cjs/lib/test/integrationTestSuite.js +7 -3
- package/build/cjs/lib/test/integrationTestSuite.js.map +2 -2
- package/build/cjs/lib/test/integrationTestSuiteShared.d.ts +1 -1
- package/build/cjs/lib/test/integrationTestSuiteShared.js +2 -1
- package/build/cjs/lib/test/integrationTestSuiteShared.js.map +2 -2
- package/build/esm/lib/_version.d.ts +1 -1
- package/build/esm/lib/_version.js +1 -1
- package/build/esm/lib/driver/Driver.d.ts +9 -1
- package/build/esm/lib/driver/Driver.d.ts.map +1 -1
- package/build/esm/lib/driver/Driver.js +274 -151
- package/build/esm/lib/driver/Driver.js.map +1 -1
- package/build/esm/lib/driver/DriverMock.d.ts +10 -1
- package/build/esm/lib/driver/DriverMock.d.ts.map +1 -1
- package/build/esm/lib/driver/DriverMock.js +64 -15
- package/build/esm/lib/driver/DriverMock.js.map +1 -1
- package/build/esm/lib/driver/PartialCCSessionManager.d.ts +69 -0
- package/build/esm/lib/driver/PartialCCSessionManager.d.ts.map +1 -0
- package/build/esm/lib/driver/PartialCCSessionManager.js +169 -0
- package/build/esm/lib/driver/PartialCCSessionManager.js.map +1 -0
- package/build/esm/lib/driver/ZWaveOptions.d.ts +5 -0
- package/build/esm/lib/driver/ZWaveOptions.d.ts.map +1 -1
- package/build/esm/lib/driver/ZWaveOptions.js.map +1 -1
- package/build/esm/lib/node/MockNodeBehaviors.d.ts.map +1 -1
- package/build/esm/lib/node/MockNodeBehaviors.js +6 -0
- package/build/esm/lib/node/MockNodeBehaviors.js.map +1 -1
- package/build/esm/lib/node/Node.d.ts +0 -1
- package/build/esm/lib/node/Node.d.ts.map +1 -1
- package/build/esm/lib/node/Node.js +113 -21
- package/build/esm/lib/node/Node.js.map +1 -1
- package/build/esm/lib/node/VirtualNode.js +6 -6
- package/build/esm/lib/node/VirtualNode.js.map +1 -1
- package/build/esm/lib/node/_Types.d.ts +5 -3
- package/build/esm/lib/node/_Types.d.ts.map +1 -1
- package/build/esm/lib/node/_Types.js +2 -1
- package/build/esm/lib/node/_Types.js.map +1 -1
- package/build/esm/lib/node/feature-apis/AccessControl.d.ts.map +1 -1
- package/build/esm/lib/node/feature-apis/AccessControl.js +62 -19
- package/build/esm/lib/node/feature-apis/AccessControl.js.map +1 -1
- package/build/esm/lib/node/mixins/90_InterviewProgress.d.ts +94 -0
- package/build/esm/lib/node/mixins/90_InterviewProgress.d.ts.map +1 -0
- package/build/esm/lib/node/mixins/90_InterviewProgress.js +283 -0
- package/build/esm/lib/node/mixins/90_InterviewProgress.js.map +1 -0
- package/build/esm/lib/node/mixins/index.d.ts +2 -2
- package/build/esm/lib/node/mixins/index.d.ts.map +1 -1
- package/build/esm/lib/node/mixins/index.js +2 -2
- package/build/esm/lib/node/mixins/index.js.map +1 -1
- package/build/esm/lib/test/integrationTestSuite.d.ts +8 -1
- package/build/esm/lib/test/integrationTestSuite.d.ts.map +1 -1
- package/build/esm/lib/test/integrationTestSuite.js +8 -3
- package/build/esm/lib/test/integrationTestSuite.js.map +1 -1
- package/build/esm/lib/test/integrationTestSuiteShared.d.ts +1 -1
- package/build/esm/lib/test/integrationTestSuiteShared.d.ts.map +1 -1
- package/build/esm/lib/test/integrationTestSuiteShared.js +2 -1
- package/build/esm/lib/test/integrationTestSuiteShared.js.map +1 -1
- package/package.json +9 -9
|
@@ -22,7 +22,7 @@ __export(version_exports, {
|
|
|
22
22
|
PACKAGE_VERSION: () => PACKAGE_VERSION
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(version_exports);
|
|
25
|
-
const PACKAGE_VERSION = "15.
|
|
25
|
+
const PACKAGE_VERSION = "15.25.0";
|
|
26
26
|
const PACKAGE_NAME = "zwave-js";
|
|
27
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
28
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/_version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is auto-generated by the codegen maintenance script\nexport const PACKAGE_VERSION = \"15.
|
|
4
|
+
"sourcesContent": ["// This file is auto-generated by the codegen maintenance script\nexport const PACKAGE_VERSION = \"15.25.0\";\nexport const PACKAGE_NAME = \"zwave-js\";\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;;;;;;AACO,MAAM,kBAAkB;AACxB,MAAM,eAAe;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -416,8 +416,16 @@ export declare class Driver extends TypedEventTarget<DriverEventCallbacks> imple
|
|
|
416
416
|
private isMissingNodeACK;
|
|
417
417
|
private shouldRequestWakeupOnDemand;
|
|
418
418
|
private partialCCSessions;
|
|
419
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Determines the request a new partial CC session is the response to, if any.
|
|
421
|
+
* This is used to re-request the response when segments are missing.
|
|
422
|
+
*/
|
|
423
|
+
private findPartialCCSessionRequest;
|
|
424
|
+
/** Re-requests the response a partial CC session belongs to because segments are missing */
|
|
425
|
+
private rerequestPartialCCSession;
|
|
420
426
|
private assemblePartialCCs;
|
|
427
|
+
/** Refreshes the timeouts of awaited messages which a partial message may belong to */
|
|
428
|
+
private refreshAwaitedMessageTimers;
|
|
421
429
|
private handleTransportServiceCommand;
|
|
422
430
|
private handleUnsolicitedMessage;
|
|
423
431
|
private handleSerialAPIStartedUnexpectedly;
|
|
@@ -62,6 +62,7 @@ var import_DriverMode = require("./DriverMode.js");
|
|
|
62
62
|
var import_EndDeviceCLI = require("./EndDeviceCLI.js");
|
|
63
63
|
var import_MessageGenerators = require("./MessageGenerators.js");
|
|
64
64
|
var import_NetworkCache = require("./NetworkCache.js");
|
|
65
|
+
var import_PartialCCSessionManager = require("./PartialCCSessionManager.js");
|
|
65
66
|
var import_Queue = require("./Queue.js");
|
|
66
67
|
var import_SerialAPICommandMachine = require("./SerialAPICommandMachine.js");
|
|
67
68
|
var import_StateMachineShared = require("./StateMachineShared.js");
|
|
@@ -117,7 +118,8 @@ const defaultOptions = {
|
|
|
117
118
|
sendDataJammed: 5,
|
|
118
119
|
nodeInterview: 5,
|
|
119
120
|
smartStartInclusion: 5,
|
|
120
|
-
firmwareUpdateOTW: 3
|
|
121
|
+
firmwareUpdateOTW: 3,
|
|
122
|
+
partialReports: 2
|
|
121
123
|
},
|
|
122
124
|
disableOptimisticValueUpdate: false,
|
|
123
125
|
features: {
|
|
@@ -210,6 +212,9 @@ function checkOptions(options) {
|
|
|
210
212
|
if (options.attempts.firmwareUpdateOTW < 1 || options.attempts.firmwareUpdateOTW > 5) {
|
|
211
213
|
throw new import_core.ZWaveError(`The OTW firmware update attempts must be between 1 and 5!`, import_core.ZWaveErrorCodes.Driver_InvalidOptions);
|
|
212
214
|
}
|
|
215
|
+
if (options.attempts.partialReports < 0 || options.attempts.partialReports > 3) {
|
|
216
|
+
throw new import_core.ZWaveError(`The partial reports attempts must be between 0 and 3!`, import_core.ZWaveErrorCodes.Driver_InvalidOptions);
|
|
217
|
+
}
|
|
213
218
|
if (options.inclusionUserCallbacks) {
|
|
214
219
|
if (!(0, import_typeguards.isObject)(options.inclusionUserCallbacks)) {
|
|
215
220
|
throw new import_core.ZWaveError(`The inclusionUserCallbacks must be an object!`, import_core.ZWaveErrorCodes.Driver_InvalidOptions);
|
|
@@ -1943,7 +1948,7 @@ class Driver extends import_shared.TypedEventTarget {
|
|
|
1943
1948
|
}
|
|
1944
1949
|
if (!await this.ensureSerialAPI()) {
|
|
1945
1950
|
if (destroyOnError) {
|
|
1946
|
-
await this.
|
|
1951
|
+
await this.destroyWithMessage("The Serial API did not respond after soft-reset");
|
|
1947
1952
|
} else {
|
|
1948
1953
|
throw new import_core.ZWaveError("The Serial API did not respond after soft-reset", import_core.ZWaveErrorCodes.Driver_Failed);
|
|
1949
1954
|
}
|
|
@@ -2218,6 +2223,7 @@ class Driver extends import_shared.TypedEventTarget {
|
|
|
2218
2223
|
]) {
|
|
2219
2224
|
timeout?.clear();
|
|
2220
2225
|
}
|
|
2226
|
+
this.partialCCSessions.clear();
|
|
2221
2227
|
}
|
|
2222
2228
|
async handleSerialData(serial) {
|
|
2223
2229
|
try {
|
|
@@ -2346,7 +2352,6 @@ class Driver extends import_shared.TypedEventTarget {
|
|
|
2346
2352
|
if (!this._controller && (0, import_serialapi.containsCC)(msg))
|
|
2347
2353
|
return;
|
|
2348
2354
|
if (msg) {
|
|
2349
|
-
let wasMessageLogged = false;
|
|
2350
2355
|
if ((0, import_serialapi.isCommandRequest)(msg) && (0, import_serialapi.containsCC)(msg)) {
|
|
2351
2356
|
if (msg.command instanceof import_cc.SecurityCCCommandEncapsulationNonceGet) {
|
|
2352
2357
|
const node = this.tryGetNode(msg);
|
|
@@ -2359,29 +2364,35 @@ class Driver extends import_shared.TypedEventTarget {
|
|
|
2359
2364
|
secondaryTags: ["partial"],
|
|
2360
2365
|
direction: "inbound"
|
|
2361
2366
|
});
|
|
2362
|
-
|
|
2363
|
-
|
|
2367
|
+
const reassembled = await this.handleTransportServiceCommand(msg.command);
|
|
2368
|
+
if (!reassembled) {
|
|
2369
|
+
this.refreshAwaitedMessageTimers(msg);
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
msg.command = reassembled;
|
|
2373
|
+
}
|
|
2374
|
+
if (this.isSecurityLevelTooLow(msg.command)) {
|
|
2375
|
+
this.driverLog.logMessage(msg, {
|
|
2376
|
+
direction: "inbound",
|
|
2377
|
+
secondaryTags: ["discarded"]
|
|
2364
2378
|
});
|
|
2379
|
+
return;
|
|
2365
2380
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
entry.timeout?.refresh();
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2381
|
+
const completeMsg = await this.assemblePartialCCs(msg);
|
|
2382
|
+
if (!completeMsg) {
|
|
2383
|
+
this.refreshAwaitedMessageTimers(msg);
|
|
2372
2384
|
return;
|
|
2373
2385
|
}
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
}
|
|
2386
|
+
msg = completeMsg;
|
|
2387
|
+
if (this.shouldDiscardCC(completeMsg.command)) {
|
|
2388
|
+
this.driverLog.logMessage(msg, {
|
|
2389
|
+
direction: "inbound",
|
|
2390
|
+
secondaryTags: ["discarded"]
|
|
2391
|
+
});
|
|
2381
2392
|
return;
|
|
2382
2393
|
}
|
|
2383
2394
|
try {
|
|
2384
|
-
this.persistCCValues(
|
|
2395
|
+
this.persistCCValues(completeMsg.command);
|
|
2385
2396
|
} catch (e) {
|
|
2386
2397
|
if ((0, import_core.isZWaveError)(e) && e.code === import_core.ZWaveErrorCodes.PacketFormat_InvalidPayload) {
|
|
2387
2398
|
this.driverLog.print(`dropping CC with invalid values${typeof e.context === "string" ? ` (Reason: ${e.context})` : ""}`, "warn");
|
|
@@ -2390,19 +2401,13 @@ class Driver extends import_shared.TypedEventTarget {
|
|
|
2390
2401
|
throw e;
|
|
2391
2402
|
}
|
|
2392
2403
|
}
|
|
2393
|
-
if ((0, import_cc.isTransportServiceEncapsulation)(msg.command)) {
|
|
2394
|
-
msg.command = msg.command.encapsulated;
|
|
2395
|
-
wasMessageLogged = false;
|
|
2396
|
-
}
|
|
2397
2404
|
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
this.driverLog.print(`Logging a message failed: ${(0, import_shared.getErrorMessage)(e)}`);
|
|
2405
|
-
}
|
|
2405
|
+
try {
|
|
2406
|
+
this.driverLog.logMessage(msg, {
|
|
2407
|
+
direction: "inbound"
|
|
2408
|
+
});
|
|
2409
|
+
} catch (e) {
|
|
2410
|
+
this.driverLog.print(`Logging a message failed: ${(0, import_shared.getErrorMessage)(e)}`);
|
|
2406
2411
|
}
|
|
2407
2412
|
void this.handleUnsolicitedMessage(msg);
|
|
2408
2413
|
}
|
|
@@ -2612,7 +2617,12 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2612
2617
|
if (this.serial.isOpen)
|
|
2613
2618
|
await this.serial.close();
|
|
2614
2619
|
await (0, import_async.wait)(1e3);
|
|
2615
|
-
|
|
2620
|
+
try {
|
|
2621
|
+
await this.openSerialport();
|
|
2622
|
+
} catch (e) {
|
|
2623
|
+
void this.destroyWithMessage((0, import_shared.getErrorMessage)(e));
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2616
2626
|
this.driverLog.print("Serial port reopened. Returning to normal operation and hoping for the best...", "warn");
|
|
2617
2627
|
this._controller?.setStatus(import_core.ControllerStatus.Ready);
|
|
2618
2628
|
this._recoveryPhase = 0;
|
|
@@ -2761,71 +2771,111 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2761
2771
|
shouldRequestWakeupOnDemand(node) {
|
|
2762
2772
|
return !!node.supportsWakeUpOnDemand && node.status === import_Types2.NodeStatus.Asleep && this.hasPendingTransactions((t) => t.requestWakeUpOnDemand && t.message.getNodeId() === node.id);
|
|
2763
2773
|
}
|
|
2764
|
-
partialCCSessions =
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2774
|
+
partialCCSessions = new import_PartialCCSessionManager.PartialCCSessionManager({
|
|
2775
|
+
getSegmentTimeout: /* @__PURE__ */ __name(() => this._options.timeouts.report, "getSegmentTimeout"),
|
|
2776
|
+
getMaxReRequestAttempts: /* @__PURE__ */ __name(() => this._options.attempts.partialReports, "getMaxReRequestAttempts"),
|
|
2777
|
+
findRequestCC: /* @__PURE__ */ __name((command) => this.findPartialCCSessionRequest(command), "findRequestCC"),
|
|
2778
|
+
rerequestSession: /* @__PURE__ */ __name((session) => this.rerequestPartialCCSession(session), "rerequestSession"),
|
|
2779
|
+
onSessionLost: /* @__PURE__ */ __name((session) => {
|
|
2780
|
+
this.controllerLog.logNode(session.nodeId, {
|
|
2781
|
+
message: `Dropping incomplete partial CC session`,
|
|
2782
|
+
level: "warn",
|
|
2783
|
+
direction: "inbound"
|
|
2773
2784
|
});
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2785
|
+
}, "onSessionLost")
|
|
2786
|
+
});
|
|
2787
|
+
/**
|
|
2788
|
+
* Determines the request a new partial CC session is the response to, if any.
|
|
2789
|
+
* This is used to re-request the response when segments are missing.
|
|
2790
|
+
*/
|
|
2791
|
+
findPartialCCSessionRequest(command) {
|
|
2792
|
+
const currentMessage = this.queue.currentTransaction?.getCurrentMessage();
|
|
2793
|
+
if (!currentMessage || !(0, import_serialapi.containsCC)(currentMessage) || currentMessage.getNodeId() !== command.nodeId || !currentMessage.expectsNodeUpdate(this)) {
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2796
|
+
const request = (0, import_cc.getInnermostCommandClass)(currentMessage.command);
|
|
2797
|
+
if (!request.isExpectedCCResponse(this, (0, import_cc.getInnermostCommandClass)(command))) {
|
|
2798
|
+
return;
|
|
2781
2799
|
}
|
|
2800
|
+
return request;
|
|
2801
|
+
}
|
|
2802
|
+
/** Re-requests the response a partial CC session belongs to because segments are missing */
|
|
2803
|
+
rerequestPartialCCSession(session) {
|
|
2804
|
+
this.refreshAwaitedMessageTimers(session.lastSegmentMsg);
|
|
2805
|
+
this.controllerLog.logNode(session.nodeId, {
|
|
2806
|
+
message: `Some expected reports were not received, requesting the response again...`,
|
|
2807
|
+
level: "warn",
|
|
2808
|
+
direction: "outbound"
|
|
2809
|
+
});
|
|
2810
|
+
void this.sendCommand(session.requestCC, {
|
|
2811
|
+
priority: import_core.MessagePriority.Immediate,
|
|
2812
|
+
maxSendAttempts: 1,
|
|
2813
|
+
ignoreNodeUpdate: true
|
|
2814
|
+
}).catch(import_shared.noop);
|
|
2782
2815
|
}
|
|
2783
2816
|
/**
|
|
2784
|
-
* Assembles partial CCs
|
|
2785
|
-
*
|
|
2817
|
+
* Assembles partial CCs in a message body. Returns the message containing the complete
|
|
2818
|
+
* command to continue handling. This is not necessarily the passed message, since responses
|
|
2819
|
+
* may be split into multiple messages.
|
|
2820
|
+
* If the message contains a partial CC and more segments are expected, this returns `undefined`.
|
|
2786
2821
|
*/
|
|
2787
2822
|
async assemblePartialCCs(msg) {
|
|
2788
2823
|
let command = msg.command;
|
|
2789
2824
|
while (true) {
|
|
2790
|
-
const
|
|
2791
|
-
if (
|
|
2792
|
-
if (
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2825
|
+
const update = this.partialCCSessions.handleCommand(command, msg);
|
|
2826
|
+
if (update?.type === "segment") {
|
|
2827
|
+
if (update.duplicate) {
|
|
2828
|
+
this.controllerLog.logNode(command.nodeId, {
|
|
2829
|
+
message: `Ignoring duplicate partial CC segment:`,
|
|
2830
|
+
level: "debug",
|
|
2831
|
+
direction: "inbound"
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2834
|
+
this.driverLog.logMessage(msg, {
|
|
2835
|
+
secondaryTags: ["partial"],
|
|
2836
|
+
direction: "inbound"
|
|
2837
|
+
});
|
|
2838
|
+
return void 0;
|
|
2839
|
+
} else if (update?.type === "complete") {
|
|
2840
|
+
if (update.partials.length > 0) {
|
|
2841
|
+
this.driverLog.logMessage(msg, {
|
|
2842
|
+
secondaryTags: ["partial"],
|
|
2843
|
+
direction: "inbound"
|
|
2844
|
+
});
|
|
2845
|
+
}
|
|
2846
|
+
try {
|
|
2847
|
+
await update.command.mergePartialCCs(update.partials, {
|
|
2848
|
+
...this.getCCParsingContext(),
|
|
2849
|
+
sourceNodeId: update.command.nodeId,
|
|
2850
|
+
frameType: update.finalMsg.frameType
|
|
2851
|
+
});
|
|
2852
|
+
assertValidCCs(update.finalMsg);
|
|
2853
|
+
if (update.partials.length > 0) {
|
|
2854
|
+
this.controllerLog.logNode(update.command.nodeId, {
|
|
2855
|
+
message: `Assembled partial CC from ${update.partials.length + 1} segments`,
|
|
2856
|
+
level: "debug",
|
|
2797
2857
|
direction: "inbound"
|
|
2798
2858
|
});
|
|
2799
2859
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
case import_core.ZWaveErrorCodes.Deserialization_NotImplemented:
|
|
2814
|
-
case import_core.ZWaveErrorCodes.CC_NotImplemented:
|
|
2815
|
-
this.driverLog.print(`Dropping message because it could not be deserialized: ${e.message}`, "warn");
|
|
2816
|
-
return false;
|
|
2817
|
-
case import_core.ZWaveErrorCodes.PacketFormat_InvalidPayload:
|
|
2818
|
-
this.driverLog.print(`Could not assemble partial CCs because the payload is invalid. Dropping them.`, "warn");
|
|
2819
|
-
return false;
|
|
2820
|
-
case import_core.ZWaveErrorCodes.Driver_NotReady:
|
|
2821
|
-
this.driverLog.print(`Could not assemble partial CCs because the driver is not ready yet. Dropping them`, "warn");
|
|
2822
|
-
return false;
|
|
2823
|
-
}
|
|
2860
|
+
} catch (e) {
|
|
2861
|
+
if ((0, import_core.isZWaveError)(e)) {
|
|
2862
|
+
switch (e.code) {
|
|
2863
|
+
case import_core.ZWaveErrorCodes.Deserialization_NotImplemented:
|
|
2864
|
+
case import_core.ZWaveErrorCodes.CC_NotImplemented:
|
|
2865
|
+
this.driverLog.print(`Dropping message because it could not be deserialized: ${e.message}`, "warn");
|
|
2866
|
+
return void 0;
|
|
2867
|
+
case import_core.ZWaveErrorCodes.PacketFormat_InvalidPayload:
|
|
2868
|
+
this.driverLog.print(`Could not assemble partial CCs because the payload is invalid. Dropping them.`, "warn");
|
|
2869
|
+
return void 0;
|
|
2870
|
+
case import_core.ZWaveErrorCodes.Driver_NotReady:
|
|
2871
|
+
this.driverLog.print(`Could not assemble partial CCs because the driver is not ready yet. Dropping them`, "warn");
|
|
2872
|
+
return void 0;
|
|
2824
2873
|
}
|
|
2825
|
-
throw e;
|
|
2826
2874
|
}
|
|
2875
|
+
throw e;
|
|
2827
2876
|
}
|
|
2828
|
-
|
|
2877
|
+
msg = update.finalMsg;
|
|
2878
|
+
command = update.command;
|
|
2829
2879
|
}
|
|
2830
2880
|
if ((0, import_cc.isEncapsulatingCommandClass)(command)) {
|
|
2831
2881
|
command = command.encapsulated;
|
|
@@ -2833,19 +2883,40 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2833
2883
|
break;
|
|
2834
2884
|
}
|
|
2835
2885
|
}
|
|
2836
|
-
return
|
|
2886
|
+
return msg;
|
|
2837
2887
|
}
|
|
2838
|
-
/**
|
|
2888
|
+
/** Refreshes the timeouts of awaited messages which a partial message may belong to */
|
|
2889
|
+
refreshAwaitedMessageTimers(msg) {
|
|
2890
|
+
for (const entry of this.awaitedMessages) {
|
|
2891
|
+
if (entry.refreshPredicate?.(msg)) {
|
|
2892
|
+
entry.timeout?.refresh();
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Is called when a Transport Service command is received.
|
|
2898
|
+
* When the command completes a datagram, the reassembled command is returned.
|
|
2899
|
+
*/
|
|
2839
2900
|
async handleTransportServiceCommand(command) {
|
|
2840
2901
|
const nodeSessions = this.ensureNodeSessions(command.nodeId);
|
|
2841
2902
|
const missingSegmentTimeout = import_cc.TransportServiceTimeouts.requestMissingSegmentR2;
|
|
2842
|
-
const
|
|
2843
|
-
const
|
|
2903
|
+
const sendSegmentComplete = /* @__PURE__ */ __name(() => {
|
|
2904
|
+
const cc = new import_cc.TransportServiceCCSegmentComplete({
|
|
2905
|
+
nodeId: command.nodeId,
|
|
2906
|
+
sessionId: command.sessionId
|
|
2907
|
+
});
|
|
2908
|
+
void this.sendCommand(cc, {
|
|
2909
|
+
maxSendAttempts: 1,
|
|
2910
|
+
priority: import_core.MessagePriority.Immediate
|
|
2911
|
+
}).catch(import_shared.noop);
|
|
2912
|
+
}, "sendSegmentComplete");
|
|
2913
|
+
const advanceTransportServiceSession = /* @__PURE__ */ __name((session2, input) => {
|
|
2914
|
+
const machine = session2.machine;
|
|
2844
2915
|
const transition = machine.next(input);
|
|
2845
2916
|
if (transition) {
|
|
2846
2917
|
machine.transition(transition.newState);
|
|
2847
2918
|
if (machine.state.value === "receive") {
|
|
2848
|
-
startMissingSegmentTimeout(
|
|
2919
|
+
startMissingSegmentTimeout(session2);
|
|
2849
2920
|
} else if (machine.state.value === "requestMissing") {
|
|
2850
2921
|
this.controllerLog.logNode(command.nodeId, {
|
|
2851
2922
|
message: `Transport Service RX session #${command.sessionId}: Segment with offset ${machine.state.offset} missing - requesting it...`,
|
|
@@ -2857,11 +2928,10 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2857
2928
|
sessionId: command.sessionId,
|
|
2858
2929
|
datagramOffset: machine.state.offset
|
|
2859
2930
|
});
|
|
2860
|
-
|
|
2931
|
+
this.sendCommand(cc, {
|
|
2861
2932
|
maxSendAttempts: 1,
|
|
2862
2933
|
priority: import_core.MessagePriority.Immediate
|
|
2863
|
-
}).catch(import_shared.noop);
|
|
2864
|
-
startMissingSegmentTimeout(session);
|
|
2934
|
+
}).catch(import_shared.noop).finally(() => startMissingSegmentTimeout(session2));
|
|
2865
2935
|
} else if (machine.state.value === "failure") {
|
|
2866
2936
|
this.controllerLog.logNode(command.nodeId, {
|
|
2867
2937
|
message: `Transport Service RX session #${command.sessionId} failed`,
|
|
@@ -2869,42 +2939,39 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2869
2939
|
direction: "none"
|
|
2870
2940
|
});
|
|
2871
2941
|
nodeSessions.transportService.delete(command.sessionId);
|
|
2872
|
-
if (
|
|
2873
|
-
clearTimeout(
|
|
2942
|
+
if (session2.timeout) {
|
|
2943
|
+
clearTimeout(session2.timeout);
|
|
2874
2944
|
}
|
|
2945
|
+
} else if (machine.state.value === "success") {
|
|
2946
|
+
this.controllerLog.logNode(command.nodeId, {
|
|
2947
|
+
message: `Transport Service RX session #${command.sessionId} complete`,
|
|
2948
|
+
level: "debug",
|
|
2949
|
+
direction: "inbound"
|
|
2950
|
+
});
|
|
2951
|
+
if (session2.timeout) {
|
|
2952
|
+
clearTimeout(session2.timeout);
|
|
2953
|
+
}
|
|
2954
|
+
sendSegmentComplete();
|
|
2955
|
+
return "completed";
|
|
2875
2956
|
}
|
|
2876
|
-
}
|
|
2877
|
-
|
|
2878
|
-
this.controllerLog.logNode(command.nodeId, {
|
|
2879
|
-
message: `Transport Service RX session #${command.sessionId} complete`,
|
|
2880
|
-
level: "debug",
|
|
2881
|
-
direction: "inbound"
|
|
2882
|
-
});
|
|
2883
|
-
if (session.timeout) {
|
|
2884
|
-
clearTimeout(session.timeout);
|
|
2885
|
-
}
|
|
2886
|
-
const cc = new import_cc.TransportServiceCCSegmentComplete({
|
|
2887
|
-
nodeId: command.nodeId,
|
|
2888
|
-
sessionId: command.sessionId
|
|
2889
|
-
});
|
|
2890
|
-
await this.sendCommand(cc, {
|
|
2891
|
-
maxSendAttempts: 1,
|
|
2892
|
-
priority: import_core.MessagePriority.Immediate
|
|
2893
|
-
}).catch(import_shared.noop);
|
|
2957
|
+
} else if (machine.state.value === "success") {
|
|
2958
|
+
sendSegmentComplete();
|
|
2894
2959
|
}
|
|
2895
2960
|
}, "advanceTransportServiceSession");
|
|
2896
|
-
function startMissingSegmentTimeout(
|
|
2897
|
-
if (
|
|
2898
|
-
clearTimeout(
|
|
2961
|
+
function startMissingSegmentTimeout(session2) {
|
|
2962
|
+
if (session2.timeout) {
|
|
2963
|
+
clearTimeout(session2.timeout);
|
|
2899
2964
|
}
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2965
|
+
session2.timeout = setTimeout(() => {
|
|
2966
|
+
session2.timeout = void 0;
|
|
2967
|
+
advanceTransportServiceSession(session2, {
|
|
2903
2968
|
value: "timeout"
|
|
2904
2969
|
});
|
|
2905
2970
|
}, missingSegmentTimeout);
|
|
2906
2971
|
}
|
|
2907
2972
|
__name(startMissingSegmentTimeout, "startMissingSegmentTimeout");
|
|
2973
|
+
let session;
|
|
2974
|
+
let datagramOffset;
|
|
2908
2975
|
if (command instanceof import_cc.TransportServiceCCFirstSegment) {
|
|
2909
2976
|
nodeSessions.transportService.clear();
|
|
2910
2977
|
this.controllerLog.logNode(command.nodeId, {
|
|
@@ -2913,21 +2980,15 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2913
2980
|
direction: "inbound"
|
|
2914
2981
|
});
|
|
2915
2982
|
const machine = (0, import_TransportServiceMachine.createTransportServiceRXMachine)(command.datagramSize, command.partialDatagram.length);
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2983
|
+
session = {
|
|
2984
|
+
machine,
|
|
2985
|
+
datagram: new import_shared.Bytes(command.datagramSize)
|
|
2919
2986
|
};
|
|
2920
2987
|
nodeSessions.transportService.set(command.sessionId, session);
|
|
2921
|
-
|
|
2988
|
+
datagramOffset = 0;
|
|
2922
2989
|
} else {
|
|
2923
|
-
|
|
2924
|
-
if (
|
|
2925
|
-
await advanceTransportServiceSession(transportSession, {
|
|
2926
|
-
value: "segment",
|
|
2927
|
-
offset: command.datagramOffset,
|
|
2928
|
-
length: command.partialDatagram.length
|
|
2929
|
-
});
|
|
2930
|
-
} else {
|
|
2990
|
+
session = nodeSessions.transportService.get(command.sessionId);
|
|
2991
|
+
if (!session) {
|
|
2931
2992
|
const cc = new import_cc.TransportServiceCCSegmentWait({
|
|
2932
2993
|
nodeId: command.nodeId,
|
|
2933
2994
|
pendingSegments: 0
|
|
@@ -2936,7 +2997,36 @@ ${(0, import_shared.buffer2hex)(data)}`, "warn");
|
|
|
2936
2997
|
maxSendAttempts: 1,
|
|
2937
2998
|
priority: import_core.MessagePriority.Immediate
|
|
2938
2999
|
}).catch(import_shared.noop);
|
|
3000
|
+
return;
|
|
2939
3001
|
}
|
|
3002
|
+
datagramOffset = command.datagramOffset;
|
|
3003
|
+
}
|
|
3004
|
+
if (datagramOffset + command.partialDatagram.length > session.datagram.length) {
|
|
3005
|
+
this.controllerLog.logNode(command.nodeId, {
|
|
3006
|
+
message: `Transport Service RX session #${command.sessionId}: Ignoring segment because it is incompatible with the datagram length`,
|
|
3007
|
+
level: "warn",
|
|
3008
|
+
direction: "inbound"
|
|
3009
|
+
});
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3012
|
+
session.datagram.set(command.partialDatagram, datagramOffset);
|
|
3013
|
+
const result = advanceTransportServiceSession(session, {
|
|
3014
|
+
value: "segment",
|
|
3015
|
+
offset: datagramOffset,
|
|
3016
|
+
length: command.partialDatagram.length
|
|
3017
|
+
});
|
|
3018
|
+
if (result !== "completed")
|
|
3019
|
+
return;
|
|
3020
|
+
try {
|
|
3021
|
+
return await import_cc.CommandClass.parse(session.datagram, {
|
|
3022
|
+
...this.getCCParsingContext(),
|
|
3023
|
+
sourceNodeId: command.nodeId,
|
|
3024
|
+
// Transport Service is only used for singlecast commands
|
|
3025
|
+
frameType: command.frameType ?? "singlecast"
|
|
3026
|
+
});
|
|
3027
|
+
} catch (e) {
|
|
3028
|
+
this.driverLog.print(`Dropping Transport Service datagram because the contained command could not be deserialized: ${(0, import_shared.getErrorMessage)(e)}`, "warn");
|
|
3029
|
+
return;
|
|
2940
3030
|
}
|
|
2941
3031
|
}
|
|
2942
3032
|
/**
|
|
@@ -3031,8 +3121,6 @@ ${handlers.length} left`);
|
|
|
3031
3121
|
this.controllerLog.logNode(cc.nodeId, `is unknown - discarding received command...`, "warn");
|
|
3032
3122
|
return true;
|
|
3033
3123
|
}
|
|
3034
|
-
if (cc instanceof import_cc.TransportServiceCC)
|
|
3035
|
-
return false;
|
|
3036
3124
|
if (cc instanceof import_cc.CRC16CCCommandEncapsulation) {
|
|
3037
3125
|
return this.isSecurityLevelTooLow(cc.encapsulated);
|
|
3038
3126
|
}
|
|
@@ -3088,7 +3176,7 @@ ${handlers.length} left`);
|
|
|
3088
3176
|
}
|
|
3089
3177
|
}
|
|
3090
3178
|
if (requiresSecurity && !isSecure) {
|
|
3091
|
-
this.controllerLog.logNode(cc.nodeId, `command was received at a lower security level than expected - discarding it
|
|
3179
|
+
this.controllerLog.logNode(cc.nodeId, `command was received at a lower security level than expected - discarding it:`, "warn");
|
|
3092
3180
|
return true;
|
|
3093
3181
|
}
|
|
3094
3182
|
return false;
|
|
@@ -4116,6 +4204,9 @@ ${handlers.length} left`);
|
|
|
4116
4204
|
if (!!options.reportTimeoutMs) {
|
|
4117
4205
|
msg.nodeUpdateTimeout = options.reportTimeoutMs;
|
|
4118
4206
|
}
|
|
4207
|
+
if (options.ignoreNodeUpdate) {
|
|
4208
|
+
msg.ignoreNodeUpdate = true;
|
|
4209
|
+
}
|
|
4119
4210
|
return msg;
|
|
4120
4211
|
}
|
|
4121
4212
|
/**
|