node-red-contrib-zwave-js 6.4.0-beta.3 → 6.4.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/CHANGELOG.md CHANGED
@@ -4,15 +4,24 @@
4
4
 
5
5
  **Fixes**
6
6
  - When a new node appears in the UI list, after it gets added to the network, its battery is correctly reported.
7
+ - Fix potential crash, if **Remove Failed Node** is called twice for the same node.
8
+ - Device nodes now clone the received network message, removing a situation where filter node outputs,
9
+ are affected by other device nodes having the same interest in the object.
10
+ - Account for 3 digit node ID's in UI
11
+ - Fixed `event-filter` ignoring `strict `mode
7
12
 
8
13
  **New Features**
9
14
  - Implemented Zwave S2 Security Smart Start.
10
15
  This includes a new mobile UI, allowing you to use it as a device inclusion tool.
16
+ - Expose further driver timeout options
11
17
 
12
18
  **Changes**
13
19
  - Controller ready checks are now made prior to showing any UI modal form, that may depend on the controller.
14
20
  - The battery icon in the node list is now updated, whenever a device transmits an update.
15
- - Bump ZWJS to 8.7.5
21
+ - JSON Keys are now quoted in the UI monitor.
22
+ - The **timestamp** value in event messages are now the time in milliseconds from the unix epoch.
23
+ - Bump ZWJS to 8.8.2
24
+ - Bump serial port to 9.2.8
16
25
 
17
26
  - 6.3.0
18
27
 
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "node-red-contrib-zwave-js",
3
- "version": "6.4.0-beta.3",
3
+ "version": "6.4.0",
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
7
  "express": "^4.17.1",
8
8
  "limiter": "^2.1.0",
9
9
  "lodash": "^4.17.21",
10
- "serialport": "9.2.4",
10
+ "serialport": "9.2.8",
11
11
  "winston": "^3.3.3",
12
12
  "winston-transport": "^4.4.0",
13
- "zwave-js": "^8.7.5",
13
+ "zwave-js": "^8.8.2",
14
14
  "ip": "^1.1.5"
15
15
  },
16
16
  "devDependencies": {
17
- "eslint": "^8.2.0",
18
- "prettier": "^2.4.1"
17
+ "eslint": "^8.3.0",
18
+ "prettier": "^2.5.0"
19
19
  },
20
20
  "engines": {
21
21
  "node": ">=12.22.2",
@@ -36,7 +36,14 @@ module.exports = function (RED) {
36
36
  if (Filter.events.includes(msg.payload.event)) {
37
37
  if (Filter.valueIds.length > 0) {
38
38
  for (const ValueID of Filter.valueIds) {
39
- if (IsValueIDMatch(ValueID, msg, msg.payload.event)) {
39
+ if (
40
+ IsValueIDMatch(
41
+ ValueID,
42
+ msg,
43
+ msg.payload.event,
44
+ Filter.strict
45
+ )
46
+ ) {
40
47
  msg.filter = Filter;
41
48
  SendingArray[ArrayIndex] = msg;
42
49
  node.status({
@@ -88,12 +95,12 @@ module.exports = function (RED) {
88
95
  }
89
96
  }
90
97
 
91
- function IsValueIDMatch(ValueID, MSG, Event) {
98
+ function IsValueIDMatch(ValueID, MSG, Event, Strict) {
92
99
  let Root = MSG.payload.object;
93
100
 
94
101
  if (Event === 'GET_VALUE_RESPONSE') {
95
102
  Root = Root.valueId;
96
- if (!config.strict) {
103
+ if (!Strict) {
97
104
  delete ValueID['endpoint'];
98
105
  }
99
106
  const Result = LD.isMatch(Root, ValueID);
@@ -101,7 +108,7 @@ module.exports = function (RED) {
101
108
  }
102
109
 
103
110
  if (Event === 'VALUE_UPDATED') {
104
- if (!config.strict) {
111
+ if (!Strict) {
105
112
  delete ValueID['endpoint'];
106
113
  }
107
114
  const Result = LD.isMatch(Root, ValueID);
@@ -114,7 +121,7 @@ module.exports = function (RED) {
114
121
  }
115
122
 
116
123
  if (Event === 'VALUE_NOTIFICATION') {
117
- if (!config.strict) {
124
+ if (!Strict) {
118
125
  delete ValueID['endpoint'];
119
126
  }
120
127
  const Result = LD.isMatch(Root, ValueID);
@@ -36,7 +36,7 @@ JSONFormatter.json = {
36
36
  var val = '<span class=json-value>';
37
37
  var str = '<span class=json-string>';
38
38
  var r = pIndent || '';
39
- if (pKey) r = r + key + pKey.replace(/[": ]/g, '') + '</span>: ';
39
+ if (pKey) r = r + key + pKey + '</span>';
40
40
  if (pVal) r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
41
41
  return r + (pEnd || '');
42
42
  },
@@ -825,8 +825,9 @@ const ZwaveJsUI = (function () {
825
825
 
826
826
  case 'EditSmartStart':
827
827
  StepsAPI.setStepIndex(StepList.SmartStartListEdit);
828
+ $('#SSPurgeButton').css({ display: 'inline-block' });
828
829
  $.ajax({
829
- url: '/zwave-js/smart-start-list',
830
+ url: 'zwave-js/smart-start-list',
830
831
  method: 'GET',
831
832
  dataType: 'json',
832
833
  success: function (List) {
@@ -919,7 +920,13 @@ const ZwaveJsUI = (function () {
919
920
  break;
920
921
 
921
922
  case 'Remove':
922
- ControllerCMD('IEAPI', 'beginExclusion', undefined, undefined, true);
923
+ ControllerCMD(
924
+ 'IEAPI',
925
+ 'beginExclusion',
926
+ undefined,
927
+ [$('#ERP').is(':checked')],
928
+ true
929
+ );
923
930
  return;
924
931
  }
925
932
 
@@ -935,6 +942,7 @@ const ZwaveJsUI = (function () {
935
942
  };
936
943
 
937
944
  function ShowIncludeExcludePrompt() {
945
+ const ParentDialog = $('<div>').css({ padding: 10 }).html('Please wait...');
938
946
  const Options = {
939
947
  draggable: false,
940
948
  modal: true,
@@ -944,6 +952,30 @@ const ZwaveJsUI = (function () {
944
952
  title: 'Node Inclusion/Exclusion',
945
953
  minHeight: 75,
946
954
  buttons: [
955
+ {
956
+ id: 'SSPurgeButton',
957
+ text: 'Remove All',
958
+ click: function () {
959
+ const Buttons = {
960
+ 'Yes - Remove': function () {
961
+ ControllerCMD(
962
+ 'IEAPI',
963
+ 'unprovisionAllSmartStart',
964
+ undefined,
965
+ undefined,
966
+ true
967
+ );
968
+ ParentDialog.dialog('destroy');
969
+ }
970
+ };
971
+ modalPrompt(
972
+ 'Are you sure you wish to remove all pre-provisioned device entries (the devices them self wont be removed)',
973
+ 'Purge Provisioning List',
974
+ Buttons,
975
+ true
976
+ );
977
+ }
978
+ },
947
979
  {
948
980
  id: 'IEButton',
949
981
  text: 'Abort',
@@ -955,7 +987,7 @@ const ZwaveJsUI = (function () {
955
987
  ClearIETimer();
956
988
  ClearSecurityCountDown();
957
989
  ControllerCMD('IEAPI', 'stop', undefined, undefined, true);
958
- $(this).dialog('destroy');
990
+ ParentDialog.dialog('destroy');
959
991
  }
960
992
  },
961
993
  {
@@ -982,22 +1014,22 @@ const ZwaveJsUI = (function () {
982
1014
  id: 'IEClose',
983
1015
  text: 'Ok',
984
1016
  click: function () {
985
- $(this).dialog('destroy');
1017
+ ParentDialog.dialog('destroy');
986
1018
  }
987
1019
  }
988
1020
  ]
989
1021
  };
990
1022
 
991
- const IncludeForm = $('<div>').css({ padding: 10 }).html('Please wait...');
992
- IncludeForm.dialog(Options);
993
- IncludeForm.html('');
1023
+ ParentDialog.dialog(Options);
1024
+ ParentDialog.html('');
994
1025
 
995
- IncludeForm.append($('#TPL_Include').html());
1026
+ ParentDialog.append($('#TPL_Include').html());
996
1027
  const Steps = $('#IncludeWizard').steps({ showFooterButtons: false });
997
1028
  StepsAPI = Steps.data('plugin_Steps');
998
1029
 
999
1030
  $('#SmartStartCommit').css({ display: 'none' });
1000
1031
  $('#IEClose').css({ display: 'none' });
1032
+ $('#SSPurgeButton').css({ display: 'none' });
1001
1033
  }
1002
1034
 
1003
1035
  function ShowReplacePrompt() {
@@ -1179,15 +1211,25 @@ const ZwaveJsUI = (function () {
1179
1211
  window.open(`https://devices.zwave-js.io/?jumpTo=${id}`, '_blank');
1180
1212
  }
1181
1213
 
1214
+ let Removing = false;
1182
1215
  function RemoveFailedNode() {
1216
+ if (Removing) {
1217
+ modalAlert(
1218
+ 'A node is already being removed, please allow a minute or 2.',
1219
+ 'Could Not Remove Node'
1220
+ );
1221
+ return;
1222
+ }
1183
1223
  const Buttons = {
1184
1224
  'Yes - Remove': function () {
1225
+ Removing = true;
1185
1226
  ControllerCMD('ControllerAPI', 'removeFailedNode', undefined, [
1186
1227
  selectedNode
1187
1228
  ]).catch((err) => {
1188
1229
  if (err.status !== 504) {
1189
1230
  modalAlert(err.responseText, 'Could Not Remove Node');
1190
1231
  }
1232
+ Removing = false;
1191
1233
  });
1192
1234
  }
1193
1235
  };
@@ -10,11 +10,11 @@
10
10
  display: flex;
11
11
  }
12
12
  .zwave-js-node-row-id {
13
- width: 5%;
13
+ width: 10%;
14
14
  padding-left: 10px;
15
15
  }
16
16
  .zwave-js-node-row-name {
17
- width: 50%;
17
+ width: 45%;
18
18
  }
19
19
  .zwave-js-node-row-status {
20
20
  width: 11%;
@@ -142,15 +142,15 @@ table#zwave-js-associations-table tr:first-of-type {
142
142
  width: 130px;
143
143
  }
144
144
 
145
- #CommandLog{
145
+ #CommandLog {
146
146
  z-index: -100;
147
147
  }
148
148
 
149
- .MonitorEntry{
150
- background-color: rgb(245,245,245);
149
+ .MonitorEntry {
150
+ background-color: rgb(245, 245, 245);
151
151
  border-style: solid;
152
152
  border-width: 2px;
153
- border-color: rgb(210,210,210);
153
+ border-color: rgb(210, 210, 210);
154
154
  padding: 5px;
155
155
  -webkit-border-radius: 8px;
156
156
  -moz-border-radius: 8px;
@@ -158,12 +158,11 @@ table#zwave-js-associations-table tr:first-of-type {
158
158
  }
159
159
 
160
160
  .json-key {
161
- color: rgb(199,48,53);
161
+ color: rgb(199, 48, 53);
162
162
  }
163
163
  .json-value {
164
- color: rgb(243,135,48);
164
+ color: rgb(243, 135, 48);
165
165
  }
166
166
  .json-string {
167
- color: rgb(130,152,52);
167
+ color: rgb(130, 152, 52);
168
168
  }
169
-
@@ -114,7 +114,7 @@ module.exports = function (RED) {
114
114
  }
115
115
 
116
116
  function processEventMessage(MSG) {
117
- RedNode.send(MSG);
117
+ RedNode.send(RED.util.cloneMessage(MSG));
118
118
  }
119
119
 
120
120
  RedNode.on('input', Input);
@@ -45,7 +45,8 @@
45
45
  </td>
46
46
  <td style='text-align: left; vertical-align: middle; '>
47
47
  S2 when supported, else S0 only when necessary, no encryption
48
- otherwise (recommended).<br /><br />
48
+ otherwise (recommended).
49
+ <div style='height: 7px !important'></div>
49
50
  <input type='checkbox' id='PS0' />
50
51
  <label for='S0'>Prefer S0 over no encryption</label>
51
52
  </td>
@@ -97,7 +98,10 @@
97
98
  >Remove Node</button>
98
99
  </td>
99
100
  <td style='text-align: left; vertical-align: middle; '>
100
- Remove a node from your network
101
+ Remove a node from your Network
102
+ <div style='height: 7px !important'></div>
103
+ <input type='checkbox' id='ERP' />
104
+ <label for='ERP'>Remove from provisioning list also</label>
101
105
  </td>
102
106
  </tr>
103
107
  <tr>
@@ -496,7 +500,7 @@
496
500
  <p>The scanned devices have now been added to a provisioning list.</p>
497
501
  <p>Once the devices have been powered up, they should broadcast a 'Here
498
502
  I Am' type message.</p>
499
- <p>The rate at which this happens, is down the device, but once the
503
+ <p>The rate at which this happens, is down to the device, but once the
500
504
  broadcast has been recieved, the device should get interviewed and
501
505
  added to your network.</p>
502
506
  </div>
@@ -759,6 +763,8 @@
759
763
  ackTimeout: { value: undefined },
760
764
  controllerTimeout: { value: undefined },
761
765
  sendResponseTimeout: { value: undefined },
766
+ sendDataCallback: { value: undefined },
767
+ serialAPIStarted: { value: undefined },
762
768
  logLevelPin: { value: 'none' },
763
769
  logLevel: { value: 'none' },
764
770
  logFile: { value: undefined },
@@ -910,6 +916,10 @@
910
916
  <label for="node-input-controllerTimeout" style="width:130px"><i class="fa fa-pencil"></i> Controller</label>
911
917
  <input type="text" id="node-input-controllerTimeout" placeholder="Use Default">
912
918
  </div>
919
+ <div class="form-row">
920
+ <label for="node-input-sendDataCallback" style="width:130px"><i class="fa fa-pencil"></i> Callback</label>
921
+ <input type="text" id="node-input-sendDataCallback" placeholder="Use Default">
922
+ </div>
913
923
  <div class="form-row">
914
924
  <label for="node-input-sendResponseTimeout" style="width:130px"><i class="fa fa-pencil"></i> Req -> Res</label>
915
925
  <input type="text" id="node-input-sendResponseTimeout" placeholder="Use Default">
@@ -974,6 +984,10 @@
974
984
  <label for="node-input-softResetUSB" style="width:130px"><i class="fa fa-pencil"></i> Soft Reset USB</label>
975
985
  <input type="checkbox" id="node-input-softResetUSB">
976
986
  </div>
987
+ <div class="form-row">
988
+ <label for="node-input-serialAPIStarted" style="width:130px"><i class="fa fa-pencil"></i> SR Timeout</label>
989
+ <input type="text" id="node-input-serialAPIStarted" placeholder="Use Default">
990
+ </div>
977
991
  <br />
978
992
  <p>
979
993
  <strong>Version Information</strong>
@@ -236,6 +236,23 @@ module.exports = function (RED) {
236
236
  'Enabled'
237
237
  );
238
238
  DriverOptions.enableSoftReset = true;
239
+
240
+ if (
241
+ config.serialAPIStarted !== undefined &&
242
+ config.serialAPIStarted.length > 0
243
+ ) {
244
+ Log(
245
+ 'debug',
246
+ 'NDERED',
247
+ undefined,
248
+ '[options] [timeouts.serialAPIStarted]',
249
+ config.serialAPIStarted
250
+ );
251
+ DriverOptions.timeouts = {};
252
+ DriverOptions.timeouts.serialAPIStarted = parseInt(
253
+ config.serialAPIStarted
254
+ );
255
+ }
239
256
  } else {
240
257
  Log(
241
258
  'debug',
@@ -293,7 +310,9 @@ module.exports = function (RED) {
293
310
  }
294
311
 
295
312
  // Timeout
296
- DriverOptions.timeouts = {};
313
+ if (!DriverOptions.hasOwnProperty('timeouts')) {
314
+ DriverOptions.timeouts = {};
315
+ }
297
316
  if (config.ackTimeout !== undefined && config.ackTimeout.length > 0) {
298
317
  Log(
299
318
  'debug',
@@ -317,6 +336,21 @@ module.exports = function (RED) {
317
336
  );
318
337
  DriverOptions.timeouts.response = parseInt(config.controllerTimeout);
319
338
  }
339
+ if (
340
+ config.sendDataCallback !== undefined &&
341
+ config.sendDataCallback.length > 0
342
+ ) {
343
+ Log(
344
+ 'debug',
345
+ 'NDERED',
346
+ undefined,
347
+ '[options] [timeouts.sendDataCallback]',
348
+ config.sendDataCallback
349
+ );
350
+ DriverOptions.timeouts.sendDataCallback = parseInt(
351
+ config.sendDataCallback
352
+ );
353
+ }
320
354
  if (
321
355
  config.sendResponseTimeout !== undefined &&
322
356
  config.sendResponseTimeout.length > 0
@@ -485,7 +519,12 @@ module.exports = function (RED) {
485
519
  'S2_Authenticated',
486
520
  'S2_AccessControl'
487
521
  ],
488
- 1: ['S0_Legacy', 'S2_Unauthenticated', 'S2_Authenticated', 'S2_AccessControl'],
522
+ 1: [
523
+ 'S0_Legacy',
524
+ 'S2_Unauthenticated',
525
+ 'S2_Authenticated',
526
+ 'S2_AccessControl'
527
+ ],
489
528
  3: ['S0_Legacy'],
490
529
  4: ['S2_Unauthenticated', 'S2_Authenticated', 'S2_AccessControl']
491
530
  };
@@ -525,6 +564,14 @@ module.exports = function (RED) {
525
564
  CheckKey(Params[0]);
526
565
  break;
527
566
 
567
+ case 'unprovisionAllSmartStart':
568
+ const Entries = Driver.controller.getProvisioningEntries();
569
+ for (let i = 0; i < Entries.length; i++) {
570
+ const Entry = Entries[i];
571
+ Driver.controller.unprovisionSmartStartNode(Entry.dsk);
572
+ }
573
+ break;
574
+
528
575
  case 'unprovisionSmartStartNode':
529
576
  Driver.controller.unprovisionSmartStartNode(Params[0]);
530
577
  break;
@@ -541,7 +588,7 @@ module.exports = function (RED) {
541
588
  break;
542
589
 
543
590
  case 'beginExclusion':
544
- await Driver.controller.beginExclusion();
591
+ await Driver.controller.beginExclusion(Params[0]);
545
592
  break;
546
593
 
547
594
  case 'grantClasses':
@@ -1326,7 +1373,7 @@ module.exports = function (RED) {
1326
1373
  }
1327
1374
  }
1328
1375
  PL.event = Subject;
1329
- PL.timestamp = new Date().toJSON();
1376
+ PL.timestamp = new Date().getTime();
1330
1377
  if (Value !== undefined) {
1331
1378
  PL.object = Value;
1332
1379
  }