iobroker.zigbee 3.1.4 → 3.1.5

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/lib/commands.js CHANGED
@@ -176,6 +176,9 @@ class Commands {
176
176
  case 'downloadIcons':
177
177
  this.triggerIconDownload(obj);
178
178
  break;
179
+ case 'aliveCheck':
180
+ this.adapter.sendTo(obj.from, obj.command, {msg:'success'}, obj.callback);
181
+ break;
179
182
  default:
180
183
  this.debug(`Commands: Command ${obj.command} is unknown`);
181
184
  //this.adapter.sendTo(obj.from, obj.command, obj.message, obj.callback);
@@ -355,7 +358,13 @@ class Commands {
355
358
  if (member && typeof member.ieee === 'string') {
356
359
  const memberId = member.ieee.substr(2);
357
360
  const device = await this.adapter.getObjectAsync(`${this.adapter.namespace}.${member.ieee.substr(2)}`);
358
- if (groups.hasOwnProperty(memberId)) { if (!groups[memberId].includes(groupID)) groups[memberId].push(groupID)} else groups[memberId] = [groupID]
361
+ const item = groups[memberId] || { groups:[], gep: { }};
362
+ const gep = item.gep[member.epid] || [];
363
+
364
+ if (!item.groups.includes(groupID)) item.groups.push(groupID);
365
+ if (!gep.includes(`${groupID}`)) gep.push(`${groupID}`);
366
+ item.gep[member.epid] = gep;
367
+ groups[memberId] = item;
359
368
  if (device) {
360
369
  member.device = device.common.name;
361
370
  } else {
@@ -422,7 +431,7 @@ class Commands {
422
431
  nwk:device.device.networkAddress,
423
432
  manuf_id:device.device.maufacturerID,
424
433
  manuf_name:device.device.manufacturerName,
425
- manufacturer:device.mapped.vendor,
434
+ manufacturer:device.mapped ? device.mapped.vendor : '',
426
435
  power:device.device.powerSource,
427
436
  app_version:device.device.applicationVersion,
428
437
  hard_version:device.device.hardwareVersion,
@@ -442,25 +451,40 @@ class Commands {
442
451
  output_clusters:ep.outputClusters,
443
452
  })
444
453
  }
445
- rv.mapped = {
446
- model:device.mapped.model,
447
- description:device.mapped.description,
448
- //fingerprint:JSON.stringify(device.mapped.fingerprint),
449
- vendor:device.mapped.vendor,
450
- hasOnEvent:device.mapped.onEvent != undefined,
451
- hasConfigure:device.mapped.configure != undefined,
452
- options:[],
453
- }
454
- if (device.mapped.options && typeof (device.mapped.options == 'object')) {
455
- const optionDesc = [];
456
- for (const option of device.mapped.options) {
457
- if (option.name)
458
- rv.mapped.options.push(option.name);
454
+ if (device.mapped) {
455
+ rv.mapped = {
456
+ model:device.mapped.model,
457
+ description:device.mapped.description,
458
+ //fingerprint:JSON.stringify(device.mapped.fingerprint),
459
+ vendor:device.mapped.vendor,
460
+ hasOnEvent:device.mapped.onEvent != undefined,
461
+ hasConfigure:device.mapped.configure != undefined,
462
+ options:[],
463
+ }
464
+ if (device.mapped.options && typeof (device.mapped.options == 'object')) {
465
+ const optionDesc = [];
466
+ for (const option of device.mapped.options) {
467
+ if (option.name)
468
+ rv.mapped.options.push(option.name);
469
+ }
470
+ }
471
+ }
472
+ else {
473
+ rv.mapped = {
474
+ model:device.name,
475
+ description:device.name,
476
+ vendor:'not set',
477
+ hasOnEvent: false,
478
+ hasConfigure: false,
479
+ options:[],
459
480
  }
460
481
  }
461
482
  }
462
483
  catch (error) {
463
- this.warn(`Error ${error && error.message + ' ' ? error.message : ''}building device info for ${JSON.stringify(device)}`);
484
+ if (device && device.name === 'Coordinator') return rv;
485
+ const dev = device ? device.device || {} : {}
486
+ const msg = device ? `device ${device.name} (${dev.ieeeAddr}, NWK ${dev.networkAddres}, ID: ${dev.ID})` : 'undefined device';
487
+ this.warn(`Error ${error && error.message ? error.message + ' ' : ''}building device info for ${msg}`);
464
488
  }
465
489
  return rv;
466
490
  }
@@ -472,17 +496,22 @@ class Commands {
472
496
  }
473
497
  const exists = devices.find((dev) => (dev._id && device.device.ieeeAddr === getZbId(dev._id)));
474
498
  if (!exists) {
475
- devices.push({
476
- _id: device.device.ieeeAddr,
477
- icon: 'img/unknown.png',
499
+ const coordinatorData = {
500
+ _id : `${this.adapter.namespace}.${device.device.ieeeAddr.substring(2)}`,
478
501
  paired: true,
479
502
  info: this.buildDeviceInfo(device),
480
- common: {
481
- name: undefined,
482
- type: undefined,
483
- },
484
- native: {}
485
- });
503
+ native: { id: device.device.ieeeAddr.substring(2) },
504
+ mapped : {},
505
+ statesDev: [],
506
+ }
507
+ if (device.device.name === 'Coordinator') {
508
+ coordinatorData.icon = 'zigbee.png';
509
+ coordinatorData.common = { name: undefined, type: undefined };
510
+ } else {
511
+ coordinatorData.common = { name: 'Coordinator', type: 'Coordinator' };
512
+ coordinatorData.icon= 'img/unknown.png';
513
+ }
514
+ devices.push(coordinatorData);
486
515
  }
487
516
 
488
517
  }
@@ -533,7 +562,7 @@ class Commands {
533
562
  PromiseChain.push(this.fillInfo(devInfo, all_stateDefs.filter(item => item._id.startsWith(devInfo._id)),all_states));
534
563
  }
535
564
  if (!id) {
536
- for (const client of this.zbController.getClientIterator(false)) {
565
+ for (const client of this.zbController.getClientIterator(true)) {
537
566
  PromiseChain.push(this.appendDevicesWithoutObjects(deviceObjects,client))
538
567
  }
539
568
  }
@@ -543,7 +572,8 @@ class Commands {
543
572
  for (const groupmember in groups) {
544
573
  const device = deviceObjects.find(dev => (groupmember === dev.native.id));
545
574
  if (device) {
546
- device.groups = groups[groupmember];
575
+ device.groups = groups[groupmember].groups;
576
+ device.groups_by_ep = groups[groupmember].gep;
547
577
  }
548
578
  }
549
579
 
@@ -777,7 +807,6 @@ class Commands {
777
807
  this.debug(`updateLocalConfigItems : ${JSON.stringify(msg)}`);
778
808
  const target = msg.target.replace(`${this.adapter.namespace}.`, '');
779
809
  const entity = await this.zbController.resolveEntity(target);
780
- //this.warn('entity for ' + target + ' is '+ JSON.stringify(entity))
781
810
  if (entity && !entity.mapped) {
782
811
  this.warn('unable to set local Override for device whithout mapped model');
783
812
  return;
@@ -811,13 +840,18 @@ class Commands {
811
840
  await this.stController.localConfig.updateLocalOverride(target, (entity ? entity.mapped.model : 'group'), prop, msg.data[prop], msg.global);
812
841
  }
813
842
  }
814
- if (entity) {
815
- this.debug('updateLocalConfigItems with Entity');
816
- this.stController.updateDev(target, entity.mapped.model, entity.mapped.model, () => {this.adapter.sendTo(from, command, {}, callback)});
843
+ try {
844
+ if (entity) {
845
+ this.debug('updateLocalConfigItems with Entity');
846
+ this.stController.updateDev(target, entity.mapped.model, entity.mapped.model, () => {this.adapter.sendTo(from, command, {}, callback)});
847
+ }
848
+ else {
849
+ this.debug('updateLocalConfigItems without Entity');
850
+ this.stController.updateDev(target, undefined, 'group',() => {this.adapter.sendTo(from, command, {}, callback)});
851
+ }
817
852
  }
818
- else {
819
- this.debug('updateLocalConfigItems without Entity');
820
- this.stController.updateDev(target, undefined, 'group',() => {this.adapter.sendTo(from, command, {}, callback)});
853
+ catch (error) {
854
+ this.adapter.sendTo(from, command, {err: error.message}, callback);
821
855
  }
822
856
  }
823
857
  }
@@ -458,7 +458,7 @@ class StatesController extends EventEmitter {
458
458
  if (stateDesc.id === 'send_payload') {
459
459
  try {
460
460
  const json_value = JSON.parse(value);
461
- const payload = {device: deviceId.replace('0x', ''), payload: json_value, model:model, stateModel:stateModel};
461
+ const payload = {device: deviceId.replace('0x', ''), payload: json_value, model:model, stateModel:stateModel, acknowledge:true};
462
462
  if (has_elevated_debug) this.emit('device_debug', { ID:debugID, data: { flag: '04' ,payload:value ,states:[{id:stateDesc.id, value:json_value, payload:'none'}], IO:false }});
463
463
 
464
464
  this.emit('send_payload', payload, debugID, has_elevated_debug);
@@ -67,7 +67,6 @@ class DeviceEvent extends BaseExtension {
67
67
 
68
68
 
69
69
  if (mappedDevice && mappedDevice.onEvent && eventData.data) {
70
- this.warn(`calling onEvent for ${eventData.type} on ${device.ieeeAddr}`);
71
70
  try {
72
71
  mappedDevice.onEvent(eventData);
73
72
  }
@@ -676,7 +676,7 @@ class ZigbeeController extends EventEmitter {
676
676
  endpoint = device.endpoints[0];
677
677
  }
678
678
  }
679
- const options = this.adapter.stController.localConfig.getOptions(device.ieeeAddr, mapped.model);
679
+ const options = mapped ? this.adapter.stController.localConfig.getOptions(device.ieeeAddr, mapped.model) : {};
680
680
  return {
681
681
  type: 'device',
682
682
  device,
@@ -731,13 +731,13 @@ class ZigbeeController extends EventEmitter {
731
731
  }
732
732
 
733
733
  try {
734
- if (this.HerdsmanStarted) {
734
+ if (this.herdsmanStarted) {
735
735
  await this.permitJoin(0);
736
736
  await this.herdsman.stop();
737
- this.HerdsmanStarted = false;
737
+ this.herdsmanStarted = false;
738
738
  this.info('zigbecontroller stopped successfully');
739
739
  }
740
- this.info('zigbecontroller stopped successfully - ZH was not running');
740
+ else this.info('zigbecontroller stopped successfully - ZH was not running');
741
741
  } catch (error) {
742
742
  this.sendError(error);
743
743
  if (this.herdsmanStarted) {
@@ -876,10 +876,11 @@ class ZigbeeController extends EventEmitter {
876
876
  async handleDeviceAnnounce(message) {
877
877
  if (this.debugActive) this.debug('handleDeviceAnnounce', message);
878
878
  const entity = await this.resolveEntity(message.device || message.ieeeAddr);
879
- const friendlyName = entity.name;
880
-
879
+ const friendlyName = entity ? entity.name : message.ieeeAddr ? message.ieeeAddr : message.device && message.device.ieeeAddr ? message.device.ieeeAddr : 'without data';
881
880
 
882
881
  this.emit('pairing', `Device '${friendlyName}' announced itself`);
882
+ if (!entity) return;
883
+
883
884
  if (this.adapter.stController.checkDebugDevice(friendlyName)) {
884
885
  this.emit('device_debug', {ID: Date.now(), data: {flag:'da', states:[{id: '--', value:'--', payload:message}] , IO:true} ,message:`Device '${friendlyName}' announced itself`});
885
886
  }
@@ -1386,7 +1387,7 @@ class ZigbeeController extends EventEmitter {
1386
1387
  // device: name of the device. For a device zigbee.0.0011223344556677 this would be 0011223344556677
1387
1388
  // payload: The data to send to the device as JSON object (key/Value pairs)
1388
1389
  // endpoint: optional: the endpoint to send the data to, if supported.
1389
- //
1390
+ // acknowledge: optional: if to update the devices 'send_payload' DP (if present) after successful publish
1390
1391
  async publishPayload(payload, debugID, has_elevated_debug) {
1391
1392
  let payloadObj = {};
1392
1393
  if (typeof payload === 'string') {
@@ -1450,6 +1451,9 @@ class ZigbeeController extends EventEmitter {
1450
1451
  }
1451
1452
  try {
1452
1453
  await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, debugID, has_elevated_debug);
1454
+ if (payload.acknowledge) {
1455
+ this.emit('acknowledge_state', payload.device, payload.model, { id:'send_payload' }, undefined);
1456
+ }
1453
1457
  return {success: true};
1454
1458
  } catch (error) {
1455
1459
  this.log.error(`Error ${error.code} on send command to ${payload.device}.` + ` Error: ${error.stack} ` + `Send command to ${payload.device} failed with ` + error);
package/main.js CHANGED
@@ -274,7 +274,6 @@ class Zigbee extends utils.Adapter {
274
274
 
275
275
  SandboxRequire(sandbox, items) {
276
276
  if (!items) return true;
277
- //let converterLoaded = true;
278
277
  for (const item of items) {
279
278
  const modulePath = item[2].replace(/['"]/gm, '');
280
279
 
@@ -350,9 +349,6 @@ class Zigbee extends utils.Adapter {
350
349
  converterLoaded = false;
351
350
  this.log.error(`converter does not export any converter array, please add 'module.exports' statement to ${mN}`);
352
351
  }
353
-
354
- //fs.writeFileSync(mN+'.tmp', modifiedCode)
355
-
356
352
  if (converterLoaded) {
357
353
  try {
358
354
  this.log.warn('Trying to run sandbox for ' + mN);
@@ -422,7 +418,6 @@ class Zigbee extends utils.Adapter {
422
418
  }
423
419
  else try {
424
420
  await this.zbController.stopHerdsman();
425
- //this.logToPairing('herdsman stopped !');
426
421
  this.sendTo(from, command, { status:true }, callback);
427
422
  } catch (error) {
428
423
  this.sendTo(from, command, { status:true, error }, callback);
@@ -458,12 +453,6 @@ class Zigbee extends utils.Adapter {
458
453
  this.setState('info.connection', false, true);
459
454
  this.logToPairing(`Failed to start Zigbee: ${error && error.message ? error.message : 'no message given'}`)
460
455
  this.log.error(`Failed to start Zigbee: ${error && error.message ? error.message : 'no message given'}`);
461
- /* if (error.stack) {
462
- this.log.error(error.stack);
463
- } else {
464
- this.log.error(error);
465
- }
466
- */
467
456
  this.sendError(error, `Failed to start Zigbee`);
468
457
  if (noReconnect) return false;
469
458
 
@@ -668,12 +657,18 @@ class Zigbee extends utils.Adapter {
668
657
  }
669
658
 
670
659
  acknowledgeState(deviceId, model, stateDesc, value) {
671
- if (model === 'group') {
672
- const stateId = `${this.namespace}.group_${deviceId}.${stateDesc.id}`;
673
- this.setState(stateId, value, true);
674
- } else {
675
- const stateId = `${this.namespace}.${deviceId.replace('0x', '')}.${stateDesc.id}`;
676
- this.setState(stateId, value, true);
660
+ const stateId = (model === 'group' ?
661
+ `${this.namespace}.group_${deviceId}.${stateDesc.id}` :
662
+ `${this.namespace}.${deviceId.replace('0x', '')}.${stateDesc.id}`);
663
+ if (value === undefined) try {
664
+ this.getState(stateId, (err, state) => { if (!err && state.hasOwnProperty('val')) this.setState(stateId, state.val, true)});
665
+ }
666
+ catch (error) {
667
+ this.log.warn(`Error acknowledging ${stateId} without value: ${error && error.message ? error.message : 'no reason given'}`);
668
+ }
669
+ else try { this.setState(stateId, value, true); }
670
+ catch (error) {
671
+ this.log.warn(`Error acknowledging ${stateId} with value ${JSON.stringify(value)}: ${error && error.message ? error.message : 'no reason given'}`);
677
672
  }
678
673
  }
679
674
 
@@ -754,10 +749,8 @@ class Zigbee extends utils.Adapter {
754
749
  this.log.info('cleaning everything up');
755
750
  await this.callPluginMethod('stop');
756
751
  if (this.stController) chain.push(this.stController.stop());
757
- if (this.zbController) {
758
- chain.push(this.zbController.stop());
759
- }
760
- Promise.all(chain);
752
+ if (this.zbController) chain.push(this.zbController.stop());
753
+ await Promise.all(chain);
761
754
  this.log.info('cleanup successful');
762
755
  callback();
763
756
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "3.1.4",
3
+ "version": "3.1.5",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -37,10 +37,10 @@
37
37
  "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
38
38
  "@alcalzone/release-script-plugin-license": "^3.7.0",
39
39
  "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
40
- "@iobroker/testing": "^5.1.0",
40
+ "@iobroker/testing": "^5.1.1",
41
41
  "chai": "^5.2.1",
42
42
  "chai-as-promised": "^7.1.1",
43
- "eslint": "^9.30.0",
43
+ "eslint": "^9.36.0",
44
44
  "eslint-config-prettier": "^9.1.0",
45
45
  "eslint-plugin-prettier": "^5.5.4",
46
46
  "mixin-deep": "^2.0.1",