iobroker.zigbee 1.5.5 → 1.6.6

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.
@@ -37,8 +37,9 @@ class ZigbeeController extends EventEmitter {
37
37
  join - join countdown (counter)
38
38
  ready - connection successfull ()
39
39
  */
40
- constructor() {
40
+ constructor(adapter) {
41
41
  super();
42
+ this.adapter = adapter;
42
43
  this._permitJoinTime = 0;
43
44
  this.herdsman_started = false;
44
45
  this.extensions = [
@@ -65,6 +66,9 @@ class ZigbeeController extends EventEmitter {
65
66
  path: options.sp.port,
66
67
  adapter: options.sp.adapter,
67
68
  },
69
+ adapter: {
70
+ forceStartWithInconsistentAdapterConfiguration: options.startWithInconsistent
71
+ },
68
72
  };
69
73
  // https://github.com/ioBroker/ioBroker.zigbee/issues/668
70
74
  if (!options.extPanIdFix) {
@@ -80,28 +84,46 @@ class ZigbeeController extends EventEmitter {
80
84
  this.disableLed = options.disableLed;
81
85
 
82
86
  this.debug(`Using zigbee-herdsman with settings: ${JSON.stringify(herdsmanSettings)}`);
83
- this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings);
87
+ this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings, this.adapter.log);
84
88
  this.callExtensionMethod('setOptions', [{ disableActivePing: options.disablePing, disableForcedPing: false, pingTimeout:300, pingCount:3 }] );
85
89
  }
86
90
 
87
91
  // Start controller
88
92
  async start() {
89
- //this.debug(`Using zigbee-herdsman with settings2: ${JSON.stringify(this)}`);
90
- this.debug(`Starting zigbee-herdsman...`);
91
- await this.herdsman.start();
92
-
93
- this.herdsman.on('adapterDisconnected', () => this.emit('disconnect'));
94
- this.herdsman.on('deviceAnnounce', this.handleDeviceAnnounce.bind(this));
95
- this.herdsman.on('deviceInterview', this.handleDeviceInterview.bind(this));
96
- this.herdsman.on('deviceJoined', this.handleDeviceJoined.bind(this));
97
- this.herdsman.on('deviceLeave', this.handleDeviceLeave.bind(this));
98
- this.herdsman.on('message', this.handleMessage.bind(this));
99
-
100
- this.debug('zigbee-herdsman started');
101
- this.herdsman_started = true;
102
- this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
103
- this.debug(`Zigbee network parameters: ${JSON.stringify(await this.herdsman.getNetworkParameters())}`);
93
+ try {
94
+ //this.debug(`Using zigbee-herdsman with settings2: ${JSON.stringify(this)}`);
95
+ this.debug(`Starting zigbee-herdsman...`);
96
+ await this.herdsman.start();
97
+
98
+ this.herdsman.on('adapterDisconnected', this.handleDisconnected.bind(this));
99
+ this.herdsman.on('deviceAnnounce', this.handleDeviceAnnounce.bind(this));
100
+ this.herdsman.on('deviceInterview', this.handleDeviceInterview.bind(this));
101
+ this.herdsman.on('deviceJoined', this.handleDeviceJoined.bind(this));
102
+ this.herdsman.on('deviceLeave', this.handleDeviceLeave.bind(this));
103
+ this.herdsman.on('message', this.handleMessage.bind(this));
104
+
105
+ this.debug('zigbee-herdsman started');
106
+ this.herdsman_started = true;
107
+ this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
108
+
109
+ // debug info from herdsman getNetworkParameters
110
+ const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
111
+ const extendedPanIDDebug = (typeof debNetworkParam.extendedPanID == 'string') ? debNetworkParam.extendedPanID.replace('0x','') : debNetworkParam.extendedPanID;
112
+
113
+ let extPanIDDebug = '';
114
+ for (let i = extendedPanIDDebug.length - 1; i >= 0; i--) {
115
+ extPanIDDebug += extendedPanIDDebug[i-1];
116
+ extPanIDDebug += extendedPanIDDebug[i];
117
+ i--;
118
+ }
104
119
 
120
+ this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
+
122
+ } catch (e) {
123
+ this.sendError(e);
124
+ this.error('Starting zigbee-herdsman problem : ' + JSON.stringify(e.message));
125
+ throw 'Error herdsman start';
126
+ }
105
127
  // Check if we have to turn off the led
106
128
  try {
107
129
  if (this.disableLed) {
@@ -112,6 +134,7 @@ class ZigbeeController extends EventEmitter {
112
134
  }
113
135
  } catch (e) {
114
136
  this.info('Unable to disable LED, unsupported function.');
137
+ this.sendError(e);
115
138
  }
116
139
 
117
140
  // only for CC1352P and CC26X2R1 transmit power
@@ -135,6 +158,7 @@ class ZigbeeController extends EventEmitter {
135
158
  try {
136
159
  await this.herdsman.setTransmitPower(this.transmitPower);
137
160
  } catch (e) {
161
+ this.sendError(e);
138
162
  this.info('Unable to set transmit power, unsupported function.');
139
163
  }
140
164
 
@@ -188,6 +212,10 @@ class ZigbeeController extends EventEmitter {
188
212
  this.emit('event', type, dev, message, data);
189
213
  }
190
214
 
215
+ sendError(error, message) {
216
+ this.adapter.sendError(error, message);
217
+ }
218
+
191
219
  callExtensionMethod(method, parameters) {
192
220
  for (const extension of this.extensions) {
193
221
  if (extension[method]) {
@@ -198,8 +226,8 @@ class ZigbeeController extends EventEmitter {
198
226
  extension[method]();
199
227
  }
200
228
  } catch (error) {
229
+ this.sendError(error);
201
230
  this.error(`Failed to call '${extension.constructor.name}' '${method}' (${error.stack})`);
202
- // throw error;
203
231
  }
204
232
  }
205
233
  }
@@ -221,8 +249,8 @@ class ZigbeeController extends EventEmitter {
221
249
  async getGroups() {
222
250
  try {
223
251
  return this.herdsman.getGroups();
224
- }
225
- catch {
252
+ } catch (error) {
253
+ this.sendError(error);
226
254
  return undefined;
227
255
  }
228
256
  }
@@ -232,6 +260,7 @@ class ZigbeeController extends EventEmitter {
232
260
  try {
233
261
  if (group) group.removeFromDatabase();
234
262
  } catch (error) {
263
+ this.sendError(error);
235
264
  this.error('error in removeGroupById: ' + error);
236
265
  }
237
266
  }
@@ -239,8 +268,8 @@ class ZigbeeController extends EventEmitter {
239
268
  async getGroupByID(id) {
240
269
  try {
241
270
  return this.herdsman.getGroupByID(id);
242
- }
243
- catch {
271
+ } catch (error) {
272
+ this.sendError(error);
244
273
  return undefined;
245
274
  }
246
275
  }
@@ -263,6 +292,7 @@ class ZigbeeController extends EventEmitter {
263
292
  }
264
293
 
265
294
  } catch (error) {
295
+ this.sendError(error);
266
296
  if (error) this.error('getGroupMembersFromController: error is ' + JSON.stringify(error) + ' ' + JSON.stringify(new Error().stack));
267
297
  else this.error('unidentifed error in getGroupMembersFromController');
268
298
  }
@@ -344,7 +374,6 @@ class ZigbeeController extends EventEmitter {
344
374
  }
345
375
  }
346
376
 
347
-
348
377
  async incMsgHandler(message){
349
378
  this.debug('incoming msg', message);
350
379
  const device = await this.herdsman.getDeviceByIeeeAddr(message.srcaddr);
@@ -371,6 +400,7 @@ class ZigbeeController extends EventEmitter {
371
400
  await this.permitJoin(0);
372
401
  await this.herdsman.stop();
373
402
  } catch (error) {
403
+ this.sendError(error);
374
404
  if (this.herdsman_started)
375
405
  this.error(`Failed to stop zigbee (${error.stack})`);
376
406
  else {
@@ -379,6 +409,15 @@ class ZigbeeController extends EventEmitter {
379
409
  }
380
410
  }
381
411
 
412
+ async handleDisconnected() {
413
+ this.herdsman_started = false;
414
+ this.emit('disconnect');
415
+ }
416
+
417
+ connected() {
418
+ return this.herdsman_started;
419
+ }
420
+
382
421
  // Permit join
383
422
  async permitJoin(permitTime, devid, failure) {
384
423
  let permitDev;
@@ -416,9 +455,8 @@ class ZigbeeController extends EventEmitter {
416
455
  await this.herdsman.permitJoin(false, permitDev);
417
456
  }
418
457
  }
419
- }
420
- catch (e)
421
- {
458
+ } catch (e) {
459
+ this.sendError(e);
422
460
  this.error(`Failed to open the network: ${e.stack}`);
423
461
  }
424
462
  }
@@ -431,6 +469,7 @@ class ZigbeeController extends EventEmitter {
431
469
  try {
432
470
  await this.herdsman.adapter.removeDevice(device.networkAddress, device.ieeeAddr);
433
471
  } catch (error) {
472
+ this.sendError(error);
434
473
  if (error)
435
474
  this.debug(`Failed to remove device ${error.stack}`);
436
475
  // skip error if force
@@ -443,6 +482,7 @@ class ZigbeeController extends EventEmitter {
443
482
  try {
444
483
  await device.removeFromDatabase();
445
484
  } catch (error) {
485
+ this.sendError(error);
446
486
  // skip error
447
487
  if (error)
448
488
  this.debug(`Failed to remove from DB ${error.stack}`);
@@ -455,6 +495,7 @@ class ZigbeeController extends EventEmitter {
455
495
  );
456
496
  }
457
497
  } catch (error) {
498
+ this.sendError(error);
458
499
  this.error(`Failed to remove ${error.stack}`);
459
500
  if (callback) callback(`Failed to remove ${error.stack}`);
460
501
  }
@@ -474,6 +515,7 @@ class ZigbeeController extends EventEmitter {
474
515
  [message, entity],
475
516
  );
476
517
  } catch (error) {
518
+ this.sendError(error);
477
519
  this.error(`Failed to handleDeviceLeave ${error.stack}`);
478
520
  }
479
521
  }
@@ -577,6 +619,7 @@ class ZigbeeController extends EventEmitter {
577
619
  try {
578
620
  result = await device.lqi();
579
621
  } catch (error) {
622
+ this.sendError(error);
580
623
  if (error)
581
624
  this.debug(`Failed to execute LQI for '${resolved.name}'. ${safeJsonStringify(error.stack)}`);
582
625
 
@@ -612,6 +655,7 @@ class ZigbeeController extends EventEmitter {
612
655
  try {
613
656
  result = await device.routingTable();
614
657
  } catch (error) {
658
+ this.sendError(error);
615
659
  if (error) {
616
660
  this.debug(`Failed to execute routing table for '${resolved.name}'. ${safeJsonStringify(error.stack)}`);
617
661
  }
@@ -637,6 +681,7 @@ class ZigbeeController extends EventEmitter {
637
681
 
638
682
  if (callback) callback({lqis: lqis, routing: routing});
639
683
  } catch (error) {
684
+ this.sendError(error);
640
685
  this.debug(`Failed to get map: ${safeJsonStringify(error.stack)}`);
641
686
  }
642
687
  }
@@ -666,7 +711,7 @@ class ZigbeeController extends EventEmitter {
666
711
 
667
712
  if (type === 'foundation') {
668
713
  cfg.disableDefaultResponse = true;
669
- if (cmd === 'read') {
714
+ if (cmd === 'read' && !Array.isArray(zclData)) {
670
715
  // needs to be iterateable (string[] | number [])
671
716
  zclData[Symbol.iterator] = function* () {
672
717
  let k;
@@ -696,8 +741,8 @@ class ZigbeeController extends EventEmitter {
696
741
  this.debug(`entity: ${safeJsonStringify(entity)}`);
697
742
  this.debug(`group: ${safeJsonStringify(group)}`);
698
743
  await entity.endpoint.addToGroup(group.mapped);
699
- }
700
- catch (error) {
744
+ } catch (error) {
745
+ this.sendError(error);
701
746
  this.error(`Exception when trying to Add ${devId} to group ${groupId}`, error);
702
747
  return { error:`Failed to add ${devId} to group ${groupId}: ${JSON.stringify(error)}` };
703
748
  }
@@ -709,8 +754,8 @@ class ZigbeeController extends EventEmitter {
709
754
  const entity = await this.resolveEntity(devId);
710
755
  this.debug(`entity: ${safeJsonStringify(entity)}`);
711
756
  await entity.endpoint.removeFromAllGroups();
712
- }
713
- catch (error) {
757
+ } catch (error) {
758
+ this.sendError(error);
714
759
  this.error(`Exception when trying remove ${devId} from all groups`, error);
715
760
  return { error: `Failed to remove dev ${devId} from all groups: ${error}`};
716
761
  }
@@ -724,6 +769,7 @@ class ZigbeeController extends EventEmitter {
724
769
  this.debug(`Binding ${log}`);
725
770
  ep.bind(cluster, target, (error) => {
726
771
  if (error) {
772
+ this.sendError(error);
727
773
  this.error(`Failed to bind ${log} - (${error})`);
728
774
  } else {
729
775
  this.debug(`Successfully bound ${log}`);
@@ -754,6 +800,7 @@ class ZigbeeController extends EventEmitter {
754
800
  this.herdsman.reset(mode);
755
801
  if (callback) callback();
756
802
  } catch (error) {
803
+ this.sendError(error);
757
804
  this.error(`Failed to reset ${error.stack}`);
758
805
  if (callback) callback(error);
759
806
  }
@@ -764,6 +811,7 @@ class ZigbeeController extends EventEmitter {
764
811
  await this.herdsman.touchlinkFactoryResetFirst();
765
812
  this.permitJoin(permitTime);
766
813
  } catch (error) {
814
+ this.sendError(error);
767
815
  this.error(`Failed to touchlinkReset ${error.stack}`);
768
816
  }
769
817
  }
package/main.js CHANGED
@@ -15,7 +15,7 @@ const originalLogMethod = debug.log;
15
15
 
16
16
  const safeJsonStringify = require('./lib/json');
17
17
  const fs = require('fs');
18
- const pathLib = require('path');
18
+ const path = require('path');
19
19
  const utils = require('@iobroker/adapter-core'); // Get common adapter utils
20
20
  const SerialListPlugin = require('./lib/seriallist');
21
21
  const CommandsPlugin = require('./lib/commands');
@@ -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 = [];
@@ -105,18 +106,46 @@ class Zigbee extends utils.Adapter {
105
106
  }
106
107
  }
107
108
 
109
+ sendError(error, message) {
110
+ if (this.supportsFeature && this.supportsFeature('PLUGINS')) {
111
+ const sentryInstance = this.getPluginInstance('sentry');
112
+ if (sentryInstance) {
113
+ const Sentry = sentryInstance.getSentryObject();
114
+ if (Sentry) {
115
+ if (message) {
116
+ Sentry.configureScope(scope => {
117
+ scope.addBreadcrumb({
118
+ type: "error", // predefined types
119
+ category: "error message",
120
+ level: Sentry.Severity.Error,
121
+ message: message
122
+ });
123
+ });
124
+ }
125
+ if (typeof error == 'string') {
126
+ Sentry.captureException(new Error(error));
127
+ } else {
128
+ Sentry.captureException(error);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+
108
135
  filterError(errormessage, message, error) {
109
136
  if (error.code === undefined)
110
137
  {
111
138
  let em = error.stack.match(/failed \((.+?)\) at/);
112
139
  if (!em) em = error.stack.match(/failed \((.+?)\)/);
113
140
  this.log.error(`${message} no error code (${(em ? em[1]:'undefined')})`);
141
+ this.sendError(error, `${message} no error code`);
114
142
  this.log.debug(`Stack trace for ${em}: ${error.stack}`);
115
143
  return;
116
144
  }
117
145
  const ecode = errorCodes[error.code];
118
146
  if (ecode === undefined) {
119
147
  this.log.error(errormessage);
148
+ this.sendError(error, errormessage);
120
149
  return;
121
150
  }
122
151
  switch (ecode.severity) {
@@ -126,14 +155,19 @@ class Zigbee extends utils.Adapter {
126
155
  break;
127
156
  case E_WARN: this.log.warn(`${message}: Code ${error.code} (${ecode.message})`);
128
157
  break;
129
- case E_ERROR: this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
158
+ case E_ERROR:
159
+ this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
160
+ this.sendError(error, `${message}: Code ${error.code} (${ecode.message})`);
130
161
  break;
131
- default: this.log.error(`${message}: Code ${error.code} (malformed error)`);
162
+ default:
163
+ this.log.error(`${message}: Code ${error.code} (malformed error)`);
164
+ this.sendError(error, `${message}: Code ${error.code} (malformed error)`);
132
165
  }
133
166
  }
134
167
 
135
- debugLog (data) {
136
- 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')));
137
171
  }
138
172
 
139
173
  async onReady() {
@@ -153,7 +187,7 @@ class Zigbee extends utils.Adapter {
153
187
  // set connection false before connect to zigbee
154
188
  this.setState('info.connection', false, true);
155
189
  const zigbeeOptions = this.getZigbeeOptions();
156
- this.zbController = new ZigbeeController();
190
+ this.zbController = new ZigbeeController(this);
157
191
  this.zbController.on('log', this.onLog.bind(this));
158
192
  this.zbController.on('ready', this.onZigbeeAdapterReady.bind(this));
159
193
  this.zbController.on('disconnect', this.onZigbeeAdapterDisconnected.bind(this));
@@ -237,6 +271,7 @@ class Zigbee extends utils.Adapter {
237
271
  } else {
238
272
  this.log.error(error);
239
273
  }
274
+ this.sendError(error, `Failed to start Zigbee`);
240
275
  if (this.reconnectCounter > 0) {
241
276
  this.tryToReconnect();
242
277
  }
@@ -246,6 +281,7 @@ class Zigbee extends utils.Adapter {
246
281
  async onZigbeeAdapterDisconnected() {
247
282
  this.reconnectCounter = 5;
248
283
  this.log.error('Adapter disconnected, stopping');
284
+ this.sendError('Adapter disconnected, stopping');
249
285
  this.setState('info.connection', false, true);
250
286
  await this.callPluginMethod('stop');
251
287
  this.tryToReconnect();
@@ -281,25 +317,31 @@ class Zigbee extends utils.Adapter {
281
317
  const adapterType = this.config.adapterType || 'zstack';
282
318
  if (adapterType === 'zstack') {
283
319
  if (configExtPanId != networkExtPanId) {
284
- // try to read from nvram
285
- const result = await this.zbController.herdsman.adapter.znp.request(
286
- 1, // Subsystem.SYS
287
- 'osalNvRead',
288
- {
289
- id: 45, // EXTENDED_PAN_ID
290
- len: 0x08,
291
- offset: 0x00,
292
- },
293
- null, [
294
- 0, // ZnpCommandStatus.SUCCESS
295
- 2, // ZnpCommandStatus.INVALID_PARAM
296
- ]
297
- );
298
- const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
299
- this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
300
- if (configExtPanId != nwExtPanId) {
301
- networkExtPanId = nwExtPanId;
302
- needChange = true;
320
+ try {
321
+ // try to read from nvram
322
+ const result = await this.zbController.herdsman.adapter.znp.request(
323
+ 1, // Subsystem.SYS
324
+ 'osalNvRead',
325
+ {
326
+ id: 45, // EXTENDED_PAN_ID
327
+ len: 0x08,
328
+ offset: 0x00,
329
+ },
330
+ null, [
331
+ 0, // ZnpCommandStatus.SUCCESS
332
+ 2, // ZnpCommandStatus.INVALID_PARAM
333
+ ]
334
+ );
335
+ const nwExtPanId = '0x'+result.payload.value.reverse().toString('hex');
336
+ this.log.debug(`Config value ${configExtPanId} : nw value ${nwExtPanId}`);
337
+ if (configExtPanId != nwExtPanId) {
338
+ networkExtPanId = nwExtPanId;
339
+ needChange = true;
340
+ }
341
+ } catch (e) {
342
+ this.log.error(`Unable to apply ExtPanID changes: ${e}`);
343
+ this.sendError(e, `Unable to apply ExtPanID changes`);
344
+ needChange = false;
303
345
  }
304
346
  } else {
305
347
  needChange = true;
@@ -368,9 +410,6 @@ class Zigbee extends utils.Adapter {
368
410
 
369
411
  async onZigbeeEvent(type, entity, message){
370
412
  this.log.debug(`Type ${type} device ${safeJsonStringify(entity)} incoming event: ${safeJsonStringify(message)}`);
371
- if (!entity.mapped) {
372
- return;
373
- }
374
413
  const device = entity.device,
375
414
  mappedModel = entity.mapped,
376
415
  model = (entity.mapped) ? entity.mapped.model : entity.device.modelID,
@@ -385,6 +424,17 @@ class Zigbee extends utils.Adapter {
385
424
  if (message.linkquality) {
386
425
  this.publishToState(devId, model, {linkquality: message.linkquality});
387
426
  }
427
+ // publish raw event to "from_zigbee"
428
+ // some cleanup
429
+ const msgForState = Object.assign({}, message);
430
+ delete msgForState['device'];
431
+ delete msgForState['endpoint'];
432
+ msgForState['endpoint_id'] = message.endpoint.ID;
433
+ this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
434
+
435
+ if (!entity.mapped) {
436
+ return;
437
+ }
388
438
  let converters = mappedModel.fromZigbee.filter(c => c && c.cluster === cluster && (
389
439
  (c.type instanceof Array) ? c.type.includes(type) : c.type === type));
390
440
  if (!converters.length && type === 'readResponse') {
@@ -447,6 +497,10 @@ class Zigbee extends utils.Adapter {
447
497
  const entity = await this.zbController.resolveEntity(deviceId);
448
498
  this.log.debug(`entity: ${safeJsonStringify(entity)}`);
449
499
  const mappedModel = entity.mapped;
500
+ if (!mappedModel) {
501
+ this.log.debug(`No mapped model for ${model}`);
502
+ return;
503
+ }
450
504
  this.log.debug('Mapped Model: ' + JSON.stringify(mappedModel));
451
505
 
452
506
  stateList.forEach(async(changedState) => {
@@ -494,6 +548,7 @@ class Zigbee extends utils.Adapter {
494
548
  const converter = mappedModel.toZigbee.find((c) => c && (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id)));
495
549
  if (!converter) {
496
550
  this.log.error(`No converter available for '${model}' with key '${stateDesc.id}' `);
551
+ this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
497
552
  return;
498
553
  }
499
554
 
@@ -511,7 +566,7 @@ class Zigbee extends utils.Adapter {
511
566
 
512
567
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
513
568
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
514
- this.log.debug(`convert ${key}, ${preparedValue}, ${safeJsonStringify(preparedOptions)}`);
569
+ this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
515
570
 
516
571
  let target;
517
572
  if (model === 'group') {
@@ -536,13 +591,15 @@ class Zigbee extends utils.Adapter {
536
591
  try {
537
592
  const result = await converter.convertSet(target, key, preparedValue, meta);
538
593
  this.log.debug(`convert result ${safeJsonStringify(result)}`);
539
- if (stateModel && !isGroup)
540
- this.acknowledgeState(deviceId, model, stateDesc, value);
541
- // process sync state list
542
- this.processSyncStatesList(deviceId, model, syncStateList);
543
- if (isGroup) {
544
- await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
545
- this.acknowledgeState(deviceId, model, stateDesc, value);
594
+ if (result !== undefined) {
595
+ if (stateModel && !isGroup)
596
+ this.acknowledgeState(deviceId, model, stateDesc, value);
597
+ // process sync state list
598
+ this.processSyncStatesList(deviceId, model, syncStateList);
599
+ if (isGroup) {
600
+ await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
601
+ this.acknowledgeState(deviceId, model, stateDesc, value);
602
+ }
546
603
  }
547
604
  } catch(error) {
548
605
  this.filterError(`Error ${error.code} on send command to ${deviceId}.`+
@@ -574,6 +631,7 @@ class Zigbee extends utils.Adapter {
574
631
  payload_obj = JSON.parse();
575
632
  } catch (e) {
576
633
  this.log.error(`Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`);
634
+ this.sendError(e, `Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`);
577
635
  return {success:false, error: `Unable to parse ${safeJsonStringify(payload)}: ${safeJsonStringify(e)}`};
578
636
  }
579
637
  } else if (typeof payload === 'object') {
@@ -590,15 +648,18 @@ class Zigbee extends utils.Adapter {
590
648
  const entity = await this.zbController.resolveEntity(devID);
591
649
  if (!entity) {
592
650
  this.log.error(`Device ${safeJsonStringify(payload_obj.device)} not found`);
651
+ this.sendError(`Device ${safeJsonStringify(payload_obj.device)} not found`);
593
652
  return {success: false, error: `Device ${safeJsonStringify(payload_obj.device)} not found`};
594
653
  }
595
654
  const mappedModel = entity.mapped;
596
655
  if (!mappedModel) {
597
656
  this.log.error(`No Model for Device ${safeJsonStringify(payload_obj.device)}`);
657
+ this.sendError(`No Model for Device ${safeJsonStringify(payload_obj.device)}`);
598
658
  return {success: false, error: `No Model for Device ${safeJsonStringify(payload_obj.device)}`};
599
659
  }
600
660
  if (typeof payload_obj.payload !== 'object') {
601
661
  this.log.error(`Illegal payload type for ${safeJsonStringify(payload_obj.device)}`);
662
+ this.sendError(`Illegal payload type for ${safeJsonStringify(payload_obj.device)}`);
602
663
  return {success: false, error: `Illegal payload type for ${safeJsonStringify(payload_obj.device)}`};
603
664
  }
604
665
  for (const key in payload_obj.payload) {
@@ -671,8 +732,10 @@ class Zigbee extends utils.Adapter {
671
732
  await plugin[method]();
672
733
  }
673
734
  } catch (error) {
674
- if (error && !error.hasOwnProperty('code'))
735
+ if (error && !error.hasOwnProperty('code')) {
675
736
  this.log.error(`Failed to call '${plugin.constructor.name}' '${method}' (${error.stack})`);
737
+ this.sendError(error, `Failed to call '${plugin.constructor.name}' '${method}'`);
738
+ }
676
739
  throw error;
677
740
  }
678
741
  }
@@ -697,19 +760,31 @@ class Zigbee extends utils.Adapter {
697
760
  }
698
761
  callback();
699
762
  } catch (error) {
700
- this.log.error(`Unload error (${error.stack})`);
763
+ if (error) {
764
+ this.log.error(`Unload error (${error.stack})`);
765
+ }
766
+ this.sendError(error, `Unload error`);
701
767
  callback();
702
768
  }
703
769
  }
704
770
 
705
771
  getZigbeeOptions() {
706
772
  // file path for db
707
- const dataDir = (this.systemConfig) ? this.systemConfig.dataDir : '';
708
- const dbDir = pathLib.normalize(utils.controllerDir + '/' + dataDir + this.namespace.replace('.', '_'));
709
- if (this.systemConfig && !fs.existsSync(dbDir)) fs.mkdirSync(dbDir);
773
+ let dbDir = path.join(utils.getAbsoluteInstanceDataDir(this), '');
774
+ dbDir = dbDir.replace('.', '_');
775
+
776
+ if (this.systemConfig && !fs.existsSync(dbDir)) {
777
+ try {
778
+ fs.mkdirSync(dbDir);
779
+ } catch (e) {
780
+ this.log.error(`Cannot create directory ${dbDir}: ${e}`);
781
+ this.sendError(`Cannot create directory ${dbDir}: ${e}`);
782
+ }
783
+ }
710
784
  const port = this.config.port;
711
785
  if (!port) {
712
786
  this.log.error('Serial port not selected! Go to settings page.');
787
+ this.sendError('Serial port not selected! Go to settings page.');
713
788
  }
714
789
  const panID = parseInt(this.config.panID ? this.config.panID : 0x1a62);
715
790
  const channel = parseInt(this.config.channel ? this.config.channel : 11);
@@ -739,6 +814,7 @@ class Zigbee extends utils.Adapter {
739
814
  disablePing: this.config.disablePing,
740
815
  transmitPower: this.config.transmitPower,
741
816
  extPanIdFix: extPanIdFix,
817
+ startWithInconsistent: this.config.startWithInconsistent || false,
742
818
  };
743
819
  }
744
820
 
@@ -770,6 +846,7 @@ class Zigbee extends utils.Adapter {
770
846
  if (data)
771
847
  data = data.toString();
772
848
  this.logToPairing('Error: ' + msg + '. ' + data, true);
849
+ this.sendError('Error: ' + msg + '. ' + data);
773
850
  break;
774
851
  case 'debug':
775
852
  logger = this.log.debug;
@@ -792,8 +869,6 @@ class Zigbee extends utils.Adapter {
792
869
  }
793
870
  }
794
871
  }
795
-
796
-
797
872
  }
798
873
 
799
874