iobroker.zigbee 2.0.5 → 3.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.
Files changed (42) hide show
  1. package/README.md +22 -3
  2. package/admin/admin.js +420 -115
  3. package/admin/index_m.html +285 -229
  4. package/admin/tab_m.html +108 -91
  5. package/docs/de/img/Bild30.png +0 -0
  6. package/docs/de/img/Bild38.png +0 -0
  7. package/docs/de/img/Info.png +0 -0
  8. package/docs/de/img/Zigbee_config_de.jpg +0 -0
  9. package/docs/de/img/battery.png +0 -0
  10. package/docs/de/img/debug.png +0 -0
  11. package/docs/de/img/delete.png +0 -0
  12. package/docs/de/img/disconnected.png +0 -0
  13. package/docs/de/img/edit_grp.png +0 -0
  14. package/docs/de/img/edit_image.png +0 -0
  15. package/docs/de/img/grp_nok.png +0 -0
  16. package/docs/de/img/grp_ok.png +0 -0
  17. package/docs/de/img/on_off.png +0 -0
  18. package/docs/de/img/reconfigure.png +0 -0
  19. package/docs/de/readme.md +52 -43
  20. package/docs/en/img/Zigbee_config_en.png +0 -0
  21. package/docs/en/img/Zigbee_pairing_en.png +0 -0
  22. package/docs/en/readme.md +66 -66
  23. package/io-package.json +32 -31
  24. package/lib/DeviceDebug.js +2 -1
  25. package/lib/commands.js +203 -40
  26. package/lib/devices.js +2 -2
  27. package/lib/exposes.js +8 -30
  28. package/lib/groups.js +1 -1
  29. package/lib/localConfig.js +33 -10
  30. package/lib/networkmap.js +2 -1
  31. package/lib/seriallist.js +9 -2
  32. package/lib/statescontroller.js +185 -91
  33. package/lib/utils.js +41 -11
  34. package/lib/zbDeviceConfigure.js +10 -3
  35. package/lib/zigbeecontroller.js +121 -94
  36. package/main.js +135 -73
  37. package/package.json +8 -8
  38. package/docs/en/img/Bild23.png +0 -0
  39. package/docs/en/img/Bild25.png +0 -0
  40. package/docs/en/img/Bild26.png +0 -0
  41. package/docs/en/img/Bild4.png +0 -0
  42. package/docs/en/img/Bild9.png +0 -0
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;
@@ -145,31 +149,92 @@ class Commands {
145
149
  this.updateDeviceImage(obj.from, obj.command, obj.message, obj.callback);
146
150
  }
147
151
  break;
148
- case 'updateDeviceData':
152
+ case 'updateLocalConfigItems':
149
153
  if (obj.message && typeof obj.message === 'object') {
150
- this.updateDeviceData(obj.from, obj.command, obj.message, obj.callback);
154
+ this.updateLocalConfigItems(obj.from, obj.command, obj.message, obj.callback);
151
155
  }
152
156
  break;
153
- case 'getDeviceCleanupRequired':
154
- if (obj) {
155
- this.adapter.sendTo(obj.from, obj.command, {clean:this.stController.CleanupRequired(), errors:this.stController.getStashedErrors()}, obj.callback);
157
+ case 'getLocalConfigItems':
158
+ if (obj.message && typeof obj.message === 'object') {
159
+ this.getLocalConfigItems(obj.from, obj.command, obj.message, obj.callback);
156
160
  }
161
+ break;
162
+ case 'getDeviceCleanupRequired':
163
+ if (this.stController) this.adapter.sendTo(obj.from, obj.command, {clean:this.stController.CleanupRequired(), errors:this.stController.getStashedErrors()}, obj.callback);
164
+ // NO Break - returning the debug-data as well is intentional
157
165
  case 'getDebugMessages':
158
- if (obj) {
159
- this.adapter.sendTo(obj.from, obj.command, {byId:this.adapter.deviceDebug.collectDebugData( obj.message.inlog)},obj.callback);
160
- }
166
+ this.adapter.sendTo(obj.from, obj.command, {byId:this.adapter.deviceDebug.collectDebugData( obj.message.inlog)},obj.callback);
167
+ break;
168
+ case 'testConnection':
169
+ this.testConnection(obj.from, obj.command, obj.message, obj.callback);
170
+ break;
171
+ case 'readNVRam':
172
+ this.readNvBackup(obj.from, obj.command, obj.message, obj.callback);
173
+ default:
174
+ //this.warn(`Commands: Command ${obj.command} is unknown`);
175
+ //this.adapter.sendTo(obj.from, obj.command, obj.message, obj.callback);
176
+ break;
161
177
  }
162
178
  }
163
179
  }
164
180
  }
165
181
 
166
- delNvBackup(from, command, msg, callback) {
182
+ async readNvBackup(from, command, msg, callback) {
183
+ this.debug('readNvBackup called')
167
184
  try {
168
- if (this.zbController) {
185
+ const zo = this.adapter.getZigbeeOptions();
186
+ const name = require('path').join(zo.dbDir, zo.backupPath);
187
+ const nvbackup = fs.readFileSync(name, {encoding: 'utf8'}).toString();
188
+ const nvBackupJson = JSON.parse(nvbackup);
189
+ const rv = {};
190
+ rv.channel = nvBackupJson.channel;
191
+ rv.precfgkey = (nvBackupJson.network_key ? nvBackupJson.network_key.key : undefined);
192
+ rv.extPanID = nvBackupJson.extended_pan_id ? reverseByteString(nvBackupJson.extended_pan_id) : undefined;
193
+ rv.panID = parseInt('0x'+nvBackupJson.pan_id);
194
+ this.debug('readNvBackup returns ' + JSON.stringify(rv))
195
+ this.adapter.sendTo(from, command, rv, callback)
196
+ }
197
+ catch (error) {
198
+ const msg = `Unable to read nvBackup ${error && error.message ? error.message : 'no message given'}`;
199
+ this.error(msg);
200
+ this.adapter.sendTo(from, command, {error:msg}, callback)
201
+ }
202
+ }
203
+
204
+ async delNvBackup(from, command, msg, callback) {
205
+ try {
206
+ if (this.zbController)
207
+ {
208
+ // stop the herdsman if needed
209
+ const wasRunning = this.zbController.herdsmanStarted;
210
+ if (wasRunning) await this.zbController.stop();
169
211
  const name = this.zbController.herdsman.adapter.backupPath;
170
- require('fs').unlinkSync(name);
212
+ fs.unlink(name, async (err) => {
213
+ const rv={};
214
+ if (err) {
215
+ this.error(`Unable to remove ${name}: ${err}`);
216
+ rv.error = `Unable to remove ${name}: ${err}`;
217
+ }
218
+ // start the herdsman again if it was stopped before
219
+ if (wasRunning) await this.zbController.start();
220
+ this.adapter.sendTo(from, command, rv, callback)
221
+ });
222
+ }
223
+ else {
224
+ const zo = this.adapter.getZigbeeOptions();
225
+ const name = require('path').join(zo.dbDir, zo.backupPath);
226
+ fs.unlink(name, async (err) => {
227
+ const rv={};
228
+ if (err) {
229
+ this.error(`Unable to remove ${name}: ${err}`);
230
+ rv.error = `Unable to remove ${name}: ${err}`;
231
+ }
232
+ // start the herdsman again if it was stopped before
233
+ this.adapter.sendTo(from, command, rv, callback)
234
+ });
171
235
  }
172
236
  } catch (error) {
237
+ this.adapter.sendTo(from, command, {error: error.message}, callback)
173
238
  this.error(error);
174
239
  }
175
240
  }
@@ -231,7 +296,7 @@ class Commands {
231
296
  }
232
297
 
233
298
  touchlinkReset(from, command, message, callback) {
234
- if (this.zbController) {
299
+ if (this.zbController && this.zbController.herdsmanStarted) {
235
300
  // allow devices to join the network within 60 secs
236
301
  this.adapter.logToPairing('Touchlink reset started ', true);
237
302
 
@@ -245,14 +310,14 @@ class Commands {
245
310
  } else {
246
311
  this.adapter.sendTo(
247
312
  from, command,
248
- {error: 'You need to setup serial port and start the adapter before pairing!'},
313
+ {error: 'No active connection to Zigbee Hardware!'},
249
314
  callback
250
315
  );
251
316
  }
252
317
  }
253
318
 
254
319
  async getDevices(from, command, id, callback) {
255
- if (this.zbController) {
320
+ if (this.zbController && this.zbController.herdsmanStarted) {
256
321
  this.debug(`getDevices called from ${from} with command ${JSON.stringify(command)} and id ${JSON.stringify(id)}`);
257
322
  const pairedDevices = await this.zbController.getClients(true);
258
323
  const groups = {};
@@ -421,18 +486,27 @@ class Commands {
421
486
  return devices;
422
487
  })
423
488
  .then(devices => {
424
- this.debug(`getDevices result: ${JSON.stringify(devices)}`);
425
- this.adapter.sendTo(from, command, devices, callback);
489
+ this.debug(`getDevices contains ${devices.length} Devices`);
490
+ const rv = { devices:devices, inLog:this.adapter.deviceDebug.logStatus, byId:this.adapter.deviceDebug.collectDebugData() }
491
+ if (this.stController) {
492
+ rv.clean = this.stController.CleanupRequired();
493
+ rv.errors = this.stController.getStashedErrors();
494
+ rv.debugDevices = this.stController.debugDevices;
495
+ }
496
+ this.adapter.sendTo(from, command, rv, callback);
426
497
  })
427
- .catch(err => this.error(`getDevices error: ${err.stack}`));
498
+ .catch(err => {
499
+ this.error(`getDevices error: ${err.stack}`);
500
+ this.adapter.sendTo(from, command, {error: `Error enumerating devices : ${err && err.message ? err.message : ''}`}, callback);
501
+ });
428
502
  } else {
429
- this.adapter.sendTo(from, command, {error: 'You need save and run adapter before pairing!'}, callback);
503
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
430
504
  }
431
505
  }
432
506
 
433
507
 
434
508
  async getCoordinatorInfo(from, command, callback) {
435
- if (this.zbController) {
509
+ if (this.zbController && this.zbController.herdsmanStarted) {
436
510
  const coordinatorinfo = {
437
511
  installSource: 'IADefault_1',
438
512
  channel: '-1',
@@ -500,7 +574,7 @@ class Commands {
500
574
  this.adapter.sendTo(from, command, coordinatorinfo, callback);
501
575
  });
502
576
  } else {
503
- this.adapter.sendTo(from, command, {error: 'You need save and run adapter before pairing!'}, callback);
577
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
504
578
  }
505
579
  }
506
580
 
@@ -515,7 +589,7 @@ class Commands {
515
589
  }
516
590
 
517
591
  deleteDevice(from, command, msg, callback) {
518
- if (this.zbController && this.stController) {
592
+ if (this.zbController && this.zbController.herdsmanStarted && this.stController) {
519
593
  this.debug(`deleteDevice message: ${JSON.stringify(msg)}`);
520
594
  const id = msg.id;
521
595
  const force = msg.force;
@@ -540,7 +614,7 @@ class Commands {
540
614
  }
541
615
  });
542
616
  } else {
543
- this.adapter.sendTo(from, command, {error: 'You need to save and start the adapter!'}, callback);
617
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
544
618
  }
545
619
  }
546
620
 
@@ -564,14 +638,14 @@ class Commands {
564
638
  }
565
639
 
566
640
  async getChannels(from, command, message, callback) {
567
- if (this.zbController) {
641
+ if (this.zbController && this.zbController.herdsmanStarted) {
568
642
  const result = await this.zbController.getChannelsEnergy();
569
643
  this.debug(`getChannels result: ${JSON.stringify(result)}`);
570
644
  this.adapter.sendTo(from, command, result, callback);
571
645
  } else {
572
646
  this.adapter.sendTo(
573
647
  from, command,
574
- {error: 'You need to setup serial port and start the adapter before pairing!'},
648
+ {error: 'No active connection to Zigbee Hardware!'},
575
649
  callback
576
650
  );
577
651
  }
@@ -604,7 +678,7 @@ class Commands {
604
678
  async getLocalImages(from, command, msg, callback) {
605
679
  if (this.stController) {
606
680
  const id = msg.id;
607
- const result = await this.stController.localConfig.enumerateImages(utils.getAbsoluteInstanceDataDir(this.adapter).replace('zigbee.','zigbee_'));
681
+ const result = await this.stController.localConfig.enumerateImages(this.adapter.getDataFolder());
608
682
  this.adapter.sendTo(from, command, {imageData:result}, callback)
609
683
  }
610
684
  }
@@ -633,10 +707,10 @@ class Commands {
633
707
  }
634
708
  }
635
709
 
636
- async updateDeviceData(from, command, msg, callback) {
710
+ async updateLocalConfigItems(from, command, msg, callback) {
637
711
  if (this.stController) {
638
- this.debug(`UpdateDeviceData : ${JSON.stringify(msg)}`)
639
- const target = msg.target.replace(`${this.adapter.namespace}.`, '');
712
+ this.debug(`updateLocalConfigItems : ${JSON.stringify(msg)}`);
713
+ const target = msg.global ? msg.target : msg.target.replace(`${this.adapter.namespace}.`, '');
640
714
  const entity = await this.zbController.resolveEntity(target);
641
715
  //this.warn('entity for ' + target + ' is '+ JSON.stringify(entity))
642
716
  if (entity && !entity.mapped) {
@@ -651,19 +725,45 @@ class Commands {
651
725
  }
652
726
  }
653
727
  if (entity) {
654
- //this.warn('with Entity');
728
+ this.debug('updateLocalConfigItems with Entity');
655
729
  this.stController.updateDev(target, entity.mapped.model, entity.mapped.model, () => {this.adapter.sendTo(from, command, {}, callback)});
656
730
  }
657
731
  else {
658
- //this.warn('without Entity');
732
+ this.debug('updateLocalConfigItems without Entity');
659
733
  this.stController.updateDev(target, undefined, 'group',() => {this.adapter.sendTo(from, command, {}, callback)});
660
734
  }
661
735
  }
662
736
  }
663
737
 
738
+ async getLocalConfigItems(from, command, msg, callback)
739
+ {
740
+ const rv = {};
741
+ if (this.stController) {
742
+ this.debug(`getLocalConfigItems : ${JSON.stringify(msg)}`)
743
+
744
+ if (msg.hasOwnProperty('global') && msg.hasOwnProperty('target') && (msg.hasOwnProperty('keys') || msg.hasOwnProperty('key')))
745
+ {
746
+ const target = msg.global ? msg.target : msg.target.replace(`${this.adapter.namespace}.`, '');
747
+ const keys = msg.hasOwnProperty('keys') ? msg.keys : [msg.key];
748
+ for (const key of keys) {
749
+ const ld = this.stController.localConfig.getOverrideWithTargetAndKey(target, key, msg.global);
750
+ if (ld != undefined) rv[key] = ld;
751
+ }
752
+
753
+ //const targetId = msg.id ? msg.id.replace(`${this.adapter.namespace}.`, '') : '';
754
+ //const targetModel = msg.model ? msg.model : '';
755
+ }
756
+ else {
757
+ rv.error = `missing data in message ${JSON.stringify(msg)}`;
758
+ }
759
+ }
760
+ else rv.error = 'stController not initialized - no Data sent'
761
+
762
+ this.adapter.sendTo(from, command, rv, callback);
763
+ }
664
764
 
665
765
  async reconfigure(from, command, msg, callback) {
666
- if (this.zbController) {
766
+ if (this.zbController && this.zbController.herdsmanStarted) {
667
767
  const devid = getZbId(msg.id);
668
768
  this.debug(`Reconfigure ${devid}`);
669
769
  const entity = await this.zbController.resolveEntity(devid);
@@ -688,6 +788,69 @@ class Commands {
688
788
  this.adapter.sendTo(from, command, {error: 'No device'}, callback);
689
789
  }
690
790
  }
791
+ else {
792
+ this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
793
+ }
794
+ }
795
+
796
+ async testConnection(from, command, msg, callback) {
797
+ this.debug(`TestConnection with ${JSON.stringify(msg)}`);
798
+ if (msg && msg.address) {
799
+ const netAddress = getNetAddress(msg.address);
800
+ if (netAddress && netAddress.host) {
801
+ this.adapter.logToPairing(`attempting dns lookup for ${netAddress.host}`);
802
+ this.debug(`attempting dns lookup for ${netAddress.host}`);
803
+ dns.lookup(netAddress.host, (err, ip, _) => {
804
+ if (err) {
805
+ const msg = `Unable to resolve name: ${err && err.message ? err.message : 'no message'}`;
806
+ this.error(msg);
807
+ this.adapter.logToPairing(`Error: ${msg}`);
808
+ this.adapter.sendTo(from, command, {error:msg}, callback);
809
+ return;
810
+ }
811
+ this.debug(`dns lookup for ${msg.address} produced ${ip}`);
812
+ this.adapter.logToPairing(`dns lookup for ${msg.address} produced ${ip}`);
813
+ const client = new net.Socket();
814
+ this.debug(`attempting to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
815
+ client.connect(netAddress.port, ip, () => {
816
+ client.destroy()
817
+ this.adapter.logToPairing(`connected successfully to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
818
+ this.debug(`connected successfully to connect to ${ip} port ${netAddress.port ? netAddress.port : 80}`);
819
+ this.adapter.sendTo(from, command, {}, callback)
820
+ })
821
+ client.on('error', (error) => {
822
+ const msg = `unable to connect to ${ip} port ${netAddress.port ? netAddress.port : 80} : ${error && error.message ? error.message : 'no message given'}`
823
+ this.error(msg);
824
+ this.adapter.logToPairing(`Error: ${msg}`);
825
+ this.adapter.sendTo(from, command, {error:msg}, callback);
826
+ });
827
+ })
828
+ }
829
+ else
830
+ {
831
+ try {
832
+ const port = msg.address.trim();
833
+ this.adapter.logToPairing(`reading access rights for ${port}`);
834
+ access(port, constants.R_OK | constants.W_OK, (error) => {
835
+ if (error) {
836
+ const msg = `unable to access ${port} : ${error && error.message ? error.message : 'no message given'}`;
837
+ this.error(msg);
838
+ this.adapter.logToPairing(`Error: ${msg}`);
839
+ this.adapter.sendTo(from, command, {error:msg}, callback);
840
+ return;
841
+ }
842
+ this.adapter.logToPairing(`read and write access available for ${port}`);
843
+ this.adapter.sendTo(from, command, {}, callback);
844
+ });
845
+ }
846
+ catch (error) {
847
+ const msg = `File access error: ${error && error.message ? error.message : 'no message given'}`;
848
+ this.error(msg);
849
+ this.adapter.logToPairing(`Error: ${msg}`);
850
+ this.adapter.sendTo(from, command, {error:msg}, callback);
851
+ }
852
+ }
853
+ }
691
854
  }
692
855
  }
693
856
 
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
 
@@ -867,34 +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
- async function applyExposeForDevice(mappedDevices, byModel, device, logger) {
889
- const t = Date.now();
869
+ async function applyExposeForDevice(mappedDevices, byModel, device) {
890
870
  const deviceDef = await zigbeeHerdsmanConverters.findByDevice(device);
891
871
  if (!deviceDef) {
892
- //logger.warn(`ZHC02,${Date.now()},${Date.now()-t},${device && device.ieeeAddr ? device.ieeeAddr : '0x0'}, failed`);
893
- return false;
872
+ return undefined;
894
873
  }
895
- //logger.warn(`ZHC02,${Date.now()},${Date.now()-t},${device && device.ieeeAddr ? device.ieeeAddr : '0x0'}, passed`);
896
- applyDeviceDef(mappedDevices, byModel, deviceDef, device);
897
- return true;
874
+ return applyDeviceDef(mappedDevices, byModel, deviceDef, device);
898
875
  }
899
876
 
900
877
  function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
@@ -905,14 +882,15 @@ function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
905
882
  const newDevice = createFromExposes(stripModel, deviceDef, device);
906
883
  mappedDevices.push(newDevice);
907
884
  byModel.set(stripModel, newDevice);
885
+ return newDevice;
908
886
 
909
887
  } catch (e) {
910
- //this.debug('empty catch in exposes');
888
+ return undefined;
911
889
  }
912
890
  }
891
+ return existsMap;
913
892
  }
914
893
 
915
894
  module.exports = {
916
- applyExposes: applyExposes,
917
895
  applyExposeForDevice: applyExposeForDevice,
918
896
  };
package/lib/groups.js CHANGED
@@ -265,7 +265,7 @@ class Groups {
265
265
  this.warn(`renameGroup caught error ${JSON.stringify(e.code)}`);
266
266
  }
267
267
  }
268
- this.warn(`rename group name ${name}, id ${id}, icon ${icon} remove ${JSON.stringify(message.removeMembers)}`);
268
+ this.debug(`rename group name ${name}, id ${id}, icon ${icon} remove ${JSON.stringify(message.removeMembers)}`);
269
269
  const group = await this.adapter.getObjectAsync(id);
270
270
  if (!group) {
271
271
  this.debug('group object doesnt exist ')
@@ -18,7 +18,6 @@ class localConfig extends EventEmitter {
18
18
  this.basefolder = undefined;
19
19
  this.retTimeoutHanlde = undefined;
20
20
  this.adapter.on('ready', () => this.onReady());
21
- this.adapter.on('unload', callback => this.onUnload(callback));
22
21
  }
23
22
 
24
23
 
@@ -28,9 +27,9 @@ class localConfig extends EventEmitter {
28
27
 
29
28
  async onUnload(callback)
30
29
  {
31
- this.info('local config saved');
32
30
  this.retainData();
33
- callback();
31
+ // No callback here -
32
+ //callback();
34
33
  }
35
34
 
36
35
  info(message) {
@@ -76,14 +75,14 @@ class localConfig extends EventEmitter {
76
75
  async updateLocalOverride(_target, model, key, data, global)
77
76
  {
78
77
  const target = (global ? model : _target);
79
- this.info(`updating local data: (${global ? 'global':'local'}) : ${target}:${key}:${data}`);
78
+ this.info(`updating local data: (${global ? 'global':'local'}) : ${target}:${key}:${JSON.stringify(data)}`);
80
79
 
81
80
  if (typeof target != 'string' || typeof key != 'string') {
82
81
  this.error(`update called with illegal id data:${JSON.stringify(target)}:${JSON.stringify(key)}:${JSON.stringify(data)}`)
83
82
  return false;
84
83
  }
85
84
  const base = global ? this.localData.by_model[target] || {} : this.localData.by_id[target] || {};
86
- if (data && data.length > 0 && data != 'none') {
85
+ if (data && Object.keys(data).length > 0 && data != 'none') {
87
86
  if (key == 'icon')
88
87
  base[key] = data.replace(this.basefolder, '.');
89
88
  else
@@ -103,10 +102,24 @@ class localConfig extends EventEmitter {
103
102
  if (base == {}) delete this.localData.by_id[target];
104
103
  else this.localData.by_id[target] = base;
105
104
  }
106
- this.info(`Local Data for ${target} is ${JSON.stringify(base)}`);
105
+ this.info(`Local Data for ${target} is ${JSON.stringify(base)} after update`);
107
106
  return true;
108
107
  }
109
108
 
109
+ async getLocalOverride(_target, model, key, global)
110
+ {
111
+ const target = (global ? model : _target);
112
+ this.info(`getting local data: (${global ? 'global':'local'}) : ${target}:${key}`);
113
+
114
+ if (typeof target != 'string' || typeof key != 'string') {
115
+ this.error(`update called with illegal id data:${JSON.stringify(target)}:${JSON.stringify(key)}`)
116
+ return false;
117
+ }
118
+ const base = global ? this.localData.by_model[target] || {} : this.localData.by_id[target] || {};
119
+ const rv = {};
120
+ if (base.hasOwnProperty(key)) rv[key] = base[key];
121
+ return rv;
122
+ }
110
123
 
111
124
  NameForId(id, model, defaultName) {
112
125
  this.debug('name for id with ' + id + ' and ' + defaultName + ' from ' + JSON.stringify(this.localData));
@@ -138,7 +151,7 @@ class localConfig extends EventEmitter {
138
151
  try {
139
152
  this.adapter.fileExists(namespace, rv, (err, result) => {
140
153
  if (result) return;
141
- const src = this.adapter.expandFileName(iconPath).replace('zigbee.','zigbee_');
154
+ const src = this.adapter.expandFileName(iconPath);
142
155
  fs.readFile(src, (err, data) => {
143
156
  if (err) {
144
157
  this.error('unable to read ' + src + ' : '+ (err && err.message? err.message:' no message given'))
@@ -213,14 +226,15 @@ class localConfig extends EventEmitter {
213
226
  return rv;
214
227
  }
215
228
 
216
- getOverrideWithKey(target, key, isGlobal) {
229
+ getOverrideWithTargetAndKey(target, key, isGlobal) {
217
230
  const targetdata = this.getOverrideData(target, isGlobal);
218
231
  if (targetdata && targetdata.hasOwnProperty(key)) return targetdata[key];
219
232
  return undefined;
220
233
  }
221
234
 
222
235
  async updateFromDeviceNames() {
223
- const fn = this.adapter.expandFileName('dev_names').replace('zigbee.', 'zigbee_').concat('.json');
236
+ const fn = this.adapter.expandFileName('dev_names.json');
237
+ this.info('Initializing localConfig from dev_names.json')
224
238
  fs.readFile(fn, (err, content) => {
225
239
  if (!err) {
226
240
  let data_js = {};
@@ -233,8 +247,10 @@ class localConfig extends EventEmitter {
233
247
  }
234
248
  try {
235
249
  for (const prop in data_js) {
236
- if (data_js[prop] != 'undefined')
250
+ if (data_js[prop] != 'undefined') {
251
+ this.info(`updating device name for ${prop} as ${data_js[prop]}`);
237
252
  this.updateDeviceName(prop, data_js[prop]);
253
+ }
238
254
  }
239
255
  }
240
256
  catch (error) {
@@ -295,6 +311,13 @@ class localConfig extends EventEmitter {
295
311
  return rv;
296
312
  }
297
313
 
314
+ getOptions(dev_id) {
315
+ const ld = this.localData.by_id[dev_id];
316
+ if (ld === undefined || ld.options === undefined) return {};
317
+ this.debug(`getOptions for ${dev_id} : ${JSON.stringify(ld.options)}`);
318
+ return ld.options;
319
+ }
320
+
298
321
  }
299
322
 
300
323
  module.exports = localConfig;
package/lib/networkmap.js CHANGED
@@ -9,6 +9,7 @@ class NetworkMap {
9
9
  start(zbController, stController) {
10
10
  this.zbController = zbController;
11
11
  this.stController = stController;
12
+ return this.stop;
12
13
  }
13
14
 
14
15
  stop() {
@@ -53,4 +54,4 @@ class NetworkMap {
53
54
  }
54
55
  }
55
56
 
56
- module.exports = NetworkMap;
57
+ module.exports = NetworkMap;
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);