iobroker.zigbee 1.5.6 → 1.6.8

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 (64) hide show
  1. package/.devcontainer/devcontainer.json +35 -35
  2. package/.devcontainer/docker-compose.yml +51 -51
  3. package/.devcontainer/iobroker/Dockerfile +1 -1
  4. package/.devcontainer/nginx/nginx.conf +32 -32
  5. package/.devcontainer/parcel/Dockerfile +8 -8
  6. package/.devcontainer/parcel/run.sh +6 -6
  7. package/.eslintignore +1 -1
  8. package/.eslintrc.json +36 -36
  9. package/.github/FUNDING.yml +3 -3
  10. package/.github/stale.yml +13 -13
  11. package/.github/workflows/test-and-release.yml +151 -151
  12. package/.travis/wiki.sh +27 -27
  13. package/LICENSE +21 -21
  14. package/README.md +385 -353
  15. package/admin/adapter-settings.js +244 -208
  16. package/admin/admin.js +2704 -2714
  17. package/admin/img/R7060.png +0 -0
  18. package/admin/img/WHD02.png +0 -0
  19. package/admin/img/ikea_E1812.png +0 -0
  20. package/admin/img/philips_hue_lom001.png +0 -0
  21. package/admin/img/tuya_rb280.png +0 -0
  22. package/admin/index.html +159 -159
  23. package/admin/index_m.html +1055 -965
  24. package/admin/moment.min.js +1 -1
  25. package/admin/shuffle.min.js +2 -2
  26. package/admin/tab_m.html +1025 -934
  27. package/admin/vis-network.min.js +26 -26
  28. package/admin/words.js +106 -106
  29. package/docs/de/readme.md +27 -27
  30. package/docs/en/readme.md +30 -30
  31. package/docs/flashing_via_arduino_(en).md +110 -110
  32. package/docs/ru/readme.md +28 -28
  33. package/docs/tutorial/groups-1.png +0 -0
  34. package/docs/tutorial/groups-2.png +0 -0
  35. package/docs/tutorial/tab-dev-1.png +0 -0
  36. package/docs/tutorial/zigbee.png +0 -0
  37. package/io-package.json +317 -290
  38. package/lib/backup.js +132 -132
  39. package/lib/binding.js +325 -325
  40. package/lib/colors.js +460 -460
  41. package/lib/commands.js +435 -434
  42. package/lib/developer.js +148 -144
  43. package/lib/devices.js +3119 -3109
  44. package/lib/exclude.js +168 -168
  45. package/lib/exposes.js +204 -51
  46. package/lib/groups.js +316 -316
  47. package/lib/json.js +60 -60
  48. package/lib/networkmap.js +56 -56
  49. package/lib/ota.js +153 -153
  50. package/lib/rgb.js +225 -225
  51. package/lib/seriallist.js +37 -37
  52. package/lib/states.js +6381 -6322
  53. package/lib/statescontroller.js +502 -495
  54. package/lib/tools.js +54 -54
  55. package/lib/utils.js +151 -132
  56. package/lib/zbBaseExtension.js +31 -27
  57. package/lib/zbDelayedAction.js +151 -146
  58. package/lib/zbDeviceAvailability.js +306 -304
  59. package/lib/zbDeviceConfigure.js +148 -143
  60. package/lib/zbDeviceEvent.js +43 -43
  61. package/lib/zigbeecontroller.js +856 -822
  62. package/main.js +113 -39
  63. package/package.json +74 -73
  64. package/support/docgen.js +93 -93
package/main.js CHANGED
@@ -30,6 +30,7 @@ const StatesController = require('./lib/statescontroller');
30
30
  const ExcludePlugin = require('./lib/exclude');
31
31
  const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
32
32
  const vm = require('vm');
33
+ const util = require('util');
33
34
 
34
35
  const createByteArray = function (hexString) {
35
36
  const bytes = [];
@@ -105,18 +106,46 @@ class Zigbee extends utils.Adapter {
105
106
  }
106
107
  }
107
108
 
109
+ sendError(error, message) {
110
+ if (this.supportsFeature && this.supportsFeature('PLUGINS')) {
111
+ const sentryInstance = this.getPluginInstance('sentry');
112
+ if (sentryInstance) {
113
+ const Sentry = sentryInstance.getSentryObject();
114
+ if (Sentry) {
115
+ if (message) {
116
+ Sentry.configureScope(scope => {
117
+ scope.addBreadcrumb({
118
+ type: "error", // predefined types
119
+ category: "error message",
120
+ level: Sentry.Severity.Error,
121
+ message: message
122
+ });
123
+ });
124
+ }
125
+ if (typeof error == 'string') {
126
+ Sentry.captureException(new Error(error));
127
+ } else {
128
+ Sentry.captureException(error);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+
108
135
  filterError(errormessage, message, error) {
109
136
  if (error.code === undefined)
110
137
  {
111
138
  let em = error.stack.match(/failed \((.+?)\) at/);
112
139
  if (!em) em = error.stack.match(/failed \((.+?)\)/);
113
140
  this.log.error(`${message} no error code (${(em ? em[1]:'undefined')})`);
141
+ this.sendError(error, `${message} no error code`);
114
142
  this.log.debug(`Stack trace for ${em}: ${error.stack}`);
115
143
  return;
116
144
  }
117
145
  const ecode = errorCodes[error.code];
118
146
  if (ecode === undefined) {
119
147
  this.log.error(errormessage);
148
+ this.sendError(error, errormessage);
120
149
  return;
121
150
  }
122
151
  switch (ecode.severity) {
@@ -126,14 +155,19 @@ class Zigbee extends utils.Adapter {
126
155
  break;
127
156
  case E_WARN: this.log.warn(`${message}: Code ${error.code} (${ecode.message})`);
128
157
  break;
129
- case E_ERROR: this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
158
+ case E_ERROR:
159
+ this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
160
+ this.sendError(error, `${message}: Code ${error.code} (${ecode.message})`);
130
161
  break;
131
- default: this.log.error(`${message}: Code ${error.code} (malformed error)`);
162
+ default:
163
+ this.log.error(`${message}: Code ${error.code} (malformed error)`);
164
+ this.sendError(error, `${message}: Code ${error.code} (malformed error)`);
132
165
  }
133
166
  }
134
167
 
135
- debugLog (data) {
136
- this.log.debug(data.slice(data.indexOf('zigbee-herdsman')));
168
+ debugLog (data, ...args) {
169
+ const message = (args) ? util.format(data, ...args) : data;
170
+ this.log.debug(message.slice(message.indexOf('zigbee-herdsman')));
137
171
  }
138
172
 
139
173
  async onReady() {
@@ -237,6 +271,7 @@ class Zigbee extends utils.Adapter {
237
271
  } else {
238
272
  this.log.error(error);
239
273
  }
274
+ this.sendError(error, `Failed to start Zigbee`);
240
275
  if (this.reconnectCounter > 0) {
241
276
  this.tryToReconnect();
242
277
  }
@@ -246,6 +281,7 @@ class Zigbee extends utils.Adapter {
246
281
  async onZigbeeAdapterDisconnected() {
247
282
  this.reconnectCounter = 5;
248
283
  this.log.error('Adapter disconnected, stopping');
284
+ this.sendError('Adapter disconnected, stopping');
249
285
  this.setState('info.connection', false, true);
250
286
  await this.callPluginMethod('stop');
251
287
  this.tryToReconnect();
@@ -281,25 +317,31 @@ class Zigbee extends utils.Adapter {
281
317
  const adapterType = this.config.adapterType || 'zstack';
282
318
  if (adapterType === 'zstack') {
283
319
  if (configExtPanId != networkExtPanId) {
284
- // try to read from nvram
285
- const result = await this.zbController.herdsman.adapter.znp.request(
286
- 1, // Subsystem.SYS
287
- 'osalNvRead',
288
- {
289
- id: 45, // EXTENDED_PAN_ID
290
- len: 0x08,
291
- offset: 0x00,
292
- },
293
- null, [
294
- 0, // ZnpCommandStatus.SUCCESS
295
- 2, // ZnpCommandStatus.INVALID_PARAM
296
- ]
297
- );
298
- const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
299
- this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
300
- if (configExtPanId != nwExtPanId) {
301
- networkExtPanId = nwExtPanId;
302
- needChange = true;
320
+ try {
321
+ // try to read from nvram
322
+ const result = await this.zbController.herdsman.adapter.znp.request(
323
+ 1, // Subsystem.SYS
324
+ 'osalNvRead',
325
+ {
326
+ id: 45, // EXTENDED_PAN_ID
327
+ len: 0x08,
328
+ offset: 0x00,
329
+ },
330
+ null, [
331
+ 0, // ZnpCommandStatus.SUCCESS
332
+ 2, // ZnpCommandStatus.INVALID_PARAM
333
+ ]
334
+ );
335
+ const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
336
+ this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
337
+ if (configExtPanId != nwExtPanId) {
338
+ networkExtPanId = nwExtPanId;
339
+ needChange = true;
340
+ }
341
+ } catch (e) {
342
+ this.log.error(`Unable to apply ExtPanID changes: ${e}`);
343
+ this.sendError(e, `Unable to apply ExtPanID changes`);
344
+ needChange = false;
303
345
  }
304
346
  } else {
305
347
  needChange = true;
@@ -368,9 +410,6 @@ class Zigbee extends utils.Adapter {
368
410
 
369
411
  async onZigbeeEvent(type, entity, message){
370
412
  this.log.debug(`Type ${type} device ${safeJsonStringify(entity)} incoming event: ${safeJsonStringify(message)}`);
371
- if (!entity.mapped) {
372
- return;
373
- }
374
413
  const device = entity.device,
375
414
  mappedModel = entity.mapped,
376
415
  model = (entity.mapped) ? entity.mapped.model : entity.device.modelID,
@@ -385,6 +424,17 @@ class Zigbee extends utils.Adapter {
385
424
  if (message.linkquality) {
386
425
  this.publishToState(devId, model, {linkquality: message.linkquality});
387
426
  }
427
+ // publish raw event to "from_zigbee"
428
+ // some cleanup
429
+ const msgForState = Object.assign({}, message);
430
+ delete msgForState['device'];
431
+ delete msgForState['endpoint'];
432
+ msgForState['endpoint_id'] = message.endpoint.ID;
433
+ this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
434
+
435
+ if (!entity.mapped) {
436
+ return;
437
+ }
388
438
  let converters = mappedModel.fromZigbee.filter(c => c && c.cluster === cluster && (
389
439
  (c.type instanceof Array) ? c.type.includes(type) : c.type === type));
390
440
  if (!converters.length && type === 'readResponse') {
@@ -447,6 +497,10 @@ class Zigbee extends utils.Adapter {
447
497
  const entity = await this.zbController.resolveEntity(deviceId);
448
498
  this.log.debug(`entity: ${safeJsonStringify(entity)}`);
449
499
  const mappedModel = entity.mapped;
500
+ if (!mappedModel) {
501
+ this.log.debug(`No mapped model for ${model}`);
502
+ return;
503
+ }
450
504
  this.log.debug('Mapped Model: ' + JSON.stringify(mappedModel));
451
505
 
452
506
  stateList.forEach(async(changedState) => {
@@ -494,6 +548,7 @@ class Zigbee extends utils.Adapter {
494
548
  const converter = mappedModel.toZigbee.find((c) => c && (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id)));
495
549
  if (!converter) {
496
550
  this.log.error(`No converter available for '${model}' with key '${stateDesc.id}' `);
551
+ this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
497
552
  return;
498
553
  }
499
554
 
@@ -511,7 +566,7 @@ class Zigbee extends utils.Adapter {
511
566
 
512
567
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
513
568
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
514
- this.log.debug(`convert ${key}, ${preparedValue}, ${safeJsonStringify(preparedOptions)}`);
569
+ this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
515
570
 
516
571
  let target;
517
572
  if (model === 'group') {
@@ -536,13 +591,15 @@ class Zigbee extends utils.Adapter {
536
591
  try {
537
592
  const result = await converter.convertSet(target, key, preparedValue, meta);
538
593
  this.log.debug(`convert result ${safeJsonStringify(result)}`);
539
- if (stateModel && !isGroup)
540
- this.acknowledgeState(deviceId, model, stateDesc, value);
541
- // process sync state list
542
- this.processSyncStatesList(deviceId, model, syncStateList);
543
- if (isGroup) {
544
- await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
545
- this.acknowledgeState(deviceId, model, stateDesc, value);
594
+ if (result !== undefined) {
595
+ if (stateModel && !isGroup)
596
+ this.acknowledgeState(deviceId, model, stateDesc, value);
597
+ // process sync state list
598
+ this.processSyncStatesList(deviceId, model, syncStateList);
599
+ if (isGroup) {
600
+ await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
601
+ this.acknowledgeState(deviceId, model, stateDesc, value);
602
+ }
546
603
  }
547
604
  } catch(error) {
548
605
  this.filterError(`Error ${error.code} on send command to ${deviceId}.`+
@@ -574,6 +631,7 @@ class Zigbee extends utils.Adapter {
574
631
  payload_obj = JSON.parse();
575
632
  } catch (e) {
576
633
  this.log.error(`Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`);
634
+ this.sendError(e, `Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`);
577
635
  return {success:false, error: `Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`};
578
636
  }
579
637
  } else if (typeof payload === 'object') {
@@ -590,15 +648,18 @@ class Zigbee extends utils.Adapter {
590
648
  const entity = await this.zbController.resolveEntity(devID);
591
649
  if (!entity) {
592
650
  this.log.error(`Device ${safeJsonStringify(payload_obj.device)} not found`);
651
+ this.sendError(`Device ${safeJsonStringify(payload_obj.device)} not found`);
593
652
  return {success: false, error: `Device ${safeJsonStringify(payload_obj.device)} not found`};
594
653
  }
595
654
  const mappedModel = entity.mapped;
596
655
  if (!mappedModel) {
597
656
  this.log.error(`No Model for Device ${safeJsonStringify(payload_obj.device)}`);
657
+ this.sendError(`No Model for Device ${safeJsonStringify(payload_obj.device)}`);
598
658
  return {success: false, error: `No Model for Device ${safeJsonStringify(payload_obj.device)}`};
599
659
  }
600
660
  if (typeof payload_obj.payload !== 'object') {
601
661
  this.log.error(`Illegal payload type for ${safeJsonStringify(payload_obj.device)}`);
662
+ this.sendError(`Illegal payload type for ${safeJsonStringify(payload_obj.device)}`);
602
663
  return {success: false, error: `Illegal payload type for ${safeJsonStringify(payload_obj.device)}`};
603
664
  }
604
665
  for (const key in payload_obj.payload) {
@@ -671,8 +732,10 @@ class Zigbee extends utils.Adapter {
671
732
  await plugin[method]();
672
733
  }
673
734
  } catch (error) {
674
- if (error && !error.hasOwnProperty('code'))
735
+ if (error && !error.hasOwnProperty('code')) {
675
736
  this.log.error(`Failed to call '${plugin.constructor.name}' '${method}' (${error.stack})`);
737
+ this.sendError(error, `Failed to call '${plugin.constructor.name}' '${method}'`);
738
+ }
676
739
  throw error;
677
740
  }
678
741
  }
@@ -697,7 +760,10 @@ class Zigbee extends utils.Adapter {
697
760
  }
698
761
  callback();
699
762
  } catch (error) {
700
- this.log.error(`Unload error (${error.stack})`);
763
+ if (error) {
764
+ this.log.error(`Unload error (${error.stack})`);
765
+ }
766
+ this.sendError(error, `Unload error`);
701
767
  callback();
702
768
  }
703
769
  }
@@ -707,10 +773,18 @@ class Zigbee extends utils.Adapter {
707
773
  let dbDir = path.join(utils.getAbsoluteInstanceDataDir(this), '');
708
774
  dbDir = dbDir.replace('.', '_');
709
775
 
710
- if (this.systemConfig && !fs.existsSync(dbDir)) fs.mkdirSync(dbDir);
776
+ if (this.systemConfig && !fs.existsSync(dbDir)) {
777
+ try {
778
+ fs.mkdirSync(dbDir);
779
+ } catch (e) {
780
+ this.log.error(`Cannot create directory ${dbDir}: ${e}`);
781
+ this.sendError(`Cannot create directory ${dbDir}: ${e}`);
782
+ }
783
+ }
711
784
  const port = this.config.port;
712
785
  if (!port) {
713
786
  this.log.error('Serial port not selected! Go to settings page.');
787
+ this.sendError('Serial port not selected! Go to settings page.');
714
788
  }
715
789
  const panID = parseInt(this.config.panID ? this.config.panID : 0x1a62);
716
790
  const channel = parseInt(this.config.channel ? this.config.channel : 11);
@@ -740,6 +814,7 @@ class Zigbee extends utils.Adapter {
740
814
  disablePing: this.config.disablePing,
741
815
  transmitPower: this.config.transmitPower,
742
816
  extPanIdFix: extPanIdFix,
817
+ startWithInconsistent: this.config.startWithInconsistent || false,
743
818
  };
744
819
  }
745
820
 
@@ -771,6 +846,7 @@ class Zigbee extends utils.Adapter {
771
846
  if (data)
772
847
  data = data.toString();
773
848
  this.logToPairing('Error: ' + msg + '. ' + data, true);
849
+ this.sendError('Error: ' + msg + '. ' + data);
774
850
  break;
775
851
  case 'debug':
776
852
  logger = this.log.debug;
@@ -793,8 +869,6 @@ class Zigbee extends utils.Adapter {
793
869
  }
794
870
  }
795
871
  }
796
-
797
-
798
872
  }
799
873
 
800
874
 
package/package.json CHANGED
@@ -1,73 +1,74 @@
1
- {
2
- "name": "iobroker.zigbee",
3
- "version": "1.5.6",
4
- "author": {
5
- "name": "Kirov Ilya",
6
- "email": "kirovilya@gmail.com"
7
- },
8
- "bugs": {
9
- "url": "https://github.com/ioBroker/ioBroker.zigbee/issues"
10
- },
11
- "contributors": [
12
- {
13
- "name": "Kirov Ilya",
14
- "email": "kirovilya@gmail.com"
15
- }
16
- ],
17
- "engines": {
18
- "node": ">=10"
19
- },
20
- "dependencies": {
21
- "zigbee-herdsman": "0.13.110",
22
- "zigbee-herdsman-converters": "14.0.162",
23
- "@iobroker/adapter-core": "^2.4.0",
24
- "tar": "^6.0.5",
25
- "typescript": "^4.0.5"
26
- },
27
- "description": "Zigbee devices",
28
- "devDependencies": {
29
- "@alcalzone/release-script": "^1.8.3",
30
- "@iobroker/testing": "^2.4.2",
31
- "axios": "^0.21.1",
32
- "mixin-deep": "^1.3.2",
33
- "chai": "^4.2.0",
34
- "eslint": "^7.18.0",
35
- "eslint-config-google": "*",
36
- "gulp": "^4.0.0",
37
- "lint-diff": "*",
38
- "mocha": "^6.0.2"
39
- },
40
- "homepage": "https://github.com/ioBroker/ioBroker.zigbee",
41
- "keywords": [
42
- "ioBroker",
43
- "zigbee",
44
- "cc2531",
45
- "cc2530",
46
- "cc2538",
47
- "cc2652",
48
- "deconz",
49
- "conbee",
50
- "raspbee",
51
- "ezsp",
52
- "efr32"
53
- ],
54
- "license": "MIT",
55
- "main": "main.js",
56
- "optionalDependencies": {},
57
- "readmeFilename": "README.md",
58
- "repository": {
59
- "type": "git",
60
- "url": "git+https://github.com/ioBroker/ioBroker.zigbee.git"
61
- },
62
- "scripts": {
63
- "test": "npm run test:package && npm run test:unit",
64
- "docgen": "node support/docgen.js",
65
- "test:package": "mocha test/package --exit",
66
- "test:unit": "mocha test/unit --exit",
67
- "test:integration": "mocha test/integration --exit",
68
- "watch:parcel": "parcel admin/src/index.tsx -d admin/build --hmr-port 1235",
69
- "test:js": "mocha --opts test/mocha.custom.opts",
70
- "lint": "npm run lint:js",
71
- "lint:js": "eslint"
72
- }
73
- }
1
+ {
2
+ "name": "iobroker.zigbee",
3
+ "version": "1.6.8",
4
+ "author": {
5
+ "name": "Kirov Ilya",
6
+ "email": "kirovilya@gmail.com"
7
+ },
8
+ "bugs": {
9
+ "url": "https://github.com/ioBroker/ioBroker.zigbee/issues"
10
+ },
11
+ "contributors": [
12
+ {
13
+ "name": "Kirov Ilya",
14
+ "email": "kirovilya@gmail.com"
15
+ }
16
+ ],
17
+ "engines": {
18
+ "node": ">=10"
19
+ },
20
+ "dependencies": {
21
+ "zigbee-herdsman": "0.13.178",
22
+ "zigbee-herdsman-converters": "14.0.339",
23
+ "@iobroker/adapter-core": "^2.4.0",
24
+ "tar": "^6.0.5",
25
+ "typescript": "^4.0.5"
26
+ },
27
+ "description": "Zigbee devices",
28
+ "devDependencies": {
29
+ "@alcalzone/release-script": "^2.2.0",
30
+ "@iobroker/testing": "^2.5.1",
31
+ "axios": "^0.21.1",
32
+ "mixin-deep": "^1.3.2",
33
+ "chai": "^4.2.0",
34
+ "eslint": "^7.18.0",
35
+ "eslint-config-google": "*",
36
+ "gulp": "^4.0.0",
37
+ "lint-diff": "*",
38
+ "mocha": "^6.0.2"
39
+ },
40
+ "homepage": "https://github.com/ioBroker/ioBroker.zigbee",
41
+ "keywords": [
42
+ "ioBroker",
43
+ "zigbee",
44
+ "cc2531",
45
+ "cc2530",
46
+ "cc2538",
47
+ "cc2652",
48
+ "deconz",
49
+ "conbee",
50
+ "raspbee",
51
+ "ezsp",
52
+ "efr32"
53
+ ],
54
+ "license": "MIT",
55
+ "main": "main.js",
56
+ "optionalDependencies": {},
57
+ "readmeFilename": "README.md",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/ioBroker/ioBroker.zigbee.git"
61
+ },
62
+ "scripts": {
63
+ "test": "npm run test:package && npm run test:unit",
64
+ "docgen": "node support/docgen.js",
65
+ "test:package": "mocha test/package --exit",
66
+ "test:unit": "mocha test/unit --exit",
67
+ "test:integration": "mocha test/integration --exit",
68
+ "watch:parcel": "parcel admin/src/index.tsx -d admin/build --hmr-port 1235",
69
+ "test:js": "mocha --opts test/mocha.custom.opts",
70
+ "lint": "npm run lint:js",
71
+ "lint:js": "eslint",
72
+ "release": "release-script"
73
+ }
74
+ }
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);