iobroker.zigbee 1.10.14 → 2.0.1

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.
package/main.js CHANGED
@@ -31,6 +31,8 @@ const ZigbeeController = require('./lib/zigbeecontroller');
31
31
  const StatesController = require('./lib/statescontroller');
32
32
  const ExcludePlugin = require('./lib/exclude');
33
33
  const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
34
+ const zigbeeHerdsmanConvertersPackage = require('zigbee-herdsman-converters/package.json')
35
+ const zigbeeHerdsmanPackage = require('zigbee-herdsman/package.json')
34
36
  const vm = require('vm');
35
37
  const util = require('util');
36
38
  const dmZigbee = require('./lib/devicemgmt.js');
@@ -68,6 +70,7 @@ class Zigbee extends utils.Adapter {
68
70
  this.on('ready', () => this.onReady());
69
71
  this.on('unload', callback => this.onUnload(callback));
70
72
  this.on('message', obj => this.onMessage(obj));
73
+ this.uploadRequired = false;
71
74
 
72
75
  this.query_device_block = [];
73
76
 
@@ -193,9 +196,8 @@ class Zigbee extends utils.Adapter {
193
196
 
194
197
  // external converters
195
198
  this.applyExternalConverters();
196
- // get exclude list from object
197
- this.getState('exclude.all', (err, state) =>
198
- this.stController.getExcludeExposes(state));
199
+ // get devices from exposes
200
+ this.stController.getExposes();
199
201
 
200
202
  this.subscribeStates('*');
201
203
  // set connection false before connect to zigbee
@@ -218,6 +220,62 @@ class Zigbee extends utils.Adapter {
218
220
  this.doConnect();
219
221
  }
220
222
 
223
+ sandboxAdd(sandbox, item, module) {
224
+ const multipleItems = item.split(',');
225
+ if (multipleItems.length > 1) {
226
+ for(const singleItem of multipleItems) {
227
+ this.log.warn(`trying to add "${singleItem.trim()} = require(${module})[${singleItem.trim()}]" to sandbox`)
228
+ sandbox[singleItem.trim()] = require(module)[singleItem.trim()];
229
+ }
230
+ }
231
+ else {
232
+ this.log.warn(`trying to add "${item} = require(${module})" to sandbox`)
233
+ sandbox[item] = require(module);
234
+ }
235
+ }
236
+
237
+ SandboxRequire(sandbox, items) {
238
+ if (!items) return true;
239
+ let converterLoaded = true;
240
+ for (const item of items) {
241
+ const modulePath = item[2].replace(/['"]/gm, '');
242
+
243
+ let zhcm1 = modulePath.match(/^zigbee-herdsman-converters\//);
244
+ if (zhcm1) {
245
+ const i2 = modulePath.replace(/^zigbee-herdsman-converters\//, `../zigbee-herdsman-converters/`);
246
+ try {
247
+ this.sandboxAdd(sandbox, item[1], i2);
248
+ }
249
+ catch (error) {
250
+ this.log.error(`Sandbox error: ${(error && error.message ? error.message : 'no error message given')}`);
251
+ }
252
+ continue;
253
+ }
254
+ zhcm1 = modulePath.match(/^..\//);
255
+ if (zhcm1) {
256
+ const i2 = modulePath.replace(/^..\//, `../zigbee-herdsman-converters/`);
257
+ try {
258
+ this.sandboxAdd(sandbox, item[1], i2);
259
+ }
260
+ catch (error) {
261
+ this.log.error(`Sandbox error: ${(error && error.message ? error.message : 'no error message given')}`);
262
+ converterLoaded = false;
263
+ }
264
+ continue;
265
+ }
266
+ try {
267
+ this.sandboxAdd(sandbox, item[1], modulePath);
268
+ }
269
+ catch (error) {
270
+ this.log.error(`Sandbox error: ${(error && error.message ? error.message : 'no error message given')}`);
271
+ converterLoaded = false;
272
+ }
273
+
274
+ }
275
+ return converterLoaded;
276
+ }
277
+
278
+
221
279
  * getExternalDefinition() {
222
280
  if (this.config.external === undefined) {
223
281
  return;
@@ -236,34 +294,40 @@ class Zigbee extends utils.Adapter {
236
294
  else {
237
295
  const converterCode = fs.readFileSync(mN, {encoding: 'utf8'}).toString();
238
296
  let converterLoaded = true;
239
- if (converterCode.match(/..\/lib\/legacy/gm)) {
240
- this.log.warn(`External converter ${mN} contains an unsupported reference to '/lib/legacy' - external converter not loaded.`);
241
- converterLoaded = false;
242
- }
243
- else
244
- {
245
- // remove the require statements and attempt to place them in the sandbox
246
- const requiredLibraries = converterCode.matchAll(/(\w+) += +require\(['"](\S+)['"]\);/gm);
247
- for (const line of requiredLibraries) {
248
- const movedLine = line[2].replace('..', '../zigbee-herdsman-converters');
249
- try {
250
- sandbox[line[1]] = require(movedLine);
251
- }
252
- catch (e) {
253
- this.log.warn(`error adding ${line[1]} (${movedLine}) to the sandbox: ${e}`);
254
- converterLoaded = false;
255
- }
256
- }
257
- }
297
+ let modifiedCode = converterCode.replace(/\s+\/\/.+/gm, ''); // remove all lines starting with // (with the exception of the first.)
298
+ //fs.writeFileSync(mN+'.tmp1', modifiedCode)
299
+ modifiedCode = modifiedCode.replace(/^\/\/.+/gm, ''); // remove the fist line if it starts with //
300
+ //fs.writeFileSync(mN+'.tmp2', modifiedCode)
301
+
302
+ converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+\*\s+as\s+(\S+)\s+from\s+(\S+);/gm)]);
303
+ modifiedCode = modifiedCode.replace(/import\s+\*\s+as\s+\S+\s+from\s+\S+;/gm, '')
304
+ //fs.writeFileSync(mN+'.tmp3', modifiedCode)
305
+ converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/import\s+\{(.+)\}\s+from\s+(\S+);/gm)]);
306
+ modifiedCode = modifiedCode.replace(/import\s+\{.+\}\s+from\s+\S+;/gm, '');
307
+ //fs.writeFileSync(mN+'.tmp4', modifiedCode)
308
+ converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/const\s+\{(.+)\}\s+=\s+require\((.+)\)/gm)]);
309
+ modifiedCode = modifiedCode.replace(/const\s+\{.+\}\s+=\s+require\(.+\)/gm, '');
310
+ //fs.writeFileSync(mN+'.tmp5', modifiedCode)
311
+ converterLoaded &= this.SandboxRequire(sandbox,[...modifiedCode.matchAll(/const\s+(\S+)\s+=\s+require\((.+)\)/gm)]);
312
+ modifiedCode = modifiedCode.replace(/const\s+\S+\s+=\s+require\(.+\)/gm, '');
313
+ //fs.writeFileSync(mN+'.tmp6', modifiedCode)
314
+
315
+ //fs.writeFileSync(mN+'.tmp', modifiedCode)
316
+
258
317
  if (converterLoaded) {
259
- this.log.info(`Apply converter from module: ${mN}`);
260
- //this.log.warn(converterCode.replace(/const (\w+) += +require\(['"](\S+)['"]\);/gm, ''));
261
318
  try {
262
- vm.runInNewContext(converterCode.replace(/const (\w+) += +require\(['"](\S+)['"]\);/gm, ''), sandbox);
319
+ this.log.warn('Trying to run sandbox for ' + mN);
320
+ vm.runInNewContext(modifiedCode, sandbox);
263
321
  const converter = sandbox.module.exports;
264
322
 
265
- if (Array.isArray(converter)) for (const item of converter) yield item;
266
- else yield converter;
323
+ if (Array.isArray(converter)) for (const item of converter) {
324
+ this.log.info('Model ' + item.model + ' defined in external converter ' + mN);
325
+ yield item;
326
+ }
327
+ else {
328
+ this.log.info('Model ' + converter.model + ' defined in external converter ' + mN);
329
+ yield converter;
330
+ }
267
331
  }
268
332
  catch (e) {
269
333
  this.log.error(`Unable to apply converter from module: ${mN} - the code does not run: ${e}`);
@@ -310,7 +374,7 @@ class Zigbee extends utils.Adapter {
310
374
  } else {
311
375
  gitVers = obj.common.installedFrom;
312
376
  }
313
- this.log.info(`Installed Version: ${gitVers}`);
377
+ this.log.info(`Installed Version: ${gitVers} (Converters ${zigbeeHerdsmanConvertersPackage.version} Herdsman ${zigbeeHerdsmanPackage.version})`);
314
378
  });
315
379
 
316
380
  await this.zbController.start();
@@ -330,6 +394,11 @@ class Zigbee extends utils.Adapter {
330
394
  }
331
395
  }
332
396
 
397
+ UploadRequired(status) {
398
+ this.uploadRequired = (typeof status === 'boolean' ? status : this.uploadRequired) ;
399
+ return status;
400
+ }
401
+
333
402
  async onZigbeeAdapterDisconnected() {
334
403
  this.reconnectCounter = 5;
335
404
  this.log.error('Adapter disconnected, stopping');
@@ -410,9 +479,10 @@ class Zigbee extends utils.Adapter {
410
479
  }
411
480
  }
412
481
 
413
- this.setState('info.connection', true, true);
482
+ await this.setState('info.connection', true, true);
414
483
 
415
- const devicesFromDB = await this.zbController.getClients(false);
484
+ const devicesFromDB = this.zbController.getClientIterator(false);
485
+ this.stController.CleanupRequired(false);
416
486
  for (const device of devicesFromDB) {
417
487
  const entity = await this.zbController.resolveEntity(device);
418
488
  if (entity) {
@@ -477,7 +547,7 @@ class Zigbee extends utils.Adapter {
477
547
  shortMessage.device = device.ieeeAddr;
478
548
  shortMessage.meta = undefined;
479
549
  shortMessage.endpoint = (message.endpoint.ID ? message.endpoint.ID: -1);
480
- this.log.warn(`ELEVATED I0: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`);
550
+ this.log.warn(`ELEVATED I00: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`);
481
551
  }
482
552
  // this assigment give possibility to use iobroker logger in code of the converters, via meta.logger
483
553
  meta.logger = this.log;
@@ -561,7 +631,7 @@ class Zigbee extends utils.Adapter {
561
631
  if (type !== 'readResponse') {
562
632
  this.log.debug(`No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
563
633
  if (has_elevated_debug)
564
- this.log.warn(`ELEVATED IE0: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
634
+ this.log.warn(`ELEVATED IE00: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`);
565
635
  }
566
636
  return;
567
637
  }
@@ -629,21 +699,26 @@ class Zigbee extends utils.Adapter {
629
699
  let isGroup = false;
630
700
  const has_elevated_debug = this.stController.checkDebugDevice(deviceId)
631
701
 
632
- this.log.debug(`publishFromState : ${deviceId} ${model} ${safeJsonStringify(stateList)}`);
702
+ if (has_elevated_debug)
703
+ {
704
+ const stateNames = [];
705
+ stateList.forEach( state => stateNames.push(state.id));
706
+ this.log.warn(`ELEVATED O03: Publishing to ${deviceId} of model ${model} ${stateNames.join(', ')}`);
707
+ }
708
+ else
709
+ this.log.debug(`publishFromState : ${deviceId} ${model} ${safeJsonStringify(stateList)}`);
633
710
  if (model === 'group') {
634
711
  isGroup = true;
635
712
  deviceId = parseInt(deviceId);
636
713
  }
637
714
  try {
638
715
  const entity = await this.zbController.resolveEntity(deviceId);
639
-
640
716
  this.log.debug(`entity: ${deviceId} ${model} ${safeJsonStringify(entity)}`);
641
-
642
- const mappedModel = entity.mapped;
717
+ const mappedModel = entity ? entity.mapped : undefined;
643
718
 
644
719
  if (!mappedModel) {
645
720
  this.log.debug(`No mapped model for ${model}`);
646
- if (has_elevated_debug) this.log.warn(`ELEVATED O2: No mapped model for ${model}`)
721
+ if (has_elevated_debug) this.log.error(`ELEVATED OE01: No mapped model ${deviceId} (model ${model})`)
647
722
  return;
648
723
  }
649
724
 
@@ -672,9 +747,17 @@ class Zigbee extends utils.Adapter {
672
747
  return;
673
748
  }
674
749
 
675
- if (stateDesc.isOption) {
750
+ if (stateDesc.isOption || stateDesc.compositeState) {
676
751
  // acknowledge state with given value
752
+ if (has_elevated_debug)
753
+ this.log.warn('ELEVATED OC: changed state: ' + JSON.stringify(changedState));
754
+ else
755
+ this.log.debug('changed composite state: ' + JSON.stringify(changedState));
756
+
677
757
  this.acknowledgeState(deviceId, model, stateDesc, value);
758
+ if (stateDesc.compositeState && stateDesc.compositeTimeout) {
759
+ this.stController.triggerComposite(deviceId, model, stateDesc, changedState.source.includes('.admin.'));
760
+ }
678
761
  // process sync state list
679
762
  //this.processSyncStatesList(deviceId, modelId, syncStateList);
680
763
  // if this is the device query state => trigger the device query
@@ -687,20 +770,29 @@ class Zigbee extends utils.Adapter {
687
770
  }
688
771
  if (mappedModel) {
689
772
  this.query_device_block.push(deviceId);
690
- this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
773
+ if (has_elevated_debug)
774
+ this.log.warn(`ELEVATED O06: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`);
775
+ else
776
+ this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
691
777
  for (const converter of mappedModel.toZigbee) {
692
778
  if (converter.hasOwnProperty('convertGet')) {
693
779
  for (const ckey of converter.key) {
694
780
  try {
695
781
  await converter.convertGet(entity.device.endpoints[0], ckey, {});
696
782
  } catch (error) {
697
- this.log.warn(`Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}' after query with '${JSON.stringify(error)}'`);
698
-
783
+ if (has_elevated_debug) {
784
+ this.log.warn(`ELEVATED OE02.1 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'}`);
785
+ }
786
+ else
787
+ this.log.info(`failed to read state ${JSON.stringify(ckey)} of ${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID} after device query`);
699
788
  }
700
789
  }
701
790
  }
702
791
  }
703
- this.log.debug(`Device query for '${entity.device.ieeeAddr}' done`);
792
+ if (has_elevated_debug)
793
+ this.log.warn(`ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`);
794
+ else
795
+ this.log.info(`Device query for '${entity.device.ieeeAddr}' done`);
704
796
  const idToRemove = deviceId;
705
797
  setTimeout(() => {
706
798
  const idx = this.query_device_block.indexOf(idToRemove);
@@ -715,6 +807,7 @@ class Zigbee extends utils.Adapter {
715
807
  }
716
808
 
717
809
  let converter = undefined;
810
+ let msg_counter = 0;
718
811
  for (const c of mappedModel.toZigbee) {
719
812
 
720
813
  if (!c.hasOwnProperty('convertSet')) continue;
@@ -725,21 +818,29 @@ class Zigbee extends utils.Adapter {
725
818
  {
726
819
  converter = c;
727
820
  if (has_elevated_debug)
728
- this.log.warn(`ELEVATED O3A: Setting converter to keyless converter for ${deviceId} of type ${model}`)
729
- this.log.debug('setting converter to keyless converter')
821
+ this.log.warn(`ELEVATED O04.${msg_counter}: Setting converter to keyless converter for ${deviceId} of type ${model}`)
822
+ else
823
+ this.log.debug(`Setting converter to keyless converter for ${deviceId} of type ${model}`)
824
+ msg_counter++;
730
825
  }
731
826
  else
732
827
  {
733
- if (has_elevated_debug) this.log.warn(`ELEVATED O3B: ignoring keyless converter for ${deviceId} of type ${model}`)
734
- this.log.debug('ignoring keyless converter')
828
+ if (has_elevated_debug)
829
+ this.log.warn(`ELEVATED O04.${msg_counter}: ignoring keyless converter for ${deviceId} of type ${model}`)
830
+ else
831
+ this.log.debug(`ignoring keyless converter for ${deviceId} of type ${model}`)
832
+ msg_counter++;
735
833
  }
736
834
  continue;
737
835
  }
738
836
  if (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id))
739
837
  {
740
- this.log.debug(`${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
741
- if (has_elevated_debug) this.log.warn(`ELEVATED O3C: ${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
838
+ if (has_elevated_debug)
839
+ this.log.warn(`ELEVATED O04.${msg_counter}: ${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
840
+ else
841
+ this.log.debug(`${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
742
842
  converter = c;
843
+ msg_counter++;
743
844
  }
744
845
  }
745
846
  if (converter === undefined) {
@@ -763,8 +864,10 @@ class Zigbee extends utils.Adapter {
763
864
 
764
865
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
765
866
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
766
- this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
767
- if (has_elevated_debug) this.log.warn(`ELEVATED O4: convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`);
867
+ if (has_elevated_debug)
868
+ this.log.warn(`ELEVATED O04: convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)} for device ${deviceId} with Endpoint ${epName}`);
869
+ else
870
+ this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
768
871
 
769
872
  let target;
770
873
  if (model === 'group') {
@@ -803,8 +906,10 @@ class Zigbee extends utils.Adapter {
803
906
 
804
907
  try {
805
908
  const result = await converter.convertSet(target, key, preparedValue, meta);
806
- this.log.debug(`convert result ${safeJsonStringify(result)}`);
807
- if (has_elevated_debug) this.log.warn(`ELEVATED O5: convert result ${safeJsonStringify(result)} for device ${deviceId}`);
909
+ if (has_elevated_debug)
910
+ this.log.warn(`ELEVATED O05: convert result ${safeJsonStringify(result)} for device ${deviceId}`);
911
+ else
912
+ this.log.debug(`convert result ${safeJsonStringify(result)}`);
808
913
  if (result !== undefined) {
809
914
  if (stateModel && !isGroup) {
810
915
  this.acknowledgeState(deviceId, model, stateDesc, value);
@@ -824,7 +929,7 @@ class Zigbee extends utils.Adapter {
824
929
  }
825
930
  });
826
931
  } catch (err) {
827
- this.log.error(`No entity for ${deviceId}`);
932
+ this.log.error(`No entity for ${deviceId} : ${err && err.message ? err.message : 'no error message'}`);
828
933
  }
829
934
  }
830
935
 
@@ -928,7 +1033,7 @@ class Zigbee extends utils.Adapter {
928
1033
  this.stController.updateDev(dev.ieeeAddr.substr(2), model, model, () =>
929
1034
  this.stController.syncDevStates(dev, model));
930
1035
  }
931
- // else this.log.warn(`Device ${safeJsonStringify(entity)} rejoined, no new device`);
1036
+ else this.log.debug(`Device ${safeJsonStringify(entity)} rejoined, no new device`);
932
1037
  });
933
1038
  }
934
1039
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "1.10.14",
3
+ "version": "2.0.1",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -28,8 +28,8 @@
28
28
  "ajv": "^8.17.1",
29
29
  "uri-js": "^4.4.1",
30
30
  "typescript": "^5.6.3",
31
- "zigbee-herdsman": "2.1.9",
32
- "zigbee-herdsman-converters": "20.58.0"
31
+ "zigbee-herdsman": "3.2.5",
32
+ "zigbee-herdsman-converters": "21.38.0"
33
33
  },
34
34
  "description": "Zigbee devices",
35
35
  "devDependencies": {
@@ -40,7 +40,7 @@
40
40
  "@iobroker/testing": "^5.0.0",
41
41
  "chai": "^5.1.2",
42
42
  "chai-as-promised": "^7.1.1",
43
- "eslint": "^9.17.0",
43
+ "eslint": "^9.19.0",
44
44
  "eslint-config-prettier": "^9.1.0",
45
45
  "eslint-plugin-prettier": "^5.2.1",
46
46
  "gulp": "^4.0.2",
@@ -91,6 +91,7 @@
91
91
  "release": "release-script",
92
92
  "release-patch": "release-script patch --yes --no-update-lockfile",
93
93
  "release-minor": "release-script minor --yes --no-update-lockfile",
94
- "release-major": "release-script major --yes --no-update-lockfile"
94
+ "release-major": "release-script major --yes --no-update-lockfile",
95
+ "dev-server": "dev-server"
95
96
  }
96
97
  }