node-red-contrib-zwave-js 6.5.1 → 6.5.5

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 (33) hide show
  1. package/CHANGELOG.md +41 -5
  2. package/README.md +3 -3
  3. package/examples/Full Example.json +1 -0
  4. package/package.json +9 -8
  5. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/Livescan.html +7 -3
  6. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/Scanchoice.html +11 -10
  7. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/Snapscan.html +0 -0
  8. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/jquery-3.6.0.min.js +0 -0
  9. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/jsQR.js +0 -0
  10. package/{zwave-js/ui/smartstart/ui → resources/SmartStart}/scripts.js +32 -14
  11. package/{zwave-js/ui → resources/UITab}/Exclude.png +0 -0
  12. package/{zwave-js/ui → resources/UITab}/Include.png +0 -0
  13. package/{zwave-js/ui → resources/UITab}/NodeAdded.png +0 -0
  14. package/{zwave-js/ui/NodeAddedInsecure.png → resources/UITab/NodeError.png} +0 -0
  15. package/{zwave-js/ui → resources/UITab}/NodeRemoved.png +0 -0
  16. package/{zwave-js/ui → resources/UITab}/client.js +35 -1
  17. package/{zwave-js/ui → resources/UITab}/handlebars.min.js +0 -0
  18. package/{zwave-js/ui → resources/UITab}/jquery-steps.css +0 -0
  19. package/{zwave-js/ui → resources/UITab}/jquery-steps.min.js +0 -0
  20. package/{zwave-js/ui → resources/UITab}/qrcode.min.js +0 -0
  21. package/{zwave-js/ui → resources/UITab}/styles.css +0 -0
  22. package/{zwave-js/ui → resources/UITab}/vis-network.min.js +0 -0
  23. package/validation_result.json +18 -0
  24. package/zwave-js/cmd-factory.html +2 -1
  25. package/zwave-js/event-filter.html +8 -2
  26. package/zwave-js/event-filter.js +20 -20
  27. package/zwave-js/ui/server.js +9 -5
  28. package/zwave-js/ui/smartstart/server.js +33 -38
  29. package/zwave-js/zwave-device.html +8 -2
  30. package/zwave-js/zwave-device.js +25 -36
  31. package/zwave-js/zwave-js.html +79 -15
  32. package/zwave-js/zwave-js.js +54 -15
  33. package/zwave-js/ui/smartstart/certificate.p12 +0 -0
package/CHANGELOG.md CHANGED
@@ -1,13 +1,49 @@
1
1
  # node-red-contrib-zwave-js Change Log
2
2
 
3
+ - 6.5.5
4
+
5
+ **Fixes**
6
+ - Fix NPM Ignore rules
7
+
8
+ - 6.5.4
9
+
10
+ **Changes**
11
+ - Smart Start Web Application, has been moved to use the express instance provided by Node RED
12
+ - Live QR Scanning now requires Node RED to be SSL Enabled - basic QR capture can still be used without SSL.
13
+ - Added Min Node RED Version to package.json
14
+ - Switched static resources to use /resources/ endpoint provided by Node RED
15
+ - Added node examples
16
+ - Bump Zwave JS to 8.11.3
17
+ - Bump ESLint to 8.8.0
18
+
19
+ - 6.5.3
20
+
21
+ **Fixes**
22
+ - Wait for driver unload.
23
+
24
+ - 6.5.2
25
+
26
+ **Fixes**
27
+ - Don't soley depend on the **node removed** event to progress the exclusion Wizard
28
+ - Check if a node is selected before opening up a dialog
29
+
30
+ **New Features**
31
+ - Expose the Driver option to disable Optimistic Value Updates
32
+ - Added the ability to hide the status label for device and event filter nodes
33
+
34
+ **Changes**
35
+ - Renamed the **Abort** button during S2 inclusion to better identify its intention
36
+ - Bump ZWJS to 8.11.2
37
+ - Bump Winston to 3.5.0
38
+
3
39
  - 6.5.1
4
40
 
5
41
  **Fixes**
6
- - Battery icon/popup text in the UI is now (finally) kept in sync.
7
- - Driver readiness for Health Checks and Keep Alive requests in the UI
42
+ - Battery icon/popup text in the UI is now (finally) kept in sync
43
+ - Driver readiness for Health Checks and Keep Alive requests in the UI
8
44
 
9
45
  **Changes**
10
- - Improvements to node redynees in the UI
46
+ - Improvements to node readiness in the UI
11
47
  - Bump ZWJS to 8.11.0
12
48
 
13
49
 
@@ -15,8 +51,8 @@
15
51
 
16
52
  **New Features**
17
53
  - Added the ability to keep a node awake via the UI
18
- - Added a new method in the UI to report the health of a nodes conection to the controller.
19
- - Added native camera/image capture controls for Smart Start QR Scanning on the mobile client.
54
+ - Added a new method in the UI to report the health of a nodes conection to the controller
55
+ - Added native camera/image capture controls for Smart Start QR Scanning on the mobile client
20
56
 
21
57
  **Changes**
22
58
  - Replace **EventEmitter** with an internal instance - to address a **MaxListenersExceeded** warning.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Image](./resources/ReadMe.png)
1
+ ![Image](./GHImages/ReadMe.png)
2
2
 
3
3
  # node-red-contrib-zwave-js
4
4
 
@@ -37,13 +37,13 @@ Since `node-red-contrib-zwave-js` is based on [Z-Wave JS](https://zwave-js.githu
37
37
 
38
38
  ### The User Interface
39
39
 
40
- ![Image](./resources/ZWUI.gif)
40
+ ![Image](./GHImages/ZWUI.gif)
41
41
 
42
42
  Included with the contrib is a [user interface](https://github.com/zwave-js/node-red-contrib-zwave-js/wiki/User-Interface) where Z-Wave network management is handled. The controller side of the UI is used to include/exclude devices, heal the network, update firmware, and view the network map for diagnosing problems. The device side of the UI is used to configure devices, manage associations, and provide setup help for the nodes which will be used in your flows.
43
43
 
44
44
  ### The Nodes
45
45
 
46
- ![Image](./resources/Demo.png)
46
+ ![Image](./GHImages/Demo.png)
47
47
 
48
48
  There are 4 node types included with this contrib ([click here](https://github.com/zwave-js/node-red-contrib-zwave-js/wiki/node-types) for full details about these nodes)
49
49
  - `zwave-js`: this node is used to set up a connection to your USB Z-Wave controller, set security keys, and manage various advanced controller options
@@ -0,0 +1 @@
1
+ [{"id":"2f2f5384cf841491","type":"tab","label":"Full Example","disabled":false,"info":"","env":[]},{"id":"159049e0f35da22b","type":"zwave-js","z":"2f2f5384cf841491","d":true,"serialPort":"Select Port","name":"Z-Wave JS Controller","encryptionKey":"","encryptionKeyS2U":"","encryptionKeyS2A":"","encryptionKeyS2AC":"","ackTimeout":"","controllerTimeout":"","sendResponseTimeout":"","sendDataCallback":"","serialAPIStarted":"","logLevelPin":"none","logLevel":"none","logFile":"","logNodeFilter":"","sendUsageStatistics":true,"valueCacheDiskThrottle":"normal","customConfigPath":"","intvwUserCodes":false,"softResetUSB":false,"outputs":1,"disableOptimisticValueUpdate":false,"x":700,"y":160,"wires":[["21a01062cb3b9839"]]},{"id":"68dc316395696ed4","type":"comment","z":"2f2f5384cf841491","name":"Controller Node (Read Me)","info":"The controller node : **zwave-js** \nis the main node. It is the node that all communication is passed.\n\nThis node supports all commands. \n\nTo set it up, double click and select your serial port, \nand if using security, provide your encryption keys (or generate new ones)\n\n**NOTE:** Only 1 copy of this node can be deployed. \nThis node has been disabled, as to not affect any setup you may have already achieved.","x":710,"y":120,"wires":[]},{"id":"6dcd0dc03e0c3559","type":"zwave-device","z":"2f2f5384cf841491","name":"Some Z-Wave Device","filteredNodeId":"All","multicast":false,"datamode":"Send/Receive","messagesPerMS":1,"messageInterval":250,"isolated":false,"outputs":1,"inputs":1,"showStatus":true,"x":860,"y":380,"wires":[["dbb0e87b15b2fd3c"]]},{"id":"dcd9a6bacdcab86b","type":"comment","z":"2f2f5384cf841491","name":"Zwave Device (Read Me)","info":"A single, or mulitple zwave device : **zwave-device**. \nThis node can represent one or multiple zwave devices. \n\nIt communicates with the main **zwave-js** node.\n\nMany copies of this node can be deployed.","x":870,"y":340,"wires":[]},{"id":"42b77dc6dca017d8","type":"function","z":"2f2f5384cf841491","name":"Command","func":"// Changing a Binary Switch State (to true) on node 5\n// You can obtain a ValueID - by double clicking a value title in the UI\n\nlet ValueID = {\n \"commandClassName\": \"Binary Switch\",\n \"commandClass\": 37,\n \"endpoint\": 0,\n \"property\": \"targetValue\",\n \"propertyName\": \"targetValue\"\n}\nlet Message = {\n \"payload\": {\n \"mode\": \"ValueAPI\",\n \"node\": 5,/* This can be omitted, if your device node is set to Specific Node */\n \"method\": \"setValue\",\n \"params\": [ValueID,true]\n }\n}\nreturn Message","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":380,"wires":[["6dcd0dc03e0c3559","59b4cf7d6f673102"]]},{"id":"80583e90febe9a15","type":"inject","z":"2f2f5384cf841491","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":380,"wires":[["42b77dc6dca017d8"]]},{"id":"c09caf2bfa47f0f4","type":"comment","z":"2f2f5384cf841491","name":"Manually constructing commands","info":"","x":320,"y":340,"wires":[]},{"id":"a34dcb38a73f4bc4","type":"comment","z":"2f2f5384cf841491","name":"Commands can be sent directly to the controler","info":"","x":460,"y":240,"wires":[]},{"id":"31396cd9b583e1d7","type":"cmd-factory","z":"2f2f5384cf841491","name":"ZWave CMD Factory","node":"Node","endpoint":"","cc":"Select Command Class","method":"Select Method","params":"payload","noEvent":false,"forceUpdate":"forceUpdate","api":"ValueAPI","vapiMode":"setValue","vapiValue":"Value","vapiValueId":"ValueID","vapiOptions":"","x":660,"y":540,"wires":[["6dcd0dc03e0c3559"]]},{"id":"d4cc366646c4013d","type":"comment","z":"2f2f5384cf841491","name":"Constructing commands with CMD-Factory","info":"","x":350,"y":500,"wires":[]},{"id":"8fb56f9d226bef12","type":"function","z":"2f2f5384cf841491","name":"Command Values","func":"// Node, ValueID and Value are referenced in the CMD Factory.\n// It uses JSONata so can be highly configurable.\n\n\nmsg.Node = 5;\nmsg.ValueID = {\n \"commandClassName\": \"Binary Switch\",\n \"commandClass\": 37,\n \"endpoint\": 0,\n \"property\": \"targetValue\",\n \"propertyName\": \"targetValue\"\n};\nmsg.Value = false;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":540,"wires":[["31396cd9b583e1d7"]]},{"id":"83159be8b5438fc4","type":"inject","z":"2f2f5384cf841491","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":540,"wires":[["8fb56f9d226bef12"]]},{"id":"dbb0e87b15b2fd3c","type":"event-filter","z":"2f2f5384cf841491","name":"ZWave Event Filter","filters":[{"index":0,"name":"Temp Changes","valueIds":[{"commandClassName":"Multilevel Sensor","commandClass":49,"endpoint":0,"property":"Air temperature","propertyName":"Air temperature"}],"events":["VALUE_UPDATED"],"strict":false,"id":"210290","_id":0},{"index":1,"name":"Light Level Changes","valueIds":[{"commandClassName":"Multilevel Sensor","commandClass":49,"endpoint":0,"property":"Illuminance","propertyName":"Illuminance"}],"events":["VALUE_UPDATED"],"strict":false,"id":"293826","_id":1}],"outputs":2,"changeDate":"2022-02-01T16:55:32.003Z","showStatus":true,"x":1210,"y":380,"wires":[["899af27929142c45"],["f7d66b6a07aa4868"]]},{"id":"f662f69f25a23e83","type":"comment","z":"2f2f5384cf841491","name":"Event Filter (Read Me)","info":"A node to split/ route events : **event-filter**. \nThis node can direct various events and ValueIDs out to different paths. \n\nEach filter can group 1 or more ValueIDs - you can add them from the UI. \ndouble click a value title and choose 'Add To Filter Set' whilst a filter set is expaned","x":1220,"y":340,"wires":[]},{"id":"59b4cf7d6f673102","type":"change","z":"2f2f5384cf841491","name":"","rules":[],"action":"","property":"","from":"","to":"","reg":false,"x":555,"y":160,"wires":[[]],"l":false},{"id":"899af27929142c45","type":"function","z":"2f2f5384cf841491","name":"Do something with temp change value","func":"const Temp = msg.payload.object.newValue","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1530,"y":340,"wires":[[]]},{"id":"f7d66b6a07aa4868","type":"function","z":"2f2f5384cf841491","name":"Do something with light level change value","func":"const Lux = msg.payload.object.newValue","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1550,"y":400,"wires":[[]]},{"id":"21a01062cb3b9839","type":"change","z":"2f2f5384cf841491","name":"","rules":[],"action":"","property":"","from":"","to":"","reg":false,"x":1075,"y":360,"wires":[[]],"l":false},{"id":"a13f0bc39b98b13e","type":"comment","z":"2f2f5384cf841491","name":"The controller also emits all events","info":"","x":960,"y":240,"wires":[]}]
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "node-red-contrib-zwave-js",
3
- "version": "6.5.1",
3
+ "version": "6.5.5",
4
4
  "license": "MIT",
5
5
  "description": "An extremely powerful, easy to use, and feature rich Z-Wave node for Node Red, based on Z-Wave JS.",
6
6
  "dependencies": {
7
- "express": "^4.17.2",
8
7
  "limiter": "^2.1.0",
9
8
  "lodash": "^4.17.21",
10
9
  "serialport": "9.2.8",
11
- "winston": "^3.4.0",
10
+ "winston": "^3.5.1",
12
11
  "winston-transport": "^4.4.2",
13
- "zwave-js": "^8.11.0",
14
- "ip": "^1.1.5"
12
+ "zwave-js": "^8.11.3"
15
13
  },
16
14
  "devDependencies": {
17
- "eslint": "^8.6.0",
15
+ "eslint": "^8.8.0",
18
16
  "prettier": "^2.5.1"
19
17
  },
18
+ "scripts": {
19
+ "validate": "node-red-dev validate -o validation_result.json"
20
+ },
20
21
  "engines": {
21
- "node": ">=12.22.2",
22
- "npm": ">=6.14.13"
22
+ "node": ">=12.22.2"
23
23
  },
24
24
  "keywords": [
25
25
  "node-red",
@@ -32,6 +32,7 @@
32
32
  "home"
33
33
  ],
34
34
  "node-red": {
35
+ "version": ">=2.0.0",
35
36
  "nodes": {
36
37
  "zwave-js": "zwave-js/zwave-js.js",
37
38
  "zwave-device": "zwave-js/zwave-device.js",
@@ -74,9 +74,13 @@
74
74
  </div>
75
75
 
76
76
  <script>
77
- SendActive().then(() => {
78
- Start();
79
- });
77
+ SendActive()
78
+ .then(() => {
79
+ Start();
80
+ })
81
+ .catch((Err) => {
82
+ alert(Err);
83
+ });
80
84
  </script>
81
85
  </body>
82
86
  </html>
@@ -18,9 +18,9 @@
18
18
  font-size: 16px;
19
19
  }
20
20
  </style>
21
- <script src="jquery-3.6.0.min.js"></script>
22
- <script src="jsQR.js"></script>
23
- <script src="scripts.js"></script>
21
+ <script src="./jquery-3.6.0.min.js"></script>
22
+ <script src="./jsQR.js"></script>
23
+ <script src="./scripts.js"></script>
24
24
  <style type="text/css">
25
25
  body {
26
26
  font-family: HelveticaNeue-Light, Roboto;
@@ -35,15 +35,16 @@
35
35
  Select the Camera Source Mode
36
36
  </p>
37
37
 
38
+ <input type="button" value="Native (More Control)" onclick="GrabImage()" />
38
39
  <input
40
+ id="LiveScanButton"
39
41
  type="button"
40
- value="Native (Slower, More Control)"
41
- onclick="GrabImage()"
42
- />
43
- <input
44
- type="button"
45
- value="Live (Faster, Less Control)"
46
- onclick="location.href='Livescan.html'"
42
+ value="Live (Less Control, Requires SSL)"
43
+ onclick="location.href='./Livescan.html'"
44
+ style="filter: grayscale(1); pointer-events: none"
47
45
  />
46
+ <script>
47
+ EnableLive();
48
+ </script>
48
49
  </body>
49
50
  </html>
@@ -7,15 +7,19 @@ let offset;
7
7
  const ScannedCodes = {};
8
8
 
9
9
  function GrabImage() {
10
- SendActive().then(() => {
11
- const FI = document.createElement('input');
12
- FI.hidden = true;
13
- document.body.append(FI);
14
- FI.addEventListener('change', SubmitPhoto, false);
15
- FI.setAttribute('type', 'file');
16
- FI.setAttribute('accept', 'image/*;capture=camera');
17
- FI.click();
18
- });
10
+ SendActive()
11
+ .then(() => {
12
+ const FI = document.createElement('input');
13
+ FI.hidden = true;
14
+ document.body.append(FI);
15
+ FI.addEventListener('change', SubmitPhoto, false);
16
+ FI.setAttribute('type', 'file');
17
+ FI.setAttribute('accept', 'image/*;capture=camera');
18
+ FI.click();
19
+ })
20
+ .catch((Err) => {
21
+ alert(Err);
22
+ });
19
23
  }
20
24
 
21
25
  function SubmitPhoto(e) {
@@ -157,10 +161,18 @@ function tick() {
157
161
  }
158
162
  }
159
163
 
160
- function SendActive() {
161
- return new Promise((resolve) => {
162
- $.ajax({ url: '/event.started', method: 'get', async: false });
163
- resolve();
164
+ async function SendActive() {
165
+ return new Promise((resolve, reject) => {
166
+ const Res = $.ajax({
167
+ url: '../../../../zwave-js/smartstart-event/started',
168
+ method: 'get',
169
+ async: false
170
+ });
171
+ if (Res.status === 200) {
172
+ resolve();
173
+ } else {
174
+ reject('Smart start is not ready.');
175
+ }
164
176
  });
165
177
  }
166
178
 
@@ -204,7 +216,7 @@ function SendCode(Code, skipRender) {
204
216
  } else {
205
217
  let Result;
206
218
  $.ajax({
207
- url: '/event.code/' + Code.data,
219
+ url: '../../../../zwave-js/smartstart-event/code/' + Code.data,
208
220
  method: 'get',
209
221
  success: (data) => {
210
222
  Result = data;
@@ -217,3 +229,9 @@ function SendCode(Code, skipRender) {
217
229
  }
218
230
  });
219
231
  }
232
+
233
+ function EnableLive() {
234
+ if (location.protocol === 'https:') {
235
+ $('#LiveScanButton').css({ filter: '', pointerEvents: 'all' });
236
+ }
237
+ }
File without changes
File without changes
File without changes
File without changes
@@ -25,7 +25,8 @@ const StepList = {
25
25
  SmartStart: 10,
26
26
  SmartStartList: 11,
27
27
  SmartStartListEdit: 12,
28
- SmartStartDone: 13
28
+ SmartStartDone: 13,
29
+ RemoveDoneUnconfirmed: 14
29
30
  };
30
31
 
31
32
  const JSONFormatter = {};
@@ -212,6 +213,7 @@ const ZwaveJsUI = (function () {
212
213
 
213
214
  function HealthCheck() {
214
215
  IsDriverReady();
216
+ IsNodeSelected();
215
217
  const Buttons = {
216
218
  'Yes (1 Round)': () => {
217
219
  RenderHealthCheck(1);
@@ -233,6 +235,7 @@ const ZwaveJsUI = (function () {
233
235
 
234
236
  function KeepAwake() {
235
237
  IsDriverReady();
238
+ IsNodeSelected();
236
239
  const Node = $(
237
240
  ".red-ui-treeList-label.zwave-js-node-row[data-nodeid='" +
238
241
  selectedNode +
@@ -793,6 +796,13 @@ const ZwaveJsUI = (function () {
793
796
  return $.ajax(Options);
794
797
  }
795
798
 
799
+ function IsNodeSelected() {
800
+ if (selectedNode === undefined) {
801
+ modalAlert('Please select a Node.', 'No Node Selected');
802
+ throw new Error('No Node Selected');
803
+ }
804
+ }
805
+
796
806
  function IsDriverReady() {
797
807
  if (!DriverReady) {
798
808
  modalAlert(
@@ -1268,6 +1278,7 @@ const ZwaveJsUI = (function () {
1268
1278
 
1269
1279
  function RenameNode(KB, El) {
1270
1280
  IsDriverReady();
1281
+ IsNodeSelected();
1271
1282
  let input;
1272
1283
  let Button;
1273
1284
  if (KB === true) {
@@ -1302,6 +1313,7 @@ const ZwaveJsUI = (function () {
1302
1313
 
1303
1314
  function SetNodeLocation(KB, El) {
1304
1315
  IsDriverReady();
1316
+ IsNodeSelected();
1305
1317
  let input;
1306
1318
  let Button;
1307
1319
  if (KB === true) {
@@ -1350,6 +1362,7 @@ const ZwaveJsUI = (function () {
1350
1362
  }
1351
1363
 
1352
1364
  function OpenDB() {
1365
+ IsNodeSelected();
1353
1366
  const info =
1354
1367
  $(`.zwave-js-node-row.selected`).data('info')?.deviceConfig || {};
1355
1368
  const id = [
@@ -1379,6 +1392,7 @@ const ZwaveJsUI = (function () {
1379
1392
  if (err.status !== 504) {
1380
1393
  modalAlert(err.responseText, 'Could Not Remove Node');
1381
1394
  }
1395
+
1382
1396
  Removing = false;
1383
1397
  });
1384
1398
  }
@@ -1604,6 +1618,7 @@ const ZwaveJsUI = (function () {
1604
1618
  .css('min-width', '125px')
1605
1619
  .click(() => {
1606
1620
  IsDriverReady();
1621
+ IsNodeSelected();
1607
1622
  InterviewNode();
1608
1623
  })
1609
1624
  .html('Interview Node')
@@ -1615,6 +1630,7 @@ const ZwaveJsUI = (function () {
1615
1630
  .css('min-width', '125px')
1616
1631
  .click(() => {
1617
1632
  IsDriverReady();
1633
+ IsNodeSelected();
1618
1634
  StartNodeHeal();
1619
1635
  })
1620
1636
  .html('Heal Node')
@@ -1628,6 +1644,7 @@ const ZwaveJsUI = (function () {
1628
1644
  .css('min-width', '125px')
1629
1645
  .click(() => {
1630
1646
  IsDriverReady();
1647
+ IsNodeSelected();
1631
1648
  RemoveFailedNode();
1632
1649
  })
1633
1650
  .html('Remove Failed Node')
@@ -1638,6 +1655,7 @@ const ZwaveJsUI = (function () {
1638
1655
  .css('min-width', '125px')
1639
1656
  .click(() => {
1640
1657
  IsDriverReady();
1658
+ IsNodeSelected();
1641
1659
  ShowReplacePrompt();
1642
1660
  })
1643
1661
  .html('Replace Failed Node')
@@ -1651,6 +1669,7 @@ const ZwaveJsUI = (function () {
1651
1669
  .css('min-width', '125px')
1652
1670
  .click(() => {
1653
1671
  IsDriverReady();
1672
+ IsNodeSelected();
1654
1673
  AssociationMGMT();
1655
1674
  })
1656
1675
  .html('Association Management')
@@ -1661,6 +1680,7 @@ const ZwaveJsUI = (function () {
1661
1680
  .css('min-width', '125px')
1662
1681
  .click(() => {
1663
1682
  IsDriverReady();
1683
+ IsNodeSelected();
1664
1684
  getProperties();
1665
1685
  })
1666
1686
  .html('Refresh Property List')
@@ -1741,6 +1761,7 @@ const ZwaveJsUI = (function () {
1741
1761
  $('#zwave-js-controller-status').html(data.status);
1742
1762
  }
1743
1763
 
1764
+ let RemovedShown = false;
1744
1765
  function handleControllerEvent(topic, data) {
1745
1766
  switch (data.type) {
1746
1767
  case 'node-collection-change':
@@ -1759,9 +1780,11 @@ const ZwaveJsUI = (function () {
1759
1780
  $('#IEButton').text('Close');
1760
1781
  }
1761
1782
  if (data.event === 'node removed') {
1783
+ RemovedShown = true;
1762
1784
  ClearIETimer();
1763
1785
  ClearSecurityCountDown();
1764
1786
  GetNodes();
1787
+ selectedNode = undefined;
1765
1788
  StepsAPI.setStepIndex(StepList.RemoveDone);
1766
1789
  $('#IEButton').text('Close');
1767
1790
  }
@@ -1769,11 +1792,13 @@ const ZwaveJsUI = (function () {
1769
1792
 
1770
1793
  case 'node-inclusion-step':
1771
1794
  if (data.event === 'grant security') {
1795
+ $('#IEButton').text('Abort S2 Bootstrap');
1772
1796
  ListRequestedClass(data.classes);
1773
1797
  ClearIETimer();
1774
1798
  StartSecurityCountDown();
1775
1799
  }
1776
1800
  if (data.event === 'verify dsk') {
1801
+ $('#IEButton').text('Abort S2 Bootstrap');
1777
1802
  DisplayDSK(data.dsk);
1778
1803
  ClearIETimer();
1779
1804
  StartSecurityCountDown();
@@ -1785,6 +1810,15 @@ const ZwaveJsUI = (function () {
1785
1810
  if (data.event === 'exclusion started') {
1786
1811
  StepsAPI.setStepIndex(StepList.Remove);
1787
1812
  StartIECountDown();
1813
+ RemovedShown = false;
1814
+ }
1815
+ if (data.event === 'exclusion stopped') {
1816
+ if (!RemovedShown) {
1817
+ ClearIETimer();
1818
+ ClearSecurityCountDown();
1819
+ StepsAPI.setStepIndex(StepList.RemoveDoneUnconfirmed);
1820
+ $('#IEButton').text('Close');
1821
+ }
1788
1822
  }
1789
1823
  if (data.event === 'aborted') {
1790
1824
  StepsAPI.setStepIndex(StepList.Aborted);
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ {
2
+ "package": { "name": "node-red-contrib-zwave-js", "version": "6.5.4" },
3
+ "P01": { "test": true, "license": "MIT" },
4
+ "P03": { "test": true },
5
+ "P04": { "test": true },
6
+ "P08": { "test": true },
7
+ "P05": { "test": true },
8
+ "P06": { "test": true, "versions": ["2.2.0"] },
9
+ "P07": { "test": false, "version": ">=12.22.2" },
10
+ "N01": { "test": true },
11
+ "N02": {
12
+ "test": true,
13
+ "nodes": ["zwave-js", "zwave-device", "event-filter", "cmd-factory"]
14
+ },
15
+ "D01": { "test": true, "total": 6 },
16
+ "D02": { "test": true },
17
+ "D03": { "test": true }
18
+ }
@@ -23,7 +23,8 @@
23
23
  label: function () {
24
24
  return this.name;
25
25
  },
26
- oneditprepare: SortUI
26
+ oneditprepare: SortUI,
27
+ paletteLabel: 'cmd-factory'
27
28
  });
28
29
 
29
30
  function GoToInfo() {
@@ -9,7 +9,8 @@
9
9
  name: { value: 'ZWave Event Filter' },
10
10
  filters: { value: [] },
11
11
  outputs: { value: 0 },
12
- changeDate: { value: undefined }
12
+ changeDate: { value: undefined },
13
+ showStatus: { value: true }
13
14
  },
14
15
  inputs: 1,
15
16
  outputs: 0,
@@ -25,7 +26,8 @@
25
26
  },
26
27
  outputLabels: function (index) {
27
28
  return this.filters[index].name;
28
- }
29
+ },
30
+ paletteLabel: 'event-filter'
29
31
  });
30
32
 
31
33
  function compare(a, b) {
@@ -257,6 +259,10 @@
257
259
  <label for="node-input-name" style="width:130px"><i class="fa fa-pencil"></i> Name</label>
258
260
  <input type="text" id="node-input-name" placeholder="Filter Name">
259
261
  </div>
262
+ <div class="form-row">
263
+ <label for="node-input-showStatus" style="width:130px"><i class="fa fa-pencil"></i> Show Status</label>
264
+ <input type="checkbox" id="node-input-showStatus" />
265
+ </div>
260
266
 
261
267
  <div>
262
268
  <ol id="filtersets" style="min-height:450px;min-width:400px"> </ol>
@@ -5,6 +5,20 @@ module.exports = function (RED) {
5
5
  RED.nodes.createNode(this, config);
6
6
  const node = this;
7
7
 
8
+ function UpdateStatus(Color, Shape, Text) {
9
+ if (config.showStatus === undefined || config.showStatus) {
10
+ node.status({
11
+ fill: Color,
12
+ shape: Shape,
13
+ text: Text
14
+ });
15
+ } else {
16
+ node.status({});
17
+ }
18
+ }
19
+
20
+ node.status({});
21
+
8
22
  node.on('input', Input);
9
23
 
10
24
  function compare(a, b) {
@@ -46,11 +60,8 @@ module.exports = function (RED) {
46
60
  ) {
47
61
  msg.filter = Filter;
48
62
  SendingArray[ArrayIndex] = msg;
49
- node.status({
50
- fill: 'green',
51
- shape: 'dot',
52
- text: 'Last match: ' + Filter.name
53
- });
63
+ UpdateStatus('green', 'dot', 'Last match: ' + Filter.name);
64
+
54
65
  send(SendingArray);
55
66
  Matched = true;
56
67
  break;
@@ -62,11 +73,8 @@ module.exports = function (RED) {
62
73
  } else {
63
74
  msg.filter = Filter;
64
75
  SendingArray[ArrayIndex] = msg;
65
- node.status({
66
- fill: 'green',
67
- shape: 'dot',
68
- text: 'Last match: ' + Filter.name
69
- });
76
+ UpdateStatus('green', 'dot', 'Last match: ' + Filter.name);
77
+
70
78
  Matched = true;
71
79
  send(SendingArray);
72
80
  break;
@@ -76,18 +84,10 @@ module.exports = function (RED) {
76
84
  }
77
85
 
78
86
  if (!Matched) {
79
- node.status({
80
- fill: 'yellow',
81
- shape: 'dot',
82
- text: 'No match'
83
- });
87
+ UpdateStatus('yellow', 'dot', 'No match');
84
88
  }
85
89
  } else {
86
- node.status({
87
- fill: 'red',
88
- shape: 'dot',
89
- text: 'Not a ZWave message'
90
- });
90
+ UpdateStatus('red', 'dot', 'Not a ZWave message');
91
91
  }
92
92
 
93
93
  if (done) {
@@ -1,4 +1,3 @@
1
- const express = require('express');
2
1
  const SP = require('serialport');
3
2
  const ModulePackage = require('../../package.json');
4
3
  const { CommandClasses } = require('@zwave-js/core');
@@ -244,9 +243,6 @@ module.exports = {
244
243
  }
245
244
  );
246
245
 
247
- /* Res */
248
- RED.httpAdmin.use('/zwave-js/res', express.static(__dirname));
249
-
250
246
  // Frimware
251
247
  RED.httpAdmin.post(
252
248
  '/zwave-js/firmwareupdate/:code',
@@ -284,13 +280,14 @@ module.exports = {
284
280
  );
285
281
 
286
282
  // Smart Start
283
+ SmartStart.Prep(RED.httpAdmin);
287
284
  RED.httpAdmin.get(
288
285
  '/zwave-js/smartstart/:Method',
289
286
  RED.auth.needsPermission('flows.write'),
290
287
  async (req, res) => {
291
288
  switch (req.params.Method) {
292
289
  case 'startserver':
293
- SmartStart.Start(SmartStartCallback).then((QRCode) => {
290
+ SmartStart.Start(SmartStartCallback, req).then((QRCode) => {
294
291
  res.status(200);
295
292
  res.end(QRCode);
296
293
  });
@@ -413,6 +410,13 @@ module.exports = {
413
410
  });
414
411
  });
415
412
 
413
+ _Context.controller.on('exclusion stopped', () => {
414
+ _RED.comms.publish(`/zwave-js/cmd`, {
415
+ type: 'node-inclusion-step',
416
+ event: 'exclusion stopped'
417
+ });
418
+ });
419
+
416
420
  _Context.controller.on('node added', (N, IR) => {
417
421
  WireNodeEvents(N);
418
422
  _RED.comms.publish(`/zwave-js/cmd`, {
@@ -1,60 +1,55 @@
1
- const express = require('express');
2
- const https = require('https');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const ip = require('ip');
6
-
7
- let App;
8
- let Server;
9
1
  let _Callback;
2
+ let _Enabled = false;
10
3
 
11
- const Options = {
12
- pfx: fs.readFileSync(path.join(__dirname, 'certificate.p12')),
13
- passphrase: 'password1'
4
+ const Prep = (HTTPAdmin) => {
5
+ HTTPAdmin.get('/zwave-js/smartstart-event/started', SendStarted);
6
+ HTTPAdmin.get('/zwave-js/smartstart-event/code/:Code', ParseCode);
14
7
  };
15
8
 
16
- const Start = (Callback) => {
9
+ const CheckStatus = (res) => {
10
+ if (_Enabled) {
11
+ return true;
12
+ } else {
13
+ res.sendStatus(503).end();
14
+ return false;
15
+ }
16
+ };
17
+
18
+ const Start = (Callback, Req) => {
17
19
  _Callback = Callback;
18
- App = express();
19
- App.use(express.static(path.join(__dirname, 'ui')));
20
- App.get('/event.started', SendStarted);
21
- App.get('/event.code/:Code', ParseCode);
22
- Server = https.createServer(Options, App);
20
+ _Enabled = true;
23
21
 
22
+ const Secure = Req.connection.encrypted !== undefined;
23
+ const Prot = Secure ? 'https://' : 'http://';
24
24
  return new Promise((resolve) => {
25
- Server.listen(0, () => {
26
- resolve(
27
- 'https://' +
28
- ip.address() +
29
- ':' +
30
- Server.address().port +
31
- '/Scanchoice.html'
32
- );
33
- });
25
+ resolve(
26
+ `${Prot}${Req.headers.host}/resources/node-red-contrib-zwave-js/SmartStart/Scanchoice.html`
27
+ );
34
28
  });
35
29
  };
36
30
 
37
31
  function SendStarted(req, res) {
38
- _Callback('Started');
39
- res.status(200);
40
- res.end();
32
+ if (CheckStatus(res)) {
33
+ _Callback('Started');
34
+ res.status(200);
35
+ res.end();
36
+ }
41
37
  }
42
38
 
43
39
  function ParseCode(req, res) {
44
- const Result = _Callback('Code', req.params.Code);
45
- res.status(200);
46
- res.end(Result.toString());
40
+ if (CheckStatus(res)) {
41
+ const Result = _Callback('Code', req.params.Code);
42
+ res.status(200);
43
+ res.end(Result.toString());
44
+ }
47
45
  }
48
46
 
49
47
  const Stop = () => {
50
- if (Server !== undefined) {
51
- Server.close();
52
- Server = undefined;
53
- App = undefined;
54
- }
48
+ _Enabled = false;
55
49
  };
56
50
 
57
51
  module.exports = {
58
52
  Start: Start,
59
- Stop: Stop
53
+ Stop: Stop,
54
+ Prep: Prep
60
55
  };
@@ -11,7 +11,8 @@
11
11
  messageInterval: { value: 250 },
12
12
  isolated: { value: false },
13
13
  outputs: { value: 1 },
14
- inputs: { value: 1 }
14
+ inputs: { value: 1 },
15
+ showStatus: { value: true }
15
16
  },
16
17
  inputs: 1,
17
18
  outputs: 1,
@@ -20,7 +21,8 @@
20
21
  return this.name;
21
22
  },
22
23
  oneditprepare: SortUI,
23
- oneditsave: SetIO
24
+ oneditsave: SetIO,
25
+ paletteLabel: 'zwave-device'
24
26
  });
25
27
 
26
28
  function SetIO() {
@@ -287,6 +289,10 @@
287
289
  <select id="node-input-filteredNodeId">
288
290
  </select>
289
291
  </div>
292
+ <div class="form-row">
293
+ <label for="node-input-showStatus" style="width:130px"><i class="fa fa-pencil"></i> Show Status</label>
294
+ <input type="checkbox" id="node-input-showStatus" />
295
+ </div>
290
296
  <div class="form-tips" id="node-tip">
291
297
  Note: This node works in conjunction with the main Z-Wave JS Controller node, therefore, ensure the controller node is in one of your flows and in a deployed state before using this node.
292
298
  </div>
@@ -6,6 +6,18 @@ module.exports = function (RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  const RedNode = this;
8
8
 
9
+ function UpdateStatus(Color, Shape, Text) {
10
+ if (config.showStatus === undefined || config.showStatus) {
11
+ RedNode.status({
12
+ fill: Color,
13
+ shape: Shape,
14
+ text: Text
15
+ });
16
+ } else {
17
+ RedNode.status({});
18
+ }
19
+ }
20
+
9
21
  const LimiterSettings = {
10
22
  tokensPerInterval: 1,
11
23
  interval: 250
@@ -73,18 +85,10 @@ module.exports = function (RED) {
73
85
  }
74
86
  if (config.multicast) {
75
87
  DeviceMode = 'Multicast';
76
- RedNode.status({
77
- fill: 'green',
78
- shape: 'dot',
79
- text: 'Mode: Mulitcast'
80
- });
88
+ UpdateStatus('green', 'dot', 'Mode: Multicast');
81
89
  } else {
82
90
  DeviceMode = 'Multiple';
83
- RedNode.status({
84
- fill: 'green',
85
- shape: 'dot',
86
- text: 'Mode: Multiple'
87
- });
91
+ UpdateStatus('green', 'dot', 'Mode: Multiple');
88
92
  }
89
93
  } else if (!isNaN(config.filteredNodeId)) {
90
94
  DeviceMode = 'Specific';
@@ -94,24 +98,20 @@ module.exports = function (RED) {
94
98
  processEventMessage
95
99
  );
96
100
  }
97
- RedNode.status({
98
- fill: 'green',
99
- shape: 'dot',
100
- text: `Mode: Specific Node (${config.filteredNodeId})`
101
- });
101
+ UpdateStatus(
102
+ 'green',
103
+ 'dot',
104
+ `Mode: Specific Node (${config.filteredNodeId})`
105
+ );
102
106
  } else if (config.filteredNodeId === 'All') {
103
107
  DeviceMode = 'All';
104
108
  if (Out) {
105
109
  NodeEventEmitter.on('zwjs:node:event:all', processEventMessage);
106
110
  }
107
- RedNode.status({ fill: 'green', shape: 'dot', text: 'Mode: All Nodes' });
111
+ UpdateStatus('green', 'dot', 'Mode: All Nodes');
108
112
  } else if (config.filteredNodeId === 'AS') {
109
113
  DeviceMode = 'AS';
110
- RedNode.status({
111
- fill: 'green',
112
- shape: 'dot',
113
- text: 'Mode: As Specifed (Waiting)'
114
- });
114
+ UpdateStatus('yellow', 'dot', 'Mode: As Specified (Waiting)');
115
115
  }
116
116
 
117
117
  function processEventMessage(MSG) {
@@ -157,11 +157,7 @@ module.exports = function (RED) {
157
157
  );
158
158
  }
159
159
  DynamicIDListener = Node;
160
- RedNode.status({
161
- fill: 'green',
162
- shape: 'dot',
163
- text: `Mode: As Specifed (${Node})`
164
- });
160
+ UpdateStatus('green', 'dot', `Mode: As Specified (${Node})`);
165
161
  }
166
162
  break;
167
163
 
@@ -200,21 +196,14 @@ module.exports = function (RED) {
200
196
 
201
197
  if (DeviceMode === 'Multiple' && msg.payload.node === undefined) {
202
198
  for (let i = 0; i < config.filteredNodeId.length; i++) {
203
- RedNode.status({
204
- fill: 'yellow',
205
- shape: 'dot',
206
- text: 'Mode: Multiple (Throttling)'
207
- });
199
+ UpdateStatus('yellow', 'dot', 'Mode: Multiple (Throttling)');
200
+
208
201
  await RateLimiter.removeTokens(1);
209
202
  const TR = LD.cloneDeep(msg);
210
203
  TR.payload.node = parseInt(config.filteredNodeId[i]);
211
204
  NodeEventEmitter.emit('zwjs:node:command', TR);
212
205
  }
213
- RedNode.status({
214
- fill: 'green',
215
- shape: 'dot',
216
- text: 'Mode: Multiple'
217
- });
206
+ UpdateStatus('green', 'dot', 'Mode: Multiple');
218
207
  } else {
219
208
  NodeEventEmitter.emit('zwjs:node:command', msg);
220
209
  }
@@ -1,15 +1,36 @@
1
- <script type="text/javascript" src="zwave-js/res/handlebars.min.js"></script>
1
+ <script
2
+ type="text/javascript"
3
+ src="resources/node-red-contrib-zwave-js/UITab/handlebars.min.js"
4
+ ></script>
2
5
  <script>
3
6
  Handlebars.registerHelper('inc', function (value, options) {
4
7
  return parseInt(value) + 1;
5
8
  });
6
9
  </script>
7
- <script type="text/javascript" src="zwave-js/res/client.js"></script>
8
- <script type="text/javascript" src="zwave-js/res/vis-network.min.js"></script>
9
- <script type="text/javascript" src="zwave-js/res/jquery-steps.min.js"></script>
10
- <script type="text/javascript" src="zwave-js/res/qrcode.min.js"></script>
11
- <link rel="stylesheet" href="zwave-js/res/styles.css" />
12
- <link rel="stylesheet" href="zwave-js/res/jquery-steps.css" />
10
+ <script
11
+ type="text/javascript"
12
+ src="resources/node-red-contrib-zwave-js/UITab/client.js"
13
+ ></script>
14
+ <script
15
+ type="text/javascript"
16
+ src="resources/node-red-contrib-zwave-js/UITab/vis-network.min.js"
17
+ ></script>
18
+ <script
19
+ type="text/javascript"
20
+ src="resources/node-red-contrib-zwave-js/UITab/jquery-steps.min.js"
21
+ ></script>
22
+ <script
23
+ type="text/javascript"
24
+ src="resources/node-red-contrib-zwave-js/UITab/qrcode.min.js"
25
+ ></script>
26
+ <link
27
+ rel="stylesheet"
28
+ href="resources/node-red-contrib-zwave-js/UITab/styles.css"
29
+ />
30
+ <link
31
+ rel="stylesheet"
32
+ href="resources/node-red-contrib-zwave-js/UITab/jquery-steps.css"
33
+ />
13
34
 
14
35
  <!-- templates used for modal dialogs *-->
15
36
 
@@ -108,6 +129,7 @@
108
129
  <li data-step-target='SmartStartList'></li>
109
130
  <li data-step-target='SmartStartListEdit'></li>
110
131
  <li data-step-target='SmartStartDone'></li>
132
+ <li data-step-target='RemoveDoneUnconfirmed'></li>
111
133
  </ul>
112
134
  <div class='step-content' style='border: none;'>
113
135
  <!-- Secuity Mode-->
@@ -205,7 +227,10 @@
205
227
  <table style='width: 100%; height: 290px;'>
206
228
  <tr>
207
229
  <td style='text-align: center;'>
208
- <img src='zwave-js/res/Include.png' width='200px' />
230
+ <img
231
+ src='resources/node-red-contrib-zwave-js/UITab/Include.png'
232
+ width='200px'
233
+ />
209
234
  </td>
210
235
  </tr>
211
236
  <tr>
@@ -229,7 +254,10 @@
229
254
  <table style='width: 100%; height: 290px;'>
230
255
  <tr>
231
256
  <td style='text-align: center;'>
232
- <img src='zwave-js/res/Exclude.png' width='200px' />
257
+ <img
258
+ src='resources/node-red-contrib-zwave-js/UITab/Exclude.png'
259
+ width='200px'
260
+ />
233
261
  </td>
234
262
  </tr>
235
263
  <tr>
@@ -387,7 +415,10 @@
387
415
  <table style='width: 100%; height: 290px;'>
388
416
  <tr>
389
417
  <td style='text-align: center;'>
390
- <img src='zwave-js/res/NodeAdded.png' width='200px' />
418
+ <img
419
+ src='resources/node-red-contrib-zwave-js/UITab/NodeAdded.png'
420
+ width='200px'
421
+ />
391
422
  </td>
392
423
  </tr>
393
424
  <tr>
@@ -405,7 +436,10 @@
405
436
  <table style='width: 100%; height: 290px;'>
406
437
  <tr>
407
438
  <td style='text-align: center;'>
408
- <img src='zwave-js/res/NodeAddedInsecure.png' width='200px' />
439
+ <img
440
+ src='resources/node-red-contrib-zwave-js/UITab/NodeError.png'
441
+ width='200px'
442
+ />
409
443
  </td>
410
444
  </tr>
411
445
  <tr>
@@ -424,7 +458,10 @@
424
458
  <table style='width: 100%; height: 290px;'>
425
459
  <tr>
426
460
  <td style='text-align: center;'>
427
- <img src='zwave-js/res/NodeRemoved.png' width='200px' />
461
+ <img
462
+ src='resources/node-red-contrib-zwave-js/UITab/NodeRemoved.png'
463
+ width='200px'
464
+ />
428
465
  </td>
429
466
  </tr>
430
467
  <tr>
@@ -478,7 +515,10 @@
478
515
  <table style='width: 100%; height: 290px;'>
479
516
  <tr>
480
517
  <td style='text-align: center;'>
481
- <img src='zwave-js/res/NodeAddedInsecure.png' width='200px' />
518
+ <img
519
+ src='resources/node-red-contrib-zwave-js/UITab/NodeError.png'
520
+ width='200px'
521
+ />
482
522
  </td>
483
523
  </tr>
484
524
  <tr>
@@ -586,6 +626,24 @@
586
626
  broadcast has been recieved, the device should get interviewed and
587
627
  added to your network.</p>
588
628
  </div>
629
+ <!--Remove Done Uncofirmed-->
630
+ <div class='step-tab-panel' data-step='RemoveDoneUnconfirmed'>
631
+ <br />
632
+ <table style='width: 100%; height: 290px;'>
633
+ <tr>
634
+ <td style='text-align: center;'>
635
+ <img
636
+ src='resources/node-red-contrib-zwave-js/UITab/NodeError.png'
637
+ width='200px'
638
+ />
639
+ </td>
640
+ </tr>
641
+ <tr>
642
+ <td style='text-align: center;'>Node exclusion has finished.<br />No
643
+ nodes were removed from this network.</td>
644
+ </tr>
645
+ </table>
646
+ </div>
589
647
  </div>
590
648
  </div>
591
649
  </script>
@@ -856,7 +914,8 @@
856
914
  customConfigPath: { value: undefined },
857
915
  intvwUserCodes: { value: false },
858
916
  softResetUSB: { value: false },
859
- outputs: { value: 1 }
917
+ outputs: { value: 1 },
918
+ disableOptimisticValueUpdate: { value: false }
860
919
  },
861
920
  inputs: 1,
862
921
  outputs: 1,
@@ -866,7 +925,8 @@
866
925
  },
867
926
  onpaletteadd: ZwaveJsUI.init,
868
927
  oneditprepare: SortUI,
869
- oneditsave: SortIO
928
+ oneditsave: SortIO,
929
+ paletteLabel: 'zwave-js'
870
930
  });
871
931
 
872
932
  function SortIO() {
@@ -1058,6 +1118,10 @@
1058
1118
  <option value="fast">Fast</option>
1059
1119
  </select>
1060
1120
  </div>
1121
+ <div class="form-row">
1122
+ <label for="node-input-disableOptimisticValueUpdate" style="width:130px"><i class="fa fa-pencil"></i> No Optimistic</label>
1123
+ <input type="checkbox" id="node-input-disableOptimisticValueUpdate">
1124
+ </div>
1061
1125
  <div class="form-row">
1062
1126
  <label for="node-input-intvwUserCodes" style="width:130px"><i class="fa fa-pencil"></i> Lock Code Intvw</label>
1063
1127
  <input type="checkbox" id="node-input-intvwUserCodes">
@@ -221,6 +221,41 @@ module.exports = function (RED) {
221
221
  DriverOptions.interview = {
222
222
  queryAllUserCodes: true
223
223
  };
224
+ } else {
225
+ Log(
226
+ 'debug',
227
+ 'NDERED',
228
+ undefined,
229
+ '[options] [interview.queryAllUserCodes]',
230
+ 'Disabled'
231
+ );
232
+ DriverOptions.interview = {
233
+ queryAllUserCodes: false
234
+ };
235
+ }
236
+
237
+ // Optimsitic Value Updates
238
+ if (
239
+ config.disableOptimisticValueUpdate !== undefined &&
240
+ config.disableOptimisticValueUpdate
241
+ ) {
242
+ Log(
243
+ 'debug',
244
+ 'NDERED',
245
+ undefined,
246
+ '[options] [disableOptimisticValueUpdate]',
247
+ 'Enabled'
248
+ );
249
+ DriverOptions.disableOptimisticValueUpdate = true;
250
+ } else {
251
+ Log(
252
+ 'debug',
253
+ 'NDERED',
254
+ undefined,
255
+ '[options] [disableOptimisticValueUpdate]',
256
+ 'Disabled'
257
+ );
258
+ DriverOptions.disableOptimisticValueUpdate = false;
224
259
  }
225
260
 
226
261
  // Soft Reset
@@ -440,21 +475,25 @@ module.exports = function (RED) {
440
475
  'Cleaning up...'
441
476
  );
442
477
  UI.unregister();
443
- Driver.destroy();
444
- NodeEventEmitter.removeListener('zwjs:node:command', processMessageEvent);
445
- if (Logger !== undefined) {
446
- Logger.clear();
447
- Logger = undefined;
448
- }
449
- if (Pin2Transport !== undefined) {
450
- Pin2Transport = undefined;
451
- }
452
- if (FileTransport !== undefined) {
453
- FileTransport = undefined;
454
- }
455
- if (done) {
456
- done();
457
- }
478
+ Driver.destroy().then(() => {
479
+ NodeEventEmitter.removeListener(
480
+ 'zwjs:node:command',
481
+ processMessageEvent
482
+ );
483
+ if (Logger !== undefined) {
484
+ Logger.clear();
485
+ Logger = undefined;
486
+ }
487
+ if (Pin2Transport !== undefined) {
488
+ Pin2Transport = undefined;
489
+ }
490
+ if (FileTransport !== undefined) {
491
+ FileTransport = undefined;
492
+ }
493
+ if (done) {
494
+ done();
495
+ }
496
+ });
458
497
  });
459
498
 
460
499
  RedNode.on('input', Input);