zwave-js 13.4.0 → 13.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.
Files changed (49) hide show
  1. package/build/lib/controller/Controller.d.ts +3 -2
  2. package/build/lib/controller/Controller.d.ts.map +1 -1
  3. package/build/lib/controller/Controller.js +236 -195
  4. package/build/lib/controller/Controller.js.map +1 -1
  5. package/build/lib/controller/MockControllerBehaviors.js +1 -1
  6. package/build/lib/controller/MockControllerBehaviors.js.map +1 -1
  7. package/build/lib/controller/utils.d.ts +3 -0
  8. package/build/lib/controller/utils.d.ts.map +1 -1
  9. package/build/lib/controller/utils.js +19 -13
  10. package/build/lib/controller/utils.js.map +1 -1
  11. package/build/lib/driver/Driver.d.ts +3 -0
  12. package/build/lib/driver/Driver.d.ts.map +1 -1
  13. package/build/lib/driver/Driver.js +11 -2
  14. package/build/lib/driver/Driver.js.map +1 -1
  15. package/build/lib/driver/MessageGenerators.d.ts.map +1 -1
  16. package/build/lib/driver/MessageGenerators.js +6 -5
  17. package/build/lib/driver/MessageGenerators.js.map +1 -1
  18. package/build/lib/driver/NetworkCache.js +12 -12
  19. package/build/lib/driver/NetworkCache.js.map +1 -1
  20. package/build/lib/driver/SerialAPICommandMachine.d.ts +8 -8
  21. package/build/lib/driver/SerialAPICommandMachine.d.ts.map +1 -1
  22. package/build/lib/driver/SerialAPICommandMachine.js.map +1 -1
  23. package/build/lib/driver/Task.d.ts +128 -0
  24. package/build/lib/driver/Task.d.ts.map +1 -0
  25. package/build/lib/driver/Task.js +406 -0
  26. package/build/lib/driver/Task.js.map +1 -0
  27. package/build/lib/driver/TransportServiceMachine.d.ts +6 -6
  28. package/build/lib/driver/TransportServiceMachine.d.ts.map +1 -1
  29. package/build/lib/driver/TransportServiceMachine.js.map +1 -1
  30. package/build/lib/driver/UpdateConfig.js +3 -3
  31. package/build/lib/driver/UpdateConfig.js.map +1 -1
  32. package/build/lib/node/Node.js +9 -9
  33. package/build/lib/node/Node.js.map +1 -1
  34. package/build/lib/node/NodeReadyMachine.d.ts +3 -3
  35. package/build/lib/node/NodeReadyMachine.d.ts.map +1 -1
  36. package/build/lib/node/NodeReadyMachine.js.map +1 -1
  37. package/build/lib/node/NodeStatusMachine.d.ts +5 -5
  38. package/build/lib/node/NodeStatusMachine.d.ts.map +1 -1
  39. package/build/lib/node/NodeStatusMachine.js +0 -1
  40. package/build/lib/node/NodeStatusMachine.js.map +1 -1
  41. package/build/lib/node/_Types.d.ts +2 -2
  42. package/build/lib/node/_Types.d.ts.map +1 -1
  43. package/build/lib/node/_Types.js.map +1 -1
  44. package/build/lib/zniffer/CCParsingContext.d.ts +3 -3
  45. package/build/lib/zniffer/CCParsingContext.d.ts.map +1 -1
  46. package/build/lib/zniffer/CCParsingContext.js.map +1 -1
  47. package/build/lib/zniffer/MPDU.js +12 -12
  48. package/build/lib/zniffer/MPDU.js.map +1 -1
  49. package/package.json +14 -14
@@ -22,6 +22,7 @@ const math_1 = require("alcalzone-shared/math");
22
22
  const typeguards_1 = require("alcalzone-shared/typeguards");
23
23
  const node_crypto_1 = __importDefault(require("node:crypto"));
24
24
  const NetworkCache_1 = require("../driver/NetworkCache");
25
+ const Task_1 = require("../driver/Task");
25
26
  const DeviceClass_1 = require("../node/DeviceClass");
26
27
  const Node_1 = require("../node/Node");
27
28
  const VirtualNode_1 = require("../node/VirtualNode");
@@ -431,10 +432,9 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
431
432
  * Remembers the indicator values set by another node
432
433
  */
433
434
  indicatorValues = new Map();
434
- _isRebuildingRoutes = false;
435
435
  /** Returns whether the routes are currently being rebuilt for one or more nodes. */
436
436
  get isRebuildingRoutes() {
437
- return this._isRebuildingRoutes;
437
+ return !!this.driver.scheduler.findTask(utils_1.isRebuildRoutesTask);
438
438
  }
439
439
  /**
440
440
  * Returns a reference to the (virtual) broadcast node, which allows sending commands to all nodes.
@@ -2875,7 +2875,7 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
2875
2875
  * The information is the same as in the `"rebuild routes progress"` event.
2876
2876
  */
2877
2877
  get rebuildRoutesProgress() {
2878
- if (!this._isRebuildingRoutes)
2878
+ if (!this.isRebuildingRoutes)
2879
2879
  return undefined;
2880
2880
  return new Map(this._rebuildRoutesProgress);
2881
2881
  }
@@ -2889,9 +2889,9 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
2889
2889
  */
2890
2890
  beginRebuildingRoutes(options = {}) {
2891
2891
  // Don't start the process twice
2892
- if (this._isRebuildingRoutes)
2892
+ const existingTask = this.driver.scheduler.findTask((t) => t.tag?.id === "rebuild-routes");
2893
+ if (existingTask)
2893
2894
  return false;
2894
- this._isRebuildingRoutes = true;
2895
2895
  options.includeSleeping ??= true;
2896
2896
  this.driver.controllerLog.print(`rebuilding routes${options.includeSleeping ? "" : " for mains-powered nodes"}...`);
2897
2897
  // Reset the progress for all nodes
@@ -2918,14 +2918,15 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
2918
2918
  }
2919
2919
  }
2920
2920
  // Rebuild routes in the background
2921
- void this.rebuildRoutes(options).catch(() => {
2922
- /* ignore errors */
2923
- });
2921
+ void this.rebuildRoutesInternal(options).catch(shared_1.noop);
2924
2922
  // And update the progress once at the start
2925
2923
  this.emit("rebuild routes progress", new Map(this._rebuildRoutesProgress));
2926
2924
  return true;
2927
2925
  }
2928
- async rebuildRoutes(options) {
2926
+ rebuildRoutesInternal(options) {
2927
+ return this.driver.scheduler.queueTask(this.getRebuildRoutesTask(options));
2928
+ }
2929
+ getRebuildRoutesTask(options) {
2929
2930
  const pendingNodes = new Set([...this._rebuildRoutesProgress]
2930
2931
  .filter(([, status]) => status === "pending")
2931
2932
  .map(([nodeId]) => nodeId));
@@ -2950,74 +2951,100 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
2950
2951
  }
2951
2952
  }
2952
2953
  };
2953
- // We work our way outwards from the controller and start with non-sleeping nodes, one by one
2954
- try {
2955
- const neighbors = await this.getNodeNeighbors(this._ownNodeId);
2956
- neighbors.forEach((id) => addTodo(id));
2957
- }
2958
- catch {
2959
- // ignore
2960
- }
2961
- const doRebuildRoutes = async (nodeId) => {
2962
- // await the process for each node and convert errors to a non-successful result
2963
- const result = await this.rebuildNodeRoutesInternal(nodeId).catch(() => false);
2964
- if (!this._isRebuildingRoutes)
2965
- return;
2966
- // Track the success in a map
2967
- this._rebuildRoutesProgress.set(nodeId, result ? "done" : "failed");
2968
- // Notify listeners about the progress
2969
- this.emit("rebuild routes progress", new Map(this._rebuildRoutesProgress));
2970
- // Figure out which nodes to do next
2971
- try {
2972
- const neighbors = await this.getNodeNeighbors(nodeId);
2973
- neighbors.forEach((id) => addTodo(id));
2974
- }
2975
- catch {
2976
- // ignore
2977
- }
2954
+ const self = this;
2955
+ return {
2956
+ priority: Task_1.TaskPriority.Lower,
2957
+ tag: { id: "rebuild-routes" },
2958
+ task: async function* rebuildRoutesTask() {
2959
+ // We work our way outwards from the controller and start with non-sleeping nodes, one by one
2960
+ try {
2961
+ const neighbors = await self.getNodeNeighbors(self._ownNodeId);
2962
+ neighbors.forEach((id) => addTodo(id));
2963
+ }
2964
+ catch {
2965
+ // ignore
2966
+ }
2967
+ yield; // Give the task scheduler time to do something else
2968
+ async function* doRebuildRoutes(nodeId) {
2969
+ // Await the process for each node and convert errors to a non-successful result
2970
+ let result;
2971
+ try {
2972
+ const node = self.nodes.getOrThrow(nodeId);
2973
+ result = yield () => self.getRebuildNodeRoutesTask(node);
2974
+ }
2975
+ catch {
2976
+ result = false;
2977
+ }
2978
+ // Track the success in a map
2979
+ self._rebuildRoutesProgress.set(nodeId, result ? "done" : "failed");
2980
+ // Notify listeners about the progress
2981
+ self.emit("rebuild routes progress", new Map(self._rebuildRoutesProgress));
2982
+ yield; // Give the task scheduler time to do something else
2983
+ // Figure out which nodes to do next
2984
+ try {
2985
+ const neighbors = await self.getNodeNeighbors(nodeId);
2986
+ neighbors.forEach((id) => addTodo(id));
2987
+ }
2988
+ catch {
2989
+ // ignore
2990
+ }
2991
+ yield; // Give the task scheduler time to do something else
2992
+ }
2993
+ // First try to rebuild routes for as many nodes as possible one by one
2994
+ while (todoListening.length > 0) {
2995
+ const nodeId = todoListening.shift();
2996
+ yield* doRebuildRoutes(nodeId);
2997
+ }
2998
+ // We might end up with a few unconnected listening nodes, try to rebuild routes for them too
2999
+ pendingNodes.forEach((nodeId) => addTodo(nodeId));
3000
+ while (todoListening.length > 0) {
3001
+ const nodeId = todoListening.shift();
3002
+ yield* doRebuildRoutes(nodeId);
3003
+ }
3004
+ if (options.includeSleeping) {
3005
+ // Now do all sleeping nodes at once
3006
+ self.driver.controllerLog.print("Rebuilding routes for sleeping nodes when they wake up");
3007
+ const sleepingNodes = todoSleeping.map((nodeId) => self.nodes.get(nodeId)).filter((node) => node != undefined);
3008
+ const wakeupPromises = new Map(sleepingNodes.map((node) => [
3009
+ node.id,
3010
+ node.waitForWakeup().then(() => node),
3011
+ ]));
3012
+ // As long as there are sleeping nodes that haven't had their routes rebuilt yet,
3013
+ // wait for any of them to wake up
3014
+ while (wakeupPromises.size > 0) {
3015
+ const wakeUpPromise = Promise.race(wakeupPromises.values());
3016
+ const wokenUpNode = (yield () => wakeUpPromise);
3017
+ if (wokenUpNode.status === _Types_1.NodeStatus.Asleep) {
3018
+ // The node has gone to sleep again since the promise was resolved. Wait again
3019
+ wakeupPromises.set(wokenUpNode.id, wokenUpNode.waitForWakeup().then(() => wokenUpNode));
3020
+ continue;
3021
+ }
3022
+ // Once the node has woken up, remove it from the list and rebuild its routes
3023
+ wakeupPromises.delete(wokenUpNode.id);
3024
+ yield* doRebuildRoutes(wokenUpNode.id);
3025
+ }
3026
+ }
3027
+ self.driver.controllerLog.print("rebuilding routes completed");
3028
+ self.emit("rebuild routes done", new Map(self._rebuildRoutesProgress));
3029
+ // We're done!
3030
+ self._rebuildRoutesProgress.clear();
3031
+ },
2978
3032
  };
2979
- // First try to rebuild routes for as many nodes as possible one by one
2980
- while (todoListening.length > 0) {
2981
- const nodeId = todoListening.shift();
2982
- await doRebuildRoutes(nodeId);
2983
- if (!this._isRebuildingRoutes)
2984
- return;
2985
- }
2986
- // We might end up with a few unconnected listening nodes, try to rebuild routes for them too
2987
- pendingNodes.forEach((nodeId) => addTodo(nodeId));
2988
- while (todoListening.length > 0) {
2989
- const nodeId = todoListening.shift();
2990
- await doRebuildRoutes(nodeId);
2991
- if (!this._isRebuildingRoutes)
2992
- return;
2993
- }
2994
- if (options.includeSleeping) {
2995
- // Now do all sleeping nodes at once
2996
- this.driver.controllerLog.print("Rebuilding routes for sleeping nodes when they wake up");
2997
- const tasks = todoSleeping.map((nodeId) => doRebuildRoutes(nodeId));
2998
- await Promise.all(tasks);
2999
- }
3000
- // Only emit the done event when the process wasn't stopped in the meantime
3001
- if (this._isRebuildingRoutes) {
3002
- this.driver.controllerLog.print("rebuilding routes completed");
3003
- this.emit("rebuild routes done", new Map(this._rebuildRoutesProgress));
3004
- }
3005
- else {
3006
- this.driver.controllerLog.print("rebuilding routes aborted");
3007
- }
3008
- // We're done!
3009
- this._isRebuildingRoutes = false;
3010
- this._rebuildRoutesProgress.clear();
3011
3033
  }
3012
3034
  /**
3013
3035
  * Stops the route rebuilding process. Resolves false if the process was not active, true otherwise.
3014
3036
  */
3015
3037
  stopRebuildingRoutes() {
3038
+ const hasTasks = !!this.driver.scheduler.findTask(utils_1.isRebuildRoutesTask);
3016
3039
  // don't stop it twice
3017
- if (!this._isRebuildingRoutes)
3040
+ if (!hasTasks)
3018
3041
  return false;
3019
- this._isRebuildingRoutes = false;
3020
3042
  this.driver.controllerLog.print(`stopping route rebuilding process...`);
3043
+ // Stop all tasks that are part of the route rebuilding process
3044
+ // FIXME: This should be an async function that waits for the task removal
3045
+ void this.driver.scheduler.removeTasks(utils_1.isRebuildRoutesTask).then(() => {
3046
+ this.driver.controllerLog.print("rebuilding routes aborted");
3047
+ });
3021
3048
  // Cancel all transactions that were created by the route rebuilding process
3022
3049
  this.driver.rejectTransactions((t) => t.message instanceof RequestNodeNeighborUpdateMessages_1.RequestNodeNeighborUpdateRequest
3023
3050
  || t.message instanceof DeleteReturnRouteMessages_1.DeleteReturnRouteRequest
@@ -3042,12 +3069,6 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
3042
3069
  if (node.protocol == core_1.Protocols.ZWaveLongRange) {
3043
3070
  throw new core_1.ZWaveError(`Cannot rebuild routes for nodes using Z-Wave Long Range!`, core_1.ZWaveErrorCodes.Argument_Invalid);
3044
3071
  }
3045
- // Don't start the process twice
3046
- if (this._isRebuildingRoutes) {
3047
- this.driver.controllerLog.logNode(nodeId, `Cannot rebuild routes because another rebuilding process is in progress.`);
3048
- return false;
3049
- }
3050
- this._isRebuildingRoutes = true;
3051
3072
  // Figure out if nodes are responsive before attempting to rebuild routes
3052
3073
  if (
3053
3074
  // The node is known to be dead
@@ -3061,139 +3082,159 @@ let ZWaveController = class ZWaveController extends shared_1.TypedEventEmitter {
3061
3082
  return false;
3062
3083
  }
3063
3084
  }
3064
- try {
3065
- return await this.rebuildNodeRoutesInternal(nodeId);
3066
- }
3067
- finally {
3068
- this._isRebuildingRoutes = false;
3069
- }
3085
+ return this.rebuildNodeRoutesInternal(nodeId);
3070
3086
  }
3071
- async rebuildNodeRoutesInternal(nodeId) {
3087
+ rebuildNodeRoutesInternal(nodeId) {
3072
3088
  const node = this.nodes.getOrThrow(nodeId);
3073
- // Keep battery powered nodes awake during the process
3074
- // and make sure that the flag gets reset at the end
3075
- const keepAwake = node.keepAwake;
3076
- try {
3077
- node.keepAwake = true;
3078
- this.driver.controllerLog.logNode(nodeId, {
3079
- message: `Rebuilding routes...`,
3080
- direction: "none",
3081
- });
3082
- // The process consists of four steps, each step is tried up to 5 times before i is considered failed
3083
- const maxAttempts = 5;
3084
- // 1. command the node to refresh its neighbor list
3085
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3086
- // If the process was stopped in the meantime, cancel
3087
- if (!this._isRebuildingRoutes)
3088
- return false;
3089
- this.driver.controllerLog.logNode(nodeId, {
3090
- message: `refreshing neighbor list (attempt ${attempt})...`,
3091
- direction: "outbound",
3089
+ const task = this.getRebuildNodeRoutesTask(node);
3090
+ if (task instanceof Promise)
3091
+ return task;
3092
+ return this.driver.scheduler.queueTask(task);
3093
+ }
3094
+ getRebuildNodeRoutesTask(node) {
3095
+ // This task should only run once at a time
3096
+ const existingTask = this.driver.scheduler.findTask((t) => t.tag?.id === "rebuild-node-routes" && t.tag.nodeId === node.id);
3097
+ if (existingTask)
3098
+ return existingTask;
3099
+ const self = this;
3100
+ let keepAwake;
3101
+ return {
3102
+ // This task is executed by users and by the network-wide route rebuilding process.
3103
+ priority: Task_1.TaskPriority.Lower,
3104
+ tag: { id: "rebuild-node-routes", nodeId: node.id },
3105
+ task: async function* rebuildNodeRoutesTask() {
3106
+ // Keep battery powered nodes awake during the process
3107
+ keepAwake = node.keepAwake;
3108
+ node.keepAwake = true;
3109
+ if (node.canSleep && node.supportsCC(core_1.CommandClasses["Wake Up"])) {
3110
+ yield () => node.waitForWakeup();
3111
+ }
3112
+ self.driver.controllerLog.logNode(node.id, {
3113
+ message: `Rebuilding routes...`,
3114
+ direction: "none",
3092
3115
  });
3093
- try {
3094
- const result = await this.discoverNodeNeighbors(nodeId);
3095
- if (result) {
3096
- this.driver.controllerLog.logNode(nodeId, {
3097
- message: "neighbor list refreshed...",
3098
- direction: "inbound",
3116
+ // The process consists of four steps, each step is tried up to 5 times before it is considered failed
3117
+ const maxAttempts = 5;
3118
+ // 1. command the node to refresh its neighbor list
3119
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3120
+ yield; // Give the task scheduler time to do something else
3121
+ self.driver.controllerLog.logNode(node.id, {
3122
+ message: `refreshing neighbor list (attempt ${attempt})...`,
3123
+ direction: "outbound",
3124
+ });
3125
+ try {
3126
+ const result = await self.discoverNodeNeighbors(node.id);
3127
+ if (result) {
3128
+ self.driver.controllerLog.logNode(node.id, {
3129
+ message: "neighbor list refreshed...",
3130
+ direction: "inbound",
3131
+ });
3132
+ // this step was successful, continue with the next
3133
+ break;
3134
+ }
3135
+ else {
3136
+ self.driver.controllerLog.logNode(node.id, {
3137
+ message: "refreshing neighbor list failed...",
3138
+ direction: "inbound",
3139
+ level: "warn",
3140
+ });
3141
+ }
3142
+ }
3143
+ catch (e) {
3144
+ self.driver.controllerLog.logNode(node.id, `refreshing neighbor list failed: ${(0, shared_1.getErrorMessage)(e)}`, "warn");
3145
+ }
3146
+ if (attempt === maxAttempts) {
3147
+ self.driver.controllerLog.logNode(node.id, {
3148
+ message: `rebuilding routes failed: could not update the neighbor list after ${maxAttempts} attempts`,
3149
+ level: "warn",
3150
+ direction: "none",
3099
3151
  });
3100
- // this step was successful, continue with the next
3152
+ return false;
3153
+ }
3154
+ }
3155
+ yield; // Give the task scheduler time to do something else
3156
+ // 2. re-create the SUC return route, just in case
3157
+ node.hasSUCReturnRoute = await self.assignSUCReturnRoutes(node.id);
3158
+ // 3. delete all return routes to get rid of potential priority return routes
3159
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3160
+ yield; // Give the task scheduler time to do something else
3161
+ self.driver.controllerLog.logNode(node.id, {
3162
+ message: `deleting return routes (attempt ${attempt})...`,
3163
+ direction: "outbound",
3164
+ });
3165
+ if (await self.deleteReturnRoutes(node.id)) {
3101
3166
  break;
3102
3167
  }
3103
- else {
3104
- this.driver.controllerLog.logNode(nodeId, {
3105
- message: "refreshing neighbor list failed...",
3106
- direction: "inbound",
3168
+ if (attempt === maxAttempts) {
3169
+ self.driver.controllerLog.logNode(node.id, {
3170
+ message: `rebuilding routes failed: failed to delete return routes after ${maxAttempts} attempts`,
3107
3171
  level: "warn",
3172
+ direction: "none",
3108
3173
  });
3174
+ return false;
3109
3175
  }
3110
3176
  }
3111
- catch (e) {
3112
- this.driver.controllerLog.logNode(nodeId, `refreshing neighbor list failed: ${(0, shared_1.getErrorMessage)(e)}`, "warn");
3113
- }
3114
- if (attempt === maxAttempts) {
3115
- this.driver.controllerLog.logNode(nodeId, {
3116
- message: `rebuilding routes failed: could not update the neighbor list after ${maxAttempts} attempts`,
3117
- level: "warn",
3118
- direction: "none",
3119
- });
3120
- return false;
3177
+ // 4. Assign return routes to all association destinations...
3178
+ let associatedNodes = [];
3179
+ try {
3180
+ associatedNodes = (0, arrays_1.distinct)((0, shared_1.flatMap)([
3181
+ ...self.getAssociations({ nodeId: node.id })
3182
+ .values(),
3183
+ ], (assocs) => assocs.map((a) => a.nodeId)))
3184
+ // ...except the controller itself, which was handled by step 2
3185
+ .filter((id) => id !== self._ownNodeId)
3186
+ // ...and the node itself
3187
+ .filter((id) => id !== node.id)
3188
+ .sort();
3121
3189
  }
3122
- }
3123
- // 2. re-create the SUC return route, just in case
3124
- node.hasSUCReturnRoute = await this.assignSUCReturnRoutes(nodeId);
3125
- // 3. delete all return routes to get rid of potential priority return routes
3126
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3127
- this.driver.controllerLog.logNode(nodeId, {
3128
- message: `deleting return routes (attempt ${attempt})...`,
3129
- direction: "outbound",
3130
- });
3131
- if (await this.deleteReturnRoutes(nodeId)) {
3132
- break;
3190
+ catch {
3191
+ // ignore
3133
3192
  }
3134
- if (attempt === maxAttempts) {
3135
- this.driver.controllerLog.logNode(nodeId, {
3136
- message: `rebuilding routes failed: failed to delete return routes after ${maxAttempts} attempts`,
3137
- level: "warn",
3138
- direction: "none",
3193
+ if (associatedNodes.length > 0) {
3194
+ self.driver.controllerLog.logNode(node.id, {
3195
+ message: `assigning return routes to the following nodes:
3196
+ ${associatedNodes.join(", ")}`,
3197
+ direction: "outbound",
3139
3198
  });
3140
- return false;
3141
- }
3142
- }
3143
- // 4. Assign return routes to all association destinations...
3144
- let associatedNodes = [];
3145
- try {
3146
- associatedNodes = (0, arrays_1.distinct)((0, shared_1.flatMap)([...this.getAssociations({ nodeId }).values()], (assocs) => assocs.map((a) => a.nodeId)))
3147
- // ...except the controller itself, which was handled by step 2
3148
- .filter((id) => id !== this._ownNodeId)
3149
- // ...and the node itself
3150
- .filter((id) => id !== nodeId)
3151
- .sort();
3152
- }
3153
- catch {
3154
- /* ignore */
3155
- }
3156
- if (associatedNodes.length > 0) {
3157
- this.driver.controllerLog.logNode(nodeId, {
3158
- message: `assigning return routes to the following nodes:
3159
- ${associatedNodes.join(", ")}`,
3160
- direction: "outbound",
3161
- });
3162
- for (const destinationNodeId of associatedNodes) {
3163
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3164
- this.driver.controllerLog.logNode(nodeId, {
3165
- message: `assigning return route to node ${destinationNodeId} (attempt ${attempt})...`,
3166
- direction: "outbound",
3167
- });
3168
- if (await this.assignReturnRoutes(nodeId, destinationNodeId)) {
3169
- // this step was successful, continue with the next
3170
- break;
3171
- }
3172
- if (attempt === maxAttempts) {
3173
- this.driver.controllerLog.logNode(nodeId, {
3174
- message: `rebuilding routes failed: failed to assign return route after ${maxAttempts} attempts`,
3175
- level: "warn",
3176
- direction: "none",
3199
+ for (const destinationNodeId of associatedNodes) {
3200
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3201
+ yield; // Give the task scheduler time to do something else
3202
+ self.driver.controllerLog.logNode(node.id, {
3203
+ message: `assigning return route to node ${destinationNodeId} (attempt ${attempt})...`,
3204
+ direction: "outbound",
3177
3205
  });
3178
- return false;
3206
+ if (await self.assignReturnRoutes(node.id, destinationNodeId)) {
3207
+ // this step was successful, continue with the next
3208
+ break;
3209
+ }
3210
+ if (attempt === maxAttempts) {
3211
+ self.driver.controllerLog.logNode(node.id, {
3212
+ message: `rebuilding routes failed: failed to assign return route after ${maxAttempts} attempts`,
3213
+ level: "warn",
3214
+ direction: "none",
3215
+ });
3216
+ return false;
3217
+ }
3179
3218
  }
3180
3219
  }
3181
3220
  }
3182
- }
3183
- this.driver.controllerLog.logNode(nodeId, {
3184
- message: `rebuilt routes successfully`,
3185
- direction: "none",
3186
- });
3187
- return true;
3188
- }
3189
- finally {
3190
- node.keepAwake = keepAwake;
3191
- if (!keepAwake) {
3192
- setImmediate(() => {
3193
- this.driver.debounceSendNodeToSleep(node);
3221
+ self.driver.controllerLog.logNode(node.id, {
3222
+ message: `rebuilt routes successfully`,
3223
+ direction: "none",
3194
3224
  });
3195
- }
3196
- }
3225
+ return true;
3226
+ },
3227
+ cleanup: () => {
3228
+ // Make sure that the keepAwake flag gets reset at the end
3229
+ node.keepAwake = keepAwake;
3230
+ if (!keepAwake) {
3231
+ setImmediate(() => {
3232
+ this.driver.debounceSendNodeToSleep(node);
3233
+ });
3234
+ }
3235
+ return Promise.resolve();
3236
+ },
3237
+ };
3197
3238
  }
3198
3239
  /** Configures the given Node to be SUC/SIS or not */
3199
3240
  async configureSUC(nodeId, enableSUC, enableSIS) {
@@ -3325,7 +3366,7 @@ ${associatedNodes.join(", ")}`,
3325
3366
  if (i !== priorityRouteIndex)
3326
3367
  assignedRoutes[i] = route;
3327
3368
  }
3328
- catch (e) {
3369
+ catch {
3329
3370
  this.driver.controllerLog.logNode(nodeId, {
3330
3371
  message: `Assigning custom SUC return route #${i} failed`,
3331
3372
  direction: "outbound",
@@ -3344,7 +3385,7 @@ ${associatedNodes.join(", ")}`,
3344
3385
  try {
3345
3386
  await this.driver.sendZWaveProtocolCC(cc);
3346
3387
  }
3347
- catch (e) {
3388
+ catch {
3348
3389
  this.driver.controllerLog.logNode(nodeId, {
3349
3390
  message: `Marking custom SUC return route as priority failed`,
3350
3391
  direction: "outbound",
@@ -3513,7 +3554,7 @@ ${associatedNodes.join(", ")}`,
3513
3554
  if (i !== priorityRouteIndex)
3514
3555
  assignedRoutes[i] = route;
3515
3556
  }
3516
- catch (e) {
3557
+ catch {
3517
3558
  this.driver.controllerLog.logNode(nodeId, {
3518
3559
  message: `Assigning custom return route #${i} failed`,
3519
3560
  direction: "outbound",
@@ -3532,7 +3573,7 @@ ${associatedNodes.join(", ")}`,
3532
3573
  try {
3533
3574
  await this.driver.sendZWaveProtocolCC(cc);
3534
3575
  }
3535
- catch (e) {
3576
+ catch {
3536
3577
  this.driver.controllerLog.logNode(nodeId, {
3537
3578
  message: `Marking custom return route as priority failed`,
3538
3579
  direction: "outbound",
@@ -5475,7 +5516,7 @@ ${associatedNodes.join(", ")}`,
5475
5516
  try {
5476
5517
  result = await this.driver.waitForBootloaderChunk((c) => c.type === serial_1.BootloaderChunkType.FlowControl, 1000);
5477
5518
  }
5478
- catch (e) {
5519
+ catch {
5479
5520
  this.driver.controllerLog.print("OTW update failed: The bootloader did not acknowledge the start of transfer.", "error");
5480
5521
  const result = {
5481
5522
  success: false,
@@ -5550,7 +5591,7 @@ ${associatedNodes.join(", ")}`,
5550
5591
  this.driver.waitForBootloaderChunk((c) => c.type === serial_1.BootloaderChunkType.Menu, 1000),
5551
5592
  ]);
5552
5593
  }
5553
- catch (e) {
5594
+ catch {
5554
5595
  this.driver.controllerLog.print("OTW update failed: The bootloader did not acknowledge the end of transfer.", "error");
5555
5596
  const result = {
5556
5597
  success: false,