iobroker.zigbee 2.0.4 → 3.0.0

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.
Files changed (48) hide show
  1. package/README.md +90 -57
  2. package/admin/admin.js +497 -120
  3. package/admin/img/philips_hue_lom001.png +0 -0
  4. package/admin/index_m.html +168 -124
  5. package/admin/tab_m.html +20 -11
  6. package/docs/de/img/Bild30.png +0 -0
  7. package/docs/de/img/Bild38.png +0 -0
  8. package/docs/de/img/Info.png +0 -0
  9. package/docs/de/img/Zigbee_config_de.jpg +0 -0
  10. package/docs/de/img/battery.png +0 -0
  11. package/docs/de/img/debug.png +0 -0
  12. package/docs/de/img/delete.png +0 -0
  13. package/docs/de/img/disconnected.png +0 -0
  14. package/docs/de/img/edit_grp.png +0 -0
  15. package/docs/de/img/edit_image.png +0 -0
  16. package/docs/de/img/grp_nok.png +0 -0
  17. package/docs/de/img/grp_ok.png +0 -0
  18. package/docs/de/img/on_off.png +0 -0
  19. package/docs/de/img/reconfigure.png +0 -0
  20. package/docs/de/readme.md +52 -43
  21. package/docs/en/img/Zigbee_config_en.png +0 -0
  22. package/docs/en/img/Zigbee_pairing_en.png +0 -0
  23. package/docs/en/readme.md +71 -66
  24. package/docs/tutorial/groups-1.png +0 -0
  25. package/docs/tutorial/groups-2.png +0 -0
  26. package/docs/tutorial/tab-dev-1.png +0 -0
  27. package/io-package.json +31 -65
  28. package/lib/DeviceDebug.js +5 -2
  29. package/lib/commands.js +182 -31
  30. package/lib/developer.js +0 -0
  31. package/lib/devices.js +2 -2
  32. package/lib/exposes.js +10 -27
  33. package/lib/groups.js +6 -8
  34. package/lib/localConfig.js +4 -5
  35. package/lib/ota.js +6 -6
  36. package/lib/seriallist.js +9 -2
  37. package/lib/statescontroller.js +397 -128
  38. package/lib/utils.js +41 -11
  39. package/lib/zbDeviceAvailability.js +2 -2
  40. package/lib/zbDeviceConfigure.js +99 -58
  41. package/lib/zigbeecontroller.js +152 -128
  42. package/main.js +251 -264
  43. package/package.json +10 -10
  44. package/docs/en/img/Bild23.png +0 -0
  45. package/docs/en/img/Bild25.png +0 -0
  46. package/docs/en/img/Bild26.png +0 -0
  47. package/docs/en/img/Bild4.png +0 -0
  48. package/docs/en/img/Bild9.png +0 -0
@@ -6,6 +6,7 @@ class DeviceDebug extends EventEmitter {
6
6
  this.adapter = adapter;
7
7
  this.dataByID = { };
8
8
  this.dataByDevice = { };
9
+ this.logStatus = true;
9
10
 
10
11
  }
11
12
 
@@ -65,14 +66,16 @@ class DeviceDebug extends EventEmitter {
65
66
  target.push(item);
66
67
  this.dataByDevice[item.deviceID] = DevData;
67
68
  }
68
- if (message.hasOwnProperty('message')) {
69
+ if (message.hasOwnProperty('message') && this.logStatus) {
69
70
  this.warn(`ELEVATED:${flag} (${dataId.toString(16).slice(-4)}) ${message.message}`)
70
71
  }
71
72
  }
72
73
  }
73
74
  }
74
75
 
75
- collectDebugData() {
76
+ collectDebugData(logStatus) {
77
+ if (logStatus != undefined)
78
+ this.logStatus = logStatus;
76
79
  return this.dataByDevice;
77
80
  }
78
81
  }
package/lib/commands.js CHANGED
@@ -1,12 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  const getZbId = require('./utils').getZbId;
4
+ const getNetAddress = require('./utils').getNetAddress;
5
+ const reverseByteString = require('./utils').reverseByteString;
4
6
  const fs = require('fs');
5
- const pathLib = require('path');
6
7
  const statesMapping = require('./devices');
7
8
  const utils = require('@iobroker/adapter-core'); // Get common adapter utils
8
9
  const colors = require('./colors.js');
9
- const { exec } = require('child_process');
10
+ const dns = require('dns');
11
+ const net = require('net');
12
+ const { access, constants } =require('fs');
10
13
 
11
14
  const disallowedDashStates = [
12
15
  'link_quality', 'available', 'battery', 'groups', 'device_query',
@@ -50,13 +53,14 @@ class Commands {
50
53
  * @param {ioBroker.Message} obj
51
54
  */
52
55
  onMessage(obj) {
53
- if (obj) {
54
- if (typeof obj === 'object' && obj.command) {
56
+ if (typeof obj === 'object' && obj.command) {
57
+ if (obj) {
55
58
  switch (obj.command) {
56
- case 'reset':
57
- if (obj.message && obj.message.mode == 'delNvbackup') {
58
- this.delNvBackup(obj.from, obj.command, obj.message, obj.callback);
59
- }
59
+ case 'testConnect':
60
+ this.adapter.testConnect(obj.from, obj.command, obj.message, obj.callback);
61
+ break;
62
+ case 'deleteNVBackup':
63
+ this.delNvBackup(obj.from, obj.command, {}, obj.callback);
60
64
  break;
61
65
  case 'letsPairing':
62
66
  if (obj.message && typeof obj.message === 'object') {
@@ -89,7 +93,7 @@ class Commands {
89
93
  }
90
94
  break;
91
95
  case 'getCoordinatorInfo':
92
- if (obj && obj.message && typeof obj.message === 'object') {
96
+ if (obj.message && typeof obj.message === 'object') {
93
97
  this.getCoordinatorInfo(obj.from, obj.command, obj.callback);
94
98
  }
95
99
  break;
@@ -151,21 +155,81 @@ class Commands {
151
155
  }
152
156
  break;
153
157
  case 'getDeviceCleanupRequired':
154
- if (obj) {
155
- this.adapter.sendTo(obj.from, obj.command, {clean:this.stController.CleanupRequired(), errors:this.stController.getStashedErrors()}, obj.callback);
156
- }
158
+ if (this.stController) this.adapter.sendTo(obj.from, obj.command, {clean:this.stController.CleanupRequired(), errors:this.stController.getStashedErrors()}, obj.callback);
159
+ // NO Break - returning the debug-data as well is intentional
160
+ case 'getDebugMessages':
161
+ this.adapter.sendTo(obj.from, obj.command, {byId:this.adapter.deviceDebug.collectDebugData( obj.message.inlog)},obj.callback);
162
+ break;
163
+ case 'testConnection':
164
+ this.testConnection(obj.from, obj.command, obj.message, obj.callback);
165
+ break;
166
+ case 'readNVRam':
167
+ this.readNvBackup(obj.from, obj.command, obj.message, obj.callback);
168
+ default:
169
+ //this.warn(`Commands: Command ${obj.command} is unknown`);
170
+ //this.adapter.sendTo(obj.from, obj.command, obj.message, obj.callback);
171
+ break;
157
172
  }
158
173
  }
159
174
  }
160
175
  }
161
176
 
162
- delNvBackup(from, command, msg, callback) {
177
+ async readNvBackup(from, command, msg, callback) {
178
+ this.warn('readNvBackup called')
179
+ try {
180
+ const zo = this.adapter.getZigbeeOptions();
181
+ const name = require('path').join(zo.dbDir, zo.backupPath);
182
+ const nvbackup = fs.readFileSync(name, {encoding: 'utf8'}).toString();
183
+ const nvBackupJson = JSON.parse(nvbackup);
184
+ const rv = {};
185
+ rv.channel = nvBackupJson.channel;
186
+ rv.precfgkey = (nvBackupJson.network_key ? nvBackupJson.network_key.key : undefined);
187
+ rv.extPanID = nvBackupJson.extended_pan_id ? reverseByteString(nvBackupJson.extended_pan_id) : undefined;
188
+ rv.panID = parseInt('0x'+nvBackupJson.pan_id);
189
+ this.warn('readNvBackup returns ' + JSON.stringify(rv))
190
+ this.adapter.sendTo(from, command, rv, callback)
191
+ }
192
+ catch (error) {
193
+ const msg = `Unable to read nvBackup ${error && error.message ? error.message : 'no message given'}`;
194
+ this.error(msg);
195
+ this.adapter.sendTo(from, command, {error:msg}, callback)
196
+ }
197
+ }
198
+
199
+ async delNvBackup(from, command, msg, callback) {
163
200
  try {
164
- if (this.zbController) {
201
+ if (this.zbController)
202
+ {
203
+ // stop the herdsman if needed
204
+ const wasRunning = this.zbController.herdsmanStarted;
205
+ if (wasRunning) await this.zbController.stop();
165
206
  const name = this.zbController.herdsman.adapter.backupPath;
166
- require('fs').unlinkSync(name);
207
+ fs.unlink(name, async (err) => {
208
+ const rv={};
209
+ if (err) {
210
+ this.error(`Unable to remove ${name}: ${err}`);
211
+ rv.error = `Unable to remove ${name}: ${err}`;
212
+ }
213
+ // start the herdsman again if it was stopped before
214
+ if (wasRunning) await this.zbController.start();
215
+ this.adapter.sendTo(from, command, rv, callback)
216
+ });
217
+ }
218
+ else {
219
+ const zo = this.adapter.getZigbeeOptions();
220
+ const name = require('path').join(zo.dbDir, zo.backupPath);
221
+ fs.unlink(name, async (err) => {
222
+ const rv={};
223
+ if (err) {
224
+ this.error(`Unable to remove ${name}: ${err}`);
225
+ rv.error = `Unable to remove ${name}: ${err}`;
226
+ }
227
+ // start the herdsman again if it was stopped before
228
+ this.adapter.sendTo(from, command, rv, callback)
229
+ });
167
230
  }
168
231
  } catch (error) {
232
+ this.adapter.sendTo(from, command, {error: error.message}, callback)
169
233
  this.error(error);
170
234
  }
171
235
  }
@@ -227,7 +291,7 @@ class Commands {
227
291
  }
228
292
 
229
293
  touchlinkReset(from, command, message, callback) {
230
- if (this.zbController) {
294
+ if (this.zbController && this.zbController.herdsmanStarted) {
231
295
  // allow devices to join the network within 60 secs
232
296
  this.adapter.logToPairing('Touchlink reset started ', true);
233
297
 
@@ -241,14 +305,14 @@ class Commands {
241
305
  } else {
242
306
  this.adapter.sendTo(
243
307
  from, command,
244
- {error: 'You need to setup serial port and start the adapter before pairing!'},
308
+ {error: 'No active connection to Zigbee Hardware!'},
245
309
  callback
246
310
  );
247
311
  }
248
312
  }
249
313
 
250
314
  async getDevices(from, command, id, callback) {
251
- if (this.zbController) {
315
+ if (this.zbController && this.zbController.herdsmanStarted) {
252
316
  this.debug(`getDevices called from ${from} with command ${JSON.stringify(command)} and id ${JSON.stringify(id)}`);
253
317
  const pairedDevices = await this.zbController.getClients(true);
254
318
  const groups = {};
@@ -352,6 +416,18 @@ class Commands {
352
416
 
353
417
  const id = getZbId(devInfo._id);
354
418
  devInfo.info = await this.zbController.resolveEntity(id);
419
+ // check configuration
420
+ try {
421
+ if (devInfo.info) {
422
+ const result = await this.zbController.callExtensionMethod(
423
+ 'shouldConfigure',
424
+ [devInfo.info.device, devInfo.info.mapped],
425
+ );
426
+ if (result.length > 0) devInfo.isConfigured = !result[0];
427
+ }
428
+ } catch (error) {
429
+ this.warn('error calling shouldConfigure: ' + error && error.message ? error.message : 'no error message');
430
+ }
355
431
 
356
432
  devInfo.rooms = [];
357
433
  for (const room in rooms) {
@@ -405,18 +481,27 @@ class Commands {
405
481
  return devices;
406
482
  })
407
483
  .then(devices => {
408
- this.debug(`getDevices result: ${JSON.stringify(devices)}`);
409
- this.adapter.sendTo(from, command, devices, callback);
484
+ this.debug(`getDevices contains ${devices.length} Devices`);
485
+ const rv = { devices:devices, inLog:this.adapter.deviceDebug.logStatus, byId:this.adapter.deviceDebug.collectDebugData() }
486
+ if (this.stController) {
487
+ rv.clean = this.stController.CleanupRequired();
488
+ rv.errors = this.stController.getStashedErrors();
489
+ rv.debugDevices = this.stController.debugDevices;
490
+ }
491
+ this.adapter.sendTo(from, command, rv, callback);
410
492
  })
411
- .catch(err => this.error(`getDevices error: ${err.stack}`));
493
+ .catch(err => {
494
+ this.error(`getDevices error: ${err.stack}`);
495
+ this.adapter.sendTo(from, command, {error: `Error enumerating devices : ${err && err.message ? err.message : ''}`}, callback);
496
+ });
412
497
  } else {
413
- this.adapter.sendTo(from, command, {error: 'You need save and run adapter before pairing!'}, callback);
498
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
414
499
  }
415
500
  }
416
501
 
417
502
 
418
503
  async getCoordinatorInfo(from, command, callback) {
419
- if (this.zbController) {
504
+ if (this.zbController && this.zbController.herdsmanStarted) {
420
505
  const coordinatorinfo = {
421
506
  installSource: 'IADefault_1',
422
507
  channel: '-1',
@@ -484,7 +569,7 @@ class Commands {
484
569
  this.adapter.sendTo(from, command, coordinatorinfo, callback);
485
570
  });
486
571
  } else {
487
- this.adapter.sendTo(from, command, {error: 'You need save and run adapter before pairing!'}, callback);
572
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
488
573
  }
489
574
  }
490
575
 
@@ -499,7 +584,7 @@ class Commands {
499
584
  }
500
585
 
501
586
  deleteDevice(from, command, msg, callback) {
502
- if (this.zbController && this.stController) {
587
+ if (this.zbController && this.zbController.herdsmanStarted && this.stController) {
503
588
  this.debug(`deleteDevice message: ${JSON.stringify(msg)}`);
504
589
  const id = msg.id;
505
590
  const force = msg.force;
@@ -524,7 +609,7 @@ class Commands {
524
609
  }
525
610
  });
526
611
  } else {
527
- this.adapter.sendTo(from, command, {error: 'You need to save and start the adapter!'}, callback);
612
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
528
613
  }
529
614
  }
530
615
 
@@ -548,14 +633,14 @@ class Commands {
548
633
  }
549
634
 
550
635
  async getChannels(from, command, message, callback) {
551
- if (this.zbController) {
636
+ if (this.zbController && this.zbController.herdsmanStarted) {
552
637
  const result = await this.zbController.getChannelsEnergy();
553
638
  this.debug(`getChannels result: ${JSON.stringify(result)}`);
554
639
  this.adapter.sendTo(from, command, result, callback);
555
640
  } else {
556
641
  this.adapter.sendTo(
557
642
  from, command,
558
- {error: 'You need to setup serial port and start the adapter before pairing!'},
643
+ {error: 'No active connection to Zigbee Hardware!'},
559
644
  callback
560
645
  );
561
646
  }
@@ -588,7 +673,7 @@ class Commands {
588
673
  async getLocalImages(from, command, msg, callback) {
589
674
  if (this.stController) {
590
675
  const id = msg.id;
591
- const result = await this.stController.localConfig.enumerateImages(utils.getAbsoluteInstanceDataDir(this.adapter).replace('.','_'));
676
+ const result = await this.stController.localConfig.enumerateImages(this.adapter.getDataFolder());
592
677
  this.adapter.sendTo(from, command, {imageData:result}, callback)
593
678
  }
594
679
  }
@@ -623,6 +708,10 @@ class Commands {
623
708
  const target = msg.target.replace(`${this.adapter.namespace}.`, '');
624
709
  const entity = await this.zbController.resolveEntity(target);
625
710
  //this.warn('entity for ' + target + ' is '+ JSON.stringify(entity))
711
+ if (entity && !entity.mapped) {
712
+ this.warn('unable to set local Override for device whithout mapped model');
713
+ return;
714
+ }
626
715
  if (msg.data)
627
716
  {
628
717
  for (const prop in msg.data) {
@@ -643,7 +732,7 @@ class Commands {
643
732
 
644
733
 
645
734
  async reconfigure(from, command, msg, callback) {
646
- if (this.zbController) {
735
+ if (this.zbController && this.zbController.herdsmanStarted) {
647
736
  const devid = getZbId(msg.id);
648
737
  this.debug(`Reconfigure ${devid}`);
649
738
  const entity = await this.zbController.resolveEntity(devid);
@@ -653,7 +742,6 @@ class Commands {
653
742
  'doConfigure',
654
743
  [entity.device, entity.mapped],
655
744
  );
656
- this.warn('do configure result is ' + JSON.stringify(result));
657
745
  const msg = result.join(',');
658
746
  if (msg.length > 5)
659
747
  this.adapter.sendTo(from, command, {error: msg}, callback);
@@ -669,6 +757,69 @@ class Commands {
669
757
  this.adapter.sendTo(from, command, {error: 'No device'}, callback);
670
758
  }
671
759
  }
760
+ else {
761
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
762
+ }
763
+ }
764
+
765
+ async testConnection(from, command, msg, callback) {
766
+ this.debug(`TestConnection with ${JSON.stringify(msg)}`);
767
+ if (msg && msg.address) {
768
+ const netAddress = getNetAddress(msg.address);
769
+ if (netAddress && netAddress.host) {
770
+ this.adapter.logToPairing(`attempting dns lookup for ${netAddress.host}`);
771
+ this.debug(`attempting dns lookup for ${netAddress.host}`);
772
+ dns.lookup(netAddress.host, (err, ip, _) => {
773
+ if (err) {
774
+ const msg = `Unable to resolve name: ${err && err.message ? err.message : 'no message'}`;
775
+ this.error(msg);
776
+ this.adapter.logToPairing(`Error: ${msg}`);
777
+ this.adapter.sendTo(from, command, {error:msg}, callback);
778
+ return;
779
+ }
780
+ this.debug(`dns lookup for ${msg.address} produced ${ip}`);
781
+ this.adapter.logToPairing(`dns lookup for ${msg.address} produced ${ip}`);
782
+ const client = new net.Socket();
783
+ this.debug(`attempting to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
784
+ client.connect(netAddress.port, ip, () => {
785
+ client.destroy()
786
+ this.adapter.logToPairing(`connected successfully to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
787
+ this.debug(`connected successfully to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
788
+ this.adapter.sendTo(from, command, {}, callback)
789
+ })
790
+ client.on('error', (error) => {
791
+ const msg = `unable to connect to ${ip} port ${netAddress.port ? netAddress.port : 80} : ${error && error.message ? error.message : 'no message given'}`
792
+ this.error(msg);
793
+ this.adapter.logToPairing(`Error: ${msg}`);
794
+ this.adapter.sendTo(from, command, {error:msg}, callback);
795
+ });
796
+ })
797
+ }
798
+ else
799
+ {
800
+ try {
801
+ const port = msg.address.trim();
802
+ this.adapter.logToPairing(`reading access rights for ${port}`);
803
+ access(port, constants.R_OK | constants.W_OK, (error) => {
804
+ if (error) {
805
+ const msg = `unable to access ${port} : ${error && error.message ? error.message : 'no message given'}`;
806
+ this.error(msg);
807
+ this.adapter.logToPairing(`Error: ${msg}`);
808
+ this.adapter.sendTo(from, command, {error:msg}, callback);
809
+ return;
810
+ }
811
+ this.adapter.logToPairing(`read and write access available for ${port}`);
812
+ this.adapter.sendTo(from, command, {}, callback);
813
+ });
814
+ }
815
+ catch (error) {
816
+ const msg = `File access error: ${error && error.message ? error.message : 'no message given'}`;
817
+ this.error(msg);
818
+ this.adapter.logToPairing(`Error: ${msg}`);
819
+ this.adapter.sendTo(from, command, {error:msg}, callback);
820
+ }
821
+ }
822
+ }
672
823
  }
673
824
  }
674
825
 
package/lib/developer.js CHANGED
File without changes
package/lib/devices.js CHANGED
@@ -3104,9 +3104,9 @@ function fillStatesWithExposes(logger) {
3104
3104
  async function addExposeToDevices(device, logger, model) {
3105
3105
  const s = DevicesByModel.size;
3106
3106
  if (s < 1) getByModel();
3107
- await applyExposeForDevice(devices, DevicesByModel, device, logger, model);
3107
+ const rv = await applyExposeForDevice(devices, DevicesByModel, device, logger, model);
3108
3108
  removeEmptyStates(devices);
3109
- return (DevicesByModel.size != s);
3109
+ return rv;
3110
3110
  }
3111
3111
 
3112
3112
  // remove empty states
package/lib/exposes.js CHANGED
@@ -251,8 +251,6 @@ function createFromExposes(model, def, device, log) {
251
251
  }
252
252
  }
253
253
 
254
- const icon = utils.getDeviceIcon(def);
255
-
256
254
  if (typeof def.exposes == 'object') {
257
255
  for (const expose of def.exposes) {
258
256
  genStateFromExpose(expose);
@@ -266,11 +264,12 @@ function createFromExposes(model, def, device, log) {
266
264
  genStateFromExpose(expose);
267
265
  }
268
266
  }
267
+ const icon = utils.getDeviceIcon(def);
269
268
 
270
269
  const newDev = {
271
270
  models: [model],
272
- icon,
273
271
  states,
272
+ icon,
274
273
  exposed: true,
275
274
  };
276
275
 
@@ -594,7 +593,7 @@ function createFromExposes(model, def, device, log) {
594
593
  break;
595
594
 
596
595
  case 'voltage':
597
- state = statesDefs.plug_voltage;
596
+ state = genState(expose);
598
597
  break;
599
598
 
600
599
  case 'temperature':
@@ -867,29 +866,12 @@ function createFromExposes(model, def, device, log) {
867
866
 
868
867
  }
869
868
 
870
- function applyExposes(mappedDevices, byModel) {
871
- // create or device from exposes
872
- for (const deviceDef of zigbeeHerdsmanConverters.definitions) {
873
- applyDeviceDef(mappedDevices, byModel, deviceDef);
874
-
875
- if (deviceDef.hasOwnProperty('whiteLabel')) {
876
- for (const deviceWhiteLabel of deviceDef.whiteLabel) {
877
- applyDeviceDef(mappedDevices, byModel, {
878
- ...deviceDef,
879
- model: deviceWhiteLabel.model,
880
- vendor: deviceWhiteLabel.vendor,
881
- description: deviceWhiteLabel.description || deviceDef.description,
882
- });
883
- }
884
- }
885
- }
886
- }
887
-
888
869
  async function applyExposeForDevice(mappedDevices, byModel, device) {
889
870
  const deviceDef = await zigbeeHerdsmanConverters.findByDevice(device);
890
- if (!deviceDef) return false;
891
- applyDeviceDef(mappedDevices, byModel, deviceDef, device);
892
- return true;
871
+ if (!deviceDef) {
872
+ return undefined;
873
+ }
874
+ return applyDeviceDef(mappedDevices, byModel, deviceDef, device);
893
875
  }
894
876
 
895
877
  function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
@@ -900,14 +882,15 @@ function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
900
882
  const newDevice = createFromExposes(stripModel, deviceDef, device);
901
883
  mappedDevices.push(newDevice);
902
884
  byModel.set(stripModel, newDevice);
885
+ return newDevice;
903
886
 
904
887
  } catch (e) {
905
- //this.debug('empty catch in exposes');
888
+ return undefined;
906
889
  }
907
890
  }
891
+ return existsMap;
908
892
  }
909
893
 
910
894
  module.exports = {
911
- applyExposes: applyExposes,
912
895
  applyExposeForDevice: applyExposeForDevice,
913
896
  };
package/lib/groups.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  const json = require('iobroker.zigbee/lib/json');
4
4
  const statesMapping = require('./devices');
5
- const { numberWithinRange } = require('zigbee-herdsman-converters/lib/utils');
6
5
  const idRegExp = new RegExp(/group_(\d+)/);
7
6
 
8
7
 
@@ -168,7 +167,7 @@ class Groups {
168
167
  for (const gpid of groups[epid]) {
169
168
  const gpidn = parseInt(gpid);
170
169
  if (gpidn < 0) {
171
- this.warn(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
170
+ this.debug(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
172
171
  const response = await this.zbController.removeDevFromGroup(sysid, (-gpidn), epid);
173
172
  if (response && response.error) {
174
173
  errors.push(response.error);
@@ -176,7 +175,7 @@ class Groups {
176
175
  }
177
176
  const icon = this.stController.getDefaultGroupIcon(-gpidn)
178
177
  } else if (gpidn > 0) {
179
- this.warn(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
178
+ this.debug(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
180
179
  const response = await this.zbController.addDevToGroup(sysid, (gpidn), epid);
181
180
  if (response && response.error) {
182
181
  errors.push(response.error);
@@ -233,7 +232,7 @@ class Groups {
233
232
  throw error;
234
233
  }
235
234
  if (result.unread.length > 0) {
236
- this.warn(`unread ${stateDesc.id} change for group members ${JSON.stringify(result.unread)}`);
235
+ this.debug(`unread ${stateDesc.id} change for group members ${JSON.stringify(result.unread)}`);
237
236
  }
238
237
  }
239
238
 
@@ -254,11 +253,10 @@ class Groups {
254
253
  if (message.remove) {
255
254
  for (const member of message.remove) {
256
255
  const response = await this.zbController.removeDevFromGroup(member.id, id, member.ep);
257
- this.warn('trying to remove ' + member.id + (member.ep ? '.'+member.ep : '') + ' ' + ' from group ' + message.id + ' response is '+JSON.stringify(response));
256
+ this.debug('trying to remove ' + member.id + (member.ep ? '.'+member.ep : '') + ' ' + ' from group ' + message.id + ' response is '+JSON.stringify(response));
258
257
  }
259
258
  }
260
259
  if (icon.match(/img\/group_\d+\.png/g)) {
261
- this.warn('.');
262
260
  icon = await this.zbController.rebuildGroupIcon(group);
263
261
  }
264
262
  } catch (e) {
@@ -270,7 +268,7 @@ class Groups {
270
268
  this.warn(`rename group name ${name}, id ${id}, icon ${icon} remove ${JSON.stringify(message.removeMembers)}`);
271
269
  const group = await this.adapter.getObjectAsync(id);
272
270
  if (!group) {
273
- this.warn('group object doesnt exist ')
271
+ this.debug('group object doesnt exist ')
274
272
  // assume we have to create the group
275
273
  this.adapter.setObjectNotExists(id, {
276
274
  type: 'device',
@@ -301,7 +299,7 @@ class Groups {
301
299
  });
302
300
  }
303
301
  else {
304
- this.warn('group object exists');
302
+ this.debug('group object exists');
305
303
  this.adapter.extendObject(id, {common: {name, type: 'group', icon: icon}});
306
304
  }
307
305
  }
@@ -138,7 +138,7 @@ class localConfig extends EventEmitter {
138
138
  try {
139
139
  this.adapter.fileExists(namespace, rv, (err, result) => {
140
140
  if (result) return;
141
- const src = this.adapter.expandFileName(iconPath).replace('.','_');
141
+ const src = this.adapter.expandFileName(iconPath);
142
142
  fs.readFile(src, (err, data) => {
143
143
  if (err) {
144
144
  this.error('unable to read ' + src + ' : '+ (err && err.message? err.message:' no message given'))
@@ -220,8 +220,7 @@ class localConfig extends EventEmitter {
220
220
  }
221
221
 
222
222
  async updateFromDeviceNames() {
223
- this.warn('updateFromDeviceNames');
224
- const fn = this.adapter.expandFileName('dev_names').replace('.', '_').concat('.json');
223
+ const fn = this.adapter.expandFileName('dev_names.json');
225
224
  fs.readFile(fn, (err, content) => {
226
225
  if (!err) {
227
226
  let data_js = {};
@@ -250,7 +249,7 @@ class localConfig extends EventEmitter {
250
249
 
251
250
  async init() {
252
251
  this.info('init localConfig');
253
- const fn = this.adapter.expandFileName('LocalOverrides').replace('.','_').concat('.json');
252
+ const fn = this.adapter.expandFileName('LocalOverrides').replace('zigbee.','zigbee_').concat('.json');
254
253
  this.filename = fn;
255
254
  this.basefolder = path.dirname(fn);
256
255
 
@@ -286,7 +285,7 @@ class localConfig extends EventEmitter {
286
285
  const files= fs.readdirSync(_path, {withFileTypes: true, recursive: true}).filter(item => (!item.isDirectory() && item.name.endsWith('.png')));
287
286
  files.forEach((item) => {
288
287
  const fn = path.join(item.parentPath, item.name);
289
- rv.push({file: fn, name: item.name, data: fs.readFileSync(path.join(item.parentPath, item.name), 'base64')})
288
+ rv.push({file: fn, name: item.name, data: fs.readFileSync(path.join(item.parentPath, item.name), 'base64'), isBase64:true});
290
289
  });
291
290
  //this.warn('enumerateImages for ' + _path + ' is ' + JSON.stringify(rv));
292
291
  }
package/lib/ota.js CHANGED
@@ -55,7 +55,7 @@ class Ota {
55
55
  async checkOtaAvail(obj) {
56
56
  const device = await this.getDeviceForMessage(obj);
57
57
  if (!device) {
58
- this.debug(`Device ${obj.message.devId} is unavailable`);
58
+ this.info(`Device ${obj.message.devId} is unavailable`);
59
59
  this.adapter.sendTo(obj.from, obj.command, {
60
60
  status: 'fail',
61
61
  device: getZbId(obj.message.devId),
@@ -64,13 +64,13 @@ class Ota {
64
64
  return;
65
65
  }
66
66
  if (this.inProgress.has(device.device.ieeeAddr)) {
67
- this.warn(`Update or check already in progress for '${device.name}', skipping...`);
67
+ this.info(`Update or check already in progress for '${device.name}', skipping...`);
68
68
  return;
69
69
  }
70
70
  // do not attempt update for a device which has been deactivated or is unavailable
71
71
  const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
72
72
  if (stateObj && stateObj.common && stateObj.common.deactivated) {
73
- this.warn(`Device ${obj.message.devId} is deactivated, skipping...`);
73
+ this.info(`Device ${obj.message.devId} is deactivated, skipping...`);
74
74
  this.adapter.sendTo(obj.from, obj.command, {
75
75
  status: 'fail',
76
76
  device: getZbId(obj.message.devId),
@@ -81,7 +81,7 @@ class Ota {
81
81
  const availablestate = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.available`);
82
82
  const lqi = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.link_quality`);
83
83
  if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
84
- this.warn(`Device ${obj.message.devId} is marked unavailable, skipping...`);
84
+ this.info(`Device ${obj.message.devId} is marked unavailable, skipping...`);
85
85
  this.adapter.sendTo(obj.from, obj.command, {
86
86
  status: 'fail',
87
87
  device: getZbId(obj.message.devId),
@@ -133,13 +133,13 @@ class Ota {
133
133
  // do not attempt update for a device which has been deactivated or is unavailable
134
134
  const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
135
135
  if (stateObj && stateObj.common && stateObj.common.deactivated) {
136
- this.warn(`Device ${obj.message.devId} is deactivated, skipping...`);
136
+ this.info(`Device ${obj.message.devId} is deactivated, skipping...`);
137
137
  return;
138
138
  }
139
139
  const availablestate = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.available`);
140
140
  const lqi = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.link_quality`);
141
141
  if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
142
- this.warn(`Device ${obj.message.devId} is marked unavailable, skipping...`);
142
+ this.info(`Device ${obj.message.devId} is marked unavailable, skipping...`);
143
143
  return;
144
144
  }
145
145
  this.inProgress.add(device.device.ieeeAddr);
package/lib/seriallist.js CHANGED
@@ -22,10 +22,17 @@ class SerialList {
22
22
  SerialPort.list()
23
23
  .then(ports => {
24
24
  this.adapter.log.info(`List of port: ${JSON.stringify(ports)}`);
25
- this.adapter.sendTo(obj.from, obj.command, ports.map(item => ({
25
+ const candidates = ports.map(item => ({
26
26
  label: item.friendlyName || item.pnpId || item.manufacturer,
27
27
  comName: item.path
28
- })), obj.callback);
28
+ }));
29
+ require('fs').readdir('/dev/serial/by-id', (err, files) => {
30
+ if (!err) {
31
+ for (const item of files)
32
+ candidates.push({comName: `/dev/serial/by-id/${item}`});
33
+ }
34
+ this.adapter.sendTo(obj.from, obj.command, candidates.reverse(), obj.callback);
35
+ })
29
36
  })
30
37
  .catch(e => {
31
38
  this.adapter.sendTo(obj.from, obj.command, [], obj.callback);