iobroker.zigbee 1.6.0 → 1.6.12

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.
@@ -4,6 +4,7 @@ const EventEmitter = require('events').EventEmitter;
4
4
  const statesMapping = require('./devices');
5
5
  const getAdId = require('./utils').getAdId;
6
6
  const getZbId = require('./utils').getZbId;
7
+ var knownUndefinedDevices = {};
7
8
 
8
9
 
9
10
  class StatesController extends EventEmitter {
@@ -55,8 +56,20 @@ class StatesController extends EventEmitter {
55
56
  });
56
57
  }
57
58
  });
58
-
59
+ this.adapter.setObject('info.undefinedDevices', {
60
+ 'type': 'state',
61
+ 'common': {
62
+ 'name': 'Recorded undefined devices',
63
+ 'role': '',
64
+ 'type': 'string',
65
+ 'read': true,
66
+ 'write': false,
67
+ },
68
+ 'native': {},
69
+ });
70
+ this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
59
71
  }
72
+
60
73
  onStateChange(id, state){
61
74
  if (!this.adapter.zbController || !this.adapter.zbController.connected()) return;
62
75
  if (this.debugDevices === undefined) this.getDebugDevices();
@@ -116,20 +129,25 @@ class StatesController extends EventEmitter {
116
129
  return;
117
130
  }
118
131
  let cnt = 0;
119
- const len = states.length;
120
- states.forEach(statedesc => {
121
- const id = this.adapter.namespace + '.' + devId + '.' + statedesc.id;
122
- this.adapter.getState(id, (err, state) => {
123
- cnt = cnt + 1;
124
- if (!err && state) {
125
- result[statedesc.id] = state.val;
126
- }
127
- if (cnt === len) {
128
- callback(result);
129
- }
132
+ try {
133
+ const len = states.length;
134
+ states.forEach(statedesc => {
135
+ const id = this.adapter.namespace + '.' + devId + '.' + statedesc.id;
136
+ this.adapter.getState(id, (err, state) => {
137
+ cnt = cnt + 1;
138
+ if (!err && state) {
139
+ result[statedesc.id] = state.val;
140
+ }
141
+ if (cnt === len) {
142
+ callback(result);
143
+ }
144
+ });
130
145
  });
131
- });
132
- if (!len) callback(result);
146
+ if (!len) callback(result);
147
+ } catch (error) {
148
+ this.sendError(error);
149
+ this.error(`Error collectOptions for ${devId}. Error: ${error.stack}`);
150
+ }
133
151
  }
134
152
 
135
153
  async getDevStates(deviceId, model) {
@@ -141,7 +159,15 @@ class StatesController extends EventEmitter {
141
159
  } else {
142
160
  stateModel = statesMapping.findModel(model);
143
161
  if (!stateModel) {
144
- this.error('Device ' + deviceId + ' "' + model + '" not described in statesMapping.');
162
+ if (knownUndefinedDevices[deviceId])
163
+ {
164
+ knownUndefinedDevices[deviceId]++;
165
+ }
166
+ else {
167
+ knownUndefinedDevices[deviceId] = 1;
168
+ this.error('Device ' + deviceId + ' "' + model + '" not described in statesMapping.');
169
+ }
170
+ this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
145
171
  states = statesMapping.commonStates;
146
172
  } else {
147
173
  states = stateModel.states;
@@ -343,13 +369,10 @@ class StatesController extends EventEmitter {
343
369
  // only change object when any common property has changed
344
370
  if (hasChanges) {
345
371
  this.adapter.extendObject(id, {type: 'state', common: new_common, native: {} }, () => {
346
- value !== undefined && this.adapter.setState(id, value, true);
372
+ value !== undefined && this.setState_typed(id, value, true, (stobj) ? stobj.common.type : new_common.type);
347
373
  });
348
374
  } else if (value !== undefined) {
349
- if (typeof(value) !== 'object') {
350
- this.adapter.setState(id, value, true);
351
- } else this.warn('set state with object for id :' + JSON.stringify(id) + ' '+ JSON.stringify(value));
352
-
375
+ this.setState_typed(id, value, true, stobj.common.type);
353
376
  }
354
377
 
355
378
  });
@@ -359,6 +382,44 @@ class StatesController extends EventEmitter {
359
382
  });
360
383
  }
361
384
 
385
+ setState_typed(id, value, ack, type, callback)
386
+ {
387
+ // never set a null or undefined value
388
+ if (value === null || value === undefined) return;
389
+ if (!type) {
390
+ this.debug("SetState_typed called without type");
391
+ // identify datatype, recursively call this function with set datatype
392
+ this.adapter.getObject(id, (err, obj) => {
393
+ if (obj && obj.common)
394
+ this.setState_typed(id, value, ack, obj.common.type, callback);
395
+ else {
396
+ this.setState_typed(id, value, ack, 'noobj', callback);
397
+ }
398
+ });
399
+ return;
400
+ }
401
+ if (typeof value != type) {
402
+ this.debug("SetState_typed : converting " + JSON.stringify(value) + " for " + id + " from " + typeof value + " to " + type);
403
+ switch (type) {
404
+ case 'number':
405
+ value = parseFloat(value);
406
+ if (isNaN (value)) value = 0;
407
+ break;
408
+ case 'string':
409
+ case 'text': value = JSON.stringify(value); break;
410
+ case 'boolean':
411
+ if (typeof value == 'number') {
412
+ value = (value != 0);
413
+ break;
414
+ }
415
+ const sval = JSON.stringify(value).toLowerCase().trim();
416
+ value = (sval == 'true' || sval == 'yes' || sval == 'on');
417
+ break;
418
+ }
419
+ }
420
+ this.adapter.setState(id, value, ack, callback);
421
+ }
422
+
362
423
  updateDev(dev_id, dev_name, model, callback) {
363
424
  const id = '' + dev_id;
364
425
  const modelDesc = statesMapping.findModel(model);
@@ -432,6 +493,7 @@ class StatesController extends EventEmitter {
432
493
  for (const addressPart of this.debugDevices) {
433
494
  if (typeof(devId) == 'string' && devId.indexOf(addressPart) > -1)
434
495
  {
496
+ if (payload.hasOwnProperty('msg_from_zigbee')) break;
435
497
  this.warn(`ELEVATED publishToState: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`);
436
498
  has_debug = true;
437
499
  break;
@@ -454,10 +516,10 @@ class StatesController extends EventEmitter {
454
516
  value = payload[statedesc.prop || statedesc.id];
455
517
  }
456
518
  // checking value
457
- if (value === undefined) continue;
519
+ if (value === undefined || value === null) continue;
458
520
  let stateID = statedesc.id;
459
521
 
460
- if (has_debug) {
522
+ if (has_debug && statedesc.id != 'msg_from_zigbee') {
461
523
  this.warn(`ELEVATED publishToState: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`);
462
524
  }
463
525
 
package/lib/utils.js CHANGED
@@ -114,6 +114,24 @@ const forceEndDevice = flatten(
114
114
  const xiaomiManufacturerID = [4151, 4447];
115
115
  const ikeaTradfriManufacturerID = [4476];
116
116
 
117
+ function sanitizeImageParameter(parameter) {
118
+ const replaceByDash = [/\?/g, /&/g, /[^a-z\d\-_./:]/gi, /[/]/gi];
119
+ let sanitized = parameter;
120
+ replaceByDash.forEach((r) => sanitized = sanitized.replace(r, '-'));
121
+ return sanitized;
122
+ }
123
+
124
+ function getDeviceIcon(definition) {
125
+ let icon = definition.icon;
126
+ if (icon) {
127
+ icon = icon.replace('${model}', sanitizeImageParameter(definition.model));
128
+ }
129
+ if (!icon) {
130
+ icon = `https://www.zigbee2mqtt.io/images/devices/${sanitizeImageParameter(definition.model)}.jpg`;
131
+ }
132
+ return icon;
133
+ }
134
+
117
135
  exports.secondsToMilliseconds = (seconds) => seconds * 1000;
118
136
  exports.bulbLevelToAdapterLevel = bulbLevelToAdapterLevel;
119
137
  exports.adapterLevelToBulbLevel = adapterLevelToBulbLevel;
@@ -130,3 +148,4 @@ exports.isXiaomiDevice = (device) => {
130
148
  (!device.manufacturerName || !device.manufacturerName.startsWith('Trust'));
131
149
  };
132
150
  exports.isIkeaTradfriDevice = (device) => ikeaTradfriManufacturerID.includes(device.manufacturerID);
151
+ exports.getDeviceIcon = getDeviceIcon;
@@ -5,6 +5,7 @@
5
5
  class BaseExtension {
6
6
  constructor(zigbee, options) {
7
7
  this.zigbee = zigbee;
8
+ this.name = 'BaseExtension';
8
9
  }
9
10
 
10
11
  info(message, data) {
@@ -12,15 +13,15 @@ class BaseExtension {
12
13
  }
13
14
 
14
15
  error(message, data) {
15
- this.zigbee.error(message, data);
16
+ this.zigbee.error(this.name + ':' + message, data);
16
17
  }
17
18
 
18
19
  warn(message, data) {
19
- this.zigbee.warn(message, data);
20
+ this.zigbee.warn(this.name + ':' + message, data);
20
21
  }
21
22
 
22
23
  debug(message, data) {
23
- this.zigbee.debug(message, data);
24
+ this.zigbee.debug(this.name + ':' + message, data);
24
25
  }
25
26
 
26
27
  sendError(error, message) {
@@ -8,6 +8,7 @@ class DelayedAction extends BaseExtension {
8
8
 
9
9
  this.actions = {};
10
10
  this.zigbee.delayAction = this.delayAction.bind(this);
11
+ this.name = "DelayedAction";
11
12
  }
12
13
 
13
14
  setOptions(options) {
@@ -50,6 +50,7 @@ class DeviceAvailability extends BaseExtension {
50
50
  this.startDevicePingQueue = []; // simple fifo array for starting device pings
51
51
  this.startDevicePingTimeout = null; // handle for the timeout which empties the queue
52
52
  this.startDevicePingDelay = 200; // 200 ms delay between starting the ping timeout
53
+ this.name = "DeviceAvailability";
53
54
  }
54
55
 
55
56
  setOptions(options) {
@@ -265,7 +266,7 @@ class DeviceAvailability extends BaseExtension {
265
266
  // }
266
267
  }
267
268
  }
268
-
269
+
269
270
  onZigbeeEvent(data) {
270
271
  const device = data.device;
271
272
  if (!device) {
@@ -18,6 +18,7 @@ class DeviceConfigure extends BaseExtension {
18
18
 
19
19
  this.configuring = new Set();
20
20
  this.attempts = {};
21
+ this.name = "DeviceConfigure";
21
22
  }
22
23
 
23
24
  setOptions(options) {
@@ -119,13 +120,8 @@ class DeviceConfigure extends BaseExtension {
119
120
  if (!this.attempts.hasOwnProperty(device.ieeeAddr)) {
120
121
  this.attempts[device.ieeeAddr] = 0;
121
122
  }
122
-
123
- this.info(`Configuring ${device.ieeeAddr} ${device.modelID}`);
124
123
  try {
125
- await mappedDevice.configure(device, this.coordinatorEndpoint);
126
- this.info(`DeviceConfigure successful ${device.ieeeAddr} ${device.modelID}`);
127
- device.meta.configured = zigbeeHerdsmanConverters.getConfigureKey(mappedDevice);
128
- device.save();
124
+ await this.doConfigure(device, mappedDevice);
129
125
  } catch (error) {
130
126
  this.sendError(error);
131
127
  this.warn(
@@ -134,7 +130,6 @@ class DeviceConfigure extends BaseExtension {
134
130
  );
135
131
  this.attempts[device.ieeeAddr]++;
136
132
  }
137
-
138
133
  this.configuring.delete(device.ieeeAddr);
139
134
  } catch (error) {
140
135
  this.sendError(error);
@@ -143,6 +138,15 @@ class DeviceConfigure extends BaseExtension {
143
138
  );
144
139
  }
145
140
  }
141
+
142
+ async doConfigure(device, mappedDevice) {
143
+ this.info(`Configuring ${device.ieeeAddr} ${device.modelID}`);
144
+ const coordinatorEndpoint = await this.zigbee.getDevicesByType('Coordinator')[0].endpoints[0];
145
+ await mappedDevice.configure(device, coordinatorEndpoint);
146
+ device.meta.configured = zigbeeHerdsmanConverters.getConfigureKey(mappedDevice);
147
+ device.save();
148
+ this.info(`DeviceConfigure successful ${device.ieeeAddr} ${device.modelID}`);
149
+ }
146
150
  }
147
151
 
148
152
  module.exports = DeviceConfigure;
@@ -4,6 +4,12 @@ const BaseExtension = require('./zbBaseExtension');
4
4
  const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
5
5
 
6
6
  class DeviceEvent extends BaseExtension {
7
+ constructor(zigbee, options) {
8
+ super(zigbee, options);
9
+ this.name = "DeviceEvent";
10
+ }
11
+
12
+
7
13
  async onZigbeeStarted() {
8
14
  for (const device of await this.zigbee.getClients()) {
9
15
  this.callOnEvent(device, 'start', {});
@@ -105,11 +105,11 @@ class ZigbeeController extends EventEmitter {
105
105
  this.debug('zigbee-herdsman started');
106
106
  this.herdsman_started = true;
107
107
  this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
108
-
108
+
109
109
  // debug info from herdsman getNetworkParameters
110
110
  const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
111
111
  const extendedPanIDDebug = (typeof debNetworkParam.extendedPanID == 'string') ? debNetworkParam.extendedPanID.replace('0x','') : debNetworkParam.extendedPanID;
112
-
112
+
113
113
  let extPanIDDebug = '';
114
114
  for (let i = extendedPanIDDebug.length - 1; i >= 0; i--) {
115
115
  extPanIDDebug += extendedPanIDDebug[i-1];
@@ -117,8 +117,8 @@ class ZigbeeController extends EventEmitter {
117
117
  i--;
118
118
  }
119
119
 
120
- this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
-
120
+ this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
+
122
122
  } catch (e) {
123
123
  this.sendError(e);
124
124
  this.error('Starting zigbee-herdsman problem : ' + JSON.stringify(e.message));
@@ -148,6 +148,9 @@ class ZigbeeController extends EventEmitter {
148
148
  case '19':
149
149
  powerText = 'high';
150
150
  break;
151
+ case '20':
152
+ powerText = 'high+';
153
+ break;
151
154
  default:
152
155
  powerText = 'normal';
153
156
  }
@@ -217,13 +220,14 @@ class ZigbeeController extends EventEmitter {
217
220
  }
218
221
 
219
222
  callExtensionMethod(method, parameters) {
223
+ const result = [];
220
224
  for (const extension of this.extensions) {
221
225
  if (extension[method]) {
222
226
  try {
223
227
  if (parameters !== undefined) {
224
- extension[method](...parameters);
228
+ result.push(extension[method](...parameters));
225
229
  } else {
226
- extension[method]();
230
+ result.push(extension[method]());
227
231
  }
228
232
  } catch (error) {
229
233
  this.sendError(error);
@@ -231,6 +235,7 @@ class ZigbeeController extends EventEmitter {
231
235
  }
232
236
  }
233
237
  }
238
+ return Promise.all(result);
234
239
  }
235
240
 
236
241
  async getClients(all) {
@@ -248,9 +253,11 @@ class ZigbeeController extends EventEmitter {
248
253
 
249
254
  async getGroups() {
250
255
  try {
251
- return this.herdsman.getGroups();
256
+ const rv = await this.herdsman.getGroups();
257
+ return rv;
252
258
  } catch (error) {
253
259
  this.sendError(error);
260
+ this.error(JSON.stringify(error));
254
261
  return undefined;
255
262
  }
256
263
  }
@@ -280,11 +287,11 @@ class ZigbeeController extends EventEmitter {
280
287
  const group = await this.getGroupByID(id);
281
288
  if (group) {
282
289
  const groupmembers = group.members;
283
-
284
290
  for (const member of groupmembers) {
291
+ const epid = (member.ID ? member.ID:-1);
285
292
  const nwk = member.deviceNetworkAddress;
286
293
  const device = this.getDeviceByNetworkAddress(nwk);
287
- if (device && device.ieeeAddr) members.push( { device:device.ieeeAddr, model:device.modelID } );
294
+ if (device && device.ieeeAddr) members.push( { ieee:device.ieeeAddr, model:device.modelID, epid:epid, ep:member } );
288
295
  }
289
296
  }
290
297
  else {
@@ -525,6 +532,13 @@ class ZigbeeController extends EventEmitter {
525
532
  const entity = await this.resolveEntity(message.device || message.ieeeAddr);
526
533
  const friendlyName = entity.name;
527
534
  this.warn(`Device '${friendlyName}' announced itself`);
535
+
536
+ if (entity && entity.mapped) {
537
+ this.callExtensionMethod(
538
+ 'onZigbeeEvent',
539
+ [ {'device': message.device, 'type': 'deviceAnnounce'}, (entity ? entity.mapped : null)]);
540
+ }
541
+
528
542
  this.emit('pairing', `Device '${friendlyName}' announced itself`);
529
543
  if (!this.herdsman.getPermitJoin()) this.callExtensionMethod('registerDevicePing', [message.device, entity]);
530
544
  // if has modelID so can create device
@@ -534,6 +548,7 @@ class ZigbeeController extends EventEmitter {
534
548
  }
535
549
  }
536
550
 
551
+
537
552
  async handleDeviceJoined(message) {
538
553
  this.debug('handleDeviceJoined', message);
539
554
  //const entity = await this.resolveEntity(message.device || message.ieeeAddr);
@@ -686,7 +701,7 @@ class ZigbeeController extends EventEmitter {
686
701
  }
687
702
  }
688
703
 
689
- async publish(deviceID, cid, cmd, zclData, cfg, ep, type, callback) {
704
+ async publish(deviceID, cid, cmd, zclData, cfg, ep, type, callback, zclSeqNum) {
690
705
  const entity = await this.resolveEntity(deviceID, ep);
691
706
  const device = entity.device;
692
707
  const endpoint = entity.endpoint;
@@ -727,20 +742,57 @@ class ZigbeeController extends EventEmitter {
727
742
  result = await endpoint[cmd](cid, zclData, cfg);
728
743
  }
729
744
  if (callback) callback(undefined, result);
730
- } else {
745
+ }
746
+ else if(type === 'functionalResp'){
747
+ cfg.disableDefaultResponse = false;
748
+ const result = await endpoint.commandResponse(cid, cmd, zclData, cfg, zclSeqNum);
749
+ if (callback) callback(undefined, result);
750
+ }
751
+ else {
731
752
  cfg.disableDefaultResponse = false;
732
753
  const result = await endpoint.command(cid, cmd, zclData, cfg);
733
754
  if (callback) callback(undefined, result);
734
755
  }
735
756
  }
736
757
 
737
- async addDevToGroup(devId, groupId) {
758
+ async addDevToGroup(devId, groupId, epid) {
738
759
  try {
739
760
  const entity = await this.resolveEntity(devId);
740
761
  const group = await this.resolveEntity(groupId);
741
- this.debug(`entity: ${safeJsonStringify(entity)}`);
742
- this.debug(`group: ${safeJsonStringify(group)}`);
743
- await entity.endpoint.addToGroup(group.mapped);
762
+ this.debug(`addDevFromGroup - entity: ${safeJsonStringify(entity)}`);
763
+ this.debug(`addDevFromGroup - group: ${safeJsonStringify(group)}`);
764
+ if (epid != undefined) {
765
+ for (const ep of entity.endpoints) {
766
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
767
+ {
768
+ this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`)
769
+ await(ep.addToGroup(group.mapped));
770
+ }
771
+ }
772
+
773
+ }
774
+ else
775
+ {
776
+ if (entity.endpoint.inputClusters.includes(4))
777
+ {
778
+ this.debug(`adding endpoint ${entity.endpoint.ID} to group`)
779
+ await entity.endpoint.addToGroup(group.mapped);
780
+ }
781
+ else {
782
+ let added = false;
783
+ for (const ep of entity.endpoints)
784
+ {
785
+ if (ep.inputClusters.includes(4))
786
+ {
787
+ this.debug(`adding endpoint ${ep.ID} to group`)
788
+ await ep.addToGroup(group.mapped);
789
+ added = true;
790
+ break;
791
+ }
792
+ }
793
+ if (!added) throw ('cluster genGroups not supported');
794
+ }
795
+ }
744
796
  } catch (error) {
745
797
  this.sendError(error);
746
798
  this.error(`Exception when trying to Add ${devId} to group ${groupId}`, error);
@@ -749,11 +801,38 @@ class ZigbeeController extends EventEmitter {
749
801
  return {};
750
802
  }
751
803
 
804
+ async removeDevFromGroup(devId, groupId, epid) {
805
+ try {
806
+ const entity = await this.resolveEntity(devId);
807
+ const group = await this.resolveEntity(groupId);
808
+ this.debug(`removeDevFromGroup - entity: ${safeJsonStringify(entity)}`);
809
+ this.debug(`removeDevFromGroup - group: ${safeJsonStringify(group)}`);
810
+ if (epid != undefined) {
811
+ for (const ep of entity.endpoints) {
812
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
813
+ {
814
+ this.debug(`removing endpoint ${ep.ID} (${epid}) group ${groupId}`)
815
+ await(ep.removeFromGroup(group.mapped))
816
+ }
817
+ }
818
+ } else await entity.endpoint.removeFromGroup(group.mapped);
819
+ } catch (error) {
820
+ this.sendError(error);
821
+ this.error(`Exception when trying remove ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`, error);
822
+ return { error: `Failed to remove dev ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`};
823
+ }
824
+ return {};
825
+ }
826
+
752
827
  async removeDevFromAllGroups(devId) {
753
828
  try {
754
829
  const entity = await this.resolveEntity(devId);
755
830
  this.debug(`entity: ${safeJsonStringify(entity)}`);
756
- await entity.endpoint.removeFromAllGroups();
831
+ for (const ep of entity.endpoints) {
832
+ if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))
833
+ await ep.removefromAllGroups();
834
+ }
835
+ //await entity.endpoint.removeFromAllGroups();
757
836
  } catch (error) {
758
837
  this.sendError(error);
759
838
  this.error(`Exception when trying remove ${devId} from all groups`, error);
package/main.js CHANGED
@@ -30,6 +30,7 @@ const StatesController = require('./lib/statescontroller');
30
30
  const ExcludePlugin = require('./lib/exclude');
31
31
  const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
32
32
  const vm = require('vm');
33
+ const util = require('util');
33
34
 
34
35
  const createByteArray = function (hexString) {
35
36
  const bytes = [];
@@ -158,14 +159,15 @@ class Zigbee extends utils.Adapter {
158
159
  this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
159
160
  this.sendError(error, `${message}: Code ${error.code} (${ecode.message})`);
160
161
  break;
161
- default:
162
+ default:
162
163
  this.log.error(`${message}: Code ${error.code} (malformed error)`);
163
164
  this.sendError(error, `${message}: Code ${error.code} (malformed error)`);
164
165
  }
165
166
  }
166
167
 
167
- debugLog (data) {
168
- this.log.debug(data.slice(data.indexOf('zigbee-herdsman')));
168
+ debugLog (data, ...args) {
169
+ const message = (args) ? util.format(data, ...args) : data;
170
+ this.log.debug(message.slice(message.indexOf('zigbee-herdsman')));
169
171
  }
170
172
 
171
173
  async onReady() {
@@ -304,6 +306,7 @@ class Zigbee extends utils.Adapter {
304
306
 
305
307
  async onZigbeeAdapterReady() {
306
308
  if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
309
+ this.log.warn("config :" + JSON.stringify(this.config));
307
310
  this.log.info(`Zigbee started`);
308
311
  // https://github.com/ioBroker/ioBroker.zigbee/issues/668
309
312
  const extPanIdFix = this.config.extPanIdFix ? this.config.extPanIdFix : false;
@@ -315,25 +318,31 @@ class Zigbee extends utils.Adapter {
315
318
  const adapterType = this.config.adapterType || 'zstack';
316
319
  if (adapterType === 'zstack') {
317
320
  if (configExtPanId != networkExtPanId) {
318
- // try to read from nvram
319
- const result = await this.zbController.herdsman.adapter.znp.request(
320
- 1, // Subsystem.SYS
321
- 'osalNvRead',
322
- {
323
- id: 45, // EXTENDED_PAN_ID
324
- len: 0x08,
325
- offset: 0x00,
326
- },
327
- null, [
328
- 0, // ZnpCommandStatus.SUCCESS
329
- 2, // ZnpCommandStatus.INVALID_PARAM
330
- ]
331
- );
332
- const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
333
- this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
334
- if (configExtPanId != nwExtPanId) {
335
- networkExtPanId = nwExtPanId;
336
- needChange = true;
321
+ try {
322
+ // try to read from nvram
323
+ const result = await this.zbController.herdsman.adapter.znp.request(
324
+ 1, // Subsystem.SYS
325
+ 'osalNvRead',
326
+ {
327
+ id: 45, // EXTENDED_PAN_ID
328
+ len: 0x08,
329
+ offset: 0x00,
330
+ },
331
+ null, [
332
+ 0, // ZnpCommandStatus.SUCCESS
333
+ 2, // ZnpCommandStatus.INVALID_PARAM
334
+ ]
335
+ );
336
+ const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
337
+ this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
338
+ if (configExtPanId != nwExtPanId) {
339
+ networkExtPanId = nwExtPanId;
340
+ needChange = true;
341
+ }
342
+ } catch (e) {
343
+ this.log.error(`Unable to apply ExtPanID changes: ${e}`);
344
+ this.sendError(e, `Unable to apply ExtPanID changes`);
345
+ needChange = false;
337
346
  }
338
347
  } else {
339
348
  needChange = true;
@@ -423,7 +432,7 @@ class Zigbee extends utils.Adapter {
423
432
  delete msgForState['endpoint'];
424
433
  msgForState['endpoint_id'] = message.endpoint.ID;
425
434
  this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
426
-
435
+
427
436
  if (!entity.mapped) {
428
437
  return;
429
438
  }
@@ -489,6 +498,10 @@ class Zigbee extends utils.Adapter {
489
498
  const entity = await this.zbController.resolveEntity(deviceId);
490
499
  this.log.debug(`entity: ${safeJsonStringify(entity)}`);
491
500
  const mappedModel = entity.mapped;
501
+ if (!mappedModel) {
502
+ this.log.debug(`No mapped model for ${model}`);
503
+ return;
504
+ }
492
505
  this.log.debug('Mapped Model: ' + JSON.stringify(mappedModel));
493
506
 
494
507
  stateList.forEach(async(changedState) => {
@@ -579,13 +592,15 @@ class Zigbee extends utils.Adapter {
579
592
  try {
580
593
  const result = await converter.convertSet(target, key, preparedValue, meta);
581
594
  this.log.debug(`convert result ${safeJsonStringify(result)}`);
582
- if (stateModel && !isGroup)
583
- this.acknowledgeState(deviceId, model, stateDesc, value);
584
- // process sync state list
585
- this.processSyncStatesList(deviceId, model, syncStateList);
586
- if (isGroup) {
587
- await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
588
- this.acknowledgeState(deviceId, model, stateDesc, value);
595
+ if (result !== undefined) {
596
+ if (stateModel && !isGroup)
597
+ this.acknowledgeState(deviceId, model, stateDesc, value);
598
+ // process sync state list
599
+ this.processSyncStatesList(deviceId, model, syncStateList);
600
+ if (isGroup) {
601
+ await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
602
+ this.acknowledgeState(deviceId, model, stateDesc, value);
603
+ }
589
604
  }
590
605
  } catch(error) {
591
606
  this.filterError(`Error ${error.code} on send command to ${deviceId}.`+
@@ -757,8 +772,8 @@ class Zigbee extends utils.Adapter {
757
772
  getZigbeeOptions() {
758
773
  // file path for db
759
774
  let dbDir = path.join(utils.getAbsoluteInstanceDataDir(this), '');
760
- dbDir = dbDir.replace('.', '_');
761
-
775
+ dbDir = dbDir.replace('.', '_');
776
+
762
777
  if (this.systemConfig && !fs.existsSync(dbDir)) {
763
778
  try {
764
779
  fs.mkdirSync(dbDir);