iobroker.zigbee 2.0.2 → 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/README.md +64 -35
- package/admin/admin.js +211 -19
- package/admin/img/philips_hue_lom001.png +0 -0
- package/admin/tab_m.html +13 -8
- 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/io-package.json +15 -49
- package/lib/DeviceDebug.js +80 -0
- package/lib/commands.js +16 -1
- package/lib/developer.js +0 -0
- package/lib/exposes.js +1 -1
- package/lib/groups.js +6 -8
- package/lib/localConfig.js +1 -2
- package/lib/ota.js +6 -6
- package/lib/statescontroller.js +270 -97
- package/lib/zbDeviceAvailability.js +2 -2
- package/lib/zbDeviceConfigure.js +22 -15
- package/lib/zigbeecontroller.js +13 -6
- package/main.js +132 -194
- package/package.json +2 -2
package/lib/zigbeecontroller.js
CHANGED
|
@@ -179,7 +179,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
179
179
|
this.warn(`Network parameters on Coordinator: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
|
|
180
180
|
}
|
|
181
181
|
catch (error) {
|
|
182
|
-
this.
|
|
182
|
+
this.info(`Unable to obtain herdsman settings`)
|
|
183
183
|
}
|
|
184
184
|
try {
|
|
185
185
|
await this.herdsman.stop();
|
|
@@ -747,7 +747,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
747
747
|
this.debug('handleDeviceLeave', message);
|
|
748
748
|
const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
749
749
|
const friendlyName = entity ? entity.name : message.ieeeAddr;
|
|
750
|
-
this.
|
|
750
|
+
if (this.adapter.stController.checkDebugDevice(friendlyName)) {
|
|
751
|
+
this.emit('device_debug', {ID: Date.now(), data: {flag:'dl', states:[{id: '--', value:'--', payload:message}], IO:true},message:`Device '${friendlyName}' has left the network`});
|
|
752
|
+
}
|
|
753
|
+
else
|
|
754
|
+
this.info(`Device '${friendlyName}' left the network`);
|
|
751
755
|
this.emit('leave', message.ieeeAddr);
|
|
752
756
|
// Call extensions
|
|
753
757
|
this.callExtensionMethod(
|
|
@@ -764,7 +768,10 @@ class ZigbeeController extends EventEmitter {
|
|
|
764
768
|
this.debug('handleDeviceAnnounce', message);
|
|
765
769
|
const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
766
770
|
const friendlyName = entity.name;
|
|
767
|
-
if (this.
|
|
771
|
+
if (this.adapter.stController.checkDebugDevice(friendlyName)) {
|
|
772
|
+
this.emit('device_debug', {ID: Date.now(), data: {flag:'da', states:[{id: '--', value:'--', payload:message}] , IO:true} ,message:`Device '${friendlyName}' announced itself`});
|
|
773
|
+
}
|
|
774
|
+
else if (this.warnOnDeviceAnnouncement) {
|
|
768
775
|
this.warn(`Device '${friendlyName}' announced itself`);
|
|
769
776
|
} else {
|
|
770
777
|
this.info(`Device '${friendlyName}' announced itself`);
|
|
@@ -883,7 +890,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
883
890
|
let resolved = await this.resolveEntity(device, 0);
|
|
884
891
|
if (!resolved) {
|
|
885
892
|
resolved = { name:'unresolved device', device:device }
|
|
886
|
-
this.
|
|
893
|
+
this.debug('resolve Entity failed for ' + device.ieeeAddr)
|
|
887
894
|
}
|
|
888
895
|
let result;
|
|
889
896
|
|
|
@@ -943,9 +950,9 @@ class ZigbeeController extends EventEmitter {
|
|
|
943
950
|
|
|
944
951
|
callback && callback({lqis, routing, errors});
|
|
945
952
|
if (errors.length) {
|
|
946
|
-
this.
|
|
953
|
+
this.debug(`Map Data collection complete with ${errors.length} issues:`);
|
|
947
954
|
for (const msg of errors)
|
|
948
|
-
this.
|
|
955
|
+
this.debug(msg);
|
|
949
956
|
}
|
|
950
957
|
else
|
|
951
958
|
this.info('Map data collection complete');
|
package/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
*
|
|
3
3
|
* Zigbee devices adapter
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -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
|
}
|
|
@@ -510,7 +530,6 @@ class Zigbee extends utils.Adapter {
|
|
|
510
530
|
for (const device of devicesFromDB) {
|
|
511
531
|
const entity = await this.zbController.resolveEntity(device);
|
|
512
532
|
if (entity) {
|
|
513
|
-
// this.log.warn('sync dev states for ' + (entity.mapped ? entity.mapped.model : entity.device.modelID));
|
|
514
533
|
const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
|
|
515
534
|
this.stController.updateDev(device.ieeeAddr.substr(2), model, model, () =>
|
|
516
535
|
this.stController.syncDevStates(device, model));
|
|
@@ -553,154 +572,6 @@ class Zigbee extends utils.Adapter {
|
|
|
553
572
|
});
|
|
554
573
|
}
|
|
555
574
|
|
|
556
|
-
async onZigbeeEvent(type, entity, message) {
|
|
557
|
-
this.log.debug(`Type ${type} device ${safeJsonStringify(entity)} incoming event: ${safeJsonStringify(message)}`);
|
|
558
|
-
|
|
559
|
-
const device = entity.device;
|
|
560
|
-
const mappedModel = entity.mapped;
|
|
561
|
-
const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
|
|
562
|
-
const cluster = message.cluster;
|
|
563
|
-
const devId = device.ieeeAddr.substr(2);
|
|
564
|
-
const meta = {device};
|
|
565
|
-
|
|
566
|
-
const has_elevated_debug = this.stController.checkDebugDevice(devId);
|
|
567
|
-
|
|
568
|
-
if (has_elevated_debug) {
|
|
569
|
-
const shortMessage = {};
|
|
570
|
-
for(const propertyName in message) {
|
|
571
|
-
shortMessage[propertyName] = message[propertyName];
|
|
572
|
-
}
|
|
573
|
-
shortMessage.device = device.ieeeAddr;
|
|
574
|
-
shortMessage.meta = undefined;
|
|
575
|
-
shortMessage.endpoint = (message.endpoint.ID ? message.endpoint.ID: -1);
|
|
576
|
-
this.log.warn(`ELEVATED I00: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`);
|
|
577
|
-
}
|
|
578
|
-
// this assigment give possibility to use iobroker logger in code of the converters, via meta.logger
|
|
579
|
-
meta.logger = this.log;
|
|
580
|
-
|
|
581
|
-
await this.checkIfModelUpdate(entity);
|
|
582
|
-
|
|
583
|
-
let _voltage = 0;
|
|
584
|
-
let _temperature = 0;
|
|
585
|
-
let _humidity = 0;
|
|
586
|
-
|
|
587
|
-
let isMessure = false;
|
|
588
|
-
let isBattKey = false;
|
|
589
|
-
|
|
590
|
-
if (mappedModel && mappedModel.meta && mappedModel.meta.battery) {
|
|
591
|
-
const isVoltage = mappedModel.meta.battery.hasOwnProperty('voltageToPercentage');
|
|
592
|
-
|
|
593
|
-
if (isVoltage) {
|
|
594
|
-
const keys = Object.keys(message.data);
|
|
595
|
-
|
|
596
|
-
for (const key of keys) {
|
|
597
|
-
const value = message.data[key];
|
|
598
|
-
|
|
599
|
-
if (value && value[1]) {
|
|
600
|
-
if (key == 65282 && value[1][1]) {
|
|
601
|
-
_voltage = value[1][1].elmVal;
|
|
602
|
-
isBattKey = true;
|
|
603
|
-
break;
|
|
604
|
-
}
|
|
605
|
-
if (key == 65281) {
|
|
606
|
-
_voltage = value[1];
|
|
607
|
-
isBattKey = true;
|
|
608
|
-
_temperature = value[100];
|
|
609
|
-
_temperature = _temperature /100;
|
|
610
|
-
_humidity = value[101];
|
|
611
|
-
_humidity = _humidity / 100;
|
|
612
|
-
isMessure = true;
|
|
613
|
-
break;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// always publish link_quality and battery
|
|
621
|
-
if (message.linkquality) { // send battery with
|
|
622
|
-
this.publishToState(devId, model, {linkquality: message.linkquality});
|
|
623
|
-
if (isBattKey) {
|
|
624
|
-
this.publishToState(devId, model, {voltage: _voltage});
|
|
625
|
-
const battProz = zigbeeHerdsmanConvertersUtils.batteryVoltageToPercentage(_voltage,entity.mapped.meta.battery.voltageToPercentage);
|
|
626
|
-
this.publishToState(devId, model, {battery: battProz});
|
|
627
|
-
}
|
|
628
|
-
if (isMessure) {
|
|
629
|
-
this.publishToState(devId, model, {temperature: _temperature});
|
|
630
|
-
this.publishToState(devId, model, {humidity: _humidity});
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// publish raw event to "from_zigbee"
|
|
635
|
-
// some cleanup
|
|
636
|
-
const msgForState = Object.assign({}, message);
|
|
637
|
-
delete msgForState['device'];
|
|
638
|
-
delete msgForState['endpoint'];
|
|
639
|
-
|
|
640
|
-
msgForState['endpoint_id'] = message.endpoint.ID;
|
|
641
|
-
this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
|
|
642
|
-
|
|
643
|
-
if (!entity.mapped) {
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
let converters = mappedModel.fromZigbee.filter(c => c && c.cluster === cluster && (
|
|
648
|
-
Array.isArray(c.type) ? c.type.includes(type) : c.type === type));
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (!converters.length && type === 'readResponse') {
|
|
652
|
-
converters = mappedModel.fromZigbee.filter(c => c.cluster === cluster && (
|
|
653
|
-
Array.isArray(c.type) ? c.type.includes('attributeReport') : c.type === 'attributeReport'));
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (!converters.length) {
|
|
657
|
-
if (type !== 'readResponse') {
|
|
658
|
-
this.log.debug(`No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
|
|
659
|
-
if (has_elevated_debug)
|
|
660
|
-
this.log.warn(`ELEVATED IE00: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
|
|
661
|
-
}
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
meta.state = { state: '' }; // for tuya
|
|
666
|
-
|
|
667
|
-
this.processConverters(converters, devId, model, mappedModel, message, meta)
|
|
668
|
-
.catch((error) => {
|
|
669
|
-
// 'Error: Expected one of: 0, 1, got: 'undefined''
|
|
670
|
-
if (cluster !== '64529') {
|
|
671
|
-
this.log.error(`Error while processing converters DEVICE_ID: '${devId}' cluster '${cluster}' type '${type}'`);
|
|
672
|
-
}
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
async processConverters(converters, devId, model, mappedModel, message, meta) {
|
|
677
|
-
for (const converter of converters) {
|
|
678
|
-
const publish = (payload) => {
|
|
679
|
-
this.log.debug(`Publish ${safeJsonStringify(payload)} to ${safeJsonStringify(devId)}`);
|
|
680
|
-
if (typeof payload === 'object') {
|
|
681
|
-
this.publishToState(devId, model, payload);
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
const options = await new Promise((resolve, reject) => {
|
|
686
|
-
this.stController.collectOptions(devId, model, (options) => {
|
|
687
|
-
resolve(options);
|
|
688
|
-
});
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
const payload = await new Promise((resolve, reject) => {
|
|
692
|
-
const payloadConv = converter.convert(mappedModel, message, publish, options, meta);
|
|
693
|
-
if (typeof payloadConv === 'object') {
|
|
694
|
-
resolve(payloadConv);
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
publish(payload);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
575
|
publishToState(devId, model, payload) {
|
|
705
576
|
this.stController.publishToState(devId, model, payload);
|
|
706
577
|
}
|
|
@@ -721,15 +592,18 @@ class Zigbee extends utils.Adapter {
|
|
|
721
592
|
});
|
|
722
593
|
}
|
|
723
594
|
|
|
724
|
-
async publishFromState(deviceId, model, stateModel, stateList, options) {
|
|
595
|
+
async publishFromState(deviceId, model, stateModel, stateList, options, debugID) {
|
|
725
596
|
let isGroup = false;
|
|
726
597
|
const has_elevated_debug = this.stController.checkDebugDevice(deviceId)
|
|
727
598
|
|
|
728
599
|
if (has_elevated_debug)
|
|
729
600
|
{
|
|
730
601
|
const stateNames = [];
|
|
731
|
-
|
|
732
|
-
|
|
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});
|
|
733
607
|
}
|
|
734
608
|
else
|
|
735
609
|
this.log.debug(`publishFromState : ${deviceId} ${model} ${safeJsonStringify(stateList)}`);
|
|
@@ -744,7 +618,10 @@ class Zigbee extends utils.Adapter {
|
|
|
744
618
|
|
|
745
619
|
if (!mappedModel) {
|
|
746
620
|
this.log.debug(`No mapped model for ${model}`);
|
|
747
|
-
if (has_elevated_debug)
|
|
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
|
+
}
|
|
748
625
|
return;
|
|
749
626
|
}
|
|
750
627
|
|
|
@@ -761,13 +638,20 @@ class Zigbee extends utils.Adapter {
|
|
|
761
638
|
if (stateDesc.id === 'send_payload') {
|
|
762
639
|
try {
|
|
763
640
|
const json_value = JSON.parse(value);
|
|
764
|
-
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
|
+
|
|
765
644
|
const result = await this.sendPayload(payload);
|
|
766
645
|
if (result.hasOwnProperty('success') && result.success) {
|
|
767
646
|
this.acknowledgeState(deviceId, model, stateDesc, value);
|
|
768
647
|
}
|
|
648
|
+
else {
|
|
649
|
+
this.error('Error in SendPayload: '+result.error.message);
|
|
650
|
+
}
|
|
769
651
|
} catch (error) {
|
|
770
|
-
|
|
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);
|
|
771
655
|
return;
|
|
772
656
|
}
|
|
773
657
|
return;
|
|
@@ -775,8 +659,10 @@ class Zigbee extends utils.Adapter {
|
|
|
775
659
|
|
|
776
660
|
if (stateDesc.isOption || stateDesc.compositeState) {
|
|
777
661
|
// acknowledge state with given value
|
|
778
|
-
if (has_elevated_debug)
|
|
662
|
+
if (has_elevated_debug) {
|
|
779
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
|
+
}
|
|
780
666
|
else
|
|
781
667
|
this.log.debug('changed composite state: ' + JSON.stringify(changedState));
|
|
782
668
|
|
|
@@ -796,8 +682,11 @@ class Zigbee extends utils.Adapter {
|
|
|
796
682
|
}
|
|
797
683
|
if (mappedModel) {
|
|
798
684
|
this.query_device_block.push(deviceId);
|
|
799
|
-
if (has_elevated_debug)
|
|
800
|
-
|
|
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
|
+
}
|
|
801
690
|
else
|
|
802
691
|
this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
|
|
803
692
|
for (const converter of mappedModel.toZigbee) {
|
|
@@ -807,7 +696,9 @@ class Zigbee extends utils.Adapter {
|
|
|
807
696
|
await converter.convertGet(entity.device.endpoints[0], ckey, {});
|
|
808
697
|
} catch (error) {
|
|
809
698
|
if (has_elevated_debug) {
|
|
810
|
-
|
|
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 });
|
|
811
702
|
}
|
|
812
703
|
else
|
|
813
704
|
this.log.info(`failed to read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
|
|
@@ -815,8 +706,11 @@ class Zigbee extends utils.Adapter {
|
|
|
815
706
|
}
|
|
816
707
|
}
|
|
817
708
|
}
|
|
818
|
-
if (has_elevated_debug)
|
|
819
|
-
|
|
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
|
+
}
|
|
820
714
|
else
|
|
821
715
|
this.log.info(`Device query for '${entity.device.ieeeAddr}' done`);
|
|
822
716
|
const idToRemove = deviceId;
|
|
@@ -840,38 +734,51 @@ class Zigbee extends utils.Adapter {
|
|
|
840
734
|
this.log.debug(`Type of toZigbee is '${typeof c}', Contains key ${(c.hasOwnProperty('key')?JSON.stringify(c.key):'false ')}`)
|
|
841
735
|
if (!c.hasOwnProperty('key'))
|
|
842
736
|
{
|
|
843
|
-
if (
|
|
737
|
+
if (converter === undefined)
|
|
844
738
|
{
|
|
845
739
|
converter = c;
|
|
846
|
-
if (has_elevated_debug)
|
|
847
|
-
|
|
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
|
+
}
|
|
848
744
|
else
|
|
849
|
-
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}`);
|
|
850
746
|
msg_counter++;
|
|
851
747
|
}
|
|
852
748
|
else
|
|
853
749
|
{
|
|
854
750
|
if (has_elevated_debug)
|
|
855
|
-
|
|
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
|
+
}
|
|
856
755
|
else
|
|
857
|
-
this.log.debug(`ignoring keyless converter for ${deviceId} of type ${model}`)
|
|
756
|
+
this.log.debug(`ignoring keyless converter for ${deviceId} of type ${model}`);
|
|
858
757
|
msg_counter++;
|
|
859
758
|
}
|
|
860
759
|
continue;
|
|
861
760
|
}
|
|
862
761
|
if (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id))
|
|
863
762
|
{
|
|
864
|
-
|
|
865
|
-
|
|
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
|
+
}
|
|
866
768
|
else
|
|
867
|
-
this.log.debug(
|
|
769
|
+
this.log.debug(message);
|
|
868
770
|
converter = c;
|
|
869
771
|
msg_counter++;
|
|
870
772
|
}
|
|
871
773
|
}
|
|
872
774
|
if (converter === undefined) {
|
|
873
|
-
|
|
874
|
-
|
|
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
|
+
}
|
|
875
782
|
return;
|
|
876
783
|
}
|
|
877
784
|
|
|
@@ -890,10 +797,12 @@ class Zigbee extends utils.Adapter {
|
|
|
890
797
|
|
|
891
798
|
const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
|
|
892
799
|
const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
|
|
893
|
-
|
|
894
|
-
|
|
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
|
+
}
|
|
895
804
|
else
|
|
896
|
-
this.log.debug(
|
|
805
|
+
this.log.debug(message);
|
|
897
806
|
|
|
898
807
|
let target;
|
|
899
808
|
if (model === 'group') {
|
|
@@ -923,6 +832,10 @@ class Zigbee extends utils.Adapter {
|
|
|
923
832
|
meta.message.state = preparedValue;
|
|
924
833
|
}
|
|
925
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
|
+
}
|
|
926
839
|
|
|
927
840
|
if (preparedOptions !== undefined) {
|
|
928
841
|
if (preparedOptions.hasOwnProperty('state')) {
|
|
@@ -932,33 +845,52 @@ class Zigbee extends utils.Adapter {
|
|
|
932
845
|
|
|
933
846
|
try {
|
|
934
847
|
const result = await converter.convertSet(target, key, preparedValue, meta);
|
|
935
|
-
|
|
936
|
-
|
|
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
|
+
}
|
|
937
852
|
else
|
|
938
|
-
this.log.debug(
|
|
853
|
+
this.log.debug(message);
|
|
939
854
|
if (result !== undefined) {
|
|
940
|
-
if (stateModel && !isGroup) {
|
|
855
|
+
if (stateModel && !isGroup && !stateDesc.noack) {
|
|
941
856
|
this.acknowledgeState(deviceId, model, stateDesc, value);
|
|
942
857
|
}
|
|
943
858
|
// process sync state list
|
|
944
859
|
this.processSyncStatesList(deviceId, model, syncStateList);
|
|
945
860
|
}
|
|
946
|
-
else
|
|
947
|
-
if (has_elevated_debug)
|
|
948
|
-
|
|
949
|
-
|
|
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
|
+
}
|
|
950
867
|
} catch (error) {
|
|
951
|
-
if (has_elevated_debug)
|
|
952
|
-
|
|
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
|
+
}
|
|
953
872
|
this.filterError(`Error ${error.code} on send command to ${deviceId}.` +
|
|
954
873
|
` Error: ${error.stack}`, `Send command to ${deviceId} failed with`, error);
|
|
955
874
|
}
|
|
956
875
|
});
|
|
957
876
|
} catch (err) {
|
|
958
|
-
|
|
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});
|
|
959
879
|
}
|
|
960
880
|
}
|
|
961
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
|
+
}
|
|
962
894
|
// This function is introduced to explicitly allow user level scripts to send Commands
|
|
963
895
|
// directly to the zigbee device. It utilizes the zigbee-herdsman-converters to generate
|
|
964
896
|
// the exact zigbee message to be sent and can be used to set device options which are
|
|
@@ -972,7 +904,6 @@ class Zigbee extends utils.Adapter {
|
|
|
972
904
|
// endpoint: optional: the endpoint to send the data to, if supported.
|
|
973
905
|
//
|
|
974
906
|
async sendPayload(payload) {
|
|
975
|
-
this.log.debug(`publishToDevice called with ${safeJsonStringify(payload)}`);
|
|
976
907
|
let payloadObj = {};
|
|
977
908
|
if (typeof payload === 'string') {
|
|
978
909
|
try {
|
|
@@ -987,7 +918,7 @@ class Zigbee extends utils.Adapter {
|
|
|
987
918
|
}
|
|
988
919
|
} else if (typeof payload === 'object') {
|
|
989
920
|
payloadObj = payload;
|
|
990
|
-
}
|
|
921
|
+
} else return { success: false, error: 'illegal type of payload: ' + typeof payload};
|
|
991
922
|
|
|
992
923
|
if (payloadObj.hasOwnProperty('device') && payloadObj.hasOwnProperty('payload')) {
|
|
993
924
|
try {
|
|
@@ -1012,16 +943,24 @@ class Zigbee extends utils.Adapter {
|
|
|
1012
943
|
this.sendError(`Illegal payload type for ${safeJsonStringify(payloadObj.device)}`);
|
|
1013
944
|
return {success: false, error: `Illegal payload type for ${safeJsonStringify(payloadObj.device)}`};
|
|
1014
945
|
}
|
|
946
|
+
const endpoints = mappedModel && mappedModel.endpoint ? mappedModel.endpoint(entity.device) : null;
|
|
1015
947
|
for (const key in payloadObj.payload) {
|
|
1016
948
|
if (payloadObj.payload[key] != undefined) {
|
|
1017
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
|
+
}
|
|
1018
955
|
stateList.push({
|
|
1019
956
|
stateDesc: {
|
|
1020
957
|
id: key,
|
|
1021
958
|
prop: key,
|
|
1022
959
|
role: 'state',
|
|
1023
960
|
type: datatype,
|
|
1024
|
-
|
|
961
|
+
noack:true,
|
|
962
|
+
epname: epobj.epname,
|
|
963
|
+
setattr: epobj.setattr,
|
|
1025
964
|
},
|
|
1026
965
|
value: payloadObj.payload[key],
|
|
1027
966
|
index: 0,
|
|
@@ -1030,8 +969,7 @@ class Zigbee extends utils.Adapter {
|
|
|
1030
969
|
}
|
|
1031
970
|
}
|
|
1032
971
|
try {
|
|
1033
|
-
this.
|
|
1034
|
-
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());
|
|
1035
973
|
return {success: true};
|
|
1036
974
|
} catch (error) {
|
|
1037
975
|
this.log.error(`Error ${error.code} on send command to ${payload.device}.` + ` Error: ${error.stack} ` + `Send command to ${payload.device} failed with ` + error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Kirov Ilya",
|
|
6
6
|
"email": "kirovilya@gmail.com"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"uri-js": "^4.4.1",
|
|
30
30
|
"typescript": "^5.6.3",
|
|
31
31
|
"zigbee-herdsman": "3.2.7",
|
|
32
|
-
"zigbee-herdsman-converters": "
|
|
32
|
+
"zigbee-herdsman-converters": "23.1.1"
|
|
33
33
|
},
|
|
34
34
|
"description": "Zigbee devices",
|
|
35
35
|
"devDependencies": {
|