iobroker.zigbee 1.8.0 → 1.8.3

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 (89) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.json +37 -0
  3. package/.github/FUNDING.yml +3 -0
  4. package/.github/auto-merge.yml +17 -0
  5. package/.github/dependabot.yml +24 -0
  6. package/.github/stale.yml +13 -0
  7. package/.github/workflows/codeql.yml +41 -0
  8. package/.github/workflows/dependabot-automerge.yml +22 -0
  9. package/.github/workflows/test-and-release.yml +149 -0
  10. package/.releaseconfig.json +3 -0
  11. package/.travis/wiki.sh +28 -0
  12. package/.travis.yml +41 -0
  13. package/README.md +32 -9
  14. package/admin/admin.js +466 -482
  15. package/admin/i18n/de/translations.json +2 -2
  16. package/admin/index_m.html +1 -1
  17. package/admin/tab_m.html +3 -44
  18. package/admin/words.js +2 -2
  19. package/gulpfile.js +464 -0
  20. package/io-package.json +19 -26
  21. package/lib/backup.js +2 -2
  22. package/lib/binding.js +24 -23
  23. package/lib/colors.js +14 -16
  24. package/lib/commands.js +82 -89
  25. package/lib/developer.js +7 -6
  26. package/lib/devices.js +153 -144
  27. package/lib/exclude.js +36 -30
  28. package/lib/exposes.js +111 -106
  29. package/lib/groups.js +54 -53
  30. package/lib/json.js +4 -3
  31. package/lib/networkmap.js +2 -2
  32. package/lib/ota.js +15 -23
  33. package/lib/rgb.js +44 -47
  34. package/lib/seriallist.js +16 -21
  35. package/lib/states.js +496 -482
  36. package/lib/statescontroller.js +164 -170
  37. package/lib/utils.js +21 -22
  38. package/lib/zbBaseExtension.js +4 -4
  39. package/lib/zbDelayedAction.js +13 -5
  40. package/lib/zbDeviceAvailability.js +44 -47
  41. package/lib/zbDeviceConfigure.js +19 -7
  42. package/lib/zbDeviceEvent.js +4 -3
  43. package/lib/zigbeecontroller.js +96 -88
  44. package/main.js +133 -149
  45. package/package.json +15 -29
  46. package/test/integration.js +5 -0
  47. package/test/mocha.custom.opts +2 -0
  48. package/test/mocha.setup.js +14 -0
  49. package/test/package.js +5 -0
  50. package/test/unit.js +5 -0
  51. package/docs/de/img/CC2531.png +0 -0
  52. package/docs/de/img/CC2538_CC2592_PA.PNG +0 -0
  53. package/docs/de/img/CC2591.png +0 -0
  54. package/docs/de/img/boards.jpg +0 -0
  55. package/docs/de/img/cc26x2r.PNG +0 -0
  56. package/docs/de/img/results.jpg +0 -0
  57. package/docs/de/img/sku_429478_2.png +0 -0
  58. package/docs/de/img/sku_429601_2.png +0 -0
  59. package/docs/de/readme.md +0 -27
  60. package/docs/en/img/CC2531.png +0 -0
  61. package/docs/en/img/CC2591.png +0 -0
  62. package/docs/en/img/deconz.png +0 -0
  63. package/docs/en/img/sku_429478_2.png +0 -0
  64. package/docs/en/img/sku_429601_2.png +0 -0
  65. package/docs/en/readme.md +0 -30
  66. package/docs/flashing_via_arduino_(en).md +0 -110
  67. package/docs/ru/img/CC2531.png +0 -0
  68. package/docs/ru/img/CC2591.png +0 -0
  69. package/docs/ru/img/sku_429478_2.png +0 -0
  70. package/docs/ru/img/sku_429601_2.png +0 -0
  71. package/docs/ru/readme.md +0 -28
  72. package/docs/tutorial/CC2530_20190425.zip +0 -0
  73. package/docs/tutorial/CC2530_CC2591_20190515.zip +0 -0
  74. package/docs/tutorial/CC2530_CC2592_20190515.zip +0 -0
  75. package/docs/tutorial/CC2531_20190425.zip +0 -0
  76. package/docs/tutorial/adm5_1.PNG +0 -0
  77. package/docs/tutorial/adm5_2.PNG +0 -0
  78. package/docs/tutorial/cat.PNG +0 -0
  79. package/docs/tutorial/groups-1.png +0 -0
  80. package/docs/tutorial/groups-2.png +0 -0
  81. package/docs/tutorial/inst.PNG +0 -0
  82. package/docs/tutorial/reflash-finish.PNG +0 -0
  83. package/docs/tutorial/reflash-step0.png +0 -0
  84. package/docs/tutorial/reflash-step1.PNG +0 -0
  85. package/docs/tutorial/reflash-step2.PNG +0 -0
  86. package/docs/tutorial/settings.png +0 -0
  87. package/docs/tutorial/tab-dev-1.png +0 -0
  88. package/docs/tutorial/zigbee.png +0 -0
  89. package/docs/tutorial/zigbee15.png +0 -0
@@ -118,12 +118,13 @@ class ZigbeeController extends EventEmitter {
118
118
  }
119
119
 
120
120
  this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
+
121
122
  } catch (e) {
122
123
  this.sendError(e);
123
- this.error(`Starting zigbee-herdsman problem : ${JSON.stringify(e.message)}`);
124
+ this.error('Starting zigbee-herdsman problem : ' + JSON.stringify(e.message));
124
125
  throw 'Error herdsman start';
125
126
  }
126
- // Check if we have to turn off the LED
127
+ // Check if we have to turn off the led
127
128
  try {
128
129
  if (this.disableLed) {
129
130
  this.info('Disable LED');
@@ -140,7 +141,7 @@ class ZigbeeController extends EventEmitter {
140
141
  let powerText = 'normal';
141
142
 
142
143
  if (this.transmitPower != '0') {
143
- switch (this.transmitPower) {
144
+ switch(this.transmitPower) {
144
145
  case '-22':
145
146
  powerText = 'low';
146
147
  break;
@@ -156,7 +157,7 @@ class ZigbeeController extends EventEmitter {
156
157
  }
157
158
 
158
159
 
159
- this.info(` --> transmitPower : ${powerText}`);
160
+ this.info(' --> transmitPower : ' + powerText);
160
161
  try {
161
162
  await this.herdsman.setTransmitPower(this.transmitPower);
162
163
  } catch (e) {
@@ -164,6 +165,7 @@ class ZigbeeController extends EventEmitter {
164
165
  this.info('Unable to set transmit power, unsupported function.');
165
166
  }
166
167
 
168
+
167
169
  // Call extensions
168
170
  this.callExtensionMethod('onZigbeeStarted', []);
169
171
 
@@ -174,21 +176,20 @@ class ZigbeeController extends EventEmitter {
174
176
  } else {
175
177
  this.info(`Currently no devices.`);
176
178
  }
177
-
178
179
  for (const device of devices) {
179
180
  const entity = await this.resolveEntity(device);
180
- this.adapter.getObject(device.ieeeAddr.substr(2), (err, obj) => {
181
- if (obj && obj.common && obj.common.deactivated) {
181
+ this.adapter.getObject(device.ieeeAddr.substr(2),(err, obj) => {
182
+ if (obj && obj.common && obj.common.deactivated)
183
+ {
182
184
  this.callExtensionMethod('deregisterDevicePing', [device, entity]);
183
- } else {
185
+ }
186
+ else {
184
187
  this.callExtensionMethod('registerDevicePing', [device, entity]);
185
188
  }
186
189
  });
187
190
  // ensure that objects for all found clients are present
188
191
 
189
- if (entity.mapped) {
190
- this.emit('new', entity);
191
- }
192
+ if (entity.mapped) this.emit('new', entity);
192
193
  this.info(
193
194
  (entity.device.ieeeAddr) +
194
195
  ` (addr ${entity.device.networkAddress}): ` +
@@ -260,7 +261,8 @@ class ZigbeeController extends EventEmitter {
260
261
 
261
262
  async getGroups() {
262
263
  try {
263
- return await this.herdsman.getGroups();
264
+ const rv = await this.herdsman.getGroups();
265
+ return rv;
264
266
  } catch (error) {
265
267
  this.sendError(error);
266
268
  this.error(JSON.stringify(error));
@@ -269,12 +271,12 @@ class ZigbeeController extends EventEmitter {
269
271
  }
270
272
 
271
273
  async removeGroupById(id) {
272
- const group = await this.getGroupByID(id);
274
+ const group = await this.getGroupByID(id);
273
275
  try {
274
- group && group.removeFromDatabase();
276
+ if (group) group.removeFromDatabase();
275
277
  } catch (error) {
276
278
  this.sendError(error);
277
- this.error(`error in removeGroupById: ${error}`);
279
+ this.error('error in removeGroupById: ' + error);
278
280
  }
279
281
  }
280
282
 
@@ -288,15 +290,16 @@ class ZigbeeController extends EventEmitter {
288
290
  }
289
291
 
290
292
  async verifyGroupExists(id) {
291
- const nid = (typeof (id) === 'number' ? id : parseInt(id));
293
+ const nid = (typeof(id) === 'number' ? id:parseInt(id));
292
294
  let group = await this.herdsman.getGroupByID(nid);
293
295
  if (!group) {
294
296
  group = await this.herdsman.createGroup(nid);
295
297
  group.toZigbee = groupConverters;
296
298
  group.model = 'group';
297
- this.debug(`verifyGroupExists: created group ${nid}`);
298
- } else {
299
- this.debug(`verifyGroupExists: group ${nid} exists`);
299
+ this.debug('verifyGroupExists: created group ' + nid);
300
+ }
301
+ else {
302
+ this.debug('verifyGroupExists: group ' + nid + ' exists');
300
303
  }
301
304
 
302
305
  }
@@ -313,17 +316,15 @@ class ZigbeeController extends EventEmitter {
313
316
  const device = this.getDeviceByNetworkAddress(nwk);
314
317
  if (device && device.ieeeAddr) members.push( { ieee:device.ieeeAddr, model:device.modelID, epid:epid, ep:member } );
315
318
  }
316
- } else {
319
+ }
320
+ else {
317
321
  return undefined;
318
322
  }
319
323
 
320
324
  } catch (error) {
321
325
  this.sendError(error);
322
- if (error) {
323
- this.error(`getGroupMembersFromController: error is ${JSON.stringify(error)} ${JSON.stringify(new Error().stack)}`);
324
- } else {
325
- this.error('unidentified error in getGroupMembersFromController');
326
- }
326
+ if (error) this.error('getGroupMembersFromController: error is ' + JSON.stringify(error) + ' ' + JSON.stringify(new Error().stack));
327
+ else this.error('unidentifed error in getGroupMembersFromController');
327
328
  }
328
329
  return members;
329
330
  }
@@ -403,7 +404,7 @@ class ZigbeeController extends EventEmitter {
403
404
  }
404
405
  }
405
406
 
406
- async incMsgHandler(message) {
407
+ async incMsgHandler(message){
407
408
  this.debug('incoming msg', message);
408
409
  const device = await this.herdsman.getDeviceByIeeeAddr(message.srcaddr);
409
410
  if (!device) {
@@ -461,8 +462,8 @@ class ZigbeeController extends EventEmitter {
461
462
  } else {
462
463
  this.info('Zigbee: disabling joining new devices.');
463
464
  }
464
-
465
- try {
465
+ try
466
+ {
466
467
  if (permitTime && !this.herdsman.getPermitJoin()) {
467
468
  clearInterval(this._permitJoinInterval);
468
469
  this._permitJoinTime = permitTime;
@@ -508,7 +509,6 @@ class ZigbeeController extends EventEmitter {
508
509
  this.debug(`Force remove`);
509
510
  }
510
511
  }
511
-
512
512
  try {
513
513
  await device.removeFromDatabase();
514
514
  } catch (error) {
@@ -518,7 +518,7 @@ class ZigbeeController extends EventEmitter {
518
518
  this.debug(`Failed to remove from DB ${error.stack}`);
519
519
  }
520
520
  this.debug('Remove successful.');
521
- callback && callback();
521
+ if (callback) callback();
522
522
  this.callExtensionMethod(
523
523
  'onDeviceRemove',
524
524
  [device],
@@ -527,7 +527,7 @@ class ZigbeeController extends EventEmitter {
527
527
  } catch (error) {
528
528
  this.sendError(error);
529
529
  this.error(`Failed to remove ${error.stack}`);
530
- callback && callback(`Failed to remove ${error.stack}`);
530
+ if (callback) callback(`Failed to remove ${error.stack}`);
531
531
  }
532
532
  }
533
533
 
@@ -536,7 +536,7 @@ class ZigbeeController extends EventEmitter {
536
536
  try {
537
537
  this.debug('handleDeviceLeave', message);
538
538
  const entity = await this.resolveEntity(message.device || message.ieeeAddr);
539
- const friendlyName = entity ? entity.name : message.ieeeAddr;
539
+ const friendlyName = (entity) ? entity.name : message.ieeeAddr;
540
540
  this.debug(`Device '${friendlyName}' left the network`);
541
541
  this.emit('leave', message.ieeeAddr);
542
542
  // Call extensions
@@ -566,7 +566,7 @@ class ZigbeeController extends EventEmitter {
566
566
  this.sendError(error);
567
567
  this.error(`Failed to handleDeviceLeave ${error.stack}`);
568
568
  }
569
-
569
+
570
570
  this.emit('pairing', `Device '${friendlyName}' announced itself`);
571
571
  if (!this.herdsman.getPermitJoin()) this.callExtensionMethod('registerDevicePing', [message.device, entity]);
572
572
  // if has modelID so can create device
@@ -650,11 +650,12 @@ class ZigbeeController extends EventEmitter {
650
650
 
651
651
  async getMap(callback) {
652
652
  try {
653
+
653
654
  const devices = this.herdsman.getDevices(true);
654
655
  const lqis = [];
655
656
  const routing = [];
656
657
 
657
- for (const device of devices.filter((d) => d.type !== 'EndDevice')) {
658
+ for (const device of devices.filter((d) => d.type != 'EndDevice')) {
658
659
  const resolved = await this.resolveEntity(device);
659
660
  let result;
660
661
 
@@ -678,7 +679,7 @@ class ZigbeeController extends EventEmitter {
678
679
 
679
680
  if (result !== undefined) {
680
681
  for (const dev of result.neighbors) {
681
- if (dev !== undefined && dev.ieeeAddr !== '0xffffffffffffffff') {
682
+ if (dev.ieeeAddr !== '0xffffffffffffffff' && dev !== undefined) {
682
683
  lqis.push({
683
684
  parent: resolved.device.ieeeAddr,
684
685
  networkAddress: dev.networkAddress,
@@ -686,7 +687,7 @@ class ZigbeeController extends EventEmitter {
686
687
  lqi: dev.linkquality,
687
688
  relationship: dev.relationship,
688
689
  depth: dev.depth,
689
- status: dev.linkquality > 0 ? 'online' : 'offline',
690
+ status: (dev.linkquality > 0) ? 'online' : 'offline',
690
691
  });
691
692
  }
692
693
  }
@@ -717,10 +718,11 @@ class ZigbeeController extends EventEmitter {
717
718
  }
718
719
  }
719
720
  this.debug(`Routing table succeeded for '${resolved.name}'`);
721
+
720
722
  }
721
723
  this.debug(`Get map succeeded ${safeJsonStringify(lqis)}`);
722
724
 
723
- callback && callback({lqis, routing});
725
+ if (callback) callback({lqis: lqis, routing: routing});
724
726
  } catch (error) {
725
727
  this.sendError(error);
726
728
  this.debug(`Failed to get map: ${safeJsonStringify(error.stack)}`);
@@ -753,7 +755,7 @@ class ZigbeeController extends EventEmitter {
753
755
  if (type === 'foundation') {
754
756
  cfg.disableDefaultResponse = true;
755
757
  if (cmd === 'read' && !Array.isArray(zclData)) {
756
- // needs to be iterable (string[] | number [])
758
+ // needs to be iterateable (string[] | number [])
757
759
  zclData[Symbol.iterator] = function* () {
758
760
  let k;
759
761
  for (k in this) {
@@ -767,15 +769,17 @@ class ZigbeeController extends EventEmitter {
767
769
  } else {
768
770
  result = await endpoint[cmd](cid, zclData, cfg);
769
771
  }
770
- callback && callback(undefined, result);
771
- } else if (type === 'functionalResp') {
772
- cfg.disableDefaultResponse = false;
773
- const result = await endpoint.commandResponse(cid, cmd, zclData, cfg, zclSeqNum);
774
- callback && callback(undefined, result);
775
- } else {
772
+ if (callback) callback(undefined, result);
773
+ }
774
+ else if(type === 'functionalResp'){
775
+ cfg.disableDefaultResponse = false;
776
+ const result = await endpoint.commandResponse(cid, cmd, zclData, cfg, zclSeqNum);
777
+ if (callback) callback(undefined, result);
778
+ }
779
+ else {
776
780
  cfg.disableDefaultResponse = false;
777
781
  const result = await endpoint.command(cid, cmd, zclData, cfg);
778
- callback && callback(undefined, result);
782
+ if (callback) callback(undefined, result);
779
783
  }
780
784
  }
781
785
 
@@ -786,61 +790,66 @@ class ZigbeeController extends EventEmitter {
786
790
  this.debug(`addDevFromGroup - entity: ${safeJsonStringify(entity)}`);
787
791
  this.debug(`addDevFromGroup - group: ${safeJsonStringify(group)}`);
788
792
  if (epid != undefined) {
789
- for (const ep of entity.endpoints) {
790
- if (ep.ID === epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))) {
791
- this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`);
792
- await (ep.addToGroup(group.mapped));
793
- }
793
+ for (const ep of entity.endpoints) {
794
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
795
+ {
796
+ this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`)
797
+ await(ep.addToGroup(group.mapped));
794
798
  }
799
+ }
795
800
 
796
- } else {
797
- if (entity.endpoint.inputClusters.includes(4)) {
798
- this.debug(`adding endpoint ${entity.endpoint.ID} to group`);
801
+ }
802
+ else
803
+ {
804
+ if (entity.endpoint.inputClusters.includes(4))
805
+ {
806
+ this.debug(`adding endpoint ${entity.endpoint.ID} to group`)
799
807
  await entity.endpoint.addToGroup(group.mapped);
800
- } else {
808
+ }
809
+ else {
801
810
  let added = false;
802
- for (const ep of entity.endpoints) {
803
- if (ep.inputClusters.includes(4)) {
804
- this.debug(`adding endpoint ${ep.ID} to group`);
811
+ for (const ep of entity.endpoints)
812
+ {
813
+ if (ep.inputClusters.includes(4))
814
+ {
815
+ this.debug(`adding endpoint ${ep.ID} to group`)
805
816
  await ep.addToGroup(group.mapped);
806
817
  added = true;
807
818
  break;
808
819
  }
809
820
  }
810
- if (!added) {
811
- throw ('cluster genGroups not supported');
812
- }
821
+ if (!added) throw ('cluster genGroups not supported');
813
822
  }
814
823
  }
815
824
  } catch (error) {
816
825
  this.sendError(error);
817
826
  this.error(`Exception when trying to Add ${devId} to group ${groupId}`, error);
818
- return {error: `Failed to add ${devId} to group ${groupId}: ${JSON.stringify(error)}`};
827
+ return { error:`Failed to add ${devId} to group ${groupId}: ${JSON.stringify(error)}` };
819
828
  }
820
829
  return {};
821
830
  }
822
831
 
823
832
  async removeDevFromGroup(devId, groupId, epid) {
824
- let entity;
825
- try {
826
- entity = await this.resolveEntity(devId);
827
- const group = await this.resolveEntity(groupId);
828
- this.debug(`removeDevFromGroup - entity: ${safeJsonStringify(entity)}`);
829
- this.debug(`removeDevFromGroup - group: ${safeJsonStringify(group)}`);
830
- if (epid != undefined) {
831
- for (const ep of entity.endpoints) {
832
- if (ep.ID === epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))) {
833
- this.debug(`removing endpoint ${ep.ID} (${epid}) group ${groupId}`);
834
- await ep.removeFromGroup(group.mapped);
835
- }
836
- }
837
- } else await entity.endpoint.removeFromGroup(group.mapped);
838
- } catch (error) {
839
- this.sendError(error);
840
- this.error(`Exception when trying remove ${devId} (ep ${epid ? epid : (entity ? entity.endpoint.ID : '')}) from group ${devId}`, error);
841
- return {error: `Failed to remove dev ${devId} (ep ${epid ? epid : (entity ? entity.endpoint.ID : '')}) from group ${devId}`};
842
- }
843
- return {};
833
+ try {
834
+ const entity = await this.resolveEntity(devId);
835
+ const group = await this.resolveEntity(groupId);
836
+ this.debug(`removeDevFromGroup - entity: ${safeJsonStringify(entity)}`);
837
+ this.debug(`removeDevFromGroup - group: ${safeJsonStringify(group)}`);
838
+ if (epid != undefined) {
839
+ for (const ep of entity.endpoints) {
840
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
841
+ {
842
+ this.debug(`removing endpoint ${ep.ID} (${epid}) group ${groupId}`)
843
+ await(ep.removeFromGroup(group.mapped))
844
+ }
845
+ }
846
+ } else await entity.endpoint.removeFromGroup(group.mapped);
847
+ } catch (error) {
848
+ this.sendError(error);
849
+ this.error(`Exception when trying remove ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`, error);
850
+ return { error: `Failed to remove dev ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`};
851
+ }
852
+ return {};
844
853
  }
845
854
 
846
855
  async removeDevFromAllGroups(devId) {
@@ -848,15 +857,14 @@ class ZigbeeController extends EventEmitter {
848
857
  const entity = await this.resolveEntity(devId);
849
858
  this.debug(`entity: ${safeJsonStringify(entity)}`);
850
859
  for (const ep of entity.endpoints) {
851
- if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)) {
852
- await ep.removefromAllGroups();
853
- }
860
+ if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))
861
+ await ep.removefromAllGroups();
854
862
  }
855
863
  //await entity.endpoint.removeFromAllGroups();
856
864
  } catch (error) {
857
865
  this.sendError(error);
858
866
  this.error(`Exception when trying remove ${devId} from all groups`, error);
859
- return {error: `Failed to remove dev ${devId} from all groups: ${error}`};
867
+ return { error: `Failed to remove dev ${devId} from all groups: ${error}`};
860
868
  }
861
869
  return {};
862
870
  }
@@ -866,7 +874,7 @@ class ZigbeeController extends EventEmitter {
866
874
  target = !target ? this.getCoordinator() : target;
867
875
 
868
876
  this.debug(`Binding ${log}`);
869
- ep.bind(cluster, target, error => {
877
+ ep.bind(cluster, target, (error) => {
870
878
  if (error) {
871
879
  this.sendError(error);
872
880
  this.error(`Failed to bind ${log} - (${error})`);
@@ -897,11 +905,11 @@ class ZigbeeController extends EventEmitter {
897
905
  reset(mode, callback) {
898
906
  try {
899
907
  this.herdsman.reset(mode);
900
- callback && callback();
908
+ if (callback) callback();
901
909
  } catch (error) {
902
910
  this.sendError(error);
903
911
  this.error(`Failed to reset ${error.stack}`);
904
- callback && callback(error);
912
+ if (callback) callback(error);
905
913
  }
906
914
  }
907
915