iobroker.zigbee 1.8.3 → 1.8.7

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 (87) hide show
  1. package/README.md +6 -0
  2. package/admin/adapter-settings.js +244 -0
  3. package/admin/admin.js +520 -494
  4. package/admin/index_m.html +1171 -1001
  5. package/admin/tab_m.html +44 -2
  6. package/docs/de/img/CC2531.png +0 -0
  7. package/docs/de/img/CC2538_CC2592_PA.PNG +0 -0
  8. package/docs/de/img/CC2591.png +0 -0
  9. package/docs/de/img/boards.jpg +0 -0
  10. package/docs/de/img/cc26x2r.PNG +0 -0
  11. package/docs/de/img/results.jpg +0 -0
  12. package/docs/de/img/sku_429478_2.png +0 -0
  13. package/docs/de/img/sku_429601_2.png +0 -0
  14. package/docs/de/readme.md +27 -0
  15. package/docs/en/img/CC2531.png +0 -0
  16. package/docs/en/img/CC2591.png +0 -0
  17. package/docs/en/img/deconz.png +0 -0
  18. package/docs/en/img/sku_429478_2.png +0 -0
  19. package/docs/en/img/sku_429601_2.png +0 -0
  20. package/docs/en/readme.md +30 -0
  21. package/docs/flashing_via_arduino_(en).md +110 -0
  22. package/docs/ru/img/CC2531.png +0 -0
  23. package/docs/ru/img/CC2591.png +0 -0
  24. package/docs/ru/img/sku_429478_2.png +0 -0
  25. package/docs/ru/img/sku_429601_2.png +0 -0
  26. package/docs/ru/readme.md +28 -0
  27. package/docs/tutorial/CC2530_20190425.zip +0 -0
  28. package/docs/tutorial/CC2530_CC2591_20190515.zip +0 -0
  29. package/docs/tutorial/CC2530_CC2592_20190515.zip +0 -0
  30. package/docs/tutorial/CC2531_20190425.zip +0 -0
  31. package/docs/tutorial/adm5_1.PNG +0 -0
  32. package/docs/tutorial/adm5_2.PNG +0 -0
  33. package/docs/tutorial/cat.PNG +0 -0
  34. package/docs/tutorial/groups-1.png +0 -0
  35. package/docs/tutorial/groups-2.png +0 -0
  36. package/docs/tutorial/inst.PNG +0 -0
  37. package/docs/tutorial/reflash-finish.PNG +0 -0
  38. package/docs/tutorial/reflash-step0.png +0 -0
  39. package/docs/tutorial/reflash-step1.PNG +0 -0
  40. package/docs/tutorial/reflash-step2.PNG +0 -0
  41. package/docs/tutorial/settings.png +0 -0
  42. package/docs/tutorial/tab-dev-1.png +0 -0
  43. package/docs/tutorial/zigbee.png +0 -0
  44. package/docs/tutorial/zigbee15.png +0 -0
  45. package/io-package.json +34 -33
  46. package/lib/backup.js +2 -2
  47. package/lib/binding.js +32 -37
  48. package/lib/colors.js +163 -158
  49. package/lib/commands.js +100 -91
  50. package/lib/developer.js +9 -12
  51. package/lib/devices.js +168 -178
  52. package/lib/exclude.js +30 -36
  53. package/lib/exposes.js +168 -143
  54. package/lib/groups.js +81 -83
  55. package/lib/json.js +5 -6
  56. package/lib/networkmap.js +2 -3
  57. package/lib/ota.js +34 -18
  58. package/lib/rgb.js +114 -72
  59. package/lib/seriallist.js +25 -20
  60. package/lib/statescontroller.js +206 -183
  61. package/lib/utils.js +29 -23
  62. package/lib/zbBaseExtension.js +4 -4
  63. package/lib/zbDelayedAction.js +5 -13
  64. package/lib/zbDeviceAvailability.js +69 -65
  65. package/lib/zbDeviceConfigure.js +9 -21
  66. package/lib/zbDeviceEvent.js +3 -4
  67. package/lib/zigbeecontroller.js +133 -128
  68. package/main.js +169 -154
  69. package/package.json +28 -14
  70. package/.eslintignore +0 -2
  71. package/.eslintrc.json +0 -37
  72. package/.github/FUNDING.yml +0 -3
  73. package/.github/auto-merge.yml +0 -17
  74. package/.github/dependabot.yml +0 -24
  75. package/.github/stale.yml +0 -13
  76. package/.github/workflows/codeql.yml +0 -41
  77. package/.github/workflows/dependabot-automerge.yml +0 -22
  78. package/.github/workflows/test-and-release.yml +0 -149
  79. package/.releaseconfig.json +0 -3
  80. package/.travis/wiki.sh +0 -28
  81. package/.travis.yml +0 -41
  82. package/gulpfile.js +0 -464
  83. package/test/integration.js +0 -5
  84. package/test/mocha.custom.opts +0 -2
  85. package/test/mocha.setup.js +0 -14
  86. package/test/package.js +0 -5
  87. package/test/unit.js +0 -5
@@ -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
- onStateChange(id, state){
105
- if (!this.adapter.zbController || !this.adapter.zbController.connected()) return;
106
- if (this.debugDevices === undefined) this.getDebugDevices();
103
+ onStateChange(id, state) {
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.includes(addressPart)) {
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
  }
@@ -153,12 +159,12 @@ class StatesController extends EventEmitter {
153
159
  async collectOptions(devId, model, callback) {
154
160
  const result = {};
155
161
  // find model states for options and get it values
156
- const devStates = await this.getDevStates('0x'+devId, model);
162
+ const devStates = await this.getDevStates('0x' + devId, model);
157
163
  if (!devStates) {
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,29 +184,29 @@ 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;
194
202
  } else {
195
203
  stateModel = statesMapping.findModel(model);
196
204
  if (!stateModel) {
197
- if (knownUndefinedDevices[deviceId])
198
- {
205
+ if (knownUndefinedDevices[deviceId]) {
199
206
  knownUndefinedDevices[deviceId]++;
200
- }
201
- else {
207
+ } else {
202
208
  knownUndefinedDevices[deviceId] = 1;
203
- this.error('Device ' + deviceId + ' "' + model + '" not described in statesMapping.');
209
+ this.error(`Device ${deviceId} "${model}" not described in statesMapping.`);
204
210
  }
205
211
  this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
206
212
  states = statesMapping.commonStates;
@@ -209,11 +215,12 @@ class StatesController extends EventEmitter {
209
215
  }
210
216
  if (typeof states === 'function' && !states.prototype) {
211
217
  const entity = await this.adapter.zbController.resolveEntity(deviceId);
212
- if (entity)
218
+ if (entity) {
213
219
  states = states(entity);
220
+ }
214
221
  }
215
222
  }
216
- return {states: states, stateModel: stateModel};
223
+ return {states, stateModel};
217
224
  } catch (error) {
218
225
  this.sendError(error);
219
226
  this.error(`Error getDevStates for ${deviceId}. Error: ${error.stack}`);
@@ -224,8 +231,7 @@ class StatesController extends EventEmitter {
224
231
  if (this.debugDevices === undefined) this.getDebugDevices();
225
232
  this.debug(`Change state '${stateKey}' at device ${deviceId} type '${model}'`);
226
233
  for (const addressPart of this.debugDevices) {
227
- if (typeof(deviceId) == 'string' && deviceId.indexOf(addressPart) > -1)
228
- {
234
+ if (typeof deviceId === 'string' && deviceId.includes(addressPart)) {
229
235
  this.warn(`ELEVATED Change state '${stateKey}' at device ${deviceId} type '${model}'`);
230
236
  break;
231
237
  }
@@ -234,8 +240,8 @@ class StatesController extends EventEmitter {
234
240
  if (!devStates) {
235
241
  return;
236
242
  }
237
- const commonStates = statesMapping.commonStates.find((statedesc) => stateKey === statedesc.id);
238
- const stateDesc = (commonStates === undefined ? devStates.states.find((statedesc) => stateKey === statedesc.id) : commonStates);
243
+ const commonStates = statesMapping.commonStates.find(statedesc => stateKey === statedesc.id);
244
+ const stateDesc = (commonStates === undefined ? devStates.states.find(statedesc => stateKey === statedesc.id) : commonStates);
239
245
  const stateModel = devStates.stateModel;
240
246
  if (!stateDesc) {
241
247
  this.error(`No state available for '${model}' with key '${stateKey}'`);
@@ -243,20 +249,20 @@ class StatesController extends EventEmitter {
243
249
  }
244
250
 
245
251
  const value = state.val;
246
- if (value === undefined || value === '')
252
+ if (value === undefined || value === '') {
247
253
  return;
254
+ }
248
255
  let stateList = [{stateDesc: stateDesc, value: value, index: 0, timeout: 0}];
249
256
  if (stateModel && stateModel.linkedStates) {
250
- stateModel.linkedStates.forEach((linkedFunct) => {
257
+ stateModel.linkedStates.forEach(linkedFunct => {
251
258
  try {
252
259
  if (typeof linkedFunct === 'function') {
253
260
  const res = linkedFunct(stateDesc, value, options, this.adapter.config.disableQueue);
254
261
  if (res) {
255
262
  stateList = stateList.concat(res);
256
263
  }
257
- }
258
- else {
259
- this.warn('publish from State - LinkedState is not a function ' + JSON.stringify(linkedFunct));
264
+ } else {
265
+ this.warn(`publish from State - LinkedState is not a function ${JSON.stringify(linkedFunct)}`);
260
266
  }
261
267
  } catch (e) {
262
268
  this.sendError(e);
@@ -265,17 +271,14 @@ class StatesController extends EventEmitter {
265
271
 
266
272
  });
267
273
  // sort by index
268
- stateList.sort((a, b) => {
269
- return a.index - b.index;
270
- });
274
+ stateList.sort((a, b) => a.index - b.index);
271
275
  }
272
276
 
273
- // holds the states for for read after write requests
277
+ // holds the states for read after write requests
274
278
  let readAfterWriteStates = [];
275
279
  if (stateModel && stateModel.readAfterWriteStates) {
276
- stateModel.readAfterWriteStates.forEach((readAfterWriteStateDesc) => {
277
- readAfterWriteStates = readAfterWriteStates.concat(readAfterWriteStateDesc.id);
278
- });
280
+ stateModel.readAfterWriteStates.forEach((readAfterWriteStateDesc) =>
281
+ readAfterWriteStates = readAfterWriteStates.concat(readAfterWriteStateDesc.id));
279
282
  }
280
283
 
281
284
  this.emit('changed', deviceId, model, stateModel, stateList, options);
@@ -287,42 +290,42 @@ class StatesController extends EventEmitter {
287
290
  }
288
291
 
289
292
  setDeviceActivated(id, active) {
290
- this.adapter.extendObject(id, {common: {deactivated: active }})
293
+ this.adapter.extendObject(id, {common: {deactivated: active}});
291
294
  }
292
295
 
293
296
  storeDeviceName(id, name) {
294
- savedDeviceNames[id.replace(`${this.adapter.namespace}.`, '')] = name;
295
- this.retainDeviceNames();
297
+ savedDeviceNames[id.replace(`${this.adapter.namespace}.`, '')] = name;
298
+ this.retainDeviceNames();
296
299
  }
297
300
 
298
301
  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];
302
+ const savedId = id.replace(`${this.adapter.namespace}.`, '');
303
+ if (!savedDeviceNames.hasOwnProperty(savedId)) {
304
+ savedDeviceNames[savedId] = name;
305
+ this.retainDeviceNames();
306
+ }
307
+ return savedDeviceNames[savedId];
305
308
  }
306
309
 
307
310
  deleteDeviceStates(devId, callback) {
308
311
  this.adapter.getStatesOf(devId, (err, states) => {
309
312
  if (!err && states) {
310
- states.forEach((state) => {
311
- this.adapter.deleteState(devId, null, state._id);
312
- });
313
+ states.forEach(state =>
314
+ this.adapter.deleteState(devId, null, state._id));
313
315
  }
314
- this.adapter.deleteDevice(devId, () => {
315
- callback && callback();
316
- });
316
+ this.adapter.deleteDevice(devId, () =>
317
+ callback && callback());
317
318
  });
318
319
  }
319
320
 
320
321
  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);
322
+ const states = await this.adapter.getStatesOf(devId);
323
+ if (states) {
324
+ for (const state of states) {
325
+ await this.adapter.deleteState(devId, null, state._id);
326
+ }
327
+ }
328
+ await this.adapter.deleteDevice(devId);
326
329
  }
327
330
 
328
331
  // eslint-disable-next-line no-unused-vars
@@ -338,20 +341,22 @@ class StatesController extends EventEmitter {
338
341
  if (arr[1] === undefined) {
339
342
  this.warn(`unable to extract id from state ${statename}`);
340
343
  const idx = statename.lastIndexOf('.');
341
- if (idx > -1) statename = statename.slice(idx+1);
344
+ if (idx > -1) {
345
+ statename = statename.slice(idx + 1);
346
+ }
342
347
  } else {
343
348
  statename = arr[1];
344
349
  }
345
- if (commonStates.find((statedesc) => statename === statedesc.id) === undefined &&
346
- devStates.states.find((statedesc) => statename === statedesc.id) === undefined) {
350
+ if (commonStates.find(statedesc => statename === statedesc.id) === undefined &&
351
+ devStates.states.find(statedesc => statename === statedesc.id) === undefined
352
+ ) {
347
353
  if (state.common.hasOwnProperty('custom') && !force) {
348
354
  this.info(`keeping disconnected state ${JSON.stringify(statename)} of ${devId} `);
349
355
  } else {
350
356
  this.info(`deleting disconnected state ${JSON.stringify(statename)} of ${devId} `);
351
357
  this.adapter.deleteState(devId, null, state._id);
352
358
  }
353
- }
354
- else {
359
+ } else {
355
360
  this.debug(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `);
356
361
  }
357
362
  });
@@ -408,10 +413,11 @@ class StatesController extends EventEmitter {
408
413
  let hasChanges = false;
409
414
  if (stobj) {
410
415
  // update state - not change name and role (user can it changed)
411
- if (stobj.common.name)
416
+ if (stobj.common.name) {
412
417
  delete new_common.name;
413
- else
414
- new_common.name = new_name + ' ' + new_common.name;
418
+ } else {
419
+ new_common.name = `${new_name} ${new_common.name}`;
420
+ }
415
421
  delete new_common.role;
416
422
 
417
423
  // check whether any common property is different
@@ -432,54 +438,58 @@ class StatesController extends EventEmitter {
432
438
 
433
439
  // only change object when any common property has changed
434
440
  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
- });
441
+ this.adapter.extendObject(id, {type: 'state', common: new_common, native: {}}, () =>
442
+ value !== undefined && this.setState_typed(id, value, true, stobj ? stobj.common.type : new_common.type));
438
443
  } else if (value !== undefined) {
439
444
  this.setState_typed(id, value, true, stobj.common.type);
440
445
  }
441
446
 
442
447
  });
448
+ } else {
449
+ this.debug(`UpdateState: Device is deactivated ${devId} ${JSON.stringify(obj)}`);
443
450
  }
444
- else this.debug(`UpdateState: Device is deactivated ${devId} ${JSON.stringify(obj)}`);
445
451
  } else {
446
452
  this.debug(`UpdateState: missing device ${devId} ${JSON.stringify(obj)}`);
447
453
  }
448
454
  });
449
455
  }
450
456
 
451
- setState_typed(id, value, ack, type, callback)
452
- {
457
+ setState_typed(id, value, ack, type, callback) {
453
458
  // never set a null or undefined value
454
459
  if (value === null || value === undefined) return;
455
460
  if (!type) {
456
- this.debug("SetState_typed called without type");
461
+ this.debug('SetState_typed called without type');
457
462
  // identify datatype, recursively call this function with set datatype
458
463
  this.adapter.getObject(id, (err, obj) => {
459
- if (obj && obj.common)
460
- this.setState_typed(id, value, ack, obj.common.type, callback);
461
- else {
464
+ if (obj && obj.common) {
465
+ this.setState_typed(id, value, ack, obj.common.type, callback);
466
+ } else {
462
467
  this.setState_typed(id, value, ack, 'noobj', callback);
463
468
  }
464
469
  });
465
470
  return;
466
471
  }
467
- if (typeof value != type) {
468
- this.debug("SetState_typed : converting " + JSON.stringify(value) + " for " + id + " from " + typeof value + " to " + type);
472
+ if (typeof value !== type) {
473
+ this.debug(`SetState_typed : converting ${JSON.stringify(value)} for ${id} from ${typeof value} to ${type}`);
469
474
  switch (type) {
470
475
  case 'number':
471
476
  value = parseFloat(value);
472
- if (isNaN (value)) value = 0;
477
+ if (isNaN(value)) {
478
+ value = 0;
479
+ }
473
480
  break;
474
481
  case 'string':
475
- case 'text': value = JSON.stringify(value); break;
476
- case 'boolean':
482
+ case 'text':
483
+ value = JSON.stringify(value);
484
+ break;
485
+ case 'boolean': {
477
486
  if (typeof value == 'number') {
478
- value = (value != 0);
487
+ value = value !== 0;
479
488
  break;
480
489
  }
481
490
  const sval = JSON.stringify(value).toLowerCase().trim();
482
- value = (sval == 'true' || sval == 'yes' || sval == 'on');
491
+ value = sval === 'true' || sval === 'yes' || sval === 'on';
492
+ }
483
493
  break;
484
494
  }
485
495
  }
@@ -491,60 +501,68 @@ class StatesController extends EventEmitter {
491
501
  const id = '' + dev_id;
492
502
  const modelDesc = statesMapping.findModel(model);
493
503
  let icon = (modelDesc && modelDesc.icon) ? modelDesc.icon : 'img/unknown.png';
494
-
504
+
495
505
  // download icon if it external and not undef
496
- if (model === undefined) {
506
+ if (model === undefined) {
497
507
  this.warn(`download icon ${__dev_name} for undefined Device not available. Check your devices.`);
498
508
  } else {
499
- const model_modif = model.replace(/\//g, '-');
500
- const pathToIcon = this.adapter.adapterDir + '/admin/img/' + model_modif + '.png';
509
+ const model_modif = model.replace(/\//g, '-');
510
+ const pathToIcon = `${this.adapter.adapterDir}/admin/img/${model_modif}.png`;
501
511
 
502
- if (icon.startsWith('http')) {
503
- try {
512
+ if (icon.startsWith('http')) {
513
+ try {
504
514
  if (!fs.existsSync(pathToIcon)) {
505
515
  this.warn(`download icon from ${icon} saved into ${pathToIcon}`);
506
- this.downloadIcon(icon, pathToIcon);
516
+ this.downloadIcon(icon, pathToIcon);
507
517
  }
508
- icon = 'img/' + model_modif + '.png';
518
+ icon = `img/${model_modif}.png`;
509
519
  } catch (e) {
510
520
  this.debug(`ERROR : icon not found from ${icon} saved into ${pathToIcon}`);
511
521
  }
512
522
  }
513
523
  }
514
-
524
+
515
525
  this.adapter.setObjectNotExists(id, {
516
526
  type: 'device',
517
527
  // actually this is an error, so device.common has no attribute type. It must be in native part
518
- common: {name: __dev_name, type: model, icon: icon, color: null, statusStates: {onlineId: `${this.adapter.namespace}.${dev_id}.available`}},
528
+ common: {
529
+ name: __dev_name,
530
+ type: model,
531
+ icon,
532
+ color: null,
533
+ statusStates: {onlineId: `${this.adapter.namespace}.${dev_id}.available`}
534
+ },
519
535
  native: {id: dev_id}
520
536
  }, () => {
521
537
  // update type and icon
522
- this.adapter.extendObject(id, {common: {type: model, icon: icon, color: null, statusStates: {onlineId: `${this.adapter.namespace}.${dev_id}.available`}}}, callback);
538
+ this.adapter.extendObject(id, {
539
+ common: {
540
+ type: model,
541
+ icon,
542
+ color: null,
543
+ statusStates: {onlineId: `${this.adapter.namespace}.${dev_id}.available`}
544
+ }
545
+ }, callback);
523
546
  });
524
547
  }
525
548
 
526
549
  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
- }
550
+ if (!fs.existsSync(image_path)) {
551
+ return new Promise((resolve, reject) => {
552
+ request.head(url, (err, res, body) => {
553
+ if (err) {
554
+ return reject(err);
555
+ }
556
+ const stream = request(url);
557
+ stream.pipe(
558
+ fs.createWriteStream(image_path)
559
+ .on('error', err => reject(err)))
560
+ .on('close', () => resolve());
561
+ });
562
+ });
563
+ }
546
564
  }
547
-
565
+
548
566
  async syncDevStates(dev, model) {
549
567
  const devId = dev.ieeeAddr.substr(2);
550
568
  // devId - iobroker device id
@@ -555,20 +573,25 @@ class StatesController extends EventEmitter {
555
573
  const states = statesMapping.commonStates.concat(devStates.states);
556
574
 
557
575
  for (const stateInd in states) {
558
- if (!states.hasOwnProperty(stateInd)) continue;
576
+ if (!states.hasOwnProperty(stateInd)) {
577
+ continue;
578
+ }
559
579
 
560
580
  const statedesc = states[stateInd];
561
- if (statedesc === undefined)
562
- {
581
+ if (statedesc === undefined) {
563
582
  this.error(`syncDevStates: Illegal state in ${JSON.stringify(dev)} - ${JSON.stringify(stateInd)}`);
564
583
  return;
565
584
  }
566
585
  // 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')
586
+ if (statedesc.id === 'available') {
587
+ if (!(dev.type === 'Router') || dev.powerSource === 'Battery') {
569
588
  continue;
589
+ }
590
+ }
570
591
  // lazy states
571
- if (statedesc.lazy) continue;
592
+ if (statedesc.lazy) {
593
+ continue;
594
+ }
572
595
 
573
596
  const common = {
574
597
  name: statedesc.name,
@@ -586,19 +609,16 @@ class StatesController extends EventEmitter {
586
609
  }
587
610
  }
588
611
 
589
-
590
612
  async getExcludeExposes(allExcludesObj) {
591
613
  statesMapping.fillStatesWithExposes(allExcludesObj);
592
614
  }
593
615
 
594
-
595
616
  async publishToState(devId, model, payload) {
596
- const devStates = await this.getDevStates('0x'+devId, model);
597
- let has_debug=false;
617
+ const devStates = await this.getDevStates(`0x${devId}`, model);
618
+ let has_debug = false;
598
619
  if (this.debugDevices === undefined) this.getDebugDevices();
599
620
  for (const addressPart of this.debugDevices) {
600
- if (typeof(devId) == 'string' && devId.indexOf(addressPart) > -1)
601
- {
621
+ if (typeof devId === 'string' && devId.includes(addressPart)) {
602
622
  if (payload.hasOwnProperty('msg_from_zigbee')) break;
603
623
  this.warn(`ELEVATED publishToState: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`);
604
624
  has_debug = true;
@@ -611,8 +631,8 @@ class StatesController extends EventEmitter {
611
631
  // find states for payload
612
632
  if (devStates.states !== undefined) {
613
633
  const states = statesMapping.commonStates.concat(
614
- devStates.states.filter((statedesc) => payload.hasOwnProperty(statedesc.prop || statedesc.id))
615
- );
634
+ devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)));
635
+
616
636
  for (const stateInd in states) {
617
637
  const statedesc = states[stateInd];
618
638
  let value;
@@ -622,10 +642,12 @@ class StatesController extends EventEmitter {
622
642
  value = payload[statedesc.prop || statedesc.id];
623
643
  }
624
644
  // checking value
625
- if (value === undefined || value === null) continue;
645
+ if (value === undefined || value === null) {
646
+ continue;
647
+ }
626
648
  let stateID = statedesc.id;
627
649
 
628
- if (has_debug && statedesc.id != 'msg_from_zigbee') {
650
+ if (has_debug && statedesc.id !== 'msg_from_zigbee') {
629
651
  this.warn(`ELEVATED publishToState: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`);
630
652
  }
631
653
 
@@ -640,24 +662,25 @@ class StatesController extends EventEmitter {
640
662
  min: statedesc.min,
641
663
  max: statedesc.max,
642
664
  };
643
- if ( (typeof(value)== 'object') && (value.hasOwnProperty('stateid'))) {
644
- stateID = stateID + '.' + value.stateid;
645
- if (value.hasOwnProperty('unit')) common.unit = value.unit;
646
- common.name = (value.name? value.name:value.stateid);
647
- common.role = (value.role ? 'value.'+value.role:'number');
648
- value = value.value;
649
665
 
666
+ if (typeof value === 'object' && value.hasOwnProperty('stateid')) {
667
+ stateID = `${stateID}.${value.stateid}`;
668
+ if (value.hasOwnProperty('unit')) {
669
+ common.unit = value.unit;
670
+ }
671
+ common.name = value.name ? value.name : value.stateid;
672
+ common.role = value.role ? `value.${value.role}` : 'number';
673
+ value = value.value;
650
674
  }
651
- // if need return value to back after timeout
675
+
676
+ // if needs to return value to back after timeout
652
677
  if (statedesc.isEvent) {
653
678
  this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, !value);
654
679
  } else {
655
680
  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
- });
681
+ this.collectOptions(devId, model, options =>
682
+ statedesc.prepublish(devId, value, newvalue =>
683
+ this.updateState(devId, stateID, newvalue, common), options));
661
684
  } else {
662
685
  this.updateState(devId, stateID, value, common);
663
686
  }