iobroker.zigbee 1.8.10 → 1.8.13

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 (104) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +417 -400
  3. package/admin/adapter-settings.js +244 -244
  4. package/admin/admin.js +2981 -2981
  5. package/admin/i18n/de/translations.json +108 -108
  6. package/admin/i18n/en/translations.json +108 -108
  7. package/admin/i18n/es/translations.json +102 -102
  8. package/admin/i18n/fr/translations.json +108 -108
  9. package/admin/i18n/it/translations.json +102 -102
  10. package/admin/i18n/nl/translations.json +108 -108
  11. package/admin/i18n/pl/translations.json +108 -108
  12. package/admin/i18n/pt/translations.json +102 -102
  13. package/admin/i18n/ru/translations.json +108 -108
  14. package/admin/i18n/uk/translations.json +108 -108
  15. package/admin/i18n/zh-cn/translations.json +102 -102
  16. package/admin/img/philips_hue_lom001.png +0 -0
  17. package/admin/index.html +159 -159
  18. package/admin/index_m.html +1356 -1356
  19. package/admin/moment.min.js +1 -1
  20. package/admin/shuffle.min.js +2 -2
  21. package/admin/tab_m.html +1009 -1009
  22. package/admin/vis-network.min.css +1 -1
  23. package/admin/vis-network.min.js +27 -27
  24. package/admin/words.js +110 -110
  25. package/docs/de/basedocu.md +19 -19
  26. package/docs/de/img/Bild10.png +0 -0
  27. package/docs/de/img/Bild12.png +0 -0
  28. package/docs/de/img/Bild13.png +0 -0
  29. package/docs/de/img/Bild14.png +0 -0
  30. package/docs/de/img/Bild15.png +0 -0
  31. package/docs/de/img/Bild16.png +0 -0
  32. package/docs/de/img/Bild17.png +0 -0
  33. package/docs/de/img/Bild18.png +0 -0
  34. package/docs/de/img/Bild19.png +0 -0
  35. package/docs/de/img/Bild2.png +0 -0
  36. package/docs/de/img/Bild20.png +0 -0
  37. package/docs/de/img/Bild21.png +0 -0
  38. package/docs/de/img/Bild22.png +0 -0
  39. package/docs/de/img/Bild23.png +0 -0
  40. package/docs/de/img/Bild24.png +0 -0
  41. package/docs/de/img/Bild25.png +0 -0
  42. package/docs/de/img/Bild26.png +0 -0
  43. package/docs/de/img/Bild28.png +0 -0
  44. package/docs/de/img/Bild3.png +0 -0
  45. package/docs/de/img/Bild30.png +0 -0
  46. package/docs/de/img/Bild31.png +0 -0
  47. package/docs/de/img/Bild32.png +0 -0
  48. package/docs/de/img/Bild33.png +0 -0
  49. package/docs/de/img/Bild34.png +0 -0
  50. package/docs/de/img/Bild35.png +0 -0
  51. package/docs/de/img/Bild36.png +0 -0
  52. package/docs/de/img/Bild37.png +0 -0
  53. package/docs/de/img/Bild4.png +0 -0
  54. package/docs/de/img/Bild5.jpg +0 -0
  55. package/docs/de/img/Bild6.png +0 -0
  56. package/docs/de/img/Bild7.png +0 -0
  57. package/docs/de/img/Bild8.png +0 -0
  58. package/docs/de/img/Bild9.png +0 -0
  59. package/docs/de/img/software1.jpg +0 -0
  60. package/docs/de/img/sonoff.png +0 -0
  61. package/docs/de/readme.md +126 -27
  62. package/docs/en/img/Bild13.png +0 -0
  63. package/docs/en/img/Bild18.png +0 -0
  64. package/docs/en/img/Bild23.png +0 -0
  65. package/docs/en/img/Bild25.png +0 -0
  66. package/docs/en/img/Bild26.png +0 -0
  67. package/docs/en/img/Bild4.png +0 -0
  68. package/docs/en/img/Bild9.png +0 -0
  69. package/docs/en/img/software1.jpg +0 -0
  70. package/docs/en/readme.md +128 -30
  71. package/docs/flashing_via_arduino_(en).md +110 -110
  72. package/docs/ru/readme.md +28 -28
  73. package/docs/tutorial/groups-1.png +0 -0
  74. package/docs/tutorial/groups-2.png +0 -0
  75. package/docs/tutorial/tab-dev-1.png +0 -0
  76. package/io-package.json +32 -21
  77. package/lib/backup.js +171 -171
  78. package/lib/binding.js +319 -319
  79. package/lib/colors.js +465 -465
  80. package/lib/commands.js +534 -534
  81. package/lib/developer.js +145 -145
  82. package/lib/devices.js +3135 -3135
  83. package/lib/exclude.js +162 -162
  84. package/lib/exposes.js +913 -830
  85. package/lib/groups.js +345 -345
  86. package/lib/json.js +59 -59
  87. package/lib/networkmap.js +55 -55
  88. package/lib/ota.js +198 -195
  89. package/lib/rgb.js +297 -297
  90. package/lib/seriallist.js +48 -48
  91. package/lib/states.js +6420 -6420
  92. package/lib/statescontroller.js +672 -693
  93. package/lib/tools.js +54 -54
  94. package/lib/utils.js +163 -163
  95. package/lib/zbBaseExtension.js +36 -36
  96. package/lib/zbDelayedAction.js +144 -144
  97. package/lib/zbDeviceAvailability.js +319 -319
  98. package/lib/zbDeviceConfigure.js +147 -147
  99. package/lib/zbDeviceEvent.js +48 -48
  100. package/lib/zigbeecontroller.js +989 -989
  101. package/main.js +133 -123
  102. package/package.json +10 -10
  103. package/support/docgen.js +93 -93
  104. /package/admin/img/{paumann_spot.png → paulmann_spot.png} +0 -0
package/main.js CHANGED
@@ -516,7 +516,7 @@ class Zigbee extends utils.Adapter {
516
516
  if (!converters.length) {
517
517
  if (type !== 'readResponse') {
518
518
  this.log.debug(
519
- `No converter available for '${mappedModel.model}' with cluster '${cluster}' and type '${type}'`
519
+ `No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`
520
520
  );
521
521
  }
522
522
  return;
@@ -562,144 +562,155 @@ class Zigbee extends utils.Adapter {
562
562
 
563
563
  async publishFromState(deviceId, model, stateModel, stateList, options) {
564
564
  let isGroup = false;
565
+
566
+ this.log.debug(`publishFromState : ${deviceId} ${model}`);
565
567
  if (model === 'group') {
566
568
  isGroup = true;
567
569
  deviceId = parseInt(deviceId);
568
570
  }
569
- const entity = await this.zbController.resolveEntity(deviceId);
570
- this.log.debug(`entity: ${safeJsonStringify(entity)}`);
571
- const mappedModel = entity.mapped;
572
- if (!mappedModel) {
573
- this.log.debug(`No mapped model for ${model}`);
574
- return;
575
- }
576
- this.log.debug(`Mapped Model: ${JSON.stringify(mappedModel)}`);
577
-
578
- stateList.forEach(async changedState => {
579
- const stateDesc = changedState.stateDesc;
580
- const value = changedState.value;
581
-
582
- if (stateDesc.id === 'send_payload') {
583
- try {
584
- const json_value = JSON.parse(value);
585
- const payload = {device: deviceId.replace('0x', ''), payload: json_value};
586
- const result = await this.sendPayload(payload);
587
- if (result.hasOwnProperty('success') && result.success) {
588
- this.acknowledgeState(deviceId, model, stateDesc, value);
589
- }
590
- } catch (error) {
591
- this.log.warn(`send_payload: ${value} does not parse as JSON Object : ${error.message}`);
592
- return;
593
- }
571
+ try {
572
+ const entity = await this.zbController.resolveEntity(deviceId);
573
+
574
+ this.log.debug(`entity: ${deviceId} ${model} ${safeJsonStringify(entity)}`);
575
+
576
+ const mappedModel = entity.mapped;
577
+
578
+ if (!mappedModel) {
579
+ this.log.debug(`No mapped model for ${model}`);
594
580
  return;
595
581
  }
596
-
597
- if (stateDesc.isOption) {
598
- // acknowledge state with given value
599
- this.acknowledgeState(deviceId, model, stateDesc, value);
600
- // process sync state list
601
- //this.processSyncStatesList(deviceId, modelId, syncStateList);
602
- // if this is the device query state => trigger the device query
603
-
604
- // on activation of the 'device_query' state trigger hardware query where possible
605
- if (stateDesc.id === 'device_query') {
606
- if (this.query_device_block.indexOf(deviceId) > -1) {
607
- this.log.warn(`Device query for '${entity.device.ieeeAddr}' blocked`);
582
+
583
+ stateList.forEach(async changedState => {
584
+ const stateDesc = changedState.stateDesc;
585
+ const value = changedState.value;
586
+
587
+ if (stateDesc.id === 'send_payload') {
588
+ try {
589
+ const json_value = JSON.parse(value);
590
+ const payload = {device: deviceId.replace('0x', ''), payload: json_value};
591
+ const result = await this.sendPayload(payload);
592
+ if (result.hasOwnProperty('success') && result.success) {
593
+ this.acknowledgeState(deviceId, model, stateDesc, value);
594
+ }
595
+ } catch (error) {
596
+ this.log.warn(`send_payload: ${value} does not parse as JSON Object : ${error.message}`);
608
597
  return;
609
598
  }
610
- if (mappedModel) {
611
- this.query_device_block.push(deviceId);
612
- this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
613
- for (const converter of mappedModel.toZigbee) {
614
- if (converter.hasOwnProperty('convertGet')) {
615
- for (const ckey of converter.key) {
616
- try {
617
- await converter.convertGet(entity.device.endpoints[0], ckey, {});
618
- } catch (error) {
619
- this.log.warn(`Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}' after query with '${JSON.stringify(error)}'`);
620
-
599
+ return;
600
+ }
601
+
602
+ if (stateDesc.isOption) {
603
+ // acknowledge state with given value
604
+ this.acknowledgeState(deviceId, model, stateDesc, value);
605
+ // process sync state list
606
+ //this.processSyncStatesList(deviceId, modelId, syncStateList);
607
+ // if this is the device query state => trigger the device query
608
+
609
+ // on activation of the 'device_query' state trigger hardware query where possible
610
+ if (stateDesc.id === 'device_query') {
611
+ if (this.query_device_block.indexOf(deviceId) > -1) {
612
+ this.log.warn(`Device query for '${entity.device.ieeeAddr}' blocked`);
613
+ return;
614
+ }
615
+ if (mappedModel) {
616
+ this.query_device_block.push(deviceId);
617
+ this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
618
+ for (const converter of mappedModel.toZigbee) {
619
+ if (converter.hasOwnProperty('convertGet')) {
620
+ for (const ckey of converter.key) {
621
+ try {
622
+ await converter.convertGet(entity.device.endpoints[0], ckey, {});
623
+ } catch (error) {
624
+ this.log.warn(`Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}' after query with '${JSON.stringify(error)}'`);
625
+
626
+ }
621
627
  }
622
628
  }
623
629
  }
630
+ this.log.debug(`Device query for '${entity.device.ieeeAddr}' done`);
631
+ const idToRemove = deviceId;
632
+ setTimeout(() => {
633
+ const idx = this.query_device_block.indexOf(idToRemove);
634
+ if (idx > -1) {
635
+ this.query_device_block.splice(idx);
636
+ }
637
+ }, 10000);
624
638
  }
625
- this.log.debug(`Device query for '${entity.device.ieeeAddr}' done`);
626
- const idToRemove = deviceId;
627
- setTimeout(() => {
628
- const idx = this.query_device_block.indexOf(idToRemove);
629
- if (idx > -1) {
630
- this.query_device_block.splice(idx);
631
- }
632
- }, 10000);
639
+ return;
633
640
  }
634
641
  return;
635
642
  }
636
- return;
637
- }
638
- const converter = mappedModel.toZigbee.find(c => c && (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id)));
639
- if (!converter) {
640
- this.log.error(`No converter available for '${model}' with key '${stateDesc.id}' `);
641
- this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
642
- return;
643
- }
644
-
645
- const preparedValue = (stateDesc.setter) ? stateDesc.setter(value, options) : value;
646
- const preparedOptions = (stateDesc.setterOpt) ? stateDesc.setterOpt(value, options) : {};
647
- let syncStateList = [];
648
- if (stateModel && stateModel.syncStates) {
649
- stateModel.syncStates.forEach(syncFunct => {
650
- const res = syncFunct(stateDesc, value, options);
651
- if (res) {
652
- syncStateList = syncStateList.concat(res);
653
- }
654
- });
655
- }
656
-
657
- const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
658
- const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
659
- this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
660
-
661
- let target;
662
- if (model === 'group') {
663
- target = entity.mapped;
664
- } else {
665
- target = await this.zbController.resolveEntity(deviceId, epName);
666
- target = target.endpoint;
667
- }
668
-
669
- this.log.debug(`target: ${safeJsonStringify(target)}`);
670
-
671
- const meta = {
672
- endpoint_name: epName,
673
- options: preparedOptions,
674
- device: entity.device,
675
- mapped: model === 'group' ? [] : mappedModel,
676
- message: {[key]: preparedValue},
677
- logger: this.log,
678
- state: {},
679
- };
680
- if (preparedOptions.hasOwnProperty('state')) {
681
- meta.state = preparedOptions.state;
682
- }
683
- try {
684
- const result = await converter.convertSet(target, key, preparedValue, meta);
685
- this.log.debug(`convert result ${safeJsonStringify(result)}`);
686
- if (result !== undefined) {
687
- if (stateModel && !isGroup) {
688
- this.acknowledgeState(deviceId, model, stateDesc, value);
689
- }
690
- // process sync state list
691
- this.processSyncStatesList(deviceId, model, syncStateList);
692
-
693
- if (isGroup) {
694
- await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
695
- this.acknowledgeState(deviceId, model, stateDesc, value);
643
+ const converter = mappedModel.toZigbee.find(c => c && (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id)));
644
+ if (!converter) {
645
+ this.log.error(`No converter available for '${model}' with key '${stateDesc.id}' `);
646
+ this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
647
+ return;
648
+ }
649
+
650
+ const preparedValue = (stateDesc.setter) ? stateDesc.setter(value, options) : value;
651
+ const preparedOptions = (stateDesc.setterOpt) ? stateDesc.setterOpt(value, options) : {};
652
+ let syncStateList = [];
653
+ if (stateModel && stateModel.syncStates) {
654
+ stateModel.syncStates.forEach(syncFunct => {
655
+ const res = syncFunct(stateDesc, value, options);
656
+ if (res) {
657
+ syncStateList = syncStateList.concat(res);
658
+ }
659
+ });
660
+ }
661
+
662
+ const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
663
+ const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
664
+ this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
665
+
666
+ let target;
667
+ if (model === 'group') {
668
+ target = entity.mapped;
669
+ } else {
670
+ target = await this.zbController.resolveEntity(deviceId, epName);
671
+ target = target.endpoint;
672
+ }
673
+
674
+ this.log.debug(`target: ${safeJsonStringify(target)}`);
675
+
676
+ const meta = {
677
+ endpoint_name: epName,
678
+ options: preparedOptions,
679
+ device: entity.device,
680
+ mapped: model === 'group' ? [] : mappedModel,
681
+ message: {[key]: preparedValue},
682
+ logger: this.log,
683
+ state: {},
684
+ };
685
+
686
+ if (preparedOptions.hasOwnProperty('state')) {
687
+ meta.state = preparedOptions.state;
688
+ }
689
+
690
+ try {
691
+ const result = await converter.convertSet(target, key, preparedValue, meta);
692
+ this.log.debug(`convert result ${safeJsonStringify(result)}`);
693
+ if (result !== undefined) {
694
+ if (stateModel && !isGroup) {
695
+ this.acknowledgeState(deviceId, model, stateDesc, value);
696
+ }
697
+ // process sync state list
698
+ this.processSyncStatesList(deviceId, model, syncStateList);
699
+
700
+ if (isGroup) {
701
+ await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
702
+ this.acknowledgeState(deviceId, model, stateDesc, value);
703
+ }
696
704
  }
705
+
706
+ } catch (error) {
707
+ this.filterError(`Error ${error.code} on send command to ${deviceId}.` +
708
+ ` Error: ${error.stack}`, `Send command to ${deviceId} failed with`, error);
697
709
  }
698
- } catch (error) {
699
- this.filterError(`Error ${error.code} on send command to ${deviceId}.` +
700
- ` Error: ${error.stack}`, `Send command to ${deviceId} failed with`, error);
701
- }
702
- });
710
+ });
711
+ } catch (err) {
712
+ this.log.error(`No entity for ${deviceId}`);
713
+ }
703
714
  }
704
715
 
705
716
  // This function is introduced to explicitly allow user level scripts to send Commands
@@ -917,7 +928,6 @@ class Zigbee extends utils.Adapter {
917
928
  if (Number.isInteger(data)) {
918
929
  _pairingMode = true;
919
930
  this.setState('info.pairingCountdown', data, true);
920
- _pairingMode = true;
921
931
  }
922
932
  if (data === 0) {
923
933
  // set pairing mode off
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "1.8.10",
3
+ "version": "1.8.13",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -21,11 +21,11 @@
21
21
  "serialport": "^10.5.0"
22
22
  },
23
23
  "dependencies": {
24
- "@iobroker/adapter-core": "^2.6.7",
25
- "tar": "^6.1.12",
26
- "typescript": "^4.9.3",
27
- "zigbee-herdsman": "0.14.83",
28
- "zigbee-herdsman-converters": "15.0.15"
24
+ "@iobroker/adapter-core": "^2.6.8",
25
+ "tar": "^6.1.15",
26
+ "typescript": "^5.1.6",
27
+ "zigbee-herdsman": "0.16.0",
28
+ "zigbee-herdsman-converters": "15.35.1"
29
29
  },
30
30
  "description": "Zigbee devices",
31
31
  "devDependencies": {
@@ -33,15 +33,15 @@
33
33
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
34
34
  "@alcalzone/release-script-plugin-license": "^3.5.9",
35
35
  "@iobroker/testing": "^4.1.0",
36
- "axios": "^1.2.0",
36
+ "axios": "^1.3.4",
37
37
  "chai": "^4.3.7",
38
38
  "chai-as-promised": "^7.1.1",
39
- "eslint": "^8.31.0",
40
- "eslint-config-prettier": "^8.5.0",
39
+ "eslint": "^8.44.0",
40
+ "eslint-config-prettier": "^8.8.0",
41
41
  "eslint-plugin-prettier": "^4.2.1",
42
42
  "gulp": "^4.0.2",
43
43
  "gulp-jsdoc3": "^3.0.0",
44
- "gulp-replace": "^1.1.3",
44
+ "gulp-replace": "^1.1.4",
45
45
  "mixin-deep": "^2.0.1",
46
46
  "mocha": "^10.2.0"
47
47
  },
package/support/docgen.js CHANGED
@@ -1,93 +1,93 @@
1
- /**
2
- * This script generates the supported devices page.
3
- *
4
- */
5
-
6
- let devices = [...require('zigbee-herdsman-converters').devices];
7
-
8
- for (const device of devices) {
9
- if (device.whiteLabel) {
10
- for (const whiteLabel of device.whiteLabel) {
11
- const whiteLabelDevice = {
12
- ...device,
13
- model: whiteLabel.model,
14
- vendor: whiteLabel.vendor,
15
- description: whiteLabel.description,
16
- whiteLabelOf: device,
17
- };
18
-
19
- delete whiteLabelDevice.whiteLabel;
20
-
21
- devices.push(whiteLabelDevice);
22
- }
23
- }
24
- }
25
-
26
- devices = new Map(devices.map((d) => [d.model, d]));
27
-
28
- const Devices = require('../lib/devices');
29
- let iobDevices = Devices.devices;
30
- Devices.fillStatesWithExposes('');
31
-
32
- const iobCount = iobDevices.filter((d) => (!d.exposed)).length;
33
- iobDevices = new Map(iobDevices.map((d) => d.models.map((m) => [m, d])).flat());
34
-
35
- const fs = require('fs');
36
- const outputdir = process.argv[2];
37
-
38
- if (!outputdir) {
39
- console.error('Please specify an output directory');
40
- }
41
-
42
- const file = 'Supported-devices.md';
43
- let text = `*NOTE: Automatically generated by 'npm run docgen'* \n\n` +
44
- `Currently **${iobDevices.size}**(${iobCount} described in adapter) devices are supported.\n\n` +
45
- `(⭐EXP) - means that the device is presented automatically, based on the 'exposes' from the zigbee-herdsman-converters.\n\n`;
46
-
47
- const logDevices = (devmodels) => {
48
- let result = '';
49
-
50
- devmodels.forEach((devmodel) => {
51
- const iobDevice = iobDevices.get(devmodel);
52
- const device = devices.get(devmodel);
53
- const pathImg = (iobDevice.icon.startsWith('http')) ? devmodel : iobDevice.icon.replace(new RegExp('img/', 'g'), '').replace(new RegExp('.png', 'g'), '');
54
- const icon = (iobDevice.icon.startsWith('http')) ? iobDevice.icon : `https://github.com/ioBroker/ioBroker.zigbee/raw/master/admin/${iobDevice.icon}`;
55
- let brand;
56
- const models = [];
57
- let zmodels;
58
- if (device.zigbeeModel) {
59
- zmodels = device.zigbeeModel;
60
- } else {
61
- zmodels = [devmodel];
62
- }
63
- zmodels.forEach((modelId) => {
64
- const re = /[^\x20-\x7E]+/g;
65
- const model = modelId.replace(re, ' ');
66
- const desc = `${device.description} (${device.supports})`;
67
- const name = `**${device.model}${(iobDevice.exposed) ? ' (⭐EXP)': ''}**<br>`;
68
- if (brand == undefined) {
69
- brand= {
70
- name: name,
71
- desc: desc,
72
- pathImg: pathImg,
73
- };
74
- }
75
- models.push(model);
76
- });
77
- const modelsStr = models.join(', ');
78
- result += `| ${brand.name} (${modelsStr}) | ${brand.desc} | ![${brand.pathImg}](${icon}) |\n`;
79
- });
80
-
81
- return result;
82
- };
83
-
84
- const vendors = Array.from(new Set([...iobDevices.keys()].map((m) => (devices.get(m)) ? devices.get(m).vendor : null)));
85
- vendors.sort();
86
- text += '| Model | Description | Picture |\n';
87
- text += '| ------------- | ------------- | -------------------------- |\n';
88
- vendors.forEach((vendor) => {
89
- text += `| | **${vendor}** | |\n`;
90
- text += logDevices([...iobDevices.keys()].map((m) => devices.get(m)).filter((d) => d && d.vendor === vendor).map((d) => d.model));
91
- });
92
-
93
- fs.writeFileSync(outputdir + '/' + file, text);
1
+ /**
2
+ * This script generates the supported devices page.
3
+ *
4
+ */
5
+
6
+ let devices = [...require('zigbee-herdsman-converters').devices];
7
+
8
+ for (const device of devices) {
9
+ if (device.whiteLabel) {
10
+ for (const whiteLabel of device.whiteLabel) {
11
+ const whiteLabelDevice = {
12
+ ...device,
13
+ model: whiteLabel.model,
14
+ vendor: whiteLabel.vendor,
15
+ description: whiteLabel.description,
16
+ whiteLabelOf: device,
17
+ };
18
+
19
+ delete whiteLabelDevice.whiteLabel;
20
+
21
+ devices.push(whiteLabelDevice);
22
+ }
23
+ }
24
+ }
25
+
26
+ devices = new Map(devices.map((d) => [d.model, d]));
27
+
28
+ const Devices = require('../lib/devices');
29
+ let iobDevices = Devices.devices;
30
+ Devices.fillStatesWithExposes('');
31
+
32
+ const iobCount = iobDevices.filter((d) => (!d.exposed)).length;
33
+ iobDevices = new Map(iobDevices.map((d) => d.models.map((m) => [m, d])).flat());
34
+
35
+ const fs = require('fs');
36
+ const outputdir = process.argv[2];
37
+
38
+ if (!outputdir) {
39
+ console.error('Please specify an output directory');
40
+ }
41
+
42
+ const file = 'Supported-devices.md';
43
+ let text = `*NOTE: Automatically generated by 'npm run docgen'* \n\n` +
44
+ `Currently **${iobDevices.size}**(${iobCount} described in adapter) devices are supported.\n\n` +
45
+ `(⭐EXP) - means that the device is presented automatically, based on the 'exposes' from the zigbee-herdsman-converters.\n\n`;
46
+
47
+ const logDevices = (devmodels) => {
48
+ let result = '';
49
+
50
+ devmodels.forEach((devmodel) => {
51
+ const iobDevice = iobDevices.get(devmodel);
52
+ const device = devices.get(devmodel);
53
+ const pathImg = (iobDevice.icon.startsWith('http')) ? devmodel : iobDevice.icon.replace(new RegExp('img/', 'g'), '').replace(new RegExp('.png', 'g'), '');
54
+ const icon = (iobDevice.icon.startsWith('http')) ? iobDevice.icon : `https://github.com/ioBroker/ioBroker.zigbee/raw/master/admin/${iobDevice.icon}`;
55
+ let brand;
56
+ const models = [];
57
+ let zmodels;
58
+ if (device.zigbeeModel) {
59
+ zmodels = device.zigbeeModel;
60
+ } else {
61
+ zmodels = [devmodel];
62
+ }
63
+ zmodels.forEach((modelId) => {
64
+ const re = /[^\x20-\x7E]+/g;
65
+ const model = modelId.replace(re, ' ');
66
+ const desc = `${device.description} (${device.supports})`;
67
+ const name = `**${device.model}${(iobDevice.exposed) ? ' (⭐EXP)': ''}**<br>`;
68
+ if (brand == undefined) {
69
+ brand= {
70
+ name: name,
71
+ desc: desc,
72
+ pathImg: pathImg,
73
+ };
74
+ }
75
+ models.push(model);
76
+ });
77
+ const modelsStr = models.join(', ');
78
+ result += `| ${brand.name} (${modelsStr}) | ${brand.desc} | ![${brand.pathImg}](${icon}) |\n`;
79
+ });
80
+
81
+ return result;
82
+ };
83
+
84
+ const vendors = Array.from(new Set([...iobDevices.keys()].map((m) => (devices.get(m)) ? devices.get(m).vendor : null)));
85
+ vendors.sort();
86
+ text += '| Model | Description | Picture |\n';
87
+ text += '| ------------- | ------------- | -------------------------- |\n';
88
+ vendors.forEach((vendor) => {
89
+ text += `| | **${vendor}** | |\n`;
90
+ text += logDevices([...iobDevices.keys()].map((m) => devices.get(m)).filter((d) => d && d.vendor === vendor).map((d) => d.model));
91
+ });
92
+
93
+ fs.writeFileSync(outputdir + '/' + file, text);