iobroker.zigbee 3.1.2 → 3.1.4

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 = 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
+ this.info('zigbecontroller stopped successfully - ZH was not running');
712
741
  } catch (error) {
713
742
  this.sendError(error);
714
743
  if (this.herdsmanStarted) {
@@ -860,25 +889,26 @@ class ZigbeeController extends EventEmitter {
860
889
  this.info(`Device '${friendlyName}' announced itself${this.readAtAnnounce ? ', trying to read its status' : ''}`);
861
890
  }
862
891
 
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}`);
892
+ if (entity.device && entity.device.modelID && entity.device.interviewState != 'SUCCESSFUL') {
893
+ this.info(`ignoring device announcement for ${entity.device.modelID} due to interview state ${entity.device.interviewState}`);
865
894
  this.emit('pairing', `device interview state is ${entity.device.interviewState}`)
866
895
  return;
867
896
  }
868
897
 
869
898
  const networkOpen = this.herdsman.getPermitJoin();
870
- if (networkOpen && entity.device && entity.device._modelID && entity.device.interviewState != 'IN_PROGRESS')
899
+ /*
900
+ if (networkOpen && entity.device && entity.device.modelID && entity.device.interviewState != 'IN_PROGRESS')
871
901
  {
872
902
  //entity.device.modelID = entity.device._modelID;
873
- this.emit('new', entity);
903
+ //this.emit('new', entity);
874
904
  return;
875
905
  }
876
-
906
+ */
877
907
  try {
878
908
  if (entity && entity.mapped) {
879
909
  this.callExtensionMethod(
880
910
  'onZigbeeEvent',
881
- [{'device': message.device, 'type': 'deviceAnnounce'}, entity ? entity.mapped : null]);
911
+ [{'device': message.device, 'type': 'deviceAnnounce', options: entity.options || {}}, entity ? entity.mapped : null]);
882
912
  this.callExtensionMethod('registerDevicePing', [message.device, entity]);
883
913
  if (this.readAtAnnounce) await this.doDeviceQuery(message.device || message.ieeeAddr, Date.now(), false);
884
914
  }
@@ -891,7 +921,8 @@ class ZigbeeController extends EventEmitter {
891
921
  async handleDeviceJoined(message) {
892
922
  if (this.debugActive) this.debug('handleDeviceJoined', message);
893
923
  //const entity = await this.resolveEntity(message.device || message.ieeeAddr);
894
- //this.emit('new', entity);
924
+ // this.emit('new', entity);
925
+ //if (entity && entity.mapped) this.callExtensionMethod([message, entity.mapped]);
895
926
  }
896
927
 
897
928
  async handleDeviceInterview(message) {
@@ -916,12 +947,12 @@ class ZigbeeController extends EventEmitter {
916
947
  const log = {friendly_name: friendlyName, model, vendor, description, supported: true};
917
948
  this.emit('pairing', 'Interview successful', JSON.stringify(log));
918
949
  //entity.device.modelID = entity.device._modelID;
919
- this.emit('new', entity);
920
- // send to extensions again (for configure)
921
950
  this.callExtensionMethod(
922
951
  'onZigbeeEvent',
923
- [message, entity ? entity.mapped : null],
952
+ [{...message,type:'deviceInterview', options: entity.options || {}}, entity.mapped],
924
953
  );
954
+ this.emit('new', entity);
955
+ // send to extensions again (for configure)
925
956
  } else {
926
957
  if (this.debugActive) this.debug(
927
958
  `Device '${friendlyName}' with Zigbee model '${message.device.modelID}' is NOT supported, ` +
@@ -936,8 +967,16 @@ class ZigbeeController extends EventEmitter {
936
967
  this.error(`Failed to interview '${friendlyName}', device has not successfully been paired. Try again !!!!!!!!!! `);
937
968
  //this.error(`Failed to interview '${friendlyName}', device has not successfully been paired. Try again !!!!!!!!!! ${message.error}`);
938
969
  this.emit('pairing', 'Interview failed', friendlyName);
970
+ this.callExtensionMethod(
971
+ 'onZigbeeEvent',
972
+ [message, entity ? entity.mapped : null],
973
+ );
939
974
  } else {
940
975
  if (message.status === 'started') {
976
+ this.callExtensionMethod(
977
+ 'onZigbeeEvent',
978
+ [message, entity ? entity.mapped : null],
979
+ );
941
980
  this.info(`Starting interview of '${friendlyName}'`);
942
981
  this.emit('pairing', 'Interview started', friendlyName);
943
982
  }
@@ -953,7 +992,7 @@ class ZigbeeController extends EventEmitter {
953
992
 
954
993
  const is = data.device.interviewState;
955
994
  if (is != 'SUCCESSFUL' && is != 'FAILED') {
956
- this.warn(`message ${JSON.stringify(data)} received during interview.`)
995
+ this.info(`message ${JSON.stringify(data)} received during interview.`)
957
996
  }
958
997
  const entity = await this.resolveEntity(data.device || data.ieeeAddr);
959
998
  const name = (entity && entity._modelID) ? entity._modelID : data.device.ieeeAddr;
@@ -963,11 +1002,10 @@ class ZigbeeController extends EventEmitter {
963
1002
  (data.hasOwnProperty('groupID') ? ` with groupID ${data.groupID}` : ``)
964
1003
  );
965
1004
  this.event(data.type, entity, data);
966
-
967
1005
  // Call extensions
968
1006
  this.callExtensionMethod(
969
1007
  'onZigbeeEvent',
970
- [data, entity ? entity.mapped : null],
1008
+ [{...data, options:entity.options || {}}, entity ? entity.mapped : null],
971
1009
  );
972
1010
  }
973
1011
 
@@ -1240,7 +1278,7 @@ class ZigbeeController extends EventEmitter {
1240
1278
 
1241
1279
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
1242
1280
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
1243
- const message = `convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`;
1281
+ const message = `convert ${key} with value ${safeJsonStringify(preparedValue)} and options ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`;
1244
1282
  if (has_elevated_debug) {
1245
1283
  this.emit('device_debug', { ID:debugID, data: { flag: '04', payload: {key:key, ep: stateDesc.epname, value:preparedValue, options:preparedOptions}, IO:false }, message:message});
1246
1284
  }
@@ -1288,7 +1326,8 @@ class ZigbeeController extends EventEmitter {
1288
1326
  try {
1289
1327
  const result = await converter.convertSet(target, key, preparedValue, meta);
1290
1328
  const message = `convert result ${safeJsonStringify(result)} for device ${deviceId}`;
1291
- this.emit('published', deviceId, model, stateModel, stateList, options, debugID, has_elevated_debug );
1329
+ if (isGroup)
1330
+ this.emit('published', deviceId, model, stateModel, stateList, options, debugID, has_elevated_debug );
1292
1331
  if (has_elevated_debug) {
1293
1332
  this.emit('device_debug', { ID:debugID, data: { flag: 'SUCCESS' , IO:false }, message:message});
1294
1333
  }
@@ -1309,7 +1348,7 @@ class ZigbeeController extends EventEmitter {
1309
1348
  }
1310
1349
  } catch (error) {
1311
1350
  if (has_elevated_debug) {
1312
- const message = `caught error ${safeJsonStringify(error)} when setting value for device ${deviceId}.`;
1351
+ const message = `caught error ${error && error.message ? error.message : 'no reason given'} when setting value for device ${deviceId}.`;
1313
1352
  this.emit('device_debug', { ID:debugID, data: { error: 'EXSET' , IO:false },message:message});
1314
1353
  }
1315
1354
  this.adapter.filterError(`Error ${error.code} on send command to ${deviceId}.` +
@@ -1348,7 +1387,7 @@ class ZigbeeController extends EventEmitter {
1348
1387
  // payload: The data to send to the device as JSON object (key/Value pairs)
1349
1388
  // endpoint: optional: the endpoint to send the data to, if supported.
1350
1389
  //
1351
- async publishPayload(payload, debugID) {
1390
+ async publishPayload(payload, debugID, has_elevated_debug) {
1352
1391
  let payloadObj = {};
1353
1392
  if (typeof payload === 'string') {
1354
1393
  try {
@@ -1410,7 +1449,7 @@ class ZigbeeController extends EventEmitter {
1410
1449
  }
1411
1450
  }
1412
1451
  try {
1413
- await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, debugID);
1452
+ await this.publishFromState(`0x${payload.device}`, payload.model, payload.stateModel, stateList, payload.options, debugID, has_elevated_debug);
1414
1453
  return {success: true};
1415
1454
  } catch (error) {
1416
1455
  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 +1469,9 @@ class ZigbeeController extends EventEmitter {
1430
1469
  if (this.debugActive) this.debug(`doDeviceQuery: resolveEntity for entity: ${deviceId} is ${safeJsonStringify(entity)}`);
1431
1470
  const mappedModel = entity ? entity.mapped : undefined;
1432
1471
  if (mappedModel) {
1472
+ const epmap = mappedModel.endpoint ? mappedModel.endpoint() : [];
1433
1473
  if (elevated) {
1434
- const message = `Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`;
1474
+ const message = `Device query for '${entity.device.ieeeAddr}' triggered`;
1435
1475
  this.emit('device_debug', { ID:debugID, data: { flag: 'qs' ,states:[{id:'device_query', value:true, payload:'device_query'}], IO:false }, message:message});
1436
1476
  }
1437
1477
  else
@@ -1440,24 +1480,32 @@ class ZigbeeController extends EventEmitter {
1440
1480
 
1441
1481
  for (const converter of mappedModel.toZigbee) {
1442
1482
  if (converter.hasOwnProperty('convertGet')) {
1443
- for (const ckey of converter.key) {
1483
+ const sources = [];
1484
+ if (converter.endpoints && epmap) {
1485
+ for (const epname of converter.endpoints) {
1486
+ const source = entity.device.endpoints.find((id) => id.ID == epmap[epname]);
1487
+ if (source) sources.push(source);
1488
+ }
1489
+ }
1490
+ if (sources.length == 0) sources.push(entity.device.endpoints[0]);
1491
+ for (const source of sources) {
1444
1492
  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`);
1493
+ await converter.convertGet(source, '', {device:entity.device});
1494
+ this.debug(`read for state${converter.key.length ? '' : 's'} '${converter.key.join(',')}' of '${entity.device.ieeeAddr}/${source.ID}' after device query`);
1447
1495
  } catch (error) {
1448
1496
  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'}`;
1497
+ 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
1498
  this.warn(`ELEVATED OE02.1 ${message}`);
1451
1499
  this.emit('device_debug', { ID:debugID, data: { error: 'NOTREAD' , IO:false }, message:message });
1452
1500
  }
1453
1501
  else
1454
- this.debug(`failed to read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
1502
+ this.debug(`failed to read for state${converter.key.length ? '' : 's'} '${converter.key.join(',')}' of '${source.ID}'after device query`);
1455
1503
  }
1456
1504
  }
1457
1505
  }
1458
1506
  }
1459
1507
  if (elevated) {
1460
- const message = `ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`;
1508
+ const message = `ELEVATED O07: Device query for '${entity.device.ieeeAddr}}' complete`;
1461
1509
  this.emit('device_debug', { ID:debugID, data: { flag: 'qe' , IO:false }, message:message});
1462
1510
  }
1463
1511
  else
@@ -1467,7 +1515,7 @@ class ZigbeeController extends EventEmitter {
1467
1515
 
1468
1516
  async deviceQuery(deviceId, debugID, elevated, callback) {
1469
1517
  if (this.deviceQueryActive.includes (deviceId)) {
1470
- this.warn(`Device query for ${deviceId} is still active.`);
1518
+ this.info(`Device query for ${deviceId} is still active.`);
1471
1519
  return;
1472
1520
  }
1473
1521
  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')
@@ -416,10 +413,11 @@ class Zigbee extends utils.Adapter {
416
413
  }
417
414
  this.zbController.configure(this.getZigbeeOptions(message.zigbeeOptions));
418
415
  response.status = await this.doConnect(true);
416
+ if (!response.status) response.error = { message: 'Unable to start the Zigbee Network. Please check the previous messages.'}
419
417
  this.sendTo(from, command, response, callback);
420
418
  }
421
419
  catch (error) {
422
- this.sendTo(from, command, { status:false }, callback);
420
+ this.sendTo(from, command, { status:false, error }, callback);
423
421
  }
424
422
  }
425
423
  else try {
@@ -427,7 +425,7 @@ class Zigbee extends utils.Adapter {
427
425
  //this.logToPairing('herdsman stopped !');
428
426
  this.sendTo(from, command, { status:true }, callback);
429
427
  } catch (error) {
430
- this.sendTo(from, command, { status:true }, callback);
428
+ this.sendTo(from, command, { status:true, error }, callback);
431
429
  }
432
430
  }
433
431
 
@@ -630,50 +628,43 @@ class Zigbee extends utils.Adapter {
630
628
 
631
629
  await this.setState('info.connection', true, true);
632
630
  this.stController.CleanupRequired(false);
631
+ const devicesFromObjects = (await this.getDevicesAsync()).filter(item => item.native.id.length ==16).map((item) => `0x${item.native.id}`);
633
632
  const devicesFromDB = this.zbController.getClientIterator(false);
634
633
  for (const device of devicesFromDB) {
635
634
  const entity = await this.zbController.resolveEntity(device);
636
635
  if (entity) {
637
636
  const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
637
+ const idx = devicesFromObjects.indexOf(device.ieeeAddr);
638
+ if (idx > -1) devicesFromObjects.splice(idx, 1);
638
639
  this.stController.updateDev(device.ieeeAddr.substr(2), model, model, () =>
639
640
  this.stController.syncDevStates(device, model));
640
641
  }
641
642
  else (this.log.warn('resolveEntity returned no entity'));
642
643
  }
644
+ for (const id of devicesFromObjects) {
645
+ try {
646
+ this.log.warn(`removing object for device ${id} - it is no longer in the zigbee database`);
647
+ await this.delObjectAsync(id.substring(2), { recursive:true })
648
+ }
649
+ catch {
650
+ this.log.warn(`error removing ${id}`)
651
+ }
652
+ }
643
653
  await this.callPluginMethod('start', [this.zbController, this.stController]);
644
654
  }
645
655
 
656
+
646
657
  async checkIfModelUpdate(entity) {
647
658
  const model = entity.mapped ? entity.mapped.model : entity.device.modelID;
648
659
  const device = entity.device;
649
660
  const devId = device.ieeeAddr.substr(2);
650
661
 
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
- });
662
+ const obj = await this.getObjectAsync(devId);
663
+ if (obj && obj.common.type !== model) {
664
+ await this.stController.deleteObj(devId);
665
+ await this.stController.updateDev(devId, model, model);
666
+ await this.stController.syncDevStates(device, model);
667
+ }
677
668
  }
678
669
 
679
670
  acknowledgeState(deviceId, model, stateDesc, value) {
@@ -754,17 +745,19 @@ class Zigbee extends utils.Adapter {
754
745
  async onUnload(callback) {
755
746
  try {
756
747
  this.log.info(`Halting zigbee adapter. Restart delay is at least ${this.ioPack.common.stopTimeout / 1000} seconds.`)
748
+ this.setState('info.connection', false, true);
749
+ const chain = [];
757
750
  if (this.config.debugHerdsman) {
758
751
  debug.disable();
759
752
  debug.log = originalLogMethod;
760
753
  }
761
-
762
- this.log.info('cleaning everything up...');
754
+ this.log.info('cleaning everything up');
763
755
  await this.callPluginMethod('stop');
764
- await this.stController.stop();
756
+ if (this.stController) chain.push(this.stController.stop());
765
757
  if (this.zbController) {
766
- await this.zbController.stop();
758
+ chain.push(this.zbController.stop());
767
759
  }
760
+ Promise.all(chain);
768
761
  this.log.info('cleanup successful');
769
762
  callback();
770
763
  } catch (error) {
@@ -776,8 +769,8 @@ class Zigbee extends utils.Adapter {
776
769
  }
777
770
  }
778
771
 
779
- getZigbeeOptions(_overrideOptions) {
780
- const override = (_overrideOptions ? _overrideOptions:{});
772
+ getZigbeeOptions(overrideOptions) {
773
+ const override = (overrideOptions ? overrideOptions:{});
781
774
  // file path for db
782
775
  const dbDir = this.expandFileName('');
783
776
 
@@ -823,7 +816,7 @@ class Zigbee extends utils.Adapter {
823
816
  dbPath: 'shepherd.db',
824
817
  backupPath: 'nvbackup.json',
825
818
  disableLed: this.config.disableLed,
826
- disablePing: this.config.disablePing,
819
+ disablePing: (this.config.pingCluster=='off'),
827
820
  transmitPower: this.config.transmitPower,
828
821
  disableBackup: this.config.disableBackup,
829
822
  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.4",
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.0",
41
41
  "chai": "^5.2.1",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "eslint": "^9.30.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"
package/lib/tools.js DELETED
@@ -1,55 +0,0 @@
1
- 'use strict';
2
-
3
- const axios = require('axios');
4
-
5
- /**
6
- * Tests whether the given variable is a real object and not an Array
7
- * @param {any} it The variable to test
8
- * @returns {it is Record<string, any>}
9
- */
10
- function isObject(it) {
11
- // This is necessary because:
12
- // typeof null === 'object'
13
- // typeof [] === 'object'
14
- // [] instanceof Object === true
15
- return Object.prototype.toString.call(it) === '[object Object]';
16
- }
17
-
18
- /**
19
- * Tests whether the given variable is really an Array
20
- * @param {any} it The variable to test
21
- * @returns {it is any[]}
22
- */
23
- function isArray(it) {
24
- if (Array.isArray != null)
25
- return Array.isArray(it);
26
- return Object.prototype.toString.call(it) === '[object Array]';
27
- }
28
-
29
- /**
30
- * Translates text using the Google Translate API
31
- * @param {string} text The text to translate
32
- * @param {string} targetLang The target languate
33
- * @returns {Promise<string>}
34
- */
35
- async function translateText(text, targetLang) {
36
- if (targetLang === 'en')
37
- return text;
38
- try {
39
- const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
40
- const response = await axios({url, timeout: 5000});
41
- if (isArray(response.data)) {
42
- // we got a valid response
43
- return response.data[0][0][0];
44
- }
45
- throw new Error('Invalid response for translate request');
46
- } catch (e) {
47
- throw new Error(`Could not translate to "${targetLang}": ${e}`);
48
- }
49
- }
50
-
51
- module.exports = {
52
- isArray,
53
- isObject,
54
- translateText
55
- };