iobroker.zigbee 1.8.3 → 1.8.7
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/README.md +6 -0
- package/admin/adapter-settings.js +244 -0
- package/admin/admin.js +520 -494
- package/admin/index_m.html +1171 -1001
- package/admin/tab_m.html +44 -2
- package/docs/de/img/CC2531.png +0 -0
- package/docs/de/img/CC2538_CC2592_PA.PNG +0 -0
- package/docs/de/img/CC2591.png +0 -0
- package/docs/de/img/boards.jpg +0 -0
- package/docs/de/img/cc26x2r.PNG +0 -0
- package/docs/de/img/results.jpg +0 -0
- package/docs/de/img/sku_429478_2.png +0 -0
- package/docs/de/img/sku_429601_2.png +0 -0
- package/docs/de/readme.md +27 -0
- package/docs/en/img/CC2531.png +0 -0
- package/docs/en/img/CC2591.png +0 -0
- package/docs/en/img/deconz.png +0 -0
- package/docs/en/img/sku_429478_2.png +0 -0
- package/docs/en/img/sku_429601_2.png +0 -0
- package/docs/en/readme.md +30 -0
- package/docs/flashing_via_arduino_(en).md +110 -0
- package/docs/ru/img/CC2531.png +0 -0
- package/docs/ru/img/CC2591.png +0 -0
- package/docs/ru/img/sku_429478_2.png +0 -0
- package/docs/ru/img/sku_429601_2.png +0 -0
- package/docs/ru/readme.md +28 -0
- package/docs/tutorial/CC2530_20190425.zip +0 -0
- package/docs/tutorial/CC2530_CC2591_20190515.zip +0 -0
- package/docs/tutorial/CC2530_CC2592_20190515.zip +0 -0
- package/docs/tutorial/CC2531_20190425.zip +0 -0
- package/docs/tutorial/adm5_1.PNG +0 -0
- package/docs/tutorial/adm5_2.PNG +0 -0
- package/docs/tutorial/cat.PNG +0 -0
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/inst.PNG +0 -0
- package/docs/tutorial/reflash-finish.PNG +0 -0
- package/docs/tutorial/reflash-step0.png +0 -0
- package/docs/tutorial/reflash-step1.PNG +0 -0
- package/docs/tutorial/reflash-step2.PNG +0 -0
- package/docs/tutorial/settings.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/docs/tutorial/zigbee.png +0 -0
- package/docs/tutorial/zigbee15.png +0 -0
- package/io-package.json +34 -33
- package/lib/backup.js +2 -2
- package/lib/binding.js +32 -37
- package/lib/colors.js +163 -158
- package/lib/commands.js +100 -91
- package/lib/developer.js +9 -12
- package/lib/devices.js +168 -178
- package/lib/exclude.js +30 -36
- package/lib/exposes.js +168 -143
- package/lib/groups.js +81 -83
- package/lib/json.js +5 -6
- package/lib/networkmap.js +2 -3
- package/lib/ota.js +34 -18
- package/lib/rgb.js +114 -72
- package/lib/seriallist.js +25 -20
- package/lib/statescontroller.js +206 -183
- package/lib/utils.js +29 -23
- package/lib/zbBaseExtension.js +4 -4
- package/lib/zbDelayedAction.js +5 -13
- package/lib/zbDeviceAvailability.js +69 -65
- package/lib/zbDeviceConfigure.js +9 -21
- package/lib/zbDeviceEvent.js +3 -4
- package/lib/zigbeecontroller.js +133 -128
- package/main.js +169 -154
- package/package.json +28 -14
- package/.eslintignore +0 -2
- package/.eslintrc.json +0 -37
- package/.github/FUNDING.yml +0 -3
- package/.github/auto-merge.yml +0 -17
- package/.github/dependabot.yml +0 -24
- package/.github/stale.yml +0 -13
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-automerge.yml +0 -22
- package/.github/workflows/test-and-release.yml +0 -149
- package/.releaseconfig.json +0 -3
- package/.travis/wiki.sh +0 -28
- package/.travis.yml +0 -41
- package/gulpfile.js +0 -464
- package/test/integration.js +0 -5
- package/test/mocha.custom.opts +0 -2
- package/test/mocha.setup.js +0 -14
- package/test/package.js +0 -5
- package/test/unit.js +0 -5
package/lib/zigbeecontroller.js
CHANGED
|
@@ -41,7 +41,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
41
41
|
super();
|
|
42
42
|
this.adapter = adapter;
|
|
43
43
|
this._permitJoinTime = 0;
|
|
44
|
-
this.
|
|
44
|
+
this.herdsmanStarted = false;
|
|
45
45
|
this.extensions = [
|
|
46
46
|
new DeviceAvailabilityExt(this, {}),
|
|
47
47
|
new DeviceConfigureExt(this, {}),
|
|
@@ -85,7 +85,12 @@ class ZigbeeController extends EventEmitter {
|
|
|
85
85
|
|
|
86
86
|
this.debug(`Using zigbee-herdsman with settings: ${JSON.stringify(herdsmanSettings)}`);
|
|
87
87
|
this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings, this.adapter.log);
|
|
88
|
-
this.callExtensionMethod('setOptions', [{
|
|
88
|
+
this.callExtensionMethod('setOptions', [{
|
|
89
|
+
disableActivePing: options.disablePing,
|
|
90
|
+
disableForcedPing: false,
|
|
91
|
+
pingTimeout: 300,
|
|
92
|
+
pingCount: 3
|
|
93
|
+
}]);
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
// Start controller
|
|
@@ -93,8 +98,8 @@ class ZigbeeController extends EventEmitter {
|
|
|
93
98
|
try {
|
|
94
99
|
//this.debug(`Using zigbee-herdsman with settings2: ${JSON.stringify(this)}`);
|
|
95
100
|
this.debug(`Starting zigbee-herdsman...`);
|
|
96
|
-
await this.herdsman.start();
|
|
97
101
|
|
|
102
|
+
// install event handlers before start
|
|
98
103
|
this.herdsman.on('adapterDisconnected', this.handleDisconnected.bind(this));
|
|
99
104
|
this.herdsman.on('deviceAnnounce', this.handleDeviceAnnounce.bind(this));
|
|
100
105
|
this.herdsman.on('deviceInterview', this.handleDeviceInterview.bind(this));
|
|
@@ -102,29 +107,30 @@ class ZigbeeController extends EventEmitter {
|
|
|
102
107
|
this.herdsman.on('deviceLeave', this.handleDeviceLeave.bind(this));
|
|
103
108
|
this.herdsman.on('message', this.handleMessage.bind(this));
|
|
104
109
|
|
|
110
|
+
await this.herdsman.start();
|
|
111
|
+
|
|
105
112
|
this.debug('zigbee-herdsman started');
|
|
106
|
-
this.
|
|
113
|
+
this.herdsmanStarted = true;
|
|
107
114
|
this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
|
|
108
115
|
|
|
109
116
|
// debug info from herdsman getNetworkParameters
|
|
110
117
|
const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
|
|
111
|
-
const extendedPanIDDebug =
|
|
118
|
+
const extendedPanIDDebug = typeof debNetworkParam.extendedPanID === 'string' ? debNetworkParam.extendedPanID.replace('0x', '') : debNetworkParam.extendedPanID;
|
|
112
119
|
|
|
113
120
|
let extPanIDDebug = '';
|
|
114
121
|
for (let i = extendedPanIDDebug.length - 1; i >= 0; i--) {
|
|
115
|
-
extPanIDDebug += extendedPanIDDebug[i-1];
|
|
122
|
+
extPanIDDebug += extendedPanIDDebug[i - 1];
|
|
116
123
|
extPanIDDebug += extendedPanIDDebug[i];
|
|
117
124
|
i--;
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
|
|
121
|
-
|
|
122
128
|
} catch (e) {
|
|
123
129
|
this.sendError(e);
|
|
124
|
-
this.error(
|
|
130
|
+
this.error(`Starting zigbee-herdsman problem : ${JSON.stringify(e.message)}`);
|
|
125
131
|
throw 'Error herdsman start';
|
|
126
132
|
}
|
|
127
|
-
// Check if we have to turn off the
|
|
133
|
+
// Check if we have to turn off the LED
|
|
128
134
|
try {
|
|
129
135
|
if (this.disableLed) {
|
|
130
136
|
this.info('Disable LED');
|
|
@@ -141,7 +147,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
141
147
|
let powerText = 'normal';
|
|
142
148
|
|
|
143
149
|
if (this.transmitPower != '0') {
|
|
144
|
-
switch(this.transmitPower) {
|
|
150
|
+
switch (this.transmitPower) {
|
|
145
151
|
case '-22':
|
|
146
152
|
powerText = 'low';
|
|
147
153
|
break;
|
|
@@ -157,7 +163,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
|
|
160
|
-
this.info(
|
|
166
|
+
this.info(` --> transmitPower : ${powerText}`);
|
|
161
167
|
try {
|
|
162
168
|
await this.herdsman.setTransmitPower(this.transmitPower);
|
|
163
169
|
} catch (e) {
|
|
@@ -165,7 +171,6 @@ class ZigbeeController extends EventEmitter {
|
|
|
165
171
|
this.info('Unable to set transmit power, unsupported function.');
|
|
166
172
|
}
|
|
167
173
|
|
|
168
|
-
|
|
169
174
|
// Call extensions
|
|
170
175
|
this.callExtensionMethod('onZigbeeStarted', []);
|
|
171
176
|
|
|
@@ -176,20 +181,21 @@ class ZigbeeController extends EventEmitter {
|
|
|
176
181
|
} else {
|
|
177
182
|
this.info(`Currently no devices.`);
|
|
178
183
|
}
|
|
184
|
+
|
|
179
185
|
for (const device of devices) {
|
|
180
186
|
const entity = await this.resolveEntity(device);
|
|
181
|
-
this.adapter.getObject(device.ieeeAddr.substr(2),(err, obj) => {
|
|
182
|
-
if (obj && obj.common && obj.common.deactivated)
|
|
183
|
-
{
|
|
187
|
+
this.adapter.getObject(device.ieeeAddr.substr(2), (err, obj) => {
|
|
188
|
+
if (obj && obj.common && obj.common.deactivated) {
|
|
184
189
|
this.callExtensionMethod('deregisterDevicePing', [device, entity]);
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
190
|
+
} else {
|
|
187
191
|
this.callExtensionMethod('registerDevicePing', [device, entity]);
|
|
188
192
|
}
|
|
189
193
|
});
|
|
190
194
|
// ensure that objects for all found clients are present
|
|
191
195
|
|
|
192
|
-
if (entity.mapped)
|
|
196
|
+
if (entity.mapped) {
|
|
197
|
+
this.emit('new', entity);
|
|
198
|
+
}
|
|
193
199
|
this.info(
|
|
194
200
|
(entity.device.ieeeAddr) +
|
|
195
201
|
` (addr ${entity.device.networkAddress}): ` +
|
|
@@ -252,7 +258,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
252
258
|
if (all) {
|
|
253
259
|
return devices;
|
|
254
260
|
} else {
|
|
255
|
-
return devices.filter(
|
|
261
|
+
return devices.filter(device => device.type !== 'Coordinator');
|
|
256
262
|
}
|
|
257
263
|
} else {
|
|
258
264
|
return [];
|
|
@@ -261,8 +267,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
261
267
|
|
|
262
268
|
async getGroups() {
|
|
263
269
|
try {
|
|
264
|
-
|
|
265
|
-
|
|
270
|
+
if (this.herdsman) {
|
|
271
|
+
return await this.herdsman.getGroups();
|
|
272
|
+
} else {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
266
275
|
} catch (error) {
|
|
267
276
|
this.sendError(error);
|
|
268
277
|
this.error(JSON.stringify(error));
|
|
@@ -271,12 +280,12 @@ class ZigbeeController extends EventEmitter {
|
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
async removeGroupById(id) {
|
|
274
|
-
const group = await
|
|
283
|
+
const group = await this.getGroupByID(id);
|
|
275
284
|
try {
|
|
276
|
-
|
|
285
|
+
group && group.removeFromDatabase();
|
|
277
286
|
} catch (error) {
|
|
278
287
|
this.sendError(error);
|
|
279
|
-
this.error(
|
|
288
|
+
this.error(`error in removeGroupById: ${error}`);
|
|
280
289
|
}
|
|
281
290
|
}
|
|
282
291
|
|
|
@@ -290,18 +299,16 @@ class ZigbeeController extends EventEmitter {
|
|
|
290
299
|
}
|
|
291
300
|
|
|
292
301
|
async verifyGroupExists(id) {
|
|
293
|
-
|
|
302
|
+
const nid = typeof id === 'number' ? id : parseInt(id);
|
|
294
303
|
let group = await this.herdsman.getGroupByID(nid);
|
|
295
304
|
if (!group) {
|
|
296
305
|
group = await this.herdsman.createGroup(nid);
|
|
297
306
|
group.toZigbee = groupConverters;
|
|
298
307
|
group.model = 'group';
|
|
299
|
-
this.debug(
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
this.debug('verifyGroupExists: group ' + nid + ' exists');
|
|
308
|
+
this.debug(`verifyGroupExists: created group ${nid}`);
|
|
309
|
+
} else {
|
|
310
|
+
this.debug(`verifyGroupExists: group ${nid} exists`);
|
|
303
311
|
}
|
|
304
|
-
|
|
305
312
|
}
|
|
306
313
|
|
|
307
314
|
async getGroupMembersFromController(id) {
|
|
@@ -309,22 +316,30 @@ class ZigbeeController extends EventEmitter {
|
|
|
309
316
|
try {
|
|
310
317
|
const group = await this.getGroupByID(id);
|
|
311
318
|
if (group) {
|
|
312
|
-
const
|
|
313
|
-
for (const member of
|
|
314
|
-
const epid =
|
|
319
|
+
const groupMembers = group.members;
|
|
320
|
+
for (const member of groupMembers) {
|
|
321
|
+
const epid = member.ID ? member.ID : -1;
|
|
315
322
|
const nwk = member.deviceNetworkAddress;
|
|
316
323
|
const device = this.getDeviceByNetworkAddress(nwk);
|
|
317
|
-
if (device && device.ieeeAddr)
|
|
324
|
+
if (device && device.ieeeAddr) {
|
|
325
|
+
members.push({
|
|
326
|
+
ieee: device.ieeeAddr,
|
|
327
|
+
model: device.modelID,
|
|
328
|
+
epid,
|
|
329
|
+
ep: member
|
|
330
|
+
});
|
|
331
|
+
}
|
|
318
332
|
}
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
333
|
+
} else {
|
|
321
334
|
return undefined;
|
|
322
335
|
}
|
|
323
|
-
|
|
324
336
|
} catch (error) {
|
|
325
337
|
this.sendError(error);
|
|
326
|
-
if (error)
|
|
327
|
-
|
|
338
|
+
if (error) {
|
|
339
|
+
this.error(`getGroupMembersFromController: error is ${JSON.stringify(error)} ${JSON.stringify(new Error().stack)}`);
|
|
340
|
+
} else {
|
|
341
|
+
this.error('unidentified error in getGroupMembersFromController');
|
|
342
|
+
}
|
|
328
343
|
}
|
|
329
344
|
return members;
|
|
330
345
|
}
|
|
@@ -342,7 +357,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
342
357
|
}
|
|
343
358
|
|
|
344
359
|
async resolveEntity(key, ep) {
|
|
345
|
-
//assert(typeof key === 'string' || key.constructor.name === 'Device', `Wrong type '${typeof key}'`);
|
|
360
|
+
// assert(typeof key === 'string' || key.constructor.name === 'Device', `Wrong type '${typeof key}'`);
|
|
346
361
|
|
|
347
362
|
if (typeof key === 'string') {
|
|
348
363
|
if (key === 'coordinator') {
|
|
@@ -379,8 +394,6 @@ class ZigbeeController extends EventEmitter {
|
|
|
379
394
|
endpoints: device.endpoints,
|
|
380
395
|
name: key,
|
|
381
396
|
};
|
|
382
|
-
} else {
|
|
383
|
-
return;
|
|
384
397
|
}
|
|
385
398
|
}
|
|
386
399
|
} else if (typeof key === 'number') {
|
|
@@ -404,7 +417,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
404
417
|
}
|
|
405
418
|
}
|
|
406
419
|
|
|
407
|
-
async incMsgHandler(message){
|
|
420
|
+
async incMsgHandler(message) {
|
|
408
421
|
this.debug('incoming msg', message);
|
|
409
422
|
const device = await this.herdsman.getDeviceByIeeeAddr(message.srcaddr);
|
|
410
423
|
if (!device) {
|
|
@@ -431,21 +444,21 @@ class ZigbeeController extends EventEmitter {
|
|
|
431
444
|
await this.herdsman.stop();
|
|
432
445
|
} catch (error) {
|
|
433
446
|
this.sendError(error);
|
|
434
|
-
if (this.
|
|
447
|
+
if (this.herdsmanStarted) {
|
|
435
448
|
this.error(`Failed to stop zigbee (${error.stack})`);
|
|
436
|
-
else {
|
|
449
|
+
} else {
|
|
437
450
|
this.warn(`Failed to stop zigbee during startup`);
|
|
438
451
|
}
|
|
439
452
|
}
|
|
440
453
|
}
|
|
441
454
|
|
|
442
455
|
async handleDisconnected() {
|
|
443
|
-
this.
|
|
456
|
+
this.herdsmanStarted = false;
|
|
444
457
|
this.emit('disconnect');
|
|
445
458
|
}
|
|
446
459
|
|
|
447
460
|
connected() {
|
|
448
|
-
return this.
|
|
461
|
+
return this.herdsmanStarted;
|
|
449
462
|
}
|
|
450
463
|
|
|
451
464
|
// Permit join
|
|
@@ -462,8 +475,8 @@ class ZigbeeController extends EventEmitter {
|
|
|
462
475
|
} else {
|
|
463
476
|
this.info('Zigbee: disabling joining new devices.');
|
|
464
477
|
}
|
|
465
|
-
|
|
466
|
-
{
|
|
478
|
+
|
|
479
|
+
try {
|
|
467
480
|
if (permitTime && !this.herdsman.getPermitJoin()) {
|
|
468
481
|
clearInterval(this._permitJoinInterval);
|
|
469
482
|
this._permitJoinTime = permitTime;
|
|
@@ -509,6 +522,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
509
522
|
this.debug(`Force remove`);
|
|
510
523
|
}
|
|
511
524
|
}
|
|
525
|
+
|
|
512
526
|
try {
|
|
513
527
|
await device.removeFromDatabase();
|
|
514
528
|
} catch (error) {
|
|
@@ -518,7 +532,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
518
532
|
this.debug(`Failed to remove from DB ${error.stack}`);
|
|
519
533
|
}
|
|
520
534
|
this.debug('Remove successful.');
|
|
521
|
-
|
|
535
|
+
callback && callback();
|
|
522
536
|
this.callExtensionMethod(
|
|
523
537
|
'onDeviceRemove',
|
|
524
538
|
[device],
|
|
@@ -527,7 +541,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
527
541
|
} catch (error) {
|
|
528
542
|
this.sendError(error);
|
|
529
543
|
this.error(`Failed to remove ${error.stack}`);
|
|
530
|
-
|
|
544
|
+
callback && callback(`Failed to remove ${error.stack}`);
|
|
531
545
|
}
|
|
532
546
|
}
|
|
533
547
|
|
|
@@ -536,7 +550,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
536
550
|
try {
|
|
537
551
|
this.debug('handleDeviceLeave', message);
|
|
538
552
|
const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
539
|
-
const friendlyName =
|
|
553
|
+
const friendlyName = entity ? entity.name : message.ieeeAddr;
|
|
540
554
|
this.debug(`Device '${friendlyName}' left the network`);
|
|
541
555
|
this.emit('leave', message.ieeeAddr);
|
|
542
556
|
// Call extensions
|
|
@@ -560,15 +574,17 @@ class ZigbeeController extends EventEmitter {
|
|
|
560
574
|
if (entity && entity.mapped) {
|
|
561
575
|
this.callExtensionMethod(
|
|
562
576
|
'onZigbeeEvent',
|
|
563
|
-
[
|
|
577
|
+
[{'device': message.device, 'type': 'deviceAnnounce'}, entity ? entity.mapped : null]);
|
|
564
578
|
}
|
|
565
579
|
} catch (error) {
|
|
566
580
|
this.sendError(error);
|
|
567
581
|
this.error(`Failed to handleDeviceLeave ${error.stack}`);
|
|
568
582
|
}
|
|
569
|
-
|
|
583
|
+
|
|
570
584
|
this.emit('pairing', `Device '${friendlyName}' announced itself`);
|
|
571
|
-
if (!this.herdsman.getPermitJoin())
|
|
585
|
+
if (!this.herdsman.getPermitJoin()) {
|
|
586
|
+
this.callExtensionMethod('registerDevicePing', [message.device, entity]);
|
|
587
|
+
}
|
|
572
588
|
// if has modelID so can create device
|
|
573
589
|
if (entity.device && entity.device._modelID) {
|
|
574
590
|
entity.device.modelID = entity.device._modelID;
|
|
@@ -576,7 +592,6 @@ class ZigbeeController extends EventEmitter {
|
|
|
576
592
|
}
|
|
577
593
|
}
|
|
578
594
|
|
|
579
|
-
|
|
580
595
|
async handleDeviceJoined(message) {
|
|
581
596
|
this.debug('handleDeviceJoined', message);
|
|
582
597
|
//const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
@@ -593,7 +608,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
593
608
|
const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
594
609
|
const friendlyName = entity.name;
|
|
595
610
|
if (message.status === 'successful') {
|
|
596
|
-
this.info(`Successfully interviewed '${friendlyName}', device has
|
|
611
|
+
this.info(`Successfully interviewed '${friendlyName}', device has successfully been paired`);
|
|
597
612
|
|
|
598
613
|
if (entity.mapped) {
|
|
599
614
|
const {vendor, description, model} = entity.mapped;
|
|
@@ -620,7 +635,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
620
635
|
this.emit('new', entity);
|
|
621
636
|
}
|
|
622
637
|
} else if (message.status === 'failed') {
|
|
623
|
-
this.error(`Failed to interview '${friendlyName}', device has not
|
|
638
|
+
this.error(`Failed to interview '${friendlyName}', device has not successfully been paired. ${message.error}`);
|
|
624
639
|
this.emit('pairing', 'Interview failed', friendlyName);
|
|
625
640
|
} else {
|
|
626
641
|
if (message.status === 'started') {
|
|
@@ -650,12 +665,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
650
665
|
|
|
651
666
|
async getMap(callback) {
|
|
652
667
|
try {
|
|
653
|
-
|
|
654
668
|
const devices = this.herdsman.getDevices(true);
|
|
655
669
|
const lqis = [];
|
|
656
670
|
const routing = [];
|
|
657
671
|
|
|
658
|
-
for (const device of devices.filter((d) => d.type
|
|
672
|
+
for (const device of devices.filter((d) => d.type !== 'EndDevice')) {
|
|
659
673
|
const resolved = await this.resolveEntity(device);
|
|
660
674
|
let result;
|
|
661
675
|
|
|
@@ -663,8 +677,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
663
677
|
result = await device.lqi();
|
|
664
678
|
} catch (error) {
|
|
665
679
|
this.sendError(error);
|
|
666
|
-
|
|
667
|
-
this.debug(`Failed to execute LQI for '${resolved.name}'. ${safeJsonStringify(error.stack)}`);
|
|
680
|
+
error && this.debug(`Failed to execute LQI for '${resolved.name}'. ${safeJsonStringify(error.stack)}`);
|
|
668
681
|
|
|
669
682
|
lqis.push({
|
|
670
683
|
parent: 'undefined',
|
|
@@ -679,7 +692,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
679
692
|
|
|
680
693
|
if (result !== undefined) {
|
|
681
694
|
for (const dev of result.neighbors) {
|
|
682
|
-
if (dev
|
|
695
|
+
if (dev !== undefined && dev.ieeeAddr !== '0xffffffffffffffff') {
|
|
683
696
|
lqis.push({
|
|
684
697
|
parent: resolved.device.ieeeAddr,
|
|
685
698
|
networkAddress: dev.networkAddress,
|
|
@@ -687,7 +700,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
687
700
|
lqi: dev.linkquality,
|
|
688
701
|
relationship: dev.relationship,
|
|
689
702
|
depth: dev.depth,
|
|
690
|
-
status:
|
|
703
|
+
status: dev.linkquality > 0 ? 'online' : 'offline',
|
|
691
704
|
});
|
|
692
705
|
}
|
|
693
706
|
}
|
|
@@ -718,11 +731,10 @@ class ZigbeeController extends EventEmitter {
|
|
|
718
731
|
}
|
|
719
732
|
}
|
|
720
733
|
this.debug(`Routing table succeeded for '${resolved.name}'`);
|
|
721
|
-
|
|
722
734
|
}
|
|
723
735
|
this.debug(`Get map succeeded ${safeJsonStringify(lqis)}`);
|
|
724
736
|
|
|
725
|
-
|
|
737
|
+
callback && callback({lqis, routing});
|
|
726
738
|
} catch (error) {
|
|
727
739
|
this.sendError(error);
|
|
728
740
|
this.debug(`Failed to get map: ${safeJsonStringify(error.stack)}`);
|
|
@@ -755,7 +767,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
755
767
|
if (type === 'foundation') {
|
|
756
768
|
cfg.disableDefaultResponse = true;
|
|
757
769
|
if (cmd === 'read' && !Array.isArray(zclData)) {
|
|
758
|
-
// needs to be
|
|
770
|
+
// needs to be iterable (string[] | number [])
|
|
759
771
|
zclData[Symbol.iterator] = function* () {
|
|
760
772
|
let k;
|
|
761
773
|
for (k in this) {
|
|
@@ -769,17 +781,15 @@ class ZigbeeController extends EventEmitter {
|
|
|
769
781
|
} else {
|
|
770
782
|
result = await endpoint[cmd](cid, zclData, cfg);
|
|
771
783
|
}
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
else {
|
|
784
|
+
callback && callback(undefined, result);
|
|
785
|
+
} else if (type === 'functionalResp') {
|
|
786
|
+
cfg.disableDefaultResponse = false;
|
|
787
|
+
const result = await endpoint.commandResponse(cid, cmd, zclData, cfg, zclSeqNum);
|
|
788
|
+
callback && callback(undefined, result);
|
|
789
|
+
} else {
|
|
780
790
|
cfg.disableDefaultResponse = false;
|
|
781
791
|
const result = await endpoint.command(cid, cmd, zclData, cfg);
|
|
782
|
-
|
|
792
|
+
callback && callback(undefined, result);
|
|
783
793
|
}
|
|
784
794
|
}
|
|
785
795
|
|
|
@@ -790,66 +800,60 @@ class ZigbeeController extends EventEmitter {
|
|
|
790
800
|
this.debug(`addDevFromGroup - entity: ${safeJsonStringify(entity)}`);
|
|
791
801
|
this.debug(`addDevFromGroup - group: ${safeJsonStringify(group)}`);
|
|
792
802
|
if (epid != undefined) {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
803
|
+
for (const ep of entity.endpoints) {
|
|
804
|
+
if (ep.ID === epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))) {
|
|
805
|
+
this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`);
|
|
806
|
+
await (ep.addToGroup(group.mapped));
|
|
807
|
+
}
|
|
798
808
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
else
|
|
803
|
-
{
|
|
804
|
-
if (entity.endpoint.inputClusters.includes(4))
|
|
805
|
-
{
|
|
806
|
-
this.debug(`adding endpoint ${entity.endpoint.ID} to group`)
|
|
809
|
+
} else {
|
|
810
|
+
if (entity.endpoint.inputClusters.includes(4)) {
|
|
811
|
+
this.debug(`adding endpoint ${entity.endpoint.ID} to group`);
|
|
807
812
|
await entity.endpoint.addToGroup(group.mapped);
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
813
|
+
} else {
|
|
810
814
|
let added = false;
|
|
811
|
-
for (const ep of entity.endpoints)
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
{
|
|
815
|
-
this.debug(`adding endpoint ${ep.ID} to group`)
|
|
815
|
+
for (const ep of entity.endpoints) {
|
|
816
|
+
if (ep.inputClusters.includes(4)) {
|
|
817
|
+
this.debug(`adding endpoint ${ep.ID} to group`);
|
|
816
818
|
await ep.addToGroup(group.mapped);
|
|
817
819
|
added = true;
|
|
818
820
|
break;
|
|
819
821
|
}
|
|
820
822
|
}
|
|
821
|
-
if (!added)
|
|
823
|
+
if (!added) {
|
|
824
|
+
throw ('cluster genGroups not supported');
|
|
825
|
+
}
|
|
822
826
|
}
|
|
823
827
|
}
|
|
824
828
|
} catch (error) {
|
|
825
829
|
this.sendError(error);
|
|
826
830
|
this.error(`Exception when trying to Add ${devId} to group ${groupId}`, error);
|
|
827
|
-
return {
|
|
831
|
+
return {error: `Failed to add ${devId} to group ${groupId}: ${JSON.stringify(error)}`};
|
|
828
832
|
}
|
|
829
833
|
return {};
|
|
830
834
|
}
|
|
831
835
|
|
|
832
836
|
async removeDevFromGroup(devId, groupId, epid) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
837
|
+
let entity;
|
|
838
|
+
try {
|
|
839
|
+
entity = await this.resolveEntity(devId);
|
|
840
|
+
const group = await this.resolveEntity(groupId);
|
|
841
|
+
this.debug(`removeDevFromGroup - entity: ${safeJsonStringify(entity)}`);
|
|
842
|
+
this.debug(`removeDevFromGroup - group: ${safeJsonStringify(group)}`);
|
|
843
|
+
if (epid != undefined) {
|
|
844
|
+
for (const ep of entity.endpoints) {
|
|
845
|
+
if (ep.ID === epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))) {
|
|
846
|
+
this.debug(`removing endpoint ${ep.ID} (${epid}) group ${groupId}`);
|
|
847
|
+
await ep.removeFromGroup(group.mapped);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
} else await entity.endpoint.removeFromGroup(group.mapped);
|
|
851
|
+
} catch (error) {
|
|
852
|
+
this.sendError(error);
|
|
853
|
+
this.error(`Exception when trying remove ${devId} (ep ${epid ? epid : (entity ? entity.endpoint.ID : '')}) from group ${devId}`, error);
|
|
854
|
+
return {error: `Failed to remove dev ${devId} (ep ${epid ? epid : (entity ? entity.endpoint.ID : '')}) from group ${devId}`};
|
|
855
|
+
}
|
|
856
|
+
return {};
|
|
853
857
|
}
|
|
854
858
|
|
|
855
859
|
async removeDevFromAllGroups(devId) {
|
|
@@ -857,14 +861,15 @@ class ZigbeeController extends EventEmitter {
|
|
|
857
861
|
const entity = await this.resolveEntity(devId);
|
|
858
862
|
this.debug(`entity: ${safeJsonStringify(entity)}`);
|
|
859
863
|
for (const ep of entity.endpoints) {
|
|
860
|
-
|
|
861
|
-
|
|
864
|
+
if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)) {
|
|
865
|
+
await ep.removefromAllGroups();
|
|
866
|
+
}
|
|
862
867
|
}
|
|
863
|
-
//await entity.endpoint.removeFromAllGroups();
|
|
868
|
+
// await entity.endpoint.removeFromAllGroups();
|
|
864
869
|
} catch (error) {
|
|
865
870
|
this.sendError(error);
|
|
866
871
|
this.error(`Exception when trying remove ${devId} from all groups`, error);
|
|
867
|
-
return {
|
|
872
|
+
return {error: `Failed to remove dev ${devId} from all groups: ${error}`};
|
|
868
873
|
}
|
|
869
874
|
return {};
|
|
870
875
|
}
|
|
@@ -874,7 +879,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
874
879
|
target = !target ? this.getCoordinator() : target;
|
|
875
880
|
|
|
876
881
|
this.debug(`Binding ${log}`);
|
|
877
|
-
ep.bind(cluster, target,
|
|
882
|
+
ep.bind(cluster, target, error => {
|
|
878
883
|
if (error) {
|
|
879
884
|
this.sendError(error);
|
|
880
885
|
this.error(`Failed to bind ${log} - (${error})`);
|
|
@@ -905,11 +910,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
905
910
|
reset(mode, callback) {
|
|
906
911
|
try {
|
|
907
912
|
this.herdsman.reset(mode);
|
|
908
|
-
|
|
913
|
+
callback && callback();
|
|
909
914
|
} catch (error) {
|
|
910
915
|
this.sendError(error);
|
|
911
916
|
this.error(`Failed to reset ${error.stack}`);
|
|
912
|
-
|
|
917
|
+
callback && callback(error);
|
|
913
918
|
}
|
|
914
919
|
}
|
|
915
920
|
|
|
@@ -933,12 +938,12 @@ class ZigbeeController extends EventEmitter {
|
|
|
933
938
|
nwkmanageraddr: 0x0000
|
|
934
939
|
};
|
|
935
940
|
const energyScan = this.herdsman.adapter.znp.waitFor(
|
|
936
|
-
2, //unpi_1.Constants.Type.AREQ,
|
|
937
|
-
5, //Subsystem.ZDO,
|
|
941
|
+
2, // unpi_1.Constants.Type.AREQ,
|
|
942
|
+
5, // Subsystem.ZDO,
|
|
938
943
|
'mgmtNwkUpdateNotify'
|
|
939
944
|
);
|
|
940
945
|
await this.herdsman.adapter.znp.request(
|
|
941
|
-
0x5, //Subsystem.ZDO
|
|
946
|
+
0x5, // Subsystem.ZDO
|
|
942
947
|
'mgmtNwkUpdateReq',
|
|
943
948
|
payload,
|
|
944
949
|
energyScan.ID
|