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.
- package/.devcontainer/devcontainer.json +35 -35
- package/.devcontainer/docker-compose.yml +51 -51
- package/.devcontainer/iobroker/Dockerfile +1 -1
- package/.devcontainer/nginx/nginx.conf +32 -32
- package/.devcontainer/parcel/Dockerfile +8 -8
- package/.devcontainer/parcel/run.sh +6 -6
- package/.eslintignore +1 -1
- package/.eslintrc.json +36 -36
- package/.github/FUNDING.yml +3 -3
- package/.github/stale.yml +13 -13
- package/.github/workflows/test-and-release.yml +151 -151
- package/.travis/wiki.sh +27 -27
- package/LICENSE +21 -21
- package/README.md +385 -353
- package/admin/adapter-settings.js +244 -208
- package/admin/admin.js +2704 -2714
- package/admin/img/R7060.png +0 -0
- package/admin/img/WHD02.png +0 -0
- package/admin/img/ikea_E1812.png +0 -0
- package/admin/img/philips_hue_lom001.png +0 -0
- package/admin/img/tuya_rb280.png +0 -0
- package/admin/index.html +159 -159
- package/admin/index_m.html +1055 -965
- package/admin/moment.min.js +1 -1
- package/admin/shuffle.min.js +2 -2
- package/admin/tab_m.html +1025 -934
- package/admin/vis-network.min.js +26 -26
- package/admin/words.js +106 -106
- package/docs/de/readme.md +27 -27
- package/docs/en/readme.md +30 -30
- package/docs/flashing_via_arduino_(en).md +110 -110
- package/docs/ru/readme.md +28 -28
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/docs/tutorial/zigbee.png +0 -0
- package/io-package.json +317 -290
- package/lib/backup.js +132 -132
- package/lib/binding.js +325 -325
- package/lib/colors.js +460 -460
- package/lib/commands.js +435 -434
- package/lib/developer.js +148 -144
- package/lib/devices.js +3119 -3109
- package/lib/exclude.js +168 -168
- package/lib/exposes.js +204 -51
- package/lib/groups.js +316 -316
- package/lib/json.js +60 -60
- package/lib/networkmap.js +56 -56
- package/lib/ota.js +153 -153
- package/lib/rgb.js +225 -225
- package/lib/seriallist.js +37 -37
- package/lib/states.js +6381 -6322
- package/lib/statescontroller.js +502 -495
- package/lib/tools.js +54 -54
- package/lib/utils.js +151 -132
- package/lib/zbBaseExtension.js +31 -27
- package/lib/zbDelayedAction.js +151 -146
- package/lib/zbDeviceAvailability.js +306 -304
- package/lib/zbDeviceConfigure.js +148 -143
- package/lib/zbDeviceEvent.js +43 -43
- package/lib/zigbeecontroller.js +856 -822
- package/main.js +113 -39
- package/package.json +74 -73
- 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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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 (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
-
|
|
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))
|
|
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.
|
|
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.
|
|
22
|
-
"zigbee-herdsman-converters": "14.0.
|
|
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": "^
|
|
30
|
-
"@iobroker/testing": "^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} |  |\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} |  |\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);
|