iobroker.zigbee 1.7.5 → 1.8.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 (50) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +22 -29
  3. package/admin/admin.js +494 -469
  4. package/admin/i18n/de/translations.json +108 -0
  5. package/admin/i18n/en/translations.json +108 -0
  6. package/admin/i18n/es/translations.json +102 -0
  7. package/admin/i18n/fr/translations.json +108 -0
  8. package/admin/i18n/it/translations.json +102 -0
  9. package/admin/i18n/nl/translations.json +108 -0
  10. package/admin/i18n/pl/translations.json +108 -0
  11. package/admin/i18n/pt/translations.json +102 -0
  12. package/admin/i18n/ru/translations.json +108 -0
  13. package/admin/i18n/uk/translations.json +108 -0
  14. package/admin/i18n/zh-cn/translations.json +102 -0
  15. package/admin/index_m.html +1 -1
  16. package/admin/tab_m.html +44 -3
  17. package/admin/words.js +107 -108
  18. package/io-package.json +326 -357
  19. package/lib/backup.js +2 -2
  20. package/lib/binding.js +23 -24
  21. package/lib/colors.js +16 -14
  22. package/lib/commands.js +89 -82
  23. package/lib/developer.js +6 -7
  24. package/lib/devices.js +145 -154
  25. package/lib/exclude.js +30 -36
  26. package/lib/exposes.js +106 -111
  27. package/lib/groups.js +53 -54
  28. package/lib/json.js +3 -4
  29. package/lib/networkmap.js +2 -2
  30. package/lib/ota.js +23 -15
  31. package/lib/rgb.js +47 -44
  32. package/lib/seriallist.js +21 -10
  33. package/lib/states.js +488 -498
  34. package/lib/statescontroller.js +170 -164
  35. package/lib/utils.js +22 -21
  36. package/lib/zbBaseExtension.js +4 -4
  37. package/lib/zbDelayedAction.js +5 -13
  38. package/lib/zbDeviceAvailability.js +47 -44
  39. package/lib/zbDeviceConfigure.js +18 -23
  40. package/lib/zbDeviceEvent.js +3 -4
  41. package/lib/zigbeecontroller.js +97 -100
  42. package/main.js +149 -133
  43. package/package.json +33 -19
  44. package/.eslintignore +0 -2
  45. package/.eslintrc.json +0 -37
  46. package/.github/FUNDING.yml +0 -3
  47. package/.github/stale.yml +0 -13
  48. package/.github/workflows/test-and-release.yml +0 -151
  49. package/.travis/wiki.sh +0 -28
  50. package/admin/adapter-settings.js +0 -244
@@ -7,9 +7,8 @@ const getZbId = require('./utils').getZbId;
7
7
  const fs = require('fs');
8
8
  const request = require('request');
9
9
 
10
- var savedDeviceNames = {};
11
- var knownUndefinedDevices = {};
12
-
10
+ let savedDeviceNames = {};
11
+ let knownUndefinedDevices = {};
13
12
 
14
13
  class StatesController extends EventEmitter {
15
14
  constructor(adapter) {
@@ -18,19 +17,16 @@ class StatesController extends EventEmitter {
18
17
  this.adapter.on('stateChange', this.onStateChange.bind(this));
19
18
  this.query_device_block = [];
20
19
  this.debugDevices = undefined;
21
- let fn = adapter.expandFileName('dev_names.json');
20
+ const fn = adapter.expandFileName('dev_names.json');
22
21
  this.dev_names_fn = fn.replace('.', '_');
23
22
  this.retTimeoutHandle = null;
24
23
  fs.readFile(this.dev_names_fn, (err, data) => {
25
24
  if (!err) {
26
- try
27
- {
25
+ try {
28
26
  savedDeviceNames = JSON.parse(data);
29
- }
30
- catch
31
- {
27
+ } catch {
32
28
  savedDeviceNames = {};
33
- };
29
+ }
34
30
  }
35
31
  });
36
32
  }
@@ -55,68 +51,77 @@ class StatesController extends EventEmitter {
55
51
  this.adapter.sendError(error, message);
56
52
  }
57
53
 
58
- retainDeviceNames()
59
- {
54
+ retainDeviceNames() {
60
55
  clearTimeout(this.retTimeoutHandle);
61
- this.retTimeoutHanlde = setTimeout(()=> {
62
- fs.writeFile(this.dev_names_fn, JSON.stringify(savedDeviceNames, null, 2), (err) => {
63
- if (err)
64
- this.error('error saving device names: ' + JSON.Stringify(err));
65
- else
56
+ this.retTimeoutHanlde = setTimeout(() => {
57
+ fs.writeFile(this.dev_names_fn, JSON.stringify(savedDeviceNames, null, 2), err => {
58
+ if (err) {
59
+ this.error(`error saving device names: ${JSON.stringify(err)}`);
60
+ } else {
66
61
  this.debug('saved device names');
67
- });},5000);
62
+ }
63
+ });
64
+ }, 5000);
68
65
  }
69
66
 
70
67
  getDebugDevices() {
71
68
  this.debugDevices = [];
72
- this.adapter.getState(this.adapter.namespace + '.info.debugmessages', (err, state) => {
69
+ this.adapter.getState(`${this.adapter.namespace}.info.debugmessages`, (err, state) => {
73
70
  if (state) {
74
- if (typeof(state.val) == 'string' && state.val.length > 2) this.debugDevices = state.val.split(';');
75
- this.info('debug devices set to ' + JSON.stringify(this.debugDevices));
71
+ if (typeof(state.val) == 'string' && state.val.length > 2) {
72
+ this.debugDevices = state.val.split(';');
73
+ }
74
+ this.info(`debug devices set to ${JSON.stringify(this.debugDevices)}`);
76
75
  } else {
77
76
  this.adapter.setObject('info.debugmessages', {
78
- 'type': 'state',
79
- 'common': {
80
- 'name': 'Log changes as warnings for',
81
- 'role': '',
82
- 'type': 'string',
83
- 'read': true,
84
- 'write': true,
77
+ type: 'state',
78
+ common: {
79
+ name: 'Log changes as warnings for',
80
+ role: '',
81
+ type: 'string',
82
+ read: true,
83
+ write: true,
85
84
  },
86
- 'native': {},
85
+ native: {},
87
86
  });
88
87
  }
89
88
  });
90
89
  this.adapter.setObject('info.undefinedDevices', {
91
- 'type': 'state',
92
- 'common': {
93
- 'name': 'Recorded undefined devices',
94
- 'role': '',
95
- 'type': 'string',
96
- 'read': true,
97
- 'write': false,
90
+ type: 'state',
91
+ common: {
92
+ name: 'Recorded undefined devices',
93
+ role: '',
94
+ type: 'string',
95
+ read: true,
96
+ write: false,
98
97
  },
99
- 'native': {},
98
+ native: {},
100
99
  });
101
100
  this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
102
101
  }
103
102
 
104
103
  onStateChange(id, state){
105
- if (!this.adapter.zbController || !this.adapter.zbController.connected()) return;
106
- if (this.debugDevices === undefined) this.getDebugDevices();
104
+ if (!this.adapter.zbController || !this.adapter.zbController.connected()) {
105
+ return;
106
+ }
107
+ if (this.debugDevices === undefined) {
108
+ this.getDebugDevices();
109
+ }
107
110
  if (state && !state.ack) {
108
- if (id.endsWith('pairingCountdown') || id.endsWith('pairingMessage') || id.endsWith('connection')) return;
111
+ if (id.endsWith('pairingCountdown') || id.endsWith('pairingMessage') || id.endsWith('connection')) {
112
+ return;
113
+ }
109
114
  if (id.endsWith('debugmessages')) {
110
- if (typeof(state.val) == 'string' && state.val.length > 2)
115
+ if (typeof(state.val) == 'string' && state.val.length > 2) {
111
116
  this.debugDevices = state.val.split(';');
112
- else {
117
+
118
+ } else {
113
119
  this.debugDevices = [];
114
120
  }
115
121
  return;
116
122
  }
117
123
  for (const addressPart of this.debugDevices) {
118
- if (typeof(id) == 'string' && id.indexOf(addressPart) > -1)
119
- {
124
+ if (typeof(id) == 'string' && id.indexOf(addressPart) > -1) {
120
125
  this.warn(`ELEVATED: User stateChange ${id} ${JSON.stringify(state)}`);
121
126
  break;
122
127
  }
@@ -134,7 +139,9 @@ class StatesController extends EventEmitter {
134
139
  this.adapter.getObject(devId, (err, obj) => {
135
140
  if (obj) {
136
141
  const model = obj.common.type;
137
- if (!model) return;
142
+ if (!model) {
143
+ return;
144
+ }
138
145
  if (obj.common.deactivated) {
139
146
  this.debug('State Change detected on deactivated Device - ignored');
140
147
  return;
@@ -142,9 +149,8 @@ class StatesController extends EventEmitter {
142
149
  if (model === 'group') {
143
150
  deviceId = parseInt(deviceId.replace('0xgroup_', ''));
144
151
  }
145
- this.collectOptions(id.split('.')[2], model, options => {
146
- this.publishFromState(deviceId, model, stateKey, state, options);
147
- });
152
+ this.collectOptions(id.split('.')[2], model, options =>
153
+ this.publishFromState(deviceId, model, stateKey, state, options));
148
154
  }
149
155
  });
150
156
  }
@@ -158,7 +164,7 @@ class StatesController extends EventEmitter {
158
164
  callback(result);
159
165
  return;
160
166
  }
161
- const states = devStates.states.filter((statedesc) => statedesc.isOption || statedesc.inOptions);
167
+ const states = devStates.states.filter(statedesc => statedesc.isOption || statedesc.inOptions);
162
168
  if (!states) {
163
169
  callback(result);
164
170
  return;
@@ -167,7 +173,7 @@ class StatesController extends EventEmitter {
167
173
  try {
168
174
  const len = states.length;
169
175
  states.forEach(statedesc => {
170
- const id = this.adapter.namespace + '.' + devId + '.' + statedesc.id;
176
+ const id = `${this.adapter.namespace}.${devId}.${statedesc.id}`;
171
177
  this.adapter.getState(id, (err, state) => {
172
178
  cnt = cnt + 1;
173
179
  if (!err && state) {
@@ -178,16 +184,18 @@ class StatesController extends EventEmitter {
178
184
  }
179
185
  });
180
186
  });
181
- if (!len) callback(result);
182
- } catch (error) {
187
+ if (!len) {
188
+ callback(result);
189
+ }
190
+ } catch (error) {
183
191
  this.sendError(error);
184
192
  this.error(`Error collectOptions for ${devId}. Error: ${error.stack}`);
185
- }
193
+ }
186
194
  }
187
195
 
188
196
  async getDevStates(deviceId, model) {
189
197
  try {
190
- let states = [];
198
+ let states;
191
199
  let stateModel;
192
200
  if (model === 'group') {
193
201
  states = statesMapping.groupStates;
@@ -200,7 +208,7 @@ class StatesController extends EventEmitter {
200
208
  }
201
209
  else {
202
210
  knownUndefinedDevices[deviceId] = 1;
203
- this.error('Device ' + deviceId + ' "' + model + '" not described in statesMapping.');
211
+ this.error(`Device ${deviceId} "${model}" not described in statesMapping.`);
204
212
  }
205
213
  this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
206
214
  states = statesMapping.commonStates;
@@ -209,11 +217,12 @@ class StatesController extends EventEmitter {
209
217
  }
210
218
  if (typeof states === 'function' && !states.prototype) {
211
219
  const entity = await this.adapter.zbController.resolveEntity(deviceId);
212
- if (entity)
220
+ if (entity) {
213
221
  states = states(entity);
222
+ }
214
223
  }
215
224
  }
216
- return {states: states, stateModel: stateModel};
225
+ return {states, stateModel};
217
226
  } catch (error) {
218
227
  this.sendError(error);
219
228
  this.error(`Error getDevStates for ${deviceId}. Error: ${error.stack}`);
@@ -224,8 +233,7 @@ class StatesController extends EventEmitter {
224
233
  if (this.debugDevices === undefined) this.getDebugDevices();
225
234
  this.debug(`Change state '${stateKey}' at device ${deviceId} type '${model}'`);
226
235
  for (const addressPart of this.debugDevices) {
227
- if (typeof(deviceId) == 'string' && deviceId.indexOf(addressPart) > -1)
228
- {
236
+ if (typeof(deviceId) == 'string' && deviceId.includes(addressPart)) {
229
237
  this.warn(`ELEVATED Change state '${stateKey}' at device ${deviceId} type '${model}'`);
230
238
  break;
231
239
  }
@@ -234,8 +242,8 @@ class StatesController extends EventEmitter {
234
242
  if (!devStates) {
235
243
  return;
236
244
  }
237
- const commonStates = statesMapping.commonStates.find((statedesc) => stateKey === statedesc.id);
238
- const stateDesc = (commonStates === undefined ? devStates.states.find((statedesc) => stateKey === statedesc.id) : commonStates);
245
+ const commonStates = statesMapping.commonStates.find(statedesc => stateKey === statedesc.id);
246
+ const stateDesc = (commonStates === undefined ? devStates.states.find(statedesc => stateKey === statedesc.id) : commonStates);
239
247
  const stateModel = devStates.stateModel;
240
248
  if (!stateDesc) {
241
249
  this.error(`No state available for '${model}' with key '${stateKey}'`);
@@ -243,11 +251,12 @@ class StatesController extends EventEmitter {
243
251
  }
244
252
 
245
253
  const value = state.val;
246
- if (value === undefined || value === '')
254
+ if (value === undefined || value === '') {
247
255
  return;
256
+ }
248
257
  let stateList = [{stateDesc: stateDesc, value: value, index: 0, timeout: 0}];
249
258
  if (stateModel && stateModel.linkedStates) {
250
- stateModel.linkedStates.forEach((linkedFunct) => {
259
+ stateModel.linkedStates.forEach(linkedFunct => {
251
260
  try {
252
261
  if (typeof linkedFunct === 'function') {
253
262
  const res = linkedFunct(stateDesc, value, options, this.adapter.config.disableQueue);
@@ -256,7 +265,7 @@ class StatesController extends EventEmitter {
256
265
  }
257
266
  }
258
267
  else {
259
- this.warn('publish from State - LinkedState is not a function ' + JSON.stringify(linkedFunct));
268
+ this.warn(`publish from State - LinkedState is not a function ${JSON.stringify(linkedFunct)}`);
260
269
  }
261
270
  } catch (e) {
262
271
  this.sendError(e);
@@ -265,17 +274,14 @@ class StatesController extends EventEmitter {
265
274
 
266
275
  });
267
276
  // sort by index
268
- stateList.sort((a, b) => {
269
- return a.index - b.index;
270
- });
277
+ stateList.sort((a, b) => a.index - b.index);
271
278
  }
272
279
 
273
- // holds the states for for read after write requests
280
+ // holds the states for read after write requests
274
281
  let readAfterWriteStates = [];
275
282
  if (stateModel && stateModel.readAfterWriteStates) {
276
- stateModel.readAfterWriteStates.forEach((readAfterWriteStateDesc) => {
277
- readAfterWriteStates = readAfterWriteStates.concat(readAfterWriteStateDesc.id);
278
- });
283
+ stateModel.readAfterWriteStates.forEach((readAfterWriteStateDesc) =>
284
+ readAfterWriteStates = readAfterWriteStates.concat(readAfterWriteStateDesc.id));
279
285
  }
280
286
 
281
287
  this.emit('changed', deviceId, model, stateModel, stateList, options);
@@ -287,42 +293,42 @@ class StatesController extends EventEmitter {
287
293
  }
288
294
 
289
295
  setDeviceActivated(id, active) {
290
- this.adapter.extendObject(id, {common: {deactivated: active }})
296
+ this.adapter.extendObject(id, {common: {deactivated: active }})
291
297
  }
292
298
 
293
299
  storeDeviceName(id, name) {
294
- savedDeviceNames[id.replace(`${this.adapter.namespace}.`, '')] = name;
295
- this.retainDeviceNames();
300
+ savedDeviceNames[id.replace(`${this.adapter.namespace}.`, '')] = name;
301
+ this.retainDeviceNames();
296
302
  }
297
303
 
298
304
  verifyDeviceName(id, name) {
299
- const savedId = id.replace(`${this.adapter.namespace}.`, '');
300
- if (!savedDeviceNames.hasOwnProperty(savedId)) {
301
- savedDeviceNames[savedId] = name;
302
- this.retainDeviceNames();
303
- }
304
- return savedDeviceNames[savedId];
305
+ const savedId = id.replace(`${this.adapter.namespace}.`, '');
306
+ if (!savedDeviceNames.hasOwnProperty(savedId)) {
307
+ savedDeviceNames[savedId] = name;
308
+ this.retainDeviceNames();
309
+ }
310
+ return savedDeviceNames[savedId];
305
311
  }
306
312
 
307
313
  deleteDeviceStates(devId, callback) {
308
314
  this.adapter.getStatesOf(devId, (err, states) => {
309
315
  if (!err && states) {
310
- states.forEach((state) => {
311
- this.adapter.deleteState(devId, null, state._id);
312
- });
316
+ states.forEach(state =>
317
+ this.adapter.deleteState(devId, null, state._id));
313
318
  }
314
- this.adapter.deleteDevice(devId, () => {
315
- callback && callback();
316
- });
319
+ this.adapter.deleteDevice(devId, () =>
320
+ callback && callback());
317
321
  });
318
322
  }
319
323
 
320
324
  async deleteDeviceStatesAsync(devId) {
321
- const states = await this.adapter.getStatesOf(devId);
322
- if (states) {
323
- await this.adapter.deleteState(devId, null, state._id);
324
- }
325
- await this.adapter.deleteDevice(devId);
325
+ const states = await this.adapter.getStatesOf(devId);
326
+ if (states) {
327
+ for (const state of states) {
328
+ await this.adapter.deleteState(devId, null, state._id);
329
+ }
330
+ }
331
+ await this.adapter.deleteDevice(devId);
326
332
  }
327
333
 
328
334
  // eslint-disable-next-line no-unused-vars
@@ -342,16 +348,16 @@ class StatesController extends EventEmitter {
342
348
  } else {
343
349
  statename = arr[1];
344
350
  }
345
- if (commonStates.find((statedesc) => statename === statedesc.id) === undefined &&
346
- devStates.states.find((statedesc) => statename === statedesc.id) === undefined) {
351
+ if (commonStates.find(statedesc => statename === statedesc.id) === undefined &&
352
+ devStates.states.find(statedesc => statename === statedesc.id) === undefined
353
+ ) {
347
354
  if (state.common.hasOwnProperty('custom') && !force) {
348
355
  this.info(`keeping disconnected state ${JSON.stringify(statename)} of ${devId} `);
349
356
  } else {
350
357
  this.info(`deleting disconnected state ${JSON.stringify(statename)} of ${devId} `);
351
358
  this.adapter.deleteState(devId, null, state._id);
352
359
  }
353
- }
354
- else {
360
+ } else {
355
361
  this.debug(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `);
356
362
  }
357
363
  });
@@ -408,10 +414,11 @@ class StatesController extends EventEmitter {
408
414
  let hasChanges = false;
409
415
  if (stobj) {
410
416
  // update state - not change name and role (user can it changed)
411
- if (stobj.common.name)
417
+ if (stobj.common.name) {
412
418
  delete new_common.name;
413
- else
414
- new_common.name = new_name + ' ' + new_common.name;
419
+ } else {
420
+ new_common.name = `${new_name} ${new_common.name}`;
421
+ }
415
422
  delete new_common.role;
416
423
 
417
424
  // check whether any common property is different
@@ -432,9 +439,8 @@ class StatesController extends EventEmitter {
432
439
 
433
440
  // only change object when any common property has changed
434
441
  if (hasChanges) {
435
- this.adapter.extendObject(id, {type: 'state', common: new_common, native: {} }, () => {
436
- value !== undefined && this.setState_typed(id, value, true, (stobj) ? stobj.common.type : new_common.type);
437
- });
442
+ this.adapter.extendObject(id, {type: 'state', common: new_common, native: {} }, () =>
443
+ value !== undefined && this.setState_typed(id, value, true, stobj ? stobj.common.type : new_common.type));
438
444
  } else if (value !== undefined) {
439
445
  this.setState_typed(id, value, true, stobj.common.type);
440
446
  }
@@ -453,19 +459,19 @@ class StatesController extends EventEmitter {
453
459
  // never set a null or undefined value
454
460
  if (value === null || value === undefined) return;
455
461
  if (!type) {
456
- this.debug("SetState_typed called without type");
462
+ this.debug('SetState_typed called without type');
457
463
  // identify datatype, recursively call this function with set datatype
458
464
  this.adapter.getObject(id, (err, obj) => {
459
- if (obj && obj.common)
460
- this.setState_typed(id, value, ack, obj.common.type, callback);
461
- else {
465
+ if (obj && obj.common) {
466
+ this.setState_typed(id, value, ack, obj.common.type, callback);
467
+ } else {
462
468
  this.setState_typed(id, value, ack, 'noobj', callback);
463
469
  }
464
470
  });
465
471
  return;
466
472
  }
467
- if (typeof value != type) {
468
- this.debug("SetState_typed : converting " + JSON.stringify(value) + " for " + id + " from " + typeof value + " to " + type);
473
+ if (typeof value !== type) {
474
+ this.debug(`SetState_typed : converting ${JSON.stringify(value)} for ${id} from ${typeof value} to ${type}`);
469
475
  switch (type) {
470
476
  case 'number':
471
477
  value = parseFloat(value);
@@ -473,13 +479,14 @@ class StatesController extends EventEmitter {
473
479
  break;
474
480
  case 'string':
475
481
  case 'text': value = JSON.stringify(value); break;
476
- case 'boolean':
482
+ case 'boolean': {
477
483
  if (typeof value == 'number') {
478
- value = (value != 0);
484
+ value = value !== 0;
479
485
  break;
480
486
  }
481
487
  const sval = JSON.stringify(value).toLowerCase().trim();
482
- value = (sval == 'true' || sval == 'yes' || sval == 'on');
488
+ value = sval === 'true' || sval === 'yes' || sval === 'on';
489
+ }
483
490
  break;
484
491
  }
485
492
  }
@@ -491,27 +498,27 @@ class StatesController extends EventEmitter {
491
498
  const id = '' + dev_id;
492
499
  const modelDesc = statesMapping.findModel(model);
493
500
  let icon = (modelDesc && modelDesc.icon) ? modelDesc.icon : 'img/unknown.png';
494
-
501
+
495
502
  // download icon if it external and not undef
496
- if (model === undefined) {
503
+ if (model === undefined) {
497
504
  this.warn(`download icon ${__dev_name} for undefined Device not available. Check your devices.`);
498
505
  } else {
499
- const model_modif = model.replace(/\//g, '-');
500
- const pathToIcon = this.adapter.adapterDir + '/admin/img/' + model_modif + '.png';
506
+ const model_modif = model.replace(/\//g, '-');
507
+ const pathToIcon = `${this.adapter.adapterDir}/admin/img/${model_modif}.png`;
501
508
 
502
- if (icon.startsWith('http')) {
503
- try {
509
+ if (icon.startsWith('http')) {
510
+ try {
504
511
  if (!fs.existsSync(pathToIcon)) {
505
512
  this.warn(`download icon from ${icon} saved into ${pathToIcon}`);
506
- this.downloadIcon(icon, pathToIcon);
513
+ this.downloadIcon(icon, pathToIcon);
507
514
  }
508
- icon = 'img/' + model_modif + '.png';
515
+ icon = `img/${model_modif}.png`;
509
516
  } catch (e) {
510
517
  this.debug(`ERROR : icon not found from ${icon} saved into ${pathToIcon}`);
511
518
  }
512
519
  }
513
520
  }
514
-
521
+
515
522
  this.adapter.setObjectNotExists(id, {
516
523
  type: 'device',
517
524
  // actually this is an error, so device.common has no attribute type. It must be in native part
@@ -524,27 +531,22 @@ class StatesController extends EventEmitter {
524
531
  }
525
532
 
526
533
  async downloadIcon(url, image_path) {
527
- if (!fs.existsSync(image_path)) {
528
- return new Promise((resolve, reject) => {
529
- request.head(url, function (err, res, body) {
530
- if (err) {
531
- return reject(err);
532
- }
533
- let stream = request(url);
534
- stream.pipe(
535
- fs.createWriteStream(image_path)
536
- .on('error', err => {
537
- reject(err);
538
- })
539
- )
540
- .on('close', function () {
541
- resolve();
542
- });
543
- });
544
- });
545
- }
534
+ if (!fs.existsSync(image_path)) {
535
+ return new Promise((resolve, reject) => {
536
+ request.head(url, (err, res, body) => {
537
+ if (err) {
538
+ return reject(err);
539
+ }
540
+ const stream = request(url);
541
+ stream.pipe(
542
+ fs.createWriteStream(image_path)
543
+ .on('error', err => reject(err)))
544
+ .on('close', () => resolve());
545
+ });
546
+ });
547
+ }
546
548
  }
547
-
549
+
548
550
  async syncDevStates(dev, model) {
549
551
  const devId = dev.ieeeAddr.substr(2);
550
552
  // devId - iobroker device id
@@ -555,20 +557,25 @@ class StatesController extends EventEmitter {
555
557
  const states = statesMapping.commonStates.concat(devStates.states);
556
558
 
557
559
  for (const stateInd in states) {
558
- if (!states.hasOwnProperty(stateInd)) continue;
560
+ if (!states.hasOwnProperty(stateInd)) {
561
+ continue;
562
+ }
559
563
 
560
564
  const statedesc = states[stateInd];
561
- if (statedesc === undefined)
562
- {
565
+ if (statedesc === undefined) {
563
566
  this.error(`syncDevStates: Illegal state in ${JSON.stringify(dev)} - ${JSON.stringify(stateInd)}`);
564
567
  return;
565
568
  }
566
569
  // Filter out non routers or devices that are battery driven for the availability flag
567
- if (statedesc.id === 'available')
568
- if (!(dev.type === 'Router') || dev.powerSource === 'Battery')
570
+ if (statedesc.id === 'available') {
571
+ if (!(dev.type === 'Router') || dev.powerSource === 'Battery') {
569
572
  continue;
573
+ }
574
+ }
570
575
  // lazy states
571
- if (statedesc.lazy) continue;
576
+ if (statedesc.lazy) {
577
+ continue;
578
+ }
572
579
 
573
580
  const common = {
574
581
  name: statedesc.name,
@@ -586,19 +593,16 @@ class StatesController extends EventEmitter {
586
593
  }
587
594
  }
588
595
 
589
-
590
596
  async getExcludeExposes(allExcludesObj) {
591
597
  statesMapping.fillStatesWithExposes(allExcludesObj);
592
598
  }
593
599
 
594
-
595
600
  async publishToState(devId, model, payload) {
596
- const devStates = await this.getDevStates('0x'+devId, model);
601
+ const devStates = await this.getDevStates(`0x${devId}`, model);
597
602
  let has_debug=false;
598
603
  if (this.debugDevices === undefined) this.getDebugDevices();
599
604
  for (const addressPart of this.debugDevices) {
600
- if (typeof(devId) == 'string' && devId.indexOf(addressPart) > -1)
601
- {
605
+ if (typeof(devId) == 'string' && devId.includes(addressPart)) {
602
606
  if (payload.hasOwnProperty('msg_from_zigbee')) break;
603
607
  this.warn(`ELEVATED publishToState: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`);
604
608
  has_debug = true;
@@ -611,8 +615,8 @@ class StatesController extends EventEmitter {
611
615
  // find states for payload
612
616
  if (devStates.states !== undefined) {
613
617
  const states = statesMapping.commonStates.concat(
614
- devStates.states.filter((statedesc) => payload.hasOwnProperty(statedesc.prop || statedesc.id))
615
- );
618
+ devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)));
619
+
616
620
  for (const stateInd in states) {
617
621
  const statedesc = states[stateInd];
618
622
  let value;
@@ -622,10 +626,12 @@ class StatesController extends EventEmitter {
622
626
  value = payload[statedesc.prop || statedesc.id];
623
627
  }
624
628
  // checking value
625
- if (value === undefined || value === null) continue;
629
+ if (value === undefined || value === null) {
630
+ continue;
631
+ }
626
632
  let stateID = statedesc.id;
627
633
 
628
- if (has_debug && statedesc.id != 'msg_from_zigbee') {
634
+ if (has_debug && statedesc.id !== 'msg_from_zigbee') {
629
635
  this.warn(`ELEVATED publishToState: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`);
630
636
  }
631
637
 
@@ -640,24 +646,24 @@ class StatesController extends EventEmitter {
640
646
  min: statedesc.min,
641
647
  max: statedesc.max,
642
648
  };
643
- if ( (typeof(value)== 'object') && (value.hasOwnProperty('stateid'))) {
644
- stateID = stateID + '.' + value.stateid;
645
- if (value.hasOwnProperty('unit')) common.unit = value.unit;
649
+ if (typeof value === 'object' && value.hasOwnProperty('stateid')) {
650
+ stateID = `${stateID}.${value.stateid}`;
651
+ if (value.hasOwnProperty('unit')) {
652
+ common.unit = value.unit;
653
+ }
646
654
  common.name = (value.name? value.name:value.stateid);
647
- common.role = (value.role ? 'value.'+value.role:'number');
655
+ common.role = (value.role ? `value.${value.role}` : 'number');
648
656
  value = value.value;
649
657
 
650
658
  }
651
- // if need return value to back after timeout
659
+ // if needs to return value to back after timeout
652
660
  if (statedesc.isEvent) {
653
661
  this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, !value);
654
662
  } else {
655
663
  if (statedesc.prepublish) {
656
- this.collectOptions(devId, model, (options) => {
657
- statedesc.prepublish(devId, value, (newvalue) => {
658
- this.updateState(devId, stateID, newvalue, common);
659
- }, options);
660
- });
664
+ this.collectOptions(devId, model, options =>
665
+ statedesc.prepublish(devId, value, newvalue =>
666
+ this.updateState(devId, stateID, newvalue, common), options));
661
667
  } else {
662
668
  this.updateState(devId, stateID, value, common);
663
669
  }