iobroker.zigbee 2.0.4 → 2.0.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.
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const EventEmitter = require('events').EventEmitter;
3
+ const safeJsonStringify = require('./json');
4
+ const { EventEmitter } = require('events');
4
5
  const statesMapping = require('./devices');
5
- const getAdId = require('./utils').getAdId;
6
- const getZbId = require('./utils').getZbId;
6
+ const { getAdId, getZbId } = require('./utils');
7
7
  const fs = require('fs');
8
8
  const axios = require('axios');
9
9
  const localConfig = require('./localConfig');
@@ -14,7 +14,8 @@ const localConfig = require('./localConfig');
14
14
  const { exec } = require('child_process');
15
15
  const { tmpdir } = require('os');
16
16
  const path = require('path');
17
- const { numberWithinRange } = require('zigbee-herdsman-converters/lib/utils');
17
+ const { throwDeprecation } = require('process');
18
+ const zigbeeHerdsmanConvertersUtils = require('zigbee-herdsman-converters/lib/utils');
18
19
 
19
20
 
20
21
  class StatesController extends EventEmitter {
@@ -32,6 +33,7 @@ class StatesController extends EventEmitter {
32
33
  this.ImagesToDownload = [];
33
34
  this.stashedErrors = {};
34
35
  this.stashedUnknownModels = [];
36
+ this.debugMessages = { nodevice:{ in:[], out: []} };
35
37
  }
36
38
 
37
39
  info(message, data) {
@@ -85,6 +87,10 @@ class StatesController extends EventEmitter {
85
87
  return rv;
86
88
  }
87
89
 
90
+ debugMessagesById() {
91
+ return this.debugMessages;
92
+ }
93
+
88
94
  async AddModelFromHerdsman(device, model) {
89
95
  // this.warn('addModelFromHerdsman ' + JSON.stringify(model) + ' ' + JSON.stringify(this.localConfig.getOverrideWithKey(model, 'legacy', true)));
90
96
  if (this.localConfig.getOverrideWithKey(model, 'legacy', true)) {
@@ -152,6 +158,7 @@ class StatesController extends EventEmitter {
152
158
  if (!this.adapter.zbController || !this.adapter.zbController.connected()) {
153
159
  return;
154
160
  }
161
+ const debugId = Date.now();
155
162
  if (state && !state.ack) {
156
163
  if (id.endsWith('pairingCountdown') || id.endsWith('pairingMessage') || id.endsWith('connection')) {
157
164
  return;
@@ -166,16 +173,18 @@ class StatesController extends EventEmitter {
166
173
  return;
167
174
  }
168
175
 
169
- if (this.checkDebugDevice(id))
170
- this.warn(`ELEVATED O01: User state change of state ${id} with value ${state.val} (ack: ${state.ack}) from ${state.from}`);
171
-
172
- this.debug(`User stateChange ${id} ${JSON.stringify(state)}`);
173
176
  const devId = getAdId(this.adapter, id); // iobroker device id
174
177
  let deviceId = getZbId(id); // zigbee device id
178
+
179
+ if (this.checkDebugDevice(id)) {
180
+ const message = `User state change of state ${id} with value ${state.val} (ack: ${state.ack}) from ${state.from}`;
181
+ this.emit('device_debug', { ID:debugId, data: { ID: deviceId, flag:'01' }, message:message});
182
+ } else
183
+ this.debug(`User stateChange ${id} ${JSON.stringify(state)}`);
175
184
  // const stateKey = id.split('.')[3];
176
185
  const arr = /zigbee.[0-9].[^.]+.(\S+)/gm.exec(id);
177
186
  if (arr[1] === undefined) {
178
- this.warn(`unable to extract id from state ${id}`);
187
+ //this.warn(`unable to extract id from state ${id}`);
179
188
  return;
180
189
  }
181
190
  const stateKey = arr[1];
@@ -199,7 +208,7 @@ class StatesController extends EventEmitter {
199
208
 
200
209
  }
201
210
  this.collectOptions(id.split('.')[2], model, options =>
202
- this.publishFromState(deviceId, model, stateKey, state, options));
211
+ this.publishFromState(deviceId, model, stateKey, state, options, debugId));
203
212
  }
204
213
  });
205
214
  }
@@ -305,29 +314,38 @@ class StatesController extends EventEmitter {
305
314
  }, (stateDesc.compositeTimeout ? stateDesc.compositeTimeout : 100) * factor);
306
315
  }
307
316
 
308
- async publishFromState(deviceId, model, stateKey, state, options) {
317
+ async publishFromState(deviceId, model, stateKey, state, options, debugId) {
309
318
  this.debug(`Change state '${stateKey}' at device ${deviceId} type '${model}'`);
310
319
  const elevated = this.checkDebugDevice(deviceId);
311
320
 
312
- if (elevated) this.warn(`ELEVATED O02: Change state '${stateKey}' at device ${deviceId} type '${model}'`);
321
+ if (elevated) {
322
+ const message = (`Change state '${stateKey}' at device ${deviceId} type '${model}'`);
323
+ this.emit('device_debug', { ID:debugId, data: { ID: deviceId, model: model, flag:'02', IO:false }, message:message});
324
+ }
313
325
 
314
326
  const devStates = await this.getDevStates(deviceId, model);
315
327
  if (!devStates) {
316
- if (elevated) this.error(`ELEVATED OE1: no device states for device ${deviceId} type '${model}'`);
328
+ if (elevated) {
329
+ const message = (`no device states for device ${deviceId} type '${model}'`);
330
+ this.emit('device_debug', { ID:debugId, data: { error: 'NOSTATES' , IO:false }, message:message});
331
+ }
317
332
  return;
318
333
  }
319
334
  const commonStates = statesMapping.commonStates.find(statedesc => stateKey === statedesc.id);
320
335
  const stateDesc = (commonStates === undefined ? devStates.states.find(statedesc => stateKey === statedesc.id) : commonStates);
321
336
  const stateModel = devStates.stateModel;
322
337
  if (!stateDesc) {
323
- this.error(`No state available for '${model}' with key '${stateKey}'`);
338
+ const message = (`No state available for '${model}' with key '${stateKey}'`);
339
+ if (elevated) this.emit('device_debug', { ID:debugId, data: { states:[{id:state.ID, value:'unknown', payload:'unknown'}], error: 'NOSTKEY' , IO:false }, message:message});
324
340
  return;
325
341
  }
326
342
 
327
343
  const value = state.val;
328
344
  if (value === undefined || value === '') {
329
- if (elevated)
330
- this.error(`ELEVATED OE2: no value for device ${deviceId} type '${model}'`);
345
+ if (elevated) {
346
+ const message = (`no value for device ${deviceId} type '${model}'`);
347
+ this.emit('device_debug', { ID:debugId, data: { states:[{id:state.ID, value:'--', payload:'error', ep:stateDesc.epname}],error: 'NOVAL' , IO:false }, message:message});
348
+ }
331
349
  return;
332
350
  }
333
351
  let stateList = [{stateDesc: stateDesc, value: value, index: 0, timeout: 0, source:state.from}];
@@ -344,7 +362,8 @@ class StatesController extends EventEmitter {
344
362
  }
345
363
  } catch (e) {
346
364
  this.sendError(e);
347
- this.error('Exception caught in publishfromstate');
365
+ if (elevated) this.emit('device_debug', { ID:debugId, data: { states:[{id:state.ID, value:state.val, payload:'unknown'}], error: 'EXLINK' , IO:false }});
366
+ this.error('Exception caught in publishfromstate: ' + (e && e.message ? e.message : 'no error message given'));
348
367
  }
349
368
 
350
369
  });
@@ -359,7 +378,7 @@ class StatesController extends EventEmitter {
359
378
  readAfterWriteStates = readAfterWriteStates.concat(readAfterWriteStateDesc.id));
360
379
  }
361
380
 
362
- this.emit('changed', deviceId, model, stateModel, stateList, options);
381
+ this.emit('changed', deviceId, model, stateModel, stateList, options, debugId);
363
382
  }
364
383
 
365
384
  async renameDevice(id, newName) {
@@ -413,7 +432,7 @@ class StatesController extends EventEmitter {
413
432
  let statename = state._id;
414
433
  const arr = /zigbee.[0-9].[^.]+.(\S+)/gm.exec(statename);
415
434
  if (arr[1] === undefined) {
416
- this.warn(`unable to extract id from state ${statename}`);
435
+ this.debug(`unable to extract id from state ${statename}`);
417
436
  const idx = statename.lastIndexOf('.');
418
437
  if (idx > -1) {
419
438
  statename = statename.slice(idx + 1);
@@ -447,8 +466,10 @@ class StatesController extends EventEmitter {
447
466
  }
448
467
  }
449
468
  } else {
450
- this.debug(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `);
451
- messages.push(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `);
469
+ if (!markOnly) {
470
+ this.debug(`keeping connected state ${JSON.stringify(statename)} of ${devId} `);
471
+ messages.push(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `);
472
+ }
452
473
  }
453
474
  });
454
475
  }
@@ -559,7 +580,7 @@ class StatesController extends EventEmitter {
559
580
  value = minval
560
581
  if (!this.stashedErrors.hasOwnProperty(`${stateId}.min`))
561
582
  {
562
- this.error(`State value for ${stateId} has value "${nval}" less than min "${minval}". - this eror is recorded and not repeated`);
583
+ this.warn(`State value for ${stateId} has value "${nval}" less than min "${minval}". - this eror is recorded and not repeated`);
563
584
  this.stashedErrors[`${stateId}.min`] = `State value for ${stateId} has value "${nval}." less than min "${minval}"`;
564
585
  }
565
586
  }
@@ -570,7 +591,7 @@ class StatesController extends EventEmitter {
570
591
  value = maxval;
571
592
  if (!this.stashedErrors.hasOwnProperty(`${stateId}.max`))
572
593
  {
573
- this.error(`State value for ${stateId} has value "${nval}" more than max "${maxval}". - this eror is recorded and not repeated`);
594
+ this.warn(`State value for ${stateId} has value "${nval}" more than max "${maxval}". - this eror is recorded and not repeated`);
574
595
  this.stashedErrors[`${stateId}.max`] = `State value for ${stateId} has value "${nval}" more than max "${maxval}".`;
575
596
  }
576
597
  }
@@ -755,7 +776,7 @@ class StatesController extends EventEmitter {
755
776
  this.adapter.fileExists(namespace, target, async (err,result) => {
756
777
  if (result) return;
757
778
  const src = `${tmpdir()}/${path.basename(target)}`;
758
- const msg = `downloading ${url} to ${src}`;
779
+ //const msg = `downloading ${url} to ${src}`;
759
780
  if (this.ImagesToDownload.indexOf(url) ==-1) {
760
781
  await this.downloadIcon(url, src)
761
782
  try {
@@ -773,7 +794,6 @@ class StatesController extends EventEmitter {
773
794
  this.info(`copied ${src} to ${target}.`)
774
795
  fs.rm(src, (err) => {
775
796
  if (err) this.warn(`error removing ${src} : ${JSON.stringify(err)}`);
776
- else this.info(`removed ${src}`)
777
797
  });
778
798
  })
779
799
  }
@@ -861,102 +881,257 @@ class StatesController extends EventEmitter {
861
881
  this.emit('debugmessage', {id: id, message:message});
862
882
  }
863
883
 
864
- async publishToState(devId, model, payload) {
865
- const devStates = await this.getDevStates(`0x${devId}`, model);
884
+ async publishToState(devId, model, payload, debugId) {
885
+ try {
886
+ if (!debugId) debugId = Date.now();
887
+ const devStates = await this.getDevStates(`0x${devId}`, model);
888
+
889
+ const has_elevated_debug = (this.checkDebugDevice(devId) && !payload.hasOwnProperty('msg_from_zigbee'));
890
+
891
+ const message = `message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`;
892
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { deviceID: devId, flag:'01', IO:true }, message:message});
893
+ else this.debug(message);
894
+ if (!devStates) {
895
+ const message = `no device states for device ${devId} type '${model}'`;
896
+ if (has_elevated_debug)this.emit('device_debug', { ID:debugId, data: { error:'NOSTATE',states:[{ id:'--', value:'--', payload:payload}], IO:true }, message:message});
897
+ else this.debug(message);
898
+ return;
899
+ }
900
+ // find states for payload
901
+ let has_published = false;
902
+ if (devStates.states !== undefined) {
903
+ try {
904
+ const states = statesMapping.commonStates.concat(
905
+ devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id))
906
+ );
907
+
908
+ for (const stateInd in states) {
909
+ const statedesc = states[stateInd];
910
+ let value;
911
+ if (statedesc.getter) {
912
+ value = statedesc.getter(payload);
913
+ } else {
914
+ value = payload[statedesc.prop || statedesc.id];
915
+ }
916
+ // checking value
917
+ if (value === undefined || value === null) {
918
+ continue;
919
+ }
866
920
 
867
- const has_elevated_debug = (this.checkDebugDevice(devId) && !payload.hasOwnProperty('msg_from_zigbee'));
921
+ let stateID = statedesc.id;
922
+
923
+ const message = `value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`;
924
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { states:[{id:stateID, value:value, payload:payload }],flag:'02', IO:true }, message});
925
+ else this.debug(message);
926
+
927
+ const common = {
928
+ name: statedesc.name,
929
+ type: statedesc.type,
930
+ unit: statedesc.unit,
931
+ read: statedesc.read,
932
+ write: statedesc.write,
933
+ icon: statedesc.icon,
934
+ role: statedesc.role,
935
+ min: statedesc.min,
936
+ max: statedesc.max,
937
+ };
938
+
939
+ if (typeof value === 'object' && value.hasOwnProperty('stateid')) {
940
+ stateID = `${stateID}.${value.stateid}`;
941
+ if (value.hasOwnProperty('unit')) {
942
+ common.unit = value.unit;
943
+ }
944
+ common.name = value.name ? value.name : value.stateid;
945
+ common.role = value.role ? `value.${value.role}` : 'number';
946
+ value = value.value;
947
+ }
868
948
 
949
+ // if needs to return value to back after timeout
950
+ if (statedesc.isEvent) {
951
+ this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, (typeof value == typeof (!value) ? !value : ''));
952
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { flag:'SUCCESS', IO:true }});
869
953
 
870
- if (has_elevated_debug)
871
- {
872
- this.elevatedMessage(devId, `ELEVATED I01: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`, false);
954
+ } else {
955
+ if (statedesc.prepublish) {
956
+ this.collectOptions(devId, model, options =>
957
+ statedesc.prepublish(devId, value, newvalue => {
958
+ this.updateState(devId, stateID, newvalue, common) }, options)
959
+ );
960
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { flag:'SUCCESS', IO:true }});
961
+ } else {
962
+ this.updateState(devId, stateID, value, common, debugId);
963
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { flag:'SUCCESS', IO:true }});
964
+ }
965
+ }
966
+ has_published = true;
967
+ }
968
+ } catch (e) {
969
+ const message = `unable to enumerate states of ${devId} for payload ${JSON.stringify(payload)}, ${(e ? e.name : 'undefined')} (${(e ? e.message : '')}).`;
970
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data:{ error:'ESTATE', IO:true }, message:message});
971
+ else this.debug(message);
972
+ }
973
+ const message = `No value published for device ${devId}`;
974
+ if (!has_published && has_elevated_debug) this.emit('device_debug', { ID:debugId, data:{ error:'NOVAL', IO:true }, message:message});
975
+ else this.debug(message);
976
+ }
977
+ else {
978
+ const message = `ELEVATED IE05 - NOSTATE: No states matching the payload ${JSON.stringify(payload)} for device ${devId}`;
979
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data:{ error:'NOSTATE', IO:true }, message});
980
+ else this.debug(message);
981
+ }
873
982
  }
874
- if (!devStates) {
875
- if (has_elevated_debug)
876
- this.elevatedMessage(devId, `ELEVATED IE02: no device states for device ${devId} type '${model}'`, true)
877
- return;
983
+ catch (error) {
984
+ this.error('Something went horribly wrong: ' + (error && error.message ? error.message : 'no reason given'));
878
985
  }
879
- // find states for payload
880
- let has_published = false;
986
+ }
881
987
 
882
- if (devStates.states !== undefined) {
883
- try {
884
- const states = statesMapping.commonStates.concat(
885
- devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id))
886
- );
887
-
888
- for (const stateInd in states) {
889
- const statedesc = states[stateInd];
890
- let value;
891
- if (statedesc.getter) {
892
- value = statedesc.getter(payload);
893
- } else {
894
- value = payload[statedesc.prop || statedesc.id];
895
- }
896
- // checking value
897
- if (value === undefined || value === null) {
898
- continue;
899
- }
988
+ async processConverters(converters, devId, model, mappedModel, message, meta, debugId) {
989
+ for (const converter of converters) {
990
+ const publish = (payload, dID) => {
991
+ if (typeof payload === 'object') {
992
+ this.publishToState(devId, model, payload,dID);
993
+ }
994
+ };
900
995
 
901
- let stateID = statedesc.id;
996
+ const options = await new Promise((resolve, reject) => {
997
+ this.collectOptions(devId, model, (options) => {
998
+ resolve(options);
999
+ });
1000
+ });
902
1001
 
903
- if (has_elevated_debug) {
904
- this.elevatedMessage(devId, `ELEVATED I02: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`, false);
905
- }
1002
+ const payload = await new Promise((resolve, reject) => {
1003
+ const payloadConv = converter.convert(mappedModel, message, publish, options, meta);
1004
+ if (typeof payloadConv === 'object') {
1005
+ resolve(payloadConv);
1006
+ }
1007
+ });
906
1008
 
907
- const common = {
908
- name: statedesc.name,
909
- type: statedesc.type,
910
- unit: statedesc.unit,
911
- read: statedesc.read,
912
- write: statedesc.write,
913
- icon: statedesc.icon,
914
- role: statedesc.role,
915
- min: statedesc.min,
916
- max: statedesc.max,
917
- };
918
-
919
- if (typeof value === 'object' && value.hasOwnProperty('stateid')) {
920
- stateID = `${stateID}.${value.stateid}`;
921
- if (value.hasOwnProperty('unit')) {
922
- common.unit = value.unit;
923
- }
924
- common.name = value.name ? value.name : value.stateid;
925
- common.role = value.role ? `value.${value.role}` : 'number';
926
- value = value.value;
927
- }
1009
+ publish(payload, debugId);
1010
+ }
1011
+ }
928
1012
 
929
- // if needs to return value to back after timeout
930
- if (statedesc.isEvent) {
931
- this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, (typeof value == typeof (!value) ? !value : ''));
932
- } else {
933
- if (statedesc.prepublish) {
934
- this.collectOptions(devId, model, options =>
935
- statedesc.prepublish(devId, value, newvalue =>
936
- this.updateState(devId, stateID, newvalue, common), options)
937
- );
938
- } else {
939
- this.updateState(devId, stateID, value, common);
1013
+
1014
+ async onZigbeeEvent(type, entity, message) {
1015
+ this.debug(`Type ${type} device ${safeJsonStringify(entity)} incoming event: ${safeJsonStringify(message)}`);
1016
+
1017
+ const device = entity.device;
1018
+ const mappedModel = entity.mapped;
1019
+ const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
1020
+ const cluster = message.cluster;
1021
+ const devId = device.ieeeAddr.substr(2);
1022
+ const meta = {device};
1023
+
1024
+ const has_elevated_debug = this.checkDebugDevice(devId);
1025
+ const debugId = Date.now();
1026
+
1027
+ // raw message data for logging and msg_from_zigbee
1028
+ const msgForState = Object.assign({}, message);
1029
+ delete msgForState['device'];
1030
+ delete msgForState['endpoint'];
1031
+ msgForState['endpoint_id'] = message.endpoint.ID;
1032
+
1033
+ if (has_elevated_debug) {
1034
+ const message = `Zigbee Event of Type ${type} from device ${device.ieeeAddr}, incoming event: ${safeJsonStringify(msgForState)}`;
1035
+ this.emit('device_debug', { ID:debugId, data: { ID: device.ieeeAddr, payload:safeJsonStringify(msgForState), flag:'01', IO:true }, message:message});
1036
+
1037
+ }
1038
+ // this assigment give possibility to use iobroker logger in code of the converters, via meta.logger
1039
+ meta.logger = this;
1040
+
1041
+ await this.adapter.checkIfModelUpdate(entity);
1042
+
1043
+ let _voltage = 0;
1044
+ let _temperature = 0;
1045
+ let _humidity = 0;
1046
+
1047
+ let isMessure = false;
1048
+ let isBattKey = false;
1049
+
1050
+ if (mappedModel && mappedModel.meta && mappedModel.meta.battery) {
1051
+ const isVoltage = mappedModel.meta.battery.hasOwnProperty('voltageToPercentage');
1052
+
1053
+ if (isVoltage) {
1054
+ const keys = Object.keys(message.data);
1055
+
1056
+ for (const key of keys) {
1057
+ const value = message.data[key];
1058
+
1059
+ if (value && value[1]) {
1060
+ if (key == 65282 && value[1][1]) {
1061
+ _voltage = value[1][1].elmVal;
1062
+ isBattKey = true;
1063
+ break;
1064
+ }
1065
+ if (key == 65281) {
1066
+ _voltage = value[1];
1067
+ isBattKey = true;
1068
+ _temperature = value[100];
1069
+ _temperature = _temperature /100;
1070
+ _humidity = value[101];
1071
+ _humidity = _humidity / 100;
1072
+ isMessure = true;
1073
+ break;
940
1074
  }
941
1075
  }
942
- has_published = true;
943
1076
  }
944
- } catch (e) {
945
- this.debug(`No states in device ${devId} : payload ${JSON.stringify(payload)}`);
946
- if (has_elevated_debug)
947
- this.elevatedMessage(devId, `ELEVATED IE03: error when enumerating states of ${devId} for payload ${JSON.stringify(payload)}, ${(e ? e.name : 'undefined')} (${(e ? e.message : '')}).`, true);
948
1077
  }
949
- if (!has_published && has_elevated_debug) {
950
- this.elevatedMessage(devId, `ELEVATED IE04: No value published for device ${devId}`, true);
1078
+ }
951
1079
 
1080
+ // always publish link_quality and battery
1081
+ if (message.linkquality) { // send battery with
1082
+ this.publishToState(devId, model, {linkquality: message.linkquality}, debugId);
1083
+ if (isBattKey) {
1084
+ this.publishToState(devId, model, {voltage: _voltage}, debugId);
1085
+ const battProz = zigbeeHerdsmanConvertersUtils.batteryVoltageToPercentage(_voltage,entity.mapped.meta.battery.voltageToPercentage);
1086
+ this.publishToState(devId, model, {battery: battProz}, debugId);
1087
+ }
1088
+ if (isMessure) {
1089
+ this.publishToState(devId, model, {temperature: _temperature}, debugId);
1090
+ this.publishToState(devId, model, {humidity: _humidity}), debugId;
952
1091
  }
953
1092
  }
954
- else {
955
- if (has_elevated_debug)
956
- this.elevatedMessage(devId, `ELEVATED IE05: No states matching the payload ${JSON.stringify(payload)} for device ${devId}`, true);
1093
+
1094
+ // publish raw event to "from_zigbee"
1095
+ // some cleanup
1096
+
1097
+ this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)}, -1);
1098
+
1099
+ if (!entity.mapped) {
1100
+ return;
1101
+ }
1102
+
1103
+ let converters = mappedModel.fromZigbee.filter(c => c && c.cluster === cluster && (
1104
+ Array.isArray(c.type) ? c.type.includes(type) : c.type === type));
1105
+
1106
+
1107
+ if (!converters.length && type === 'readResponse') {
1108
+ converters = mappedModel.fromZigbee.filter(c => c.cluster === cluster && (
1109
+ Array.isArray(c.type) ? c.type.includes('attributeReport') : c.type === 'attributeReport'));
957
1110
  }
1111
+
1112
+ if (!converters.length) {
1113
+ if (type !== 'readResponse') {
1114
+ const message = `No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`;
1115
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { error:'NOCONV', IO:true }, message:message});
1116
+ else this.debug(message);
1117
+ }
1118
+ return;
1119
+ }
1120
+
1121
+ meta.state = { state: '' }; // for tuya
1122
+
1123
+ this.processConverters(converters, devId, model, mappedModel, message, meta, debugId)
1124
+ .catch((error) => {
1125
+ // 'Error: Expected one of: 0, 1, got: 'undefined''
1126
+ if (cluster !== '64529') {
1127
+ if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { error:'EPROC', IO:true }});
1128
+ this.error(`Error while processing converters DEVICE_ID: '${devId}' cluster '${cluster}' type '${type}'`);
1129
+ }
1130
+ });
958
1131
  }
959
1132
 
1133
+
1134
+
960
1135
  }
961
1136
 
962
1137
  module.exports = StatesController;
@@ -178,7 +178,7 @@ class DeviceAvailability extends BaseExtension {
178
178
  this.publishAvailability(device, false);
179
179
  if (pingCount.failed++ <= this.max_ping) {
180
180
  if (pingCount.failed < 2 && pingCount.reported < this.max_ping) {
181
- this.warn(`Failed to ping ${ieeeAddr} ${device.modelID}`);
181
+ this.info(`Failed to ping ${ieeeAddr} ${device.modelID}`);
182
182
  pingCount.reported++;
183
183
  } else {
184
184
  this.debug(`Failed to ping ${ieeeAddr} ${device.modelID} on ${pingCount} consecutive attempts`);
@@ -186,7 +186,7 @@ class DeviceAvailability extends BaseExtension {
186
186
  this.setTimerPingable(device, pingCount.failed);
187
187
  this.ping_counters[device.ieeeAddr] = pingCount;
188
188
  } else {
189
- this.warn(`Stopping to ping ${ieeeAddr} ${device.modelID} after ${pingCount.failed} ping attempts`);
189
+ this.info(`Stopping to ping ${ieeeAddr} ${device.modelID} after ${pingCount.failed} ping attempts`);
190
190
  }
191
191
  }
192
192
  }