iobroker.zigbee 2.0.1 → 2.0.3

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/main.js CHANGED
@@ -36,6 +36,7 @@ const zigbeeHerdsmanPackage = require('zigbee-herdsman/package.json')
36
36
  const vm = require('vm');
37
37
  const util = require('util');
38
38
  const dmZigbee = require('./lib/devicemgmt.js');
39
+ const DeviceDebug = require('./lib/DeviceDebug');
39
40
 
40
41
  const createByteArray = function (hexString) {
41
42
  const bytes = [];
@@ -79,6 +80,9 @@ class Zigbee extends utils.Adapter {
79
80
  this.stController.on('changed', this.publishFromState.bind(this));
80
81
 
81
82
  this.deviceManagement = new dmZigbee(this);
83
+ this.deviceDebug = new DeviceDebug(this),
84
+ this.deviceDebug.on('log', this.onLog.bind(this));
85
+
82
86
 
83
87
  this.plugins = [
84
88
  new SerialListPlugin(this),
@@ -115,6 +119,19 @@ class Zigbee extends utils.Adapter {
115
119
  }
116
120
  }
117
121
 
122
+ warn(message) {
123
+ this.log.warn(message);
124
+ }
125
+ debug(message) {
126
+ this.log.debug(message);
127
+ }
128
+ error(message) {
129
+ this.log.error(message);
130
+ }
131
+ info(message) {
132
+ this.log.info(message);
133
+ }
134
+
118
135
  sendError(error, message) {
119
136
  try {
120
137
  if (this.supportsFeature && this.supportsFeature('PLUGINS')) {
@@ -210,12 +227,15 @@ class Zigbee extends utils.Adapter {
210
227
  this.zbController.on('new', this.newDevice.bind(this));
211
228
  this.zbController.on('leave', this.leaveDevice.bind(this));
212
229
  this.zbController.on('pairing', this.onPairing.bind(this));
213
- this.zbController.on('event', this.onZigbeeEvent.bind(this));
214
- this.zbController.on('msg', this.onZigbeeEvent.bind(this));
230
+ this.zbController.on('event', this.stController.onZigbeeEvent.bind(this.stController));
231
+ this.zbController.on('msg', this.stController.onZigbeeEvent.bind(this.stController));
215
232
  this.zbController.on('publish', this.publishToState.bind(this));
216
233
  this.zbController.configure(zigbeeOptions);
217
234
  await this.callPluginMethod('configure', [zigbeeOptions]);
218
235
 
236
+ // elevated debug handling
237
+ this.deviceDebug.start(this.stController, this.zbController);
238
+
219
239
  this.reconnectCounter = 1;
220
240
  this.doConnect();
221
241
  }
@@ -304,6 +324,9 @@ class Zigbee extends utils.Adapter {
304
324
  //fs.writeFileSync(mN+'.tmp3', modifiedCode)
305
325
  converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+\{(.+)\}\s+from\s+(\S+);/gm)]);
306
326
  modifiedCode = modifiedCode.replace(/import\s+\{.+\}\s+from\s+\S+;/gm, '');
327
+
328
+ converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+(.+)\s+from\s+(\S+);/gm)]);
329
+ modifiedCode = modifiedCode.replace(/import\s+.+\s+from\s+\S+;/gm, '');
307
330
  //fs.writeFileSync(mN+'.tmp4', modifiedCode)
308
331
  converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/const\s+\{(.+)\}\s+=\s+require\((.+)\)/gm)]);
309
332
  modifiedCode = modifiedCode.replace(/const\s+\{.+\}\s+=\s+require\(.+\)/gm, '');
@@ -312,7 +335,12 @@ class Zigbee extends utils.Adapter {
312
335
  modifiedCode = modifiedCode.replace(/const\s+\S+\s+=\s+require\(.+\)/gm, '');
313
336
  //fs.writeFileSync(mN+'.tmp6', modifiedCode)
314
337
 
315
- //fs.writeFileSync(mN+'.tmp', modifiedCode)
338
+ for(const component of modifiedCode.matchAll(/const (.+):(.+)=/gm)) {
339
+ modifiedCode = modifiedCode.replace(component[0], `const ${component[1]} = `);
340
+ }
341
+ modifiedCode = modifiedCode.replace(/export .+;/gm, '');
342
+
343
+ fs.writeFileSync(mN+'.tmp', modifiedCode)
316
344
 
317
345
  if (converterLoaded) {
318
346
  try {
@@ -345,10 +373,27 @@ class Zigbee extends utils.Adapter {
345
373
  const toAdd = {...definition};
346
374
  delete toAdd['homeassistant'];
347
375
  try {
348
- zigbeeHerdsmanConverters.addDefinition(toAdd);
376
+ if (zigbeeHerdsmanConverters.hasOwnProperty('addExternalDefinition')) {
377
+ zigbeeHerdsmanConverters.addExternalDefinition(toAdd);
378
+ this.log.info('added external converter using addExternalDefinition')
379
+ }
380
+ else if (zigbeeHerdsmanConverters.hasOwnProperty('addDefinition')) {
381
+ zigbeeHerdsmanConverters.addDefinition(toAdd);
382
+ this.log.info('added external converter using addDefinition')
383
+ }
384
+
385
+ /*
386
+ for (const zigbeeModel of toAdd.zigbeeModel)
387
+ {
388
+ try {
389
+ zigbeeHerdsmanConverters.addToExternalDefinitionsLookup(zigbeeModel, toAdd.toAdd);
390
+ } catch (e) {
391
+ this.log.error(`unable to apply external converter ${JSON.stringify(toAdd)} for device ${zigbeeModel}: ${e && e.message ? e.message : 'no error message available'}`);
392
+ }
393
+ }
394
+ */
349
395
  } catch (e) {
350
- this.log.error(`unable to apply external converter ${JSON.stringify(toAdd)}`);
351
- this.log.error(`${e}`);
396
+ this.log.error(`unable to apply external converter for ${JSON.stringify(toAdd.model)}: ${e && e.message ? e.message : 'no error message available'}`);
352
397
  }
353
398
  }
354
399
  }
@@ -359,15 +404,15 @@ class Zigbee extends utils.Adapter {
359
404
  const DebugIdentify = require('./debugidentify');
360
405
  debugversion = DebugIdentify.ReportIdentifier();
361
406
  } catch {
362
- debugversion = ' npm ...';
407
+ debugversion = 'npm ...';
363
408
  }
364
409
 
365
410
  // installed version
366
411
  let gitVers = '';
367
412
  try {
368
- this.log.info(`Starting Zigbee ${debugversion}`);
413
+ this.log.info(`Starting Adapter ${debugversion}`);
369
414
 
370
- await this.getForeignObject(`system.adapter.${this.namespace}`, (err, obj) => {
415
+ this.getForeignObject(`system.adapter.${this.namespace}`,async (err, obj) => {
371
416
  if (!err && obj && obj.common.installedFrom && obj.common.installedFrom.includes('://')) {
372
417
  const instFrom = obj.common.installedFrom;
373
418
  gitVers = gitVers + instFrom.replace('tarball', 'commit');
@@ -375,9 +420,9 @@ class Zigbee extends utils.Adapter {
375
420
  gitVers = obj.common.installedFrom;
376
421
  }
377
422
  this.log.info(`Installed Version: ${gitVers} (Converters ${zigbeeHerdsmanConvertersPackage.version} Herdsman ${zigbeeHerdsmanPackage.version})`);
423
+ await this.zbController.start();
378
424
  });
379
425
 
380
- await this.zbController.start();
381
426
  } catch (error) {
382
427
  this.setState('info.connection', false, true);
383
428
  this.log.error(`Failed to start Zigbee`);
@@ -434,7 +479,7 @@ class Zigbee extends utils.Adapter {
434
479
  const configExtPanId = this.config.extPanID ? `0x${this.config.extPanID.toLowerCase()}` : '0xdddddddddddddddd';
435
480
  let networkExtPanId = (await this.zbController.herdsman.getNetworkParameters()).extendedPanID;
436
481
  let needChange = false;
437
- this.log.debug(`Config value ${configExtPanId} : Network value ${networkExtPanId}`);
482
+ this.log.info(`Config value ${configExtPanId} : Network value ${networkExtPanId}`);
438
483
  const adapterType = this.config.adapterType || 'zstack';
439
484
  if (adapterType === 'zstack') {
440
485
  if (configExtPanId !== networkExtPanId) {
@@ -480,9 +525,8 @@ class Zigbee extends utils.Adapter {
480
525
  }
481
526
 
482
527
  await this.setState('info.connection', true, true);
483
-
484
- const devicesFromDB = this.zbController.getClientIterator(false);
485
528
  this.stController.CleanupRequired(false);
529
+ const devicesFromDB = this.zbController.getClientIterator(false);
486
530
  for (const device of devicesFromDB) {
487
531
  const entity = await this.zbController.resolveEntity(device);
488
532
  if (entity) {
@@ -490,6 +534,7 @@ class Zigbee extends utils.Adapter {
490
534
  this.stController.updateDev(device.ieeeAddr.substr(2), model, model, () =>
491
535
  this.stController.syncDevStates(device, model));
492
536
  }
537
+ else (this.log.warn('resolveEntity returned no entity'));
493
538
  }
494
539
  await this.callPluginMethod('start', [this.zbController, this.stController]);
495
540
  }
@@ -527,154 +572,6 @@ class Zigbee extends utils.Adapter {
527
572
  });
528
573
  }
529
574
 
530
- async onZigbeeEvent(type, entity, message) {
531
- this.log.debug(`Type ${type} device ${safeJsonStringify(entity)} incoming event: ${safeJsonStringify(message)}`);
532
-
533
- const device = entity.device;
534
- const mappedModel = entity.mapped;
535
- const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
536
- const cluster = message.cluster;
537
- const devId = device.ieeeAddr.substr(2);
538
- const meta = {device};
539
-
540
- const has_elevated_debug = this.stController.checkDebugDevice(devId);
541
-
542
- if (has_elevated_debug) {
543
- const shortMessage = {};
544
- for(const propertyName in message) {
545
- shortMessage[propertyName] = message[propertyName];
546
- }
547
- shortMessage.device = device.ieeeAddr;
548
- shortMessage.meta = undefined;
549
- shortMessage.endpoint = (message.endpoint.ID ? message.endpoint.ID: -1);
550
- this.log.warn(`ELEVATED I00: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`);
551
- }
552
- // this assigment give possibility to use iobroker logger in code of the converters, via meta.logger
553
- meta.logger = this.log;
554
-
555
- await this.checkIfModelUpdate(entity);
556
-
557
- let _voltage = 0;
558
- let _temperature = 0;
559
- let _humidity = 0;
560
-
561
- let isMessure = false;
562
- let isBattKey = false;
563
-
564
- if (mappedModel && mappedModel.meta && mappedModel.meta.battery) {
565
- const isVoltage = mappedModel.meta.battery.hasOwnProperty('voltageToPercentage');
566
-
567
- if (isVoltage) {
568
- const keys = Object.keys(message.data);
569
-
570
- for (const key of keys) {
571
- const value = message.data[key];
572
-
573
- if (value && value[1]) {
574
- if (key == 65282 && value[1][1]) {
575
- _voltage = value[1][1].elmVal;
576
- isBattKey = true;
577
- break;
578
- }
579
- if (key == 65281) {
580
- _voltage = value[1];
581
- isBattKey = true;
582
- _temperature = value[100];
583
- _temperature = _temperature /100;
584
- _humidity = value[101];
585
- _humidity = _humidity / 100;
586
- isMessure = true;
587
- break;
588
- }
589
- }
590
- }
591
- }
592
- }
593
-
594
- // always publish link_quality and battery
595
- if (message.linkquality) { // send battery with
596
- this.publishToState(devId, model, {linkquality: message.linkquality});
597
- if (isBattKey) {
598
- this.publishToState(devId, model, {voltage: _voltage});
599
- const battProz = zigbeeHerdsmanConvertersUtils.batteryVoltageToPercentage(_voltage,entity.mapped.meta.battery.voltageToPercentage);
600
- this.publishToState(devId, model, {battery: battProz});
601
- }
602
- if (isMessure) {
603
- this.publishToState(devId, model, {temperature: _temperature});
604
- this.publishToState(devId, model, {humidity: _humidity});
605
- }
606
- }
607
-
608
- // publish raw event to "from_zigbee"
609
- // some cleanup
610
- const msgForState = Object.assign({}, message);
611
- delete msgForState['device'];
612
- delete msgForState['endpoint'];
613
-
614
- msgForState['endpoint_id'] = message.endpoint.ID;
615
- this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
616
-
617
- if (!entity.mapped) {
618
- return;
619
- }
620
-
621
- let converters = mappedModel.fromZigbee.filter(c => c && c.cluster === cluster && (
622
- Array.isArray(c.type) ? c.type.includes(type) : c.type === type));
623
-
624
-
625
- if (!converters.length && type === 'readResponse') {
626
- converters = mappedModel.fromZigbee.filter(c => c.cluster === cluster && (
627
- Array.isArray(c.type) ? c.type.includes('attributeReport') : c.type === 'attributeReport'));
628
- }
629
-
630
- if (!converters.length) {
631
- if (type !== 'readResponse') {
632
- this.log.debug(`No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
633
- if (has_elevated_debug)
634
- this.log.warn(`ELEVATED IE00: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
635
- }
636
- return;
637
- }
638
-
639
- meta.state = { state: '' }; // for tuya
640
-
641
- this.processConverters(converters, devId, model, mappedModel, message, meta)
642
- .catch((error) => {
643
- // 'Error: Expected one of: 0, 1, got: 'undefined''
644
- if (cluster !== '64529') {
645
- this.log.error(`Error while processing converters DEVICE_ID: '${devId}' cluster '${cluster}' type '${type}'`);
646
- }
647
- });
648
- }
649
-
650
- async processConverters(converters, devId, model, mappedModel, message, meta) {
651
- for (const converter of converters) {
652
- const publish = (payload) => {
653
- this.log.debug(`Publish ${safeJsonStringify(payload)} to ${safeJsonStringify(devId)}`);
654
- if (typeof payload === 'object') {
655
- this.publishToState(devId, model, payload);
656
- }
657
- };
658
-
659
- const options = await new Promise((resolve, reject) => {
660
- this.stController.collectOptions(devId, model, (options) => {
661
- resolve(options);
662
- });
663
- });
664
-
665
- const payload = await new Promise((resolve, reject) => {
666
- const payloadConv = converter.convert(mappedModel, message, publish, options, meta);
667
- if (typeof payloadConv === 'object') {
668
- resolve(payloadConv);
669
- }
670
- });
671
-
672
- publish(payload);
673
- }
674
- }
675
-
676
-
677
-
678
575
  publishToState(devId, model, payload) {
679
576
  this.stController.publishToState(devId, model, payload);
680
577
  }
@@ -695,15 +592,18 @@ class Zigbee extends utils.Adapter {
695
592
  });
696
593
  }
697
594
 
698
- async publishFromState(deviceId, model, stateModel, stateList, options) {
595
+ async publishFromState(deviceId, model, stateModel, stateList, options, debugID) {
699
596
  let isGroup = false;
700
597
  const has_elevated_debug = this.stController.checkDebugDevice(deviceId)
701
598
 
702
599
  if (has_elevated_debug)
703
600
  {
704
601
  const stateNames = [];
705
- stateList.forEach( state => stateNames.push(state.id));
706
- this.log.warn(`ELEVATED O03: Publishing to ${deviceId} of model ${model} ${stateNames.join(', ')}`);
602
+ for (const state of stateList) {
603
+ stateNames.push(state.stateDesc.id);
604
+ }
605
+ const message = `Publishing to ${deviceId} of model ${model} with ${stateNames.join(', ')}`;
606
+ this.emit('device_debug', { ID:debugID, data: { ID: deviceId, flag: '03', IO:false }, message: message});
707
607
  }
708
608
  else
709
609
  this.log.debug(`publishFromState : ${deviceId} ${model} ${safeJsonStringify(stateList)}`);
@@ -718,7 +618,10 @@ class Zigbee extends utils.Adapter {
718
618
 
719
619
  if (!mappedModel) {
720
620
  this.log.debug(`No mapped model for ${model}`);
721
- if (has_elevated_debug) this.log.error(`ELEVATED OE01: No mapped model ${deviceId} (model ${model})`)
621
+ if (has_elevated_debug) {
622
+ const message=`No mapped model ${deviceId} (model ${model})`;
623
+ this.emit('device_debug', { ID:debugID, data: { error: 'NOMODEL' , IO:false }, message: message});
624
+ }
722
625
  return;
723
626
  }
724
627
 
@@ -735,13 +638,20 @@ class Zigbee extends utils.Adapter {
735
638
  if (stateDesc.id === 'send_payload') {
736
639
  try {
737
640
  const json_value = JSON.parse(value);
738
- const payload = {device: deviceId.replace('0x', ''), payload: json_value};
641
+ const payload = {device: deviceId.replace('0x', ''), payload: json_value, model:model, stateModel:stateModel};
642
+ 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 }});
643
+
739
644
  const result = await this.sendPayload(payload);
740
645
  if (result.hasOwnProperty('success') && result.success) {
741
646
  this.acknowledgeState(deviceId, model, stateDesc, value);
742
647
  }
648
+ else {
649
+ this.error('Error in SendPayload: '+result.error.message);
650
+ }
743
651
  } catch (error) {
744
- this.log.warn(`send_payload: ${value} does not parse as JSON Object : ${error.message}`);
652
+ const message = `send_payload: ${value} does not parse as JSON Object : ${error.message}`;
653
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugID, data: { error: 'EXSEND' ,states:[{id:stateDesc.id, value:value, payload:error.message}], IO:false }, message:message});
654
+ else this.error(message);
745
655
  return;
746
656
  }
747
657
  return;
@@ -749,8 +659,10 @@ class Zigbee extends utils.Adapter {
749
659
 
750
660
  if (stateDesc.isOption || stateDesc.compositeState) {
751
661
  // acknowledge state with given value
752
- if (has_elevated_debug)
662
+ if (has_elevated_debug) {
753
663
  this.log.warn('ELEVATED OC: changed state: ' + JSON.stringify(changedState));
664
+ this.emit('device_debug', { ID:debugID, data: { flag: 'cc', states:[{id:stateDesc.id, value:value, payload:'none (OC State)'}] , IO:false }});
665
+ }
754
666
  else
755
667
  this.log.debug('changed composite state: ' + JSON.stringify(changedState));
756
668
 
@@ -770,8 +682,11 @@ class Zigbee extends utils.Adapter {
770
682
  }
771
683
  if (mappedModel) {
772
684
  this.query_device_block.push(deviceId);
773
- if (has_elevated_debug)
774
- this.log.warn(`ELEVATED O06: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`);
685
+ if (has_elevated_debug) {
686
+ const message = `Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`;
687
+ //this.log.warn(`ELEVATED O06: ${message}`);
688
+ this.emit('device_debug', { ID:debugID, data: { flag: 'qs' ,states:[{id:stateDesc.id, value:value, payload:'none for device query'}], IO:false }, message:message});
689
+ }
775
690
  else
776
691
  this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
777
692
  for (const converter of mappedModel.toZigbee) {
@@ -781,7 +696,9 @@ class Zigbee extends utils.Adapter {
781
696
  await converter.convertGet(entity.device.endpoints[0], ckey, {});
782
697
  } catch (error) {
783
698
  if (has_elevated_debug) {
784
- this.log.warn(`ELEVATED OE02.1 Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' from query with '${error && error.message ? error.message : 'no error message'}`);
699
+ const message = `Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' from query with '${error && error.message ? error.message : 'no error message'}`;
700
+ this.log.warn(`ELEVATED OE02.1 ${message}`);
701
+ this.emit('device_debug', { ID:debugID, data: { error: 'NOTREAD' , IO:false }, message:message });
785
702
  }
786
703
  else
787
704
  this.log.info(`failed to read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
@@ -789,8 +706,11 @@ class Zigbee extends utils.Adapter {
789
706
  }
790
707
  }
791
708
  }
792
- if (has_elevated_debug)
793
- this.log.warn(`ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`);
709
+ if (has_elevated_debug) {
710
+ const message = `ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`;
711
+ //this.log.warn(`ELEVATED O07: ${message}`);
712
+ this.emit('device_debug', { ID:debugID, data: { flag: 'qe' , IO:false }, message:message});
713
+ }
794
714
  else
795
715
  this.log.info(`Device query for '${entity.device.ieeeAddr}' done`);
796
716
  const idToRemove = deviceId;
@@ -814,38 +734,51 @@ class Zigbee extends utils.Adapter {
814
734
  this.log.debug(`Type of toZigbee is '${typeof c}', Contains key ${(c.hasOwnProperty('key')?JSON.stringify(c.key):'false ')}`)
815
735
  if (!c.hasOwnProperty('key'))
816
736
  {
817
- if (c.hasOwnProperty('convertSet') && converter === undefined)
737
+ if (converter === undefined)
818
738
  {
819
739
  converter = c;
820
- if (has_elevated_debug)
821
- this.log.warn(`ELEVATED O04.${msg_counter}: Setting converter to keyless converter for ${deviceId} of type ${model}`)
740
+ if (has_elevated_debug) {
741
+ const message = `Setting converter to keyless converter for ${deviceId} of type ${model}`;
742
+ this.emit('device_debug', { ID:debugID, data: { flag: `s4.${msg_counter}` , IO:false }, message:message});
743
+ }
822
744
  else
823
- this.log.debug(`Setting converter to keyless converter for ${deviceId} of type ${model}`)
745
+ this.log.debug(`Setting converter to keyless converter for ${deviceId} of type ${model}`);
824
746
  msg_counter++;
825
747
  }
826
748
  else
827
749
  {
828
750
  if (has_elevated_debug)
829
- this.log.warn(`ELEVATED O04.${msg_counter}: ignoring keyless converter for ${deviceId} of type ${model}`)
751
+ {
752
+ const message = `ignoring keyless converter for ${deviceId} of type ${model}`;
753
+ this.emit('device_debug', { ID:debugID, data: { flag: `i4.${msg_counter}` , IO:false} , message:message});
754
+ }
830
755
  else
831
- this.log.debug(`ignoring keyless converter for ${deviceId} of type ${model}`)
756
+ this.log.debug(`ignoring keyless converter for ${deviceId} of type ${model}`);
832
757
  msg_counter++;
833
758
  }
834
759
  continue;
835
760
  }
836
761
  if (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id))
837
762
  {
838
- if (has_elevated_debug)
839
- this.log.warn(`ELEVATED O04.${msg_counter}: ${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
763
+ const message = `${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`;
764
+ if (has_elevated_debug) {
765
+ this.emit('device_debugug', { ID:debugID, data: { flag: `${converter===undefined ? 's' : 'o'}4.${msg_counter}` , IO:false }, message:message});
766
+
767
+ }
840
768
  else
841
- this.log.debug(`${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
769
+ this.log.debug(message);
842
770
  converter = c;
843
771
  msg_counter++;
844
772
  }
845
773
  }
846
774
  if (converter === undefined) {
847
- this.log.error(`No converter available for '${model}' with key '${stateDesc.id}' `);
848
- this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
775
+ const message = `No converter available for '${model}' with key '${stateDesc.id}' `;
776
+ if (has_elevated_debug) {
777
+ this.emit('device_debug', { ID:debugID, data: { error: 'NOCONV',states:[{id:stateDesc.id, value:value, payload:'no converter'}] , IO:false }, message:message});
778
+ }
779
+ else {
780
+ this.log.warn(message);
781
+ }
849
782
  return;
850
783
  }
851
784
 
@@ -864,10 +797,12 @@ class Zigbee extends utils.Adapter {
864
797
 
865
798
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
866
799
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
867
- if (has_elevated_debug)
868
- this.log.warn(`ELEVATED O04: convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`);
800
+ const message = `convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`;
801
+ if (has_elevated_debug) {
802
+ this.emit('device_debug', { ID:debugID, data: { flag: '04', payload: {key:key, ep: stateDesc.epname, value:preparedValue, options:preparedOptions}, IO:false }, message:message});
803
+ }
869
804
  else
870
- this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
805
+ this.log.debug(message);
871
806
 
872
807
  let target;
873
808
  if (model === 'group') {
@@ -897,6 +832,10 @@ class Zigbee extends utils.Adapter {
897
832
  meta.message.state = preparedValue;
898
833
  }
899
834
  }
835
+ if (has_elevated_debug) {
836
+ //this.log.warn('epname is ' + epName + ' or ' + stateDesc.epname);
837
+ this.emit('device_debug', { ID:debugID, data: { states:[{id:stateDesc.id, value:value, payload:preparedValue, ep:stateDesc.epname}] , IO:false }});
838
+ }
900
839
 
901
840
  if (preparedOptions !== undefined) {
902
841
  if (preparedOptions.hasOwnProperty('state')) {
@@ -906,33 +845,52 @@ class Zigbee extends utils.Adapter {
906
845
 
907
846
  try {
908
847
  const result = await converter.convertSet(target, key, preparedValue, meta);
909
- if (has_elevated_debug)
910
- this.log.warn(`ELEVATED O05: convert result ${safeJsonStringify(result)} for device ${deviceId}`);
848
+ const message = `convert result ${safeJsonStringify(result)} for device ${deviceId}`;
849
+ if (has_elevated_debug) {
850
+ this.emit('device_debug', { ID:debugID, data: { flag: 'SUCCESS' , IO:false }, message:message});
851
+ }
911
852
  else
912
- this.log.debug(`convert result ${safeJsonStringify(result)}`);
853
+ this.log.debug(message);
913
854
  if (result !== undefined) {
914
- if (stateModel && !isGroup) {
855
+ if (stateModel && !isGroup && !stateDesc.noack) {
915
856
  this.acknowledgeState(deviceId, model, stateDesc, value);
916
857
  }
917
858
  // process sync state list
918
859
  this.processSyncStatesList(deviceId, model, syncStateList);
919
860
  }
920
- else
921
- if (has_elevated_debug)
922
- this.log.error(`ELEVATED OE2: Error convert result for ${key} with ${safeJsonStringify(preparedValue)} is undefined on device ${deviceId}.`);
923
-
861
+ else {
862
+ if (has_elevated_debug) {
863
+ const message = `Convert does not return a result result for ${key} with ${safeJsonStringify(preparedValue)} on device ${deviceId}.`;
864
+ this.emit('device_debug', { ID:debugID, data: { flag: '06' , IO:false }, message:message});
865
+ }
866
+ }
924
867
  } catch (error) {
925
- if (has_elevated_debug)
926
- this.log.error(`ELEVATED OE3: caught error ${safeJsonStringify(error)} when setting value for device ${deviceId}.`);
868
+ if (has_elevated_debug) {
869
+ const message = `caught error ${safeJsonStringify(error)} when setting value for device ${deviceId}.`;
870
+ this.emit('device_debug', { ID:debugID, data: { error: 'EXSET' , IO:false },message:message});
871
+ }
927
872
  this.filterError(`Error ${error.code} on send command to ${deviceId}.` +
928
873
  ` Error: ${error.stack}`, `Send command to ${deviceId} failed with`, error);
929
874
  }
930
875
  });
931
876
  } catch (err) {
932
- this.log.error(`No entity for ${deviceId} : ${err && err.message ? err.message : 'no error message'}`);
877
+ const message = `No entity for ${deviceId} : ${err && err.message ? err.message : 'no error message'}`;
878
+ this.emit('device_debug', { ID:debugID, data: { error: 'EXPUB' , IO:false }, message:message});
933
879
  }
934
880
  }
935
881
 
882
+
883
+ extractEP(key, endpoints) {
884
+ try {
885
+ if (endpoints) for (const ep of Object.keys(endpoints)) {
886
+ if (key.endsWith('_'+ep)) return { setattr: key.replace('_'+ep, ''), epname:ep }
887
+ }
888
+ }
889
+ catch {
890
+ return {};
891
+ }
892
+ return {};
893
+ }
936
894
  // This function is introduced to explicitly allow user level scripts to send Commands
937
895
  // directly to the zigbee device. It utilizes the zigbee-herdsman-converters to generate
938
896
  // the exact zigbee message to be sent and can be used to set device options which are
@@ -946,7 +904,6 @@ class Zigbee extends utils.Adapter {
946
904
  // endpoint: optional: the endpoint to send the data to, if supported.
947
905
  //
948
906
  async sendPayload(payload) {
949
- this.log.debug(`publishToDevice called with ${safeJsonStringify(payload)}`);
950
907
  let payloadObj = {};
951
908
  if (typeof payload === 'string') {
952
909
  try {
@@ -961,7 +918,7 @@ class Zigbee extends utils.Adapter {
961
918
  }
962
919
  } else if (typeof payload === 'object') {
963
920
  payloadObj = payload;
964
- }
921
+ } else return { success: false, error: 'illegal type of payload: ' + typeof payload};
965
922
 
966
923
  if (payloadObj.hasOwnProperty('device') && payloadObj.hasOwnProperty('payload')) {
967
924
  try {
@@ -986,16 +943,24 @@ class Zigbee extends utils.Adapter {
986
943
  this.sendError(`Illegal payload type for ${safeJsonStringify(payloadObj.device)}`);
987
944
  return {success: false, error: `Illegal payload type for ${safeJsonStringify(payloadObj.device)}`};
988
945
  }
946
+ const endpoints = mappedModel && mappedModel.endpoint ? mappedModel.endpoint(entity.device) : null;
989
947
  for (const key in payloadObj.payload) {
990
948
  if (payloadObj.payload[key] != undefined) {
991
949
  const datatype = typeof payloadObj.payload[key];
950
+ const epobj = this.extractEP(key, endpoints);
951
+ if (payloadObj.endpoint) {
952
+ epobj.epname = payloadObj.endpoint;
953
+ delete epobj.setattr;
954
+ }
992
955
  stateList.push({
993
956
  stateDesc: {
994
957
  id: key,
995
958
  prop: key,
996
959
  role: 'state',
997
960
  type: datatype,
998
- epname: payloadObj.endpoint,
961
+ noack:true,
962
+ epname: epobj.epname,
963
+ setattr: epobj.setattr,
999
964
  },
1000
965
  value: payloadObj.payload[key],
1001
966
  index: 0,
@@ -1004,8 +969,7 @@ class Zigbee extends utils.Adapter {
1004
969
  }
1005
970
  }
1006
971
  try {
1007
- this.log.debug(`Calling publish to state for ${safeJsonStringify(payloadObj.device)} with ${safeJsonStringify(stateList)}`);
1008
- await this.publishFromState(`0x${payload.device}`, '', undefined, stateList, payload.options);
972
+ await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, Date.now());
1009
973
  return {success: true};
1010
974
  } catch (error) {
1011
975
  this.log.error(`Error ${error.code} on send command to ${payload.device}.` + ` Error: ${error.stack} ` + `Send command to ${payload.device} failed with ` + error);
@@ -1023,6 +987,7 @@ class Zigbee extends utils.Adapter {
1023
987
 
1024
988
  newDevice(entity) {
1025
989
  this.log.debug(`New device event: ${safeJsonStringify(entity)}`);
990
+ this.stController.AddModelFromHerdsman(entity.device, entity.mapped.model)
1026
991
  const dev = entity.device;
1027
992
  if (dev) {
1028
993
  this.getObject(dev.ieeeAddr.substr(2), (err, obj) => {