iobroker.zigbee 3.0.3 → 3.1.2
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 +26 -0
- package/admin/admin.js +153 -86
- package/admin/i18n/de/translations.json +16 -16
- package/admin/index_m.html +59 -90
- package/admin/tab_m.html +7 -5
- package/docs/de/readme.md +4 -1
- package/docs/en/readme.md +3 -1
- package/io-package.json +110 -54
- package/lib/binding.js +1 -1
- package/lib/commands.js +129 -97
- package/lib/developer.js +1 -1
- package/lib/devices.js +11 -7
- package/lib/exposes.js +14 -3
- package/lib/groups.js +400 -63
- package/lib/localConfig.js +16 -5
- package/lib/states.js +32 -2
- package/lib/statescontroller.js +254 -146
- package/lib/utils.js +7 -5
- package/lib/zbDeviceAvailability.js +78 -21
- package/lib/zbDeviceEvent.js +1 -1
- package/lib/zigbeecontroller.js +485 -56
- package/main.js +139 -469
- package/package.json +7 -7
package/lib/commands.js
CHANGED
|
@@ -196,7 +196,7 @@ class Commands {
|
|
|
196
196
|
}
|
|
197
197
|
catch (error) {
|
|
198
198
|
const msg = `Unable to read nvBackup ${error && error.message ? error.message : 'no message given'}`;
|
|
199
|
-
this.error(msg);
|
|
199
|
+
//this.error(msg);
|
|
200
200
|
this.adapter.sendTo(from, command, {error:msg}, callback)
|
|
201
201
|
}
|
|
202
202
|
}
|
|
@@ -240,12 +240,20 @@ class Commands {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
async letsPairing(from, command, message, callback) {
|
|
243
|
-
if (this.zbController) {
|
|
243
|
+
if (this.zbController && this.zbController.herdsmanStarted) {
|
|
244
244
|
let devId = '';
|
|
245
245
|
if (message) {
|
|
246
246
|
if (message.id && message.id != undefined) {
|
|
247
247
|
devId = getZbId(message.id);
|
|
248
248
|
}
|
|
249
|
+
if (typeof devId == 'number') {
|
|
250
|
+
this.adapter.sendTo(
|
|
251
|
+
from, command,
|
|
252
|
+
{error: 'Pairing on a group is not supported'},
|
|
253
|
+
callback
|
|
254
|
+
);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
249
257
|
if (message.code && message.code != undefined) {
|
|
250
258
|
try {
|
|
251
259
|
this.debug(`letsPairing called with code ${message.code}`);
|
|
@@ -273,23 +281,28 @@ class Commands {
|
|
|
273
281
|
}
|
|
274
282
|
// allow devices to join the network within 60 secs
|
|
275
283
|
// this.adapter.logToPairing('Pairing started ' + devId, true);
|
|
276
|
-
|
|
277
284
|
let cTimer = Number(this.adapter.config.countDown);
|
|
278
285
|
if (!this.adapter.config.countDown || !cTimer) {
|
|
279
286
|
cTimer = 60;
|
|
280
287
|
}
|
|
288
|
+
if (message.stop) cTimer = 0;
|
|
281
289
|
|
|
282
|
-
this.zbController.permitJoin(cTimer, devId
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
+
if (await this.zbController.permitJoin(cTimer, devId)) {
|
|
291
|
+
this.adapter.setState('info.pairingMode', cTimer > 0, true);
|
|
292
|
+
this.adapter.sendTo(from, command, cTimer ? 'Start pairing!':'Stop pairing!', callback);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
this.adapter.sendTo(
|
|
296
|
+
from, command,
|
|
297
|
+
{error: 'Error opening the network'},
|
|
298
|
+
callback
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
290
303
|
this.adapter.sendTo(
|
|
291
304
|
from, command,
|
|
292
|
-
{error: '
|
|
305
|
+
{error: 'No connection to zigbee Hardware!'},
|
|
293
306
|
callback
|
|
294
307
|
);
|
|
295
308
|
}
|
|
@@ -389,23 +402,25 @@ class Commands {
|
|
|
389
402
|
if (groupmembers && groupmembers.length > 0) {
|
|
390
403
|
const memberinfo = [];
|
|
391
404
|
for (const member of groupmembers) {
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (
|
|
396
|
-
|
|
405
|
+
if (member && typeof member.ieee === 'string') {
|
|
406
|
+
if (groups) {
|
|
407
|
+
const grouparray = groups[member.ieee];
|
|
408
|
+
if (grouparray) {
|
|
409
|
+
if (!grouparray.includes(groupID)) {
|
|
410
|
+
groups[member.ieee].push(groupID);
|
|
411
|
+
}
|
|
412
|
+
} else {
|
|
413
|
+
groups[member.ieee] = [groupID];
|
|
397
414
|
}
|
|
415
|
+
}
|
|
416
|
+
const device = await this.adapter.getObjectAsync(`${this.adapter.namespace}.${member.ieee.substr(2)}`);
|
|
417
|
+
if (device) {
|
|
418
|
+
member.device = device.common.name;
|
|
398
419
|
} else {
|
|
399
|
-
|
|
420
|
+
member.device = 'unknown';
|
|
400
421
|
}
|
|
422
|
+
memberinfo.push(member);
|
|
401
423
|
}
|
|
402
|
-
const device = await this.adapter.getObjectAsync(`${this.adapter.namespace}.${member.ieee.substr(2)}`);
|
|
403
|
-
if (device) {
|
|
404
|
-
member.device = device.common.name;
|
|
405
|
-
} else {
|
|
406
|
-
member.device = 'unknown';
|
|
407
|
-
}
|
|
408
|
-
memberinfo.push(member);
|
|
409
424
|
}
|
|
410
425
|
devInfo.memberinfo = memberinfo;
|
|
411
426
|
this.debug(`memberinfo for ${match[1]}: ${JSON.stringify(devInfo.memberinfo)}`);
|
|
@@ -464,7 +479,7 @@ class Commands {
|
|
|
464
479
|
if (!id) {
|
|
465
480
|
for (const d of pairedDevices) {
|
|
466
481
|
const device = await this.zbController.resolveEntity(d.ieeeAddr);
|
|
467
|
-
if (!device) {
|
|
482
|
+
if (!device || !device.device) {
|
|
468
483
|
continue;
|
|
469
484
|
}
|
|
470
485
|
const exists = devices.find((dev) => (dev._id && device.device.ieeeAddr === getZbId(dev._id)));
|
|
@@ -506,76 +521,84 @@ class Commands {
|
|
|
506
521
|
|
|
507
522
|
|
|
508
523
|
async getCoordinatorInfo(from, command, callback) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
524
|
+
const coordinatorinfo = {
|
|
525
|
+
installSource: 'IADefault_1',
|
|
526
|
+
channel: '-1',
|
|
527
|
+
port: 'Default_1',
|
|
528
|
+
installedVersion: 'Default_1',
|
|
529
|
+
type: 'Default_1',
|
|
530
|
+
revision: 'unknown',
|
|
531
|
+
version: 'unknown',
|
|
532
|
+
herdsman: this.adapter.zhversion,
|
|
533
|
+
converters: this.adapter.zhcversion,
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const coordinatorVersion = this.zbController && this.zbController.herdsmanStarted ? await this.adapter.zbController.herdsman.getCoordinatorVersion() : {};
|
|
537
|
+
|
|
538
|
+
await this.adapter.getForeignObject(`system.adapter.${this.adapter.namespace}`, (err, obj) => {
|
|
539
|
+
if (!err && obj) {
|
|
540
|
+
if (obj.common.installedFrom && obj.common.installedFrom.includes('://')) {
|
|
541
|
+
const instFrom = obj.common.installedFrom;
|
|
542
|
+
coordinatorinfo.installSource = instFrom.replace('tarball', 'commit');
|
|
543
|
+
} else {
|
|
544
|
+
coordinatorinfo.installSource = obj.common.installedFrom;
|
|
530
545
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
vt = vt + meta.maintrel + '.';
|
|
563
|
-
} else {
|
|
564
|
-
vt = vt + 'x.';
|
|
565
|
-
}
|
|
566
|
-
coordinatorinfo.version = vt;
|
|
546
|
+
}
|
|
547
|
+
try {
|
|
548
|
+
coordinatorinfo.port = obj.native.port;
|
|
549
|
+
coordinatorinfo.type = obj.native.adapterType;
|
|
550
|
+
coordinatorinfo.channel = obj.native.channel;
|
|
551
|
+
coordinatorinfo.installedVersion = obj.common.version;
|
|
552
|
+
if (coordinatorVersion && coordinatorVersion.type && coordinatorVersion.meta) {
|
|
553
|
+
coordinatorinfo.type = coordinatorVersion.type;
|
|
554
|
+
const meta = coordinatorVersion.meta;
|
|
555
|
+
if (typeof meta == 'object') {
|
|
556
|
+
if (meta.hasOwnProperty('revision')) {
|
|
557
|
+
coordinatorinfo.revision = meta.revision;
|
|
558
|
+
}
|
|
559
|
+
let vt = 'x-';
|
|
560
|
+
if (meta.hasOwnProperty('transportrev')) {
|
|
561
|
+
vt = meta.transportrev + '-';
|
|
562
|
+
}
|
|
563
|
+
if (meta.hasOwnProperty('product')) {
|
|
564
|
+
vt = vt + meta.product + '.';
|
|
565
|
+
} else {
|
|
566
|
+
vt = vt + 'x.';
|
|
567
|
+
}
|
|
568
|
+
if (meta.hasOwnProperty('majorrel')) {
|
|
569
|
+
vt = vt + meta.majorrel + '.';
|
|
570
|
+
} else {
|
|
571
|
+
vt = vt + 'x.';
|
|
572
|
+
}
|
|
573
|
+
if (meta.hasOwnProperty('minorrel')) {
|
|
574
|
+
vt = vt + meta.minorrel + '.';
|
|
575
|
+
} else {
|
|
576
|
+
vt = vt + 'x.';
|
|
567
577
|
}
|
|
578
|
+
if (meta.hasOwnProperty('maintrel')) {
|
|
579
|
+
vt = vt + meta.maintrel + '.';
|
|
580
|
+
} else {
|
|
581
|
+
vt = vt + 'x.';
|
|
582
|
+
}
|
|
583
|
+
coordinatorinfo.version = vt;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
coordinatorinfo.version = 'illegal data';
|
|
587
|
+
coordinatorinfo.revision = 'illegal data';
|
|
568
588
|
}
|
|
569
|
-
} catch {
|
|
570
|
-
this.warn('exception raised in getCoordinatorInfo');
|
|
571
589
|
}
|
|
590
|
+
else {
|
|
591
|
+
coordinatorinfo.version = 'not connected';
|
|
592
|
+
coordinatorinfo.revision = 'not connected';
|
|
572
593
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
594
|
+
}
|
|
595
|
+
} catch {
|
|
596
|
+
this.warn('exception raised in getCoordinatorInfo');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
this.debug(`getCoordinatorInfo result: ${JSON.stringify(coordinatorinfo)}`);
|
|
600
|
+
this.adapter.sendTo(from, command, coordinatorinfo, callback);
|
|
601
|
+
});
|
|
579
602
|
}
|
|
580
603
|
|
|
581
604
|
|
|
@@ -598,18 +621,19 @@ class Commands {
|
|
|
598
621
|
this.debug(`deleteDevice sysid: ${sysid}`);
|
|
599
622
|
const dev = this.zbController.getDevice(sysid);
|
|
600
623
|
if (!dev) {
|
|
601
|
-
this.
|
|
602
|
-
this.debug(`Try delete dev ${devId} from iobroker.`);
|
|
624
|
+
this.info(`Attempted to delete device ${devId} - the device is not known to the zigbee controller.`);
|
|
603
625
|
this.stController.deleteObj(devId, () =>
|
|
604
626
|
this.adapter.sendTo(from, command, {}, callback));
|
|
605
627
|
return;
|
|
606
628
|
}
|
|
629
|
+
this.info(`${force ? 'Force removing' : 'Gracefully removing '} device ${devId} from the network.`);
|
|
607
630
|
this.zbController.remove(sysid, force, err => {
|
|
608
631
|
if (!err) {
|
|
609
|
-
this.
|
|
610
|
-
|
|
632
|
+
this.info('Device removed from the network, deleting objects.')
|
|
633
|
+
this.stController.deleteObj(devId, () => {
|
|
634
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
635
|
+
});
|
|
611
636
|
} else {
|
|
612
|
-
this.debug(`Error on remove! ${err}`);
|
|
613
637
|
this.adapter.sendTo(from, command, {error: err}, callback);
|
|
614
638
|
}
|
|
615
639
|
});
|
|
@@ -710,7 +734,7 @@ class Commands {
|
|
|
710
734
|
async updateLocalConfigItems(from, command, msg, callback) {
|
|
711
735
|
if (this.stController) {
|
|
712
736
|
this.debug(`updateLocalConfigItems : ${JSON.stringify(msg)}`);
|
|
713
|
-
const target = msg.
|
|
737
|
+
const target = msg.target.replace(`${this.adapter.namespace}.`, '');
|
|
714
738
|
const entity = await this.zbController.resolveEntity(target);
|
|
715
739
|
//this.warn('entity for ' + target + ' is '+ JSON.stringify(entity))
|
|
716
740
|
if (entity && !entity.mapped) {
|
|
@@ -794,6 +818,13 @@ class Commands {
|
|
|
794
818
|
}
|
|
795
819
|
|
|
796
820
|
async testConnection(from, command, msg, callback) {
|
|
821
|
+
const result = await this.adapter.testConnection(msg.address, true);
|
|
822
|
+
if (result.error) {
|
|
823
|
+
this.error(result.error);
|
|
824
|
+
this.adapter.logToPairing(`Error: ${result.error}`)
|
|
825
|
+
}
|
|
826
|
+
this.adapter.sendTo(from, command, result, callback);
|
|
827
|
+
/*
|
|
797
828
|
this.debug(`TestConnection with ${JSON.stringify(msg)}`);
|
|
798
829
|
if (msg && msg.address) {
|
|
799
830
|
const netAddress = getNetAddress(msg.address);
|
|
@@ -851,6 +882,7 @@ class Commands {
|
|
|
851
882
|
}
|
|
852
883
|
}
|
|
853
884
|
}
|
|
885
|
+
*/
|
|
854
886
|
}
|
|
855
887
|
}
|
|
856
888
|
|
package/lib/developer.js
CHANGED
|
@@ -112,7 +112,7 @@ class Developer {
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
} catch (error) {
|
|
115
|
-
this.error(`SendToZigbee failed from publishTarget ${devId} (${error})`);
|
|
115
|
+
this.error(`SendToZigbee failed from publishTarget ${devId} (${error && error.message ? error.message : 'no details given'})`);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
if (!cid || !cmd) {
|
package/lib/devices.js
CHANGED
|
@@ -119,11 +119,12 @@ const sync = {
|
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
122
|
+
const lightStates = [states.state, states.brightness, states.brightness_move, states.transition_time, states.brightness_step];
|
|
123
|
+
const lightStatesWithColortemp = [...lightStates, states.colortemp, states.colortemp_move];
|
|
124
|
+
const lightStatesWithColor = [...lightStatesWithColortemp, states.color];
|
|
125
|
+
const lightStatesWithColor_hue = [...lightStatesWithColor, states.hue_move, states.transition_time, states.effect_type_hue];
|
|
126
|
+
const lightStatesWithColorNoTemp = [...lightStates, states.color];
|
|
127
|
+
const onOffStates = [states.state];
|
|
127
128
|
|
|
128
129
|
const gl_lightStatesWithColor = [states.gl_state, states.gl_brightness, states.gl_colortemp, states.gl_color, states.transition_time];
|
|
129
130
|
const gl_white_channel = [states.white_brightness, states.white_state, states.white_colortemp];
|
|
@@ -3072,7 +3073,7 @@ const commonStates = [
|
|
|
3072
3073
|
const DevicesByModel = new Map();
|
|
3073
3074
|
const LegacyDevicesByModel = new Map();
|
|
3074
3075
|
|
|
3075
|
-
const groupStates = [states.brightness_step].concat(lightStatesWithColor);
|
|
3076
|
+
const groupStates = [states.groupstateupdate, states.groupmemberupdate, states.brightness_step].concat(lightStatesWithColor);
|
|
3076
3077
|
|
|
3077
3078
|
function getByModel() {
|
|
3078
3079
|
DevicesByModel.clear();
|
|
@@ -3171,8 +3172,11 @@ module.exports = {
|
|
|
3171
3172
|
devices,
|
|
3172
3173
|
legacy_devices,
|
|
3173
3174
|
commonStates,
|
|
3175
|
+
commonGroupStates: [...commonStates, states.groupmemberupdate, states.groupstateupdate],
|
|
3174
3176
|
groupStates,
|
|
3175
|
-
|
|
3177
|
+
lightStatesWithColor,
|
|
3178
|
+
onOffStates,
|
|
3179
|
+
lightStates,
|
|
3176
3180
|
fillStatesWithExposes,
|
|
3177
3181
|
addExposeToDevices,
|
|
3178
3182
|
getByModel,
|
package/lib/exposes.js
CHANGED
|
@@ -412,14 +412,25 @@ function createFromExposes(model, def, device, log) {
|
|
|
412
412
|
return {...options, transition: transitionTime};
|
|
413
413
|
},
|
|
414
414
|
getter: payload => {
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
// Requires testing!
|
|
416
|
+
|
|
417
|
+
try {
|
|
418
|
+
// JSON
|
|
419
|
+
const colorJSON = JSON.parse(payload.replaceAll("'",'"'));
|
|
420
|
+
const numProp = Object.keys(colorJSON).length;
|
|
417
421
|
if (hasMultipleProperties(colorJSON, ['r', 'g', 'b'], numProp)) {
|
|
418
422
|
const hexstring = (colorJSON.r*65536 + colorJSON.g * 256 + colorJSON.b).toString(16).padStart(6);
|
|
419
423
|
return `#${hexstring.substring(2)}`;
|
|
420
424
|
}
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
// intentionally empty;
|
|
421
429
|
}
|
|
422
|
-
if (
|
|
430
|
+
if (payload.color.startsWith('#')) return payload.color;
|
|
431
|
+
const p = payload.replace('0x', '');
|
|
432
|
+
const m = p.match(/[0123456789abcdefABCDEF]+/);
|
|
433
|
+
if (p.length < 7 && m && m[0].length == p.length) return '#000000'.substring(0, 7-p.length) + p;
|
|
423
434
|
return undefined;
|
|
424
435
|
},
|
|
425
436
|
epname: expose.endpoint,
|