iobroker.zigbee 3.1.2 → 3.1.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.
@@ -11,7 +11,6 @@ const DeviceAvailabilityExt = require('./zbDeviceAvailability');
11
11
  const DeviceConfigureExt = require('./zbDeviceConfigure');
12
12
  const DeviceEventExt = require('./zbDeviceEvent');
13
13
  const DelayedActionExt = require('./zbDelayedAction');
14
- const Groups = require('./groups');
15
14
  const utils = require('./utils');
16
15
 
17
16
  const { access, constants } =require('node:fs/promises');
@@ -75,7 +74,7 @@ class ZigbeeController extends EventEmitter {
75
74
  this.herdsmanTimeoutRegexp = new RegExp(/(\d+)ms/);
76
75
  this.herdsmanLogSettings = {};
77
76
  this.debugActive = true;
78
- this.ListDevicesAtStart = true;
77
+ this.ListDevicesAtStart = adapter.config.listDevicesAtStart;
79
78
  this.deviceQueryActive = [];
80
79
  this.storedOptions = undefined;
81
80
  this.isConfigured = false;
@@ -167,7 +166,7 @@ class ZigbeeController extends EventEmitter {
167
166
  this.herdsmanLogSettings.extendedPanID = utils.byteArrayToString(herdsmanSettings.network.extendedPanID);
168
167
  this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings, this.adapter.log);
169
168
  this.callExtensionMethod('setOptions', [{
170
- disableActivePing: this.adapter.config.disablePing,
169
+ pingCluster: this.adapter.config.pingCluster,
171
170
  startReadDelay: this.adapter.config.readAllAtStart ? this.adapter.config.startReadDelay : 0,
172
171
  disableForcedPing: false,
173
172
  pingTimeout: 300,
@@ -283,8 +282,7 @@ class ZigbeeController extends EventEmitter {
283
282
  // get the model description for the known devices
284
283
  const entity = await this.resolveEntity(device);
285
284
  if (!entity) {
286
- this.warn('failed to resolve Entity for ' + device.ieeeAddr);
287
- //this.emit('pairing','failed to resolve Entity for ' + device.ieeeAddr)
285
+ this.debug('failed to resolve Entity for ' + device.ieeeAddr);
288
286
  continue;
289
287
  }
290
288
  //await this.adapter.stController.AddModelFromHerdsman(device, entity.mapped.model);
@@ -305,7 +303,6 @@ class ZigbeeController extends EventEmitter {
305
303
  ` (addr ${entity.device.networkAddress}): ` +
306
304
  (entity.mapped ? `${entity.mapped.model} - ${entity.mapped.vendor} ${entity.mapped.description} ` : `Unsupported (model ${entity.device.modelID})`) +
307
305
  `(${entity.device.type})`);
308
- //this.emit('pairing',msg);
309
306
  if (this.ListDevicesAtStart) this.info(msg);
310
307
  }
311
308
 
@@ -536,9 +533,10 @@ class ZigbeeController extends EventEmitter {
536
533
  return members;
537
534
  }
538
535
 
539
- getDevice(key) {
536
+ async getDevice(key) {
540
537
  try {
541
- return this.herdsman.getDeviceByIeeeAddr(key);
538
+ const dev = await this.herdsman.getDeviceByIeeeAddr(key);
539
+ return dev;
542
540
  }
543
541
  catch (error) {
544
542
  this.error(`getDeviceByIeeeAddr: ${(error && error.message ? error.message : 'no error message')}`);
@@ -572,7 +570,9 @@ class ZigbeeController extends EventEmitter {
572
570
  key: key,
573
571
  message: 'success'
574
572
  }
575
- if (typeof key === 'object') return rv;
573
+ if (typeof key === 'object') {
574
+ return rv;
575
+ }
576
576
  if (typeof key === 'number') {
577
577
  rv.kind = 'group';
578
578
  return rv;
@@ -602,8 +602,11 @@ class ZigbeeController extends EventEmitter {
602
602
  return rv;
603
603
  }
604
604
 
605
+ async getGroup(id) {
606
+ return await this.herdsman.getGroupByID(id);
607
+ }
608
+
605
609
  async resolveEntity(key, ep) {
606
- // this.warn('resolve entity with key of tyoe ' + typeof (key));
607
610
  try {
608
611
  const _key = await this.analyzeKey(key);
609
612
  if (_key.message !== 'success') return undefined;
@@ -615,6 +618,7 @@ class ZigbeeController extends EventEmitter {
615
618
  device: coordinator,
616
619
  endpoint: coordinator.getEndpoint(1),
617
620
  name: 'Coordinator',
621
+ options:{}
618
622
  };
619
623
  }
620
624
  if (_key.kind === 'group') {
@@ -626,18 +630,38 @@ class ZigbeeController extends EventEmitter {
626
630
  type: 'group',
627
631
  mapped: group,
628
632
  device: group,
633
+ endpoint: group,
629
634
  //group,
630
635
  name: `Group ${_key.key}`,
636
+ options: {},
631
637
  };
632
638
 
633
639
  }
634
640
  //if (_key.kind === 'ieee')
635
641
  const device = (_key.kind === 'ieee' ? this.herdsman.getDeviceByIeeeAddr(_key.key) : key);
642
+ if (device && device.model === 'group') {
643
+ return {
644
+ type: 'group',
645
+ mapped: device,
646
+ device,
647
+ endpoint: device,
648
+ name: `Group ${device.groupID}`,
649
+ options:{}
650
+ }
651
+ }
636
652
  if (device) {
637
653
  const t = Date.now();
638
654
  const mapped = await zigbeeHerdsmanConverters.findByDevice(device, false);
639
- if (!mapped)
640
- this.warn(`Resolve Entity did not manage to find a mapped device for ${device}`);
655
+ if (!mapped) {
656
+ if (device.type === 'Coordinator')
657
+ return {
658
+ type: 'device',
659
+ device: device,
660
+ endpoint: device.getEndpoint(1),
661
+ name: 'Coordinator',
662
+ };
663
+ this.warn(`Resolve Entity did not manage to find a mapped device for ${device.ieeeAddr} of type ${device.modelID}`);
664
+ }
641
665
  const endpoints = mapped && mapped.endpoint ? mapped.endpoint(device) : null;
642
666
  let endpoint;
643
667
  if (endpoints && ep != undefined && endpoints[ep]) {
@@ -652,6 +676,7 @@ class ZigbeeController extends EventEmitter {
652
676
  endpoint = device.endpoints[0];
653
677
  }
654
678
  }
679
+ const options = mapped ? this.adapter.stController.localConfig.getOptions(device.ieeeAddr, mapped.model) : {};
655
680
  return {
656
681
  type: 'device',
657
682
  device,
@@ -659,10 +684,11 @@ class ZigbeeController extends EventEmitter {
659
684
  endpoint,
660
685
  endpoints: device.endpoints,
661
686
  name: device._ieeeAddr,
687
+ options:options
662
688
  };
663
689
  }
664
690
  else {
665
- this.warn(`resolve_entity failed for ${JSON.stringify(_key)}`);
691
+ this.debug(`resolve_entity failed for ${JSON.stringify(_key)}`);
666
692
  }
667
693
  }
668
694
  catch (error)
@@ -705,10 +731,13 @@ class ZigbeeController extends EventEmitter {
705
731
  }
706
732
 
707
733
  try {
708
- if (this.HerdsmanStarted) await this.permitJoin(0);
709
- await this.herdsman.stop();
710
- this.HerdsmanStarted = false;
711
- this.info('zigbecontroller stopped successfully');
734
+ if (this.herdsmanStarted) {
735
+ await this.permitJoin(0);
736
+ await this.herdsman.stop();
737
+ this.herdsmanStarted = false;
738
+ this.info('zigbecontroller stopped successfully');
739
+ }
740
+ else this.info('zigbecontroller stopped successfully - ZH was not running');
712
741
  } catch (error) {
713
742
  this.sendError(error);
714
743
  if (this.herdsmanStarted) {
@@ -847,10 +876,11 @@ class ZigbeeController extends EventEmitter {
847
876
  async handleDeviceAnnounce(message) {
848
877
  if (this.debugActive) this.debug('handleDeviceAnnounce', message);
849
878
  const entity = await this.resolveEntity(message.device || message.ieeeAddr);
850
- const friendlyName = entity.name;
851
-
879
+ const friendlyName = entity ? entity.name : message.ieeeAddr ? message.ieeeAddr : message.device && message.device.ieeeAddr ? message.device.ieeeAddr : 'without data';
852
880
 
853
881
  this.emit('pairing', `Device '${friendlyName}' announced itself`);
882
+ if (!entity) return;
883
+
854
884
  if (this.adapter.stController.checkDebugDevice(friendlyName)) {
855
885
  this.emit('device_debug', {ID: Date.now(), data: {flag:'da', states:[{id: '--', value:'--', payload:message}] , IO:true} ,message:`Device '${friendlyName}' announced itself`});
856
886
  }
@@ -860,25 +890,26 @@ class ZigbeeController extends EventEmitter {
860
890
  this.info(`Device '${friendlyName}' announced itself${this.readAtAnnounce ? ', trying to read its status' : ''}`);
861
891
  }
862
892
 
863
- if (entity.device && entity.device._modelID && entity.device.interviewState != 'SUCCESSFUL') {
864
- this.warn(`ignoring device announcement for ${entity.device._modelID} due to interview state ${entity.device.interviewState}`);
893
+ if (entity.device && entity.device.modelID && entity.device.interviewState != 'SUCCESSFUL') {
894
+ this.info(`ignoring device announcement for ${entity.device.modelID} due to interview state ${entity.device.interviewState}`);
865
895
  this.emit('pairing', `device interview state is ${entity.device.interviewState}`)
866
896
  return;
867
897
  }
868
898
 
869
899
  const networkOpen = this.herdsman.getPermitJoin();
870
- if (networkOpen && entity.device && entity.device._modelID && entity.device.interviewState != 'IN_PROGRESS')
900
+ /*
901
+ if (networkOpen && entity.device && entity.device.modelID && entity.device.interviewState != 'IN_PROGRESS')
871
902
  {
872
903
  //entity.device.modelID = entity.device._modelID;
873
- this.emit('new', entity);
904
+ //this.emit('new', entity);
874
905
  return;
875
906
  }
876
-
907
+ */
877
908
  try {
878
909
  if (entity && entity.mapped) {
879
910
  this.callExtensionMethod(
880
911
  'onZigbeeEvent',
881
- [{'device': message.device, 'type': 'deviceAnnounce'}, entity ? entity.mapped : null]);
912
+ [{'device': message.device, 'type': 'deviceAnnounce', options: entity.options || {}}, entity ? entity.mapped : null]);
882
913
  this.callExtensionMethod('registerDevicePing', [message.device, entity]);
883
914
  if (this.readAtAnnounce) await this.doDeviceQuery(message.device || message.ieeeAddr, Date.now(), false);
884
915
  }
@@ -891,7 +922,8 @@ class ZigbeeController extends EventEmitter {
891
922
  async handleDeviceJoined(message) {
892
923
  if (this.debugActive) this.debug('handleDeviceJoined', message);
893
924
  //const entity = await this.resolveEntity(message.device || message.ieeeAddr);
894
- //this.emit('new', entity);
925
+ // this.emit('new', entity);
926
+ //if (entity && entity.mapped) this.callExtensionMethod([message, entity.mapped]);
895
927
  }
896
928
 
897
929
  async handleDeviceInterview(message) {
@@ -916,12 +948,12 @@ class ZigbeeController extends EventEmitter {
916
948
  const log = {friendly_name: friendlyName, model, vendor, description, supported: true};
917
949
  this.emit('pairing', 'Interview successful', JSON.stringify(log));
918
950
  //entity.device.modelID = entity.device._modelID;
919
- this.emit('new', entity);
920
- // send to extensions again (for configure)
921
951
  this.callExtensionMethod(
922
952
  'onZigbeeEvent',
923
- [message, entity ? entity.mapped : null],
953
+ [{...message,type:'deviceInterview', options: entity.options || {}}, entity.mapped],
924
954
  );
955
+ this.emit('new', entity);
956
+ // send to extensions again (for configure)
925
957
  } else {
926
958
  if (this.debugActive) this.debug(
927
959
  `Device '${friendlyName}' with Zigbee model '${message.device.modelID}' is NOT supported, ` +
@@ -936,8 +968,16 @@ class ZigbeeController extends EventEmitter {
936
968
  this.error(`Failed to interview '${friendlyName}', device has not successfully been paired. Try again !!!!!!!!!! `);
937
969
  //this.error(`Failed to interview '${friendlyName}', device has not successfully been paired. Try again !!!!!!!!!! ${message.error}`);
938
970
  this.emit('pairing', 'Interview failed', friendlyName);
971
+ this.callExtensionMethod(
972
+ 'onZigbeeEvent',
973
+ [message, entity ? entity.mapped : null],
974
+ );
939
975
  } else {
940
976
  if (message.status === 'started') {
977
+ this.callExtensionMethod(
978
+ 'onZigbeeEvent',
979
+ [message, entity ? entity.mapped : null],
980
+ );
941
981
  this.info(`Starting interview of '${friendlyName}'`);
942
982
  this.emit('pairing', 'Interview started', friendlyName);
943
983
  }
@@ -953,7 +993,7 @@ class ZigbeeController extends EventEmitter {
953
993
 
954
994
  const is = data.device.interviewState;
955
995
  if (is != 'SUCCESSFUL' && is != 'FAILED') {
956
- this.warn(`message ${JSON.stringify(data)} received during interview.`)
996
+ this.info(`message ${JSON.stringify(data)} received during interview.`)
957
997
  }
958
998
  const entity = await this.resolveEntity(data.device || data.ieeeAddr);
959
999
  const name = (entity && entity._modelID) ? entity._modelID : data.device.ieeeAddr;
@@ -963,11 +1003,10 @@ class ZigbeeController extends EventEmitter {
963
1003
  (data.hasOwnProperty('groupID') ? ` with groupID ${data.groupID}` : ``)
964
1004
  );
965
1005
  this.event(data.type, entity, data);
966
-
967
1006
  // Call extensions
968
1007
  this.callExtensionMethod(
969
1008
  'onZigbeeEvent',
970
- [data, entity ? entity.mapped : null],
1009
+ [{...data, options:entity.options || {}}, entity ? entity.mapped : null],
971
1010
  );
972
1011
  }
973
1012
 
@@ -1240,7 +1279,7 @@ class ZigbeeController extends EventEmitter {
1240
1279
 
1241
1280
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
1242
1281
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
1243
- const message = `convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`;
1282
+ const message = `convert ${key} with value ${safeJsonStringify(preparedValue)} and options ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`;
1244
1283
  if (has_elevated_debug) {
1245
1284
  this.emit('device_debug', { ID:debugID, data: { flag: '04', payload: {key:key, ep: stateDesc.epname, value:preparedValue, options:preparedOptions}, IO:false }, message:message});
1246
1285
  }
@@ -1288,7 +1327,8 @@ class ZigbeeController extends EventEmitter {
1288
1327
  try {
1289
1328
  const result = await converter.convertSet(target, key, preparedValue, meta);
1290
1329
  const message = `convert result ${safeJsonStringify(result)} for device ${deviceId}`;
1291
- this.emit('published', deviceId, model, stateModel, stateList, options, debugID, has_elevated_debug );
1330
+ if (isGroup)
1331
+ this.emit('published', deviceId, model, stateModel, stateList, options, debugID, has_elevated_debug );
1292
1332
  if (has_elevated_debug) {
1293
1333
  this.emit('device_debug', { ID:debugID, data: { flag: 'SUCCESS' , IO:false }, message:message});
1294
1334
  }
@@ -1309,7 +1349,7 @@ class ZigbeeController extends EventEmitter {
1309
1349
  }
1310
1350
  } catch (error) {
1311
1351
  if (has_elevated_debug) {
1312
- const message = `caught error ${safeJsonStringify(error)} when setting value for device ${deviceId}.`;
1352
+ const message = `caught error ${error && error.message ? error.message : 'no reason given'} when setting value for device ${deviceId}.`;
1313
1353
  this.emit('device_debug', { ID:debugID, data: { error: 'EXSET' , IO:false },message:message});
1314
1354
  }
1315
1355
  this.adapter.filterError(`Error ${error.code} on send command to ${deviceId}.` +
@@ -1347,8 +1387,8 @@ class ZigbeeController extends EventEmitter {
1347
1387
  // device: name of the device. For a device zigbee.0.0011223344556677 this would be 0011223344556677
1348
1388
  // payload: The data to send to the device as JSON object (key/Value pairs)
1349
1389
  // endpoint: optional: the endpoint to send the data to, if supported.
1350
- //
1351
- async publishPayload(payload, debugID) {
1390
+ // acknowledge: optional: if to update the devices 'send_payload' DP (if present) after successful publish
1391
+ async publishPayload(payload, debugID, has_elevated_debug) {
1352
1392
  let payloadObj = {};
1353
1393
  if (typeof payload === 'string') {
1354
1394
  try {
@@ -1410,7 +1450,10 @@ class ZigbeeController extends EventEmitter {
1410
1450
  }
1411
1451
  }
1412
1452
  try {
1413
- await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, debugID);
1453
+ await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, debugID, has_elevated_debug);
1454
+ if (payload.acknowledge) {
1455
+ this.emit('acknowledge_state', payload.device, payload.model, { id:'send_payload' }, undefined);
1456
+ }
1414
1457
  return {success: true};
1415
1458
  } catch (error) {
1416
1459
  this.log.error(`Error ${error.code} on send command to ${payload.device}.` + ` Error: ${error.stack} ` + `Send command to ${payload.device} failed with ` + error);
@@ -1430,8 +1473,9 @@ class ZigbeeController extends EventEmitter {
1430
1473
  if (this.debugActive) this.debug(`doDeviceQuery: resolveEntity for entity: ${deviceId} is ${safeJsonStringify(entity)}`);
1431
1474
  const mappedModel = entity ? entity.mapped : undefined;
1432
1475
  if (mappedModel) {
1476
+ const epmap = mappedModel.endpoint ? mappedModel.endpoint() : [];
1433
1477
  if (elevated) {
1434
- const message = `Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`;
1478
+ const message = `Device query for '${entity.device.ieeeAddr}' triggered`;
1435
1479
  this.emit('device_debug', { ID:debugID, data: { flag: 'qs' ,states:[{id:'device_query', value:true, payload:'device_query'}], IO:false }, message:message});
1436
1480
  }
1437
1481
  else
@@ -1440,24 +1484,32 @@ class ZigbeeController extends EventEmitter {
1440
1484
 
1441
1485
  for (const converter of mappedModel.toZigbee) {
1442
1486
  if (converter.hasOwnProperty('convertGet')) {
1443
- for (const ckey of converter.key) {
1487
+ const sources = [];
1488
+ if (converter.endpoints && epmap) {
1489
+ for (const epname of converter.endpoints) {
1490
+ const source = entity.device.endpoints.find((id) => id.ID == epmap[epname]);
1491
+ if (source) sources.push(source);
1492
+ }
1493
+ }
1494
+ if (sources.length == 0) sources.push(entity.device.endpoints[0]);
1495
+ for (const source of sources) {
1444
1496
  try {
1445
- await converter.convertGet(entity.device.endpoints[0], ckey, {device:entity.device});
1446
- this.debug(`read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
1497
+ await converter.convertGet(source, '', {device:entity.device});
1498
+ this.debug(`read for state${converter.key.length ? '' : 's'} '${converter.key.join(',')}' of '${entity.device.ieeeAddr}/${source.ID}' after device query`);
1447
1499
  } catch (error) {
1448
1500
  if (elevated) {
1449
- 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'}`;
1501
+ const message = `Failed to read for state${converter.key.length ? '' : 's'} '${converter.key.join(',')}' of '${source.ID}' from query with '${error && error.message ? error.message : 'no error message'}`;
1450
1502
  this.warn(`ELEVATED OE02.1 ${message}`);
1451
1503
  this.emit('device_debug', { ID:debugID, data: { error: 'NOTREAD' , IO:false }, message:message });
1452
1504
  }
1453
1505
  else
1454
- this.debug(`failed to read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
1506
+ this.debug(`failed to read for state${converter.key.length ? '' : 's'} '${converter.key.join(',')}' of '${source.ID}'after device query`);
1455
1507
  }
1456
1508
  }
1457
1509
  }
1458
1510
  }
1459
1511
  if (elevated) {
1460
- const message = `ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`;
1512
+ const message = `ELEVATED O07: Device query for '${entity.device.ieeeAddr}}' complete`;
1461
1513
  this.emit('device_debug', { ID:debugID, data: { flag: 'qe' , IO:false }, message:message});
1462
1514
  }
1463
1515
  else
@@ -1467,7 +1519,7 @@ class ZigbeeController extends EventEmitter {
1467
1519
 
1468
1520
  async deviceQuery(deviceId, debugID, elevated, callback) {
1469
1521
  if (this.deviceQueryActive.includes (deviceId)) {
1470
- this.warn(`Device query for ${deviceId} is still active.`);
1522
+ this.info(`Device query for ${deviceId} is still active.`);
1471
1523
  return;
1472
1524
  }
1473
1525
  this.deviceQueryActive.push(deviceId);
package/main.js CHANGED
@@ -13,8 +13,6 @@ try {
13
13
  }
14
14
  const originalLogMethod = debug.log;
15
15
 
16
- const zigbeeHerdsmanConvertersUtils = require('zigbee-herdsman-converters/lib/utils');
17
-
18
16
  const safeJsonStringify = require('./lib/json');
19
17
  const fs = require('fs');
20
18
  const path = require('path');
@@ -37,7 +35,6 @@ const vm = require('vm');
37
35
  const util = require('util');
38
36
  const dmZigbee = require('./lib/devicemgmt.js');
39
37
  const DeviceDebug = require('./lib/DeviceDebug');
40
- const { regexpCode } = require('ajv/dist/compile/codegen');
41
38
  const dns = require('dns');
42
39
  const net = require('net');
43
40
  const { getNetAddress } = require('./lib/utils')
@@ -277,7 +274,6 @@ class Zigbee extends utils.Adapter {
277
274
 
278
275
  SandboxRequire(sandbox, items) {
279
276
  if (!items) return true;
280
- //let converterLoaded = true;
281
277
  for (const item of items) {
282
278
  const modulePath = item[2].replace(/['"]/gm, '');
283
279
 
@@ -353,9 +349,6 @@ class Zigbee extends utils.Adapter {
353
349
  converterLoaded = false;
354
350
  this.log.error(`converter does not export any converter array, please add 'module.exports' statement to ${mN}`);
355
351
  }
356
-
357
- //fs.writeFileSync(mN+'.tmp', modifiedCode)
358
-
359
352
  if (converterLoaded) {
360
353
  try {
361
354
  this.log.warn('Trying to run sandbox for ' + mN);
@@ -416,18 +409,18 @@ class Zigbee extends utils.Adapter {
416
409
  }
417
410
  this.zbController.configure(this.getZigbeeOptions(message.zigbeeOptions));
418
411
  response.status = await this.doConnect(true);
412
+ if (!response.status) response.error = { message: 'Unable to start the Zigbee Network. Please check the previous messages.'}
419
413
  this.sendTo(from, command, response, callback);
420
414
  }
421
415
  catch (error) {
422
- this.sendTo(from, command, { status:false }, callback);
416
+ this.sendTo(from, command, { status:false, error }, callback);
423
417
  }
424
418
  }
425
419
  else try {
426
420
  await this.zbController.stopHerdsman();
427
- //this.logToPairing('herdsman stopped !');
428
421
  this.sendTo(from, command, { status:true }, callback);
429
422
  } catch (error) {
430
- this.sendTo(from, command, { status:true }, callback);
423
+ this.sendTo(from, command, { status:true, error }, callback);
431
424
  }
432
425
  }
433
426
 
@@ -460,12 +453,6 @@ class Zigbee extends utils.Adapter {
460
453
  this.setState('info.connection', false, true);
461
454
  this.logToPairing(`Failed to start Zigbee: ${error && error.message ? error.message : 'no message given'}`)
462
455
  this.log.error(`Failed to start Zigbee: ${error && error.message ? error.message : 'no message given'}`);
463
- /* if (error.stack) {
464
- this.log.error(error.stack);
465
- } else {
466
- this.log.error(error);
467
- }
468
- */
469
456
  this.sendError(error, `Failed to start Zigbee`);
470
457
  if (noReconnect) return false;
471
458
 
@@ -630,59 +617,58 @@ class Zigbee extends utils.Adapter {
630
617
 
631
618
  await this.setState('info.connection', true, true);
632
619
  this.stController.CleanupRequired(false);
620
+ const devicesFromObjects = (await this.getDevicesAsync()).filter(item => item.native.id.length ==16).map((item) => `0x${item.native.id}`);
633
621
  const devicesFromDB = this.zbController.getClientIterator(false);
634
622
  for (const device of devicesFromDB) {
635
623
  const entity = await this.zbController.resolveEntity(device);
636
624
  if (entity) {
637
625
  const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
626
+ const idx = devicesFromObjects.indexOf(device.ieeeAddr);
627
+ if (idx > -1) devicesFromObjects.splice(idx, 1);
638
628
  this.stController.updateDev(device.ieeeAddr.substr(2), model, model, () =>
639
629
  this.stController.syncDevStates(device, model));
640
630
  }
641
631
  else (this.log.warn('resolveEntity returned no entity'));
642
632
  }
633
+ for (const id of devicesFromObjects) {
634
+ try {
635
+ this.log.warn(`removing object for device ${id} - it is no longer in the zigbee database`);
636
+ await this.delObjectAsync(id.substring(2), { recursive:true })
637
+ }
638
+ catch {
639
+ this.log.warn(`error removing ${id}`)
640
+ }
641
+ }
643
642
  await this.callPluginMethod('start', [this.zbController, this.stController]);
644
643
  }
645
644
 
645
+
646
646
  async checkIfModelUpdate(entity) {
647
647
  const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
648
648
  const device = entity.device;
649
649
  const devId = device.ieeeAddr.substr(2);
650
650
 
651
- return new Promise((resolve) => {
652
- this.getObject(devId, (err, obj) => {
653
- if (obj && obj.common.type !== model) {
654
- // let's change model
655
- this.getStatesOf(devId, (err, states) => {
656
- if (!err && states) {
657
- const chain = [];
658
- states.forEach((state) =>
659
- chain.push(this.deleteStateAsync(devId, null, state._id)));
660
-
661
- Promise.all(chain)
662
- .then(() =>
663
- this.stController.deleteObj(devId, () =>
664
- this.stController.updateDev(devId, model, model, async () => {
665
- await this.stController.syncDevStates(device, model);
666
- resolve();
667
- })));
668
- } else {
669
- resolve();
670
- }
671
- });
672
- } else {
673
- resolve();
674
- }
675
- });
676
- });
651
+ const obj = await this.getObjectAsync(devId);
652
+ if (obj && obj.common.type !== model) {
653
+ await this.stController.deleteObj(devId);
654
+ await this.stController.updateDev(devId, model, model);
655
+ await this.stController.syncDevStates(device, model);
656
+ }
677
657
  }
678
658
 
679
659
  acknowledgeState(deviceId, model, stateDesc, value) {
680
- if (model === 'group') {
681
- const stateId = `${this.namespace}.group_${deviceId}.${stateDesc.id}`;
682
- this.setState(stateId, value, true);
683
- } else {
684
- const stateId = `${this.namespace}.${deviceId.replace('0x', '')}.${stateDesc.id}`;
685
- this.setState(stateId, value, true);
660
+ const stateId = (model === 'group' ?
661
+ `${this.namespace}.group_${deviceId}.${stateDesc.id}` :
662
+ `${this.namespace}.${deviceId.replace('0x', '')}.${stateDesc.id}`);
663
+ if (value === undefined) try {
664
+ this.getState(stateId, (err, state) => { if (!err && state.hasOwnProperty('val')) this.setState(stateId, state.val, true)});
665
+ }
666
+ catch (error) {
667
+ this.log.warn(`Error acknowledging ${stateId} without value: ${error && error.message ? error.message : 'no reason given'}`);
668
+ }
669
+ else try { this.setState(stateId, value, true); }
670
+ catch (error) {
671
+ this.log.warn(`Error acknowledging ${stateId} with value ${JSON.stringify(value)}: ${error && error.message ? error.message : 'no reason given'}`);
686
672
  }
687
673
  }
688
674
 
@@ -754,17 +740,17 @@ class Zigbee extends utils.Adapter {
754
740
  async onUnload(callback) {
755
741
  try {
756
742
  this.log.info(`Halting zigbee adapter. Restart delay is at least ${this.ioPack.common.stopTimeout / 1000} seconds.`)
743
+ this.setState('info.connection', false, true);
744
+ const chain = [];
757
745
  if (this.config.debugHerdsman) {
758
746
  debug.disable();
759
747
  debug.log = originalLogMethod;
760
748
  }
761
-
762
- this.log.info('cleaning everything up...');
749
+ this.log.info('cleaning everything up');
763
750
  await this.callPluginMethod('stop');
764
- await this.stController.stop();
765
- if (this.zbController) {
766
- await this.zbController.stop();
767
- }
751
+ if (this.stController) chain.push(this.stController.stop());
752
+ if (this.zbController) chain.push(this.zbController.stop());
753
+ await Promise.all(chain);
768
754
  this.log.info('cleanup successful');
769
755
  callback();
770
756
  } catch (error) {
@@ -776,8 +762,8 @@ class Zigbee extends utils.Adapter {
776
762
  }
777
763
  }
778
764
 
779
- getZigbeeOptions(_overrideOptions) {
780
- const override = (_overrideOptions ? _overrideOptions:{});
765
+ getZigbeeOptions(overrideOptions) {
766
+ const override = (overrideOptions ? overrideOptions:{});
781
767
  // file path for db
782
768
  const dbDir = this.expandFileName('');
783
769
 
@@ -823,7 +809,7 @@ class Zigbee extends utils.Adapter {
823
809
  dbPath: 'shepherd.db',
824
810
  backupPath: 'nvbackup.json',
825
811
  disableLed: this.config.disableLed,
826
- disablePing: this.config.disablePing,
812
+ disablePing: (this.config.pingCluster=='off'),
827
813
  transmitPower: this.config.transmitPower,
828
814
  disableBackup: this.config.disableBackup,
829
815
  extPanIdFix: extPanIdFix,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "3.1.2",
3
+ "version": "3.1.5",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -21,15 +21,15 @@
21
21
  "serialport": "^13.0.0"
22
22
  },
23
23
  "dependencies": {
24
- "@iobroker/adapter-core": "^3.2.3",
24
+ "@iobroker/adapter-core": "^3.3.2",
25
25
  "@iobroker/dm-utils": "^1.0.10",
26
26
  "humanize-duration": "^3.33.0",
27
27
  "tar": "^7.4.3",
28
28
  "ajv": "^8.17.1",
29
29
  "uri-js": "^4.4.1",
30
- "typescript": "^5.8.3",
30
+ "typescript": "^5.9.2",
31
31
  "zigbee-herdsman": "^6.0.0",
32
- "zigbee-herdsman-converters": "^25.0.0"
32
+ "zigbee-herdsman-converters": "25.31.0"
33
33
  },
34
34
  "description": "Zigbee devices",
35
35
  "devDependencies": {
@@ -37,15 +37,12 @@
37
37
  "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
38
38
  "@alcalzone/release-script-plugin-license": "^3.7.0",
39
39
  "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
40
- "@iobroker/testing": "^5.0.4",
40
+ "@iobroker/testing": "^5.1.1",
41
41
  "chai": "^5.2.1",
42
42
  "chai-as-promised": "^7.1.1",
43
- "eslint": "^9.30.0",
43
+ "eslint": "^9.36.0",
44
44
  "eslint-config-prettier": "^9.1.0",
45
45
  "eslint-plugin-prettier": "^5.5.4",
46
- "gulp": "^4.0.2",
47
- "gulp-jsdoc3": "^3.0.0",
48
- "gulp-replace": "^1.1.4",
49
46
  "mixin-deep": "^2.0.1",
50
47
  "mocha": "^11.7.1",
51
48
  "@iobroker/dev-server": "^0.7.8"