iobroker.zigbee 2.0.0 → 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
  }
@@ -643,11 +713,11 @@ class Zigbee extends utils.Adapter {
643
713
  }
644
714
  try {
645
715
  const entity = await this.zbController.resolveEntity(deviceId);
646
-
647
- const mappedModel = (entity ? entity.mapped : undefined);
716
+ this.log.debug(`entity: ${deviceId} ${model} ${safeJsonStringify(entity)}`);
717
+ const mappedModel = entity ? entity.mapped : undefined;
648
718
 
649
719
  if (!mappedModel) {
650
- this.log.debug(`No mapped model for ${deviceId} (model ${model})`);
720
+ this.log.debug(`No mapped model for ${model}`);
651
721
  if (has_elevated_debug) this.log.error(`ELEVATED OE01: No mapped model ${deviceId} (model ${model})`)
652
722
  return;
653
723
  }
@@ -677,9 +747,17 @@ class Zigbee extends utils.Adapter {
677
747
  return;
678
748
  }
679
749
 
680
- if (stateDesc.isOption) {
750
+ if (stateDesc.isOption || stateDesc.compositeState) {
681
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
+
682
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
+ }
683
761
  // process sync state list
684
762
  //this.processSyncStatesList(deviceId, modelId, syncStateList);
685
763
  // if this is the device query state => trigger the device query
@@ -687,19 +765,20 @@ class Zigbee extends utils.Adapter {
687
765
  // on activation of the 'device_query' state trigger hardware query where possible
688
766
  if (stateDesc.id === 'device_query') {
689
767
  if (this.query_device_block.indexOf(deviceId) > -1) {
690
- this.log.info(`Device query for '${entity.device.ieeeAddr}' blocked`);
768
+ this.log.warn(`Device query for '${entity.device.ieeeAddr}' blocked`);
691
769
  return;
692
770
  }
693
771
  if (mappedModel) {
694
772
  this.query_device_block.push(deviceId);
695
773
  if (has_elevated_debug)
696
774
  this.log.warn(`ELEVATED O06: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' triggered`);
697
- let t;
775
+ else
776
+ this.log.debug(`Device query for '${entity.device.ieeeAddr}' started`);
698
777
  for (const converter of mappedModel.toZigbee) {
699
778
  if (converter.hasOwnProperty('convertGet')) {
700
779
  for (const ckey of converter.key) {
701
780
  try {
702
- await converter.convertGet(entity.device.endpoints[0], ckey, {endpoint_name:entity.device.endpoints[0].ID.toString()});
781
+ await converter.convertGet(entity.device.endpoints[0], ckey, {});
703
782
  } catch (error) {
704
783
  if (has_elevated_debug) {
705
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'}`);
@@ -713,8 +792,7 @@ class Zigbee extends utils.Adapter {
713
792
  if (has_elevated_debug)
714
793
  this.log.warn(`ELEVATED O07: Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`);
715
794
  else
716
- this.log.info(`Device query for '${entity.device.ieeeAddr}/${entity.device.endpoints[0].ID}' complete`);
717
-
795
+ this.log.info(`Device query for '${entity.device.ieeeAddr}' done`);
718
796
  const idToRemove = deviceId;
719
797
  setTimeout(() => {
720
798
  const idx = this.query_device_block.indexOf(idToRemove);
@@ -729,7 +807,7 @@ class Zigbee extends utils.Adapter {
729
807
  }
730
808
 
731
809
  let converter = undefined;
732
- let msgCnt = 1;
810
+ let msg_counter = 0;
733
811
  for (const c of mappedModel.toZigbee) {
734
812
 
735
813
  if (!c.hasOwnProperty('convertSet')) continue;
@@ -739,23 +817,30 @@ class Zigbee extends utils.Adapter {
739
817
  if (c.hasOwnProperty('convertSet') && converter === undefined)
740
818
  {
741
819
  converter = c;
742
- if (has_elevated_debug) {
743
- this.log.warn(`ELEVATED O4.${msgCnt++}: Setting converter to keyless converter for ${deviceId} of type ${model}`)
744
- }
745
- this.log.debug('setting converter to keyless converter')
820
+ if (has_elevated_debug)
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++;
746
825
  }
747
826
  else
748
827
  {
749
- if (has_elevated_debug) this.log.warn(`ELEVATED O4.${msgCnt++}: ignoring keyless converter for ${deviceId} of type ${model}`)
750
- 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++;
751
833
  }
752
834
  continue;
753
835
  }
754
836
  if (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id))
755
837
  {
756
- this.log.debug(`${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`)
757
- if (has_elevated_debug) this.log.warn(`ELEVATED O4.${msgCnt++}: ${(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)}}`)
758
842
  converter = c;
843
+ msg_counter++;
759
844
  }
760
845
  }
761
846
  if (converter === undefined) {
@@ -779,8 +864,10 @@ class Zigbee extends utils.Adapter {
779
864
 
780
865
  const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
781
866
  const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
782
- this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
783
- 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)}`);
784
871
 
785
872
  let target;
786
873
  if (model === 'group') {
@@ -819,8 +906,10 @@ class Zigbee extends utils.Adapter {
819
906
 
820
907
  try {
821
908
  const result = await converter.convertSet(target, key, preparedValue, meta);
822
- this.log.debug(`convert result ${safeJsonStringify(result)}`);
823
- if (has_elevated_debug) this.log.warn(`ELEVATED O05: convert result ${safeJsonStringify(result)} sent to 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)}`);
824
913
  if (result !== undefined) {
825
914
  if (stateModel && !isGroup) {
826
915
  this.acknowledgeState(deviceId, model, stateDesc, value);
@@ -840,7 +929,7 @@ class Zigbee extends utils.Adapter {
840
929
  }
841
930
  });
842
931
  } catch (err) {
843
- this.log.error(`No entity for ${deviceId} : ${err && err.message ? err.message : ''}`);
932
+ this.log.error(`No entity for ${deviceId} : ${err && err.message ? err.message : 'no error message'}`);
844
933
  }
845
934
  }
846
935
 
@@ -944,7 +1033,7 @@ class Zigbee extends utils.Adapter {
944
1033
  this.stController.updateDev(dev.ieeeAddr.substr(2), model, model, () =>
945
1034
  this.stController.syncDevStates(dev, model));
946
1035
  }
947
- // else this.log.warn(`Device ${safeJsonStringify(entity)} rejoined, no new device`);
1036
+ else this.log.debug(`Device ${safeJsonStringify(entity)} rejoined, no new device`);
948
1037
  });
949
1038
  }
950
1039
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -22,14 +22,14 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@iobroker/adapter-core": "^3.2.2",
25
- "@iobroker/dm-utils": "^1.0.9",
25
+ "@iobroker/dm-utils": "^0.5.0",
26
26
  "humanize-duration": "^3.32.1",
27
27
  "tar": "^7.4.3",
28
28
  "ajv": "^8.17.1",
29
29
  "uri-js": "^4.4.1",
30
- "typescript": "^5.7.3",
31
- "zigbee-herdsman": "2.1.9",
32
- "zigbee-herdsman-converters": "20.58.0"
30
+ "typescript": "^5.6.3",
31
+ "zigbee-herdsman": "3.2.5",
32
+ "zigbee-herdsman-converters": "21.38.0"
33
33
  },
34
34
  "description": "Zigbee devices",
35
35
  "devDependencies": {
@@ -47,7 +47,7 @@
47
47
  "gulp-jsdoc3": "^3.0.0",
48
48
  "gulp-replace": "^1.1.4",
49
49
  "mixin-deep": "^2.0.1",
50
- "mocha": "^11.1.0"
50
+ "mocha": "^10.8.2"
51
51
  },
52
52
  "homepage": "https://github.com/ioBroker/ioBroker.zigbee",
53
53
  "keywords": [
@@ -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
  }