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
package/lib/exposes.js CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
4
- const statesDefs = require(__dirname + '/states.js').states;
5
- const rgb = require(__dirname + '/rgb.js');
6
- const utils = require(__dirname + '/utils.js');
7
- const colors = require(__dirname + '/colors.js');
4
+ const statesDefs = require('./states.js').states;
5
+ const rgb = require('./rgb.js');
6
+ const utils = require('./utils.js');
7
+ const colors = require('./colors.js');
8
8
  const ea = zigbeeHerdsmanConverters.exposes.access;
9
9
 
10
10
  function genState(expose, role, name, desc) {
@@ -29,10 +29,9 @@ function genState(expose, role, name, desc) {
29
29
  type: 'boolean',
30
30
  };
31
31
  if (readable) {
32
- state.getter = payload => (payload[propName] === (expose.value_on || 'ON'));
33
- }
34
- else {
35
- state.getter = payload => ( undefined);
32
+ state.getter = payload => payload[propName] === (expose.value_on || 'ON');
33
+ } else {
34
+ state.getter = payload => undefined;
36
35
  }
37
36
  if (writable) {
38
37
  state.setter = (value) => (value) ? (expose.value_on || 'ON') : ((expose.value_off != undefined) ? expose.value_off : 'OFF');
@@ -72,7 +71,7 @@ function genState(expose, role, name, desc) {
72
71
  write: writable,
73
72
  read: true,
74
73
  type: 'string',
75
- states: expose.values.map((item) => `${item}:${item}`).join(';'),
74
+ states: expose.values.map(item => `${item}:${item}`).join(';'),
76
75
  };
77
76
  if (expose.endpoint) {
78
77
  state.epname = expose.endpoint;
@@ -103,8 +102,6 @@ function genState(expose, role, name, desc) {
103
102
  return state;
104
103
  }
105
104
 
106
-
107
-
108
105
  function createFromExposes(model, def) {
109
106
  const states = [];
110
107
  // make the different (set and get) part of state is updatable if different exposes is used for get and set
@@ -121,30 +118,31 @@ function createFromExposes(model, def) {
121
118
  if (state === undefined) {
122
119
  return 0;
123
120
  }
124
- if (access === undefined) access = ea.ALL;
121
+ if (access === undefined) {
122
+ access = ea.ALL;
123
+ }
125
124
  state.readable = (access & ea.STATE) > 0;
126
125
  state.writable = (access & ea.SET) > 0;
127
- const stateExists = states.findIndex( (element, index, array) => (element.id === state.id ));
128
- if (stateExists < 0 ) {
126
+ const stateExists = states.findIndex((element, index, array) => element.id === state.id);
127
+ if (stateExists < 0) {
129
128
  state.write = state.writable;
130
- if (! state.writable) {
131
- if ( state.hasOwnProperty('setter') ) {
129
+ if (!state.writable) {
130
+ if (state.hasOwnProperty('setter')) {
132
131
  delete state.setter;
133
132
  }
134
- if ( state.hasOwnProperty('setattr') ) {
133
+ if (state.hasOwnProperty('setattr')) {
135
134
  delete state.setattr;
136
135
  }
137
136
  }
138
- if (! state.readable) {
139
- if (state.hasOwnProperty('getter') ) {
140
- //to awid some worning on unprocessed data
141
- state.getter = payload => ( undefined );
137
+ if (!state.readable) {
138
+ if (state.hasOwnProperty('getter')) {
139
+ // to awoid some warnings on unprocessed data
140
+ state.getter = payload => undefined;
142
141
  }
143
142
  }
144
143
  return states.push(state);
145
- }
146
- else {
147
- if ( (state.readable) && (! states[stateExists].readable ) ) {
144
+ } else {
145
+ if ((state.readable) && (!states[stateExists].readable)) {
148
146
  states[stateExists].read = state.read;
149
147
  // as state is readable, it can't be button or event
150
148
  if (states[stateExists].role === 'button') {
@@ -154,69 +152,70 @@ function createFromExposes(model, def) {
154
152
  delete states[stateExists].isEvent;
155
153
  }
156
154
  // we have to use the getter from "new" state
157
- if ( state.hasOwnProperty('getter') ) {
155
+ if (state.hasOwnProperty('getter')) {
158
156
  states[stateExists].getter = state.getter;
159
157
  }
160
158
  // trying to remove the `prop` property, as main key for get and set,
161
159
  // as it can be different in new and old states, and leave only:
162
160
  // setattr for old and id for new
163
- if (( state.hasOwnProperty('prop') ) && (state.prop === state.id)) {
164
- if ( states[stateExists].hasOwnProperty('prop') ) {
161
+ if ((state.hasOwnProperty('prop')) && (state.prop === state.id)) {
162
+ if (states[stateExists].hasOwnProperty('prop')) {
165
163
  if (states[stateExists].prop !== states[stateExists].id) {
166
- if (! states[stateExists].hasOwnProperty('setattr')) {
164
+ if (!states[stateExists].hasOwnProperty('setattr')) {
167
165
  states[stateExists].setattr = states[stateExists].prop;
168
166
  }
169
167
  }
170
168
  delete states[stateExists].prop;
171
169
  }
172
- }
173
- else if ( state.hasOwnProperty('prop') ) {
170
+ } else if (state.hasOwnProperty('prop')) {
174
171
  states[stateExists].prop = state.prop;
175
172
  }
176
173
  states[stateExists].readable = true;
177
174
  }
178
- if ( (state.writable) && (! states[stateExists].writable ) ) {
175
+ if ((state.writable) && (!states[stateExists].writable)) {
179
176
  states[stateExists].write = state.writable;
180
177
  // use new state `setter`
181
- if ( state.hasOwnProperty('setter') ) {
178
+ if (state.hasOwnProperty('setter')) {
182
179
  states[stateExists].setter = state.setter;
183
180
  }
184
181
  // use new state `setterOpt`
185
- if ( state.hasOwnProperty('setterOpt') ) {
182
+ if (state.hasOwnProperty('setterOpt')) {
186
183
  states[stateExists].setterOpt = state.setterOpt;
187
184
  }
188
185
  // use new state `inOptions`
189
- if ( state.hasOwnProperty('inOptions') ) {
186
+ if (state.hasOwnProperty('inOptions')) {
190
187
  states[stateExists].inOptions = state.inOptions;
191
188
  }
192
189
  // as we have new state, responsible for set, we have to use new `isOption`
193
190
  // or remove it
194
- if (((! state.hasOwnProperty('isOption') ) || (state.isOptions === false))
195
- && (states[stateExists].hasOwnProperty('isOption'))) {
191
+ if (((!state.hasOwnProperty('isOption')) || (state.isOptions === false))
192
+ && (states[stateExists].hasOwnProperty('isOption'))) {
196
193
  delete states[stateExists].isOption;
197
- }
198
- else {
194
+ } else {
199
195
  states[stateExists].isOption = state.isOption;
200
196
  }
197
+
201
198
  // use new `setattr` or `prop` as `setattr`
202
- if ( state.hasOwnProperty('setattr') ) {
199
+ if (state.hasOwnProperty('setattr')) {
203
200
  states[stateExists].setattr = state.setattr;
204
- }
205
- else if ( state.hasOwnProperty('prop') ) {
201
+ } else if (state.hasOwnProperty('prop')) {
206
202
  states[stateExists].setattr = state.prop;
207
203
  }
204
+
208
205
  // remove `prop` equal to if, due to prop is uses as key in set and get
209
- if ( states[stateExists].prop === states[stateExists].id) {
206
+ if (states[stateExists].prop === states[stateExists].id) {
210
207
  delete states[stateExists].prop;
211
208
  }
212
- if ( state.hasOwnProperty('epname') ) {
209
+ if (state.hasOwnProperty('epname')) {
213
210
  states[stateExists].epname = state.epname;
214
211
  }
212
+
215
213
  states[stateExists].writable = true;
216
214
  }
217
215
  return states.length;
218
216
  }
219
217
  }
218
+
220
219
  const icon = utils.getDeviceIcon(def);
221
220
  for (const expose of def.exposes) {
222
221
  let state;
@@ -242,6 +241,7 @@ function createFromExposes(model, def) {
242
241
  }, prop.access);
243
242
  break;
244
243
  }
244
+
245
245
  case 'brightness': {
246
246
  const stateNameB = expose.endpoint ? `brightness_${expose.endpoint}` : 'brightness';
247
247
  pushToStates({
@@ -255,12 +255,8 @@ function createFromExposes(model, def) {
255
255
  min: 0, // ignore expose.value_min
256
256
  max: 100, // ignore expose.value_max
257
257
  inOptions: true,
258
- getter: payload => {
259
- return utils.bulbLevelToAdapterLevel(payload[stateNameB]);
260
- },
261
- setter: (value) => {
262
- return utils.adapterLevelToBulbLevel(value);
263
- },
258
+ getter: payload => utils.bulbLevelToAdapterLevel(payload[stateNameB]),
259
+ setter: value => utils.adapterLevelToBulbLevel(value),
264
260
  setterOpt: (value, options) => {
265
261
  const hasTransitionTime = options && options.hasOwnProperty('transition_time');
266
262
  const transitionTime = hasTransitionTime ? options.transition_time : 0;
@@ -268,7 +264,7 @@ function createFromExposes(model, def) {
268
264
  preparedOptions.brightness = utils.adapterLevelToBulbLevel(value);
269
265
  return preparedOptions;
270
266
  },
271
- readResponse: (resp) => {
267
+ readResponse: resp => {
272
268
  const respObj = resp[0];
273
269
  if (respObj.status === 0 && respObj.attrData != undefined) {
274
270
  return utils.bulbLevelToAdapterLevel(respObj.attrData);
@@ -282,30 +278,30 @@ function createFromExposes(model, def) {
282
278
  }
283
279
  case 'color_temp': {
284
280
  const stateNameT = expose.endpoint ? `colortemp_${expose.endpoint}` : 'colortemp';
285
- pushToStates({
286
- id: stateNameT,
287
- prop: expose.endpoint ? `color_temp_${expose.endpoint}` : 'color_temp',
288
- name: `Color temperature ${expose.endpoint ? expose.endpoint : ''}`.trim(),
289
- icon: undefined,
290
- role: 'level.color.temperature',
291
- write: true,
292
- read: true,
293
- type: 'number',
294
- // Ignore min and max value, so setting mireds and Kelvin with conversion to mireds works.
295
- // https://github.com/ioBroker/ioBroker.zigbee/pull/1433#issuecomment-1113837035
296
- min: undefined,
297
- max: undefined,
298
- setter: (value) => {
299
- return utils.toMired(value);
300
- },
301
- setterOpt: (value, options) => {
302
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
303
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
304
- return {...options, transition: transitionTime};
281
+ pushToStates(
282
+ {
283
+ id: stateNameT,
284
+ prop: expose.endpoint ? `color_temp_${expose.endpoint}` : 'color_temp',
285
+ name: `Color temperature ${expose.endpoint ? expose.endpoint : ''}`.trim(),
286
+ icon: undefined,
287
+ role: 'level.color.temperature',
288
+ write: true,
289
+ read: true,
290
+ type: 'number',
291
+ // Ignore min and max value, so setting mireds and Kelvin with conversion to mireds works.
292
+ // https://github.com/ioBroker/ioBroker.zigbee/pull/1433#issuecomment-1113837035
293
+ min: undefined,
294
+ max: undefined,
295
+ setter: value => utils.toMired(value),
296
+ setterOpt: (value, options) => {
297
+ const hasTransitionTime = options && options.hasOwnProperty('transition_time');
298
+ const transitionTime = hasTransitionTime ? options.transition_time : 0;
299
+ return {...options, transition: transitionTime};
300
+ },
301
+ epname: expose.endpoint,
302
+ setattr: 'color_temp',
305
303
  },
306
- epname: expose.endpoint,
307
- setattr: 'color_temp',
308
- }, prop.access);
304
+ prop.access);
309
305
  pushToStates(statesDefs.colortemp_move, prop.access);
310
306
  break;
311
307
  }
@@ -320,8 +316,8 @@ function createFromExposes(model, def) {
320
316
  write: true,
321
317
  read: true,
322
318
  type: 'string',
323
- setter: (value) => {
324
- // convert RGB to XY for set
319
+ setter: value => {
320
+ // convert RGB to XY for set
325
321
  /*
326
322
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(value);
327
323
  let xy = [0, 0];
@@ -342,9 +338,8 @@ function createFromExposes(model, def) {
342
338
  xy = rgb.rgb_to_cie(rgbcolor.r, rgbcolor.g, rgbcolor.b);
343
339
  return {
344
340
  x: xy[0],
345
- y: xy[1]
341
+ y: xy[1],
346
342
  };
347
-
348
343
  },
349
344
  setterOpt: (value, options) => {
350
345
  const hasTransitionTime = options && options.hasOwnProperty('transition_time');
@@ -354,7 +349,7 @@ function createFromExposes(model, def) {
354
349
  getter: payload => {
355
350
  if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
356
351
  const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
357
- return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
352
+ return `#${utils.decimalToHex(colorval[0])}${utils.decimalToHex(colorval[1])}${utils.decimalToHex(colorval[2])}`;
358
353
  } else {
359
354
  return undefined;
360
355
  }
@@ -375,14 +370,13 @@ function createFromExposes(model, def) {
375
370
  write: true,
376
371
  read: true,
377
372
  type: 'string',
378
- setter: (value) => {
373
+ setter: value => {
379
374
  const _rgb = colors.ParseColor(value);
380
375
  const hsv = rgb.rgbToHSV(_rgb.r, _rgb.g, _rgb.b, true);
381
376
  return {
382
- hue: Math.min(Math.max(hsv.h,1),359),
377
+ hue: Math.min(Math.max(hsv.h, 1), 359),
383
378
  saturation: hsv.s,
384
379
  // brightness: Math.floor(hsv.v * 2.55),
385
-
386
380
  };
387
381
  },
388
382
  setterOpt: (value, options) => {
@@ -396,7 +390,7 @@ function createFromExposes(model, def) {
396
390
  pushToStates({
397
391
  id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
398
392
  prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
399
- name: `Hue ${expose.endpoint ? expose.endpoint : ''}`.trim(),
393
+ name: `Hue ${expose.endpoint || ''}`.trim(),
400
394
  icon: undefined,
401
395
  role: 'level.color.hue',
402
396
  write: true,
@@ -417,17 +411,28 @@ function createFromExposes(model, def) {
417
411
  const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
418
412
  if (hasHueCalibrationTable)
419
413
  try {
420
- return {...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration)};
421
- }
422
- catch {
414
+ return {
415
+ ...options,
416
+ transition: transitionTime,
417
+ hue_correction: JSON.parse(options.hue_calibration)
418
+ };
419
+ } catch {
423
420
  const hue_correction_table = [];
424
421
  options.hue_calibration.split(',').forEach(element => {
425
422
  const match = /([0-9]+):([0-9]+)/.exec(element);
426
- if (match && match.length ==3)
427
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
423
+ if (match && match.length === 3)
424
+ hue_correction_table.push({
425
+ in: Number(match[1]),
426
+ out: Number(match[2])
427
+ });
428
428
  });
429
- if (hue_correction_table.length > 0)
430
- return {...options, transition: transitionTime, hue_correction: hue_correction_table};
429
+ if (hue_correction_table.length > 0) {
430
+ return {
431
+ ...options,
432
+ transition: transitionTime,
433
+ hue_correction: hue_correction_table
434
+ };
435
+ }
431
436
  }
432
437
  return {...options, transition: transitionTime};
433
438
  },
@@ -445,29 +450,38 @@ function createFromExposes(model, def) {
445
450
  min: 0,
446
451
  max: 100,
447
452
  inOptions: true,
448
- setter: (value, options) => {
449
- return {
450
- hue: options.hue,
451
- saturation: value,
452
- };
453
- },
453
+ setter: (value, options) => ({
454
+ hue: options.hue,
455
+ saturation: value,
456
+ }),
454
457
  setterOpt: (value, options) => {
455
458
  const hasTransitionTime = options && options.hasOwnProperty('transition_time');
456
459
  const transitionTime = hasTransitionTime ? options.transition_time : 0;
457
460
  const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
458
461
  if (hasHueCalibrationTable)
459
462
  try {
460
- return {...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration)};
461
- }
462
- catch {
463
+ return {
464
+ ...options,
465
+ transition: transitionTime,
466
+ hue_correction: JSON.parse(options.hue_calibration)
467
+ };
468
+ } catch {
463
469
  const hue_correction_table = [];
464
470
  options.hue_calibration.split(',').forEach(element => {
465
471
  const match = /([0-9]+):([0-9]+)/.exec(element);
466
- if (match && match.length ==3)
467
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
472
+ if (match && match.length === 3)
473
+ hue_correction_table.push({
474
+ in: Number(match[1]),
475
+ out: Number(match[2])
476
+ });
468
477
  });
469
- if (hue_correction_table.length > 0)
470
- return {...options, transition: transitionTime, hue_correction: hue_correction_table};
478
+ if (hue_correction_table.length > 0) {
479
+ return {
480
+ ...options,
481
+ transition: transitionTime,
482
+ hue_correction: hue_correction_table
483
+ };
484
+ }
471
485
  }
472
486
  return {...options, transition: transitionTime};
473
487
  },
@@ -485,33 +499,42 @@ function createFromExposes(model, def) {
485
499
  read: false,
486
500
  type: 'string',
487
501
  inOptions: true,
488
- setter: (value, options) => {
489
- return {
490
- hue: options.hue,
491
- saturation: options.saturation,
492
- };
493
- },
502
+ setter: (value, options) => ({
503
+ hue: options.hue,
504
+ saturation: options.saturation,
505
+ }),
494
506
  setterOpt: (value, options) => {
495
507
  const hasTransitionTime = options && options.hasOwnProperty('transition_time');
496
508
  const transitionTime = hasTransitionTime ? options.transition_time : 0;
497
509
  const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
498
510
  if (hasHueCalibrationTable)
499
511
  try {
500
- return {...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration)};
501
- }
502
- catch {
512
+ return {
513
+ ...options,
514
+ transition: transitionTime,
515
+ hue_correction: JSON.parse(options.hue_calibration)
516
+ };
517
+ } catch {
503
518
  const hue_correction_table = [];
504
519
  options.hue_calibration.split(',').forEach(element => {
505
520
  const match = /([0-9]+):([0-9]+)/.exec(element);
506
- if (match && match.length ==3)
507
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
521
+ if (match && match.length === 3) {
522
+ hue_correction_table.push({
523
+ in: Number(match[1]),
524
+ out: Number(match[2])
525
+ });
526
+ }
508
527
  });
509
- if (hue_correction_table.length > 0)
510
- return {...options, transition: transitionTime, hue_correction: hue_correction_table};
528
+ if (hue_correction_table.length > 0) {
529
+ return {
530
+ ...options,
531
+ transition: transitionTime,
532
+ hue_correction: hue_correction_table
533
+ };
534
+ }
511
535
  }
512
536
  return {...options, transition: transitionTime};
513
537
  },
514
-
515
538
  }, prop.access);
516
539
  break;
517
540
  }
@@ -582,19 +605,20 @@ function createFromExposes(model, def) {
582
605
  break;
583
606
  }
584
607
  }
585
- if (state) pushToStates(state, expose.access);
608
+ if (state) {
609
+ pushToStates(state, expose.access);
610
+ }
586
611
  break;
587
612
 
588
613
  case 'enum':
589
614
  switch (expose.name) {
590
615
  case 'action': {
591
-
592
616
  // Ansatz:
593
617
 
594
- // Action aufspalten in 2 Blöcke:
595
- // Action (bekommt text ausser hold und release, auto reset nach 250 ms)
596
- // Hold: wird gesetzt bei hold, gelöscht bei passendem Release
597
-
618
+ // Action aufspalten in 2 Blöcke:
619
+ // Action (bekommt text ausser hold und release, auto reset nach 250 ms)
620
+ // Hold: wird gesetzt bei hold, gelöscht bei passendem Release
621
+
598
622
  if (!Array.isArray(expose.values)) break;
599
623
  const hasHold = expose.values.find((actionName) => actionName.includes('hold'));
600
624
  const hasRelease = expose.values.find((actionName) => actionName.includes('release'));
@@ -613,7 +637,7 @@ function createFromExposes(model, def) {
613
637
  write: false,
614
638
  read: true,
615
639
  type: 'boolean',
616
- getter: payload => (payload.action === actionName) ? true : (payload.action === releaseActionName) ? false : undefined,
640
+ getter: payload => payload.action === actionName ? true : (payload.action === releaseActionName ? false : undefined),
617
641
  };
618
642
  } else {
619
643
  state = {
@@ -625,7 +649,7 @@ function createFromExposes(model, def) {
625
649
  write: false,
626
650
  read: true,
627
651
  type: 'boolean',
628
- getter: payload => (payload.action === actionName) ? true : undefined,
652
+ getter: payload => payload.action === actionName ? true : undefined,
629
653
  isEvent: true,
630
654
  };
631
655
  }
@@ -676,7 +700,9 @@ function createFromExposes(model, def) {
676
700
  break;
677
701
  }
678
702
  }
679
- if (state) pushToStates(state, expose.access);
703
+ if (state) {
704
+ pushToStates(state, expose.access);
705
+ }
680
706
  break;
681
707
 
682
708
  case 'text':
@@ -739,22 +765,20 @@ function createFromExposes(model, def) {
739
765
  return result;
740
766
  };
741
767
  st.setattr = expose.property;
742
- };
768
+ }
743
769
  // if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
744
770
  if (prop.access & ea.STATE) {
745
771
  st.getter = payload => {
746
- if ( (payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
747
- return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined
748
- }
749
- else {
772
+ if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
773
+ return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined;
774
+ } else {
750
775
  return undefined;
751
776
  }
752
777
  };
778
+ } else {
779
+ st.getter = payload => undefined;
753
780
  }
754
- else {
755
- st.getter = payload => { return undefined };
756
- }
757
- ;
781
+
758
782
  pushToStates(st, prop.access);
759
783
  }
760
784
  break;
@@ -764,8 +788,8 @@ function createFromExposes(model, def) {
764
788
  }
765
789
  const newDev = {
766
790
  models: [model],
767
- icon: icon,
768
- states: states,
791
+ icon,
792
+ states,
769
793
  exposed: true,
770
794
  };
771
795
  // make the function code printable in log
@@ -775,26 +799,27 @@ function createFromExposes(model, def) {
775
799
  }
776
800
 
777
801
  function applyExposes(mappedDevices, byModel, allExcludesObj) {
778
- // for exlude search
802
+ // for exclude search
779
803
  const allExcludesStr = JSON.stringify(allExcludesObj);
780
804
  // create or update device from exposes
781
805
  for (const deviceDef of zigbeeHerdsmanConverters.definitions) {
782
- const strippedModel = (deviceDef.model) ? deviceDef.model.replace(/\0.*$/g, '').trim() : '';
806
+
807
+ const stripModel = utils.getModelRegEx(deviceDef.model);
783
808
  // check if device is mapped
784
- const existsMap = byModel.get(strippedModel);
809
+ const existsMap = byModel.get(stripModel);
785
810
 
786
- if ((deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) || allExcludesStr.indexOf(strippedModel) > 0) {
811
+ if ((deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) || allExcludesStr.indexOf(stripModel) > 0) {
787
812
  try {
788
- const newDevice = createFromExposes(strippedModel, deviceDef);
813
+ const newDevice = createFromExposes(stripModel, deviceDef);
789
814
  if (!existsMap) {
790
815
  mappedDevices.push(newDevice);
791
- byModel.set(strippedModel, newDevice);
816
+ byModel.set(stripModel, newDevice);
792
817
  } else {
793
818
  existsMap.states = newDevice.states;
794
819
  existsMap.exposed = true;
795
820
  }
796
821
  } catch (e) {
797
- console.log(`Wrong expose devicedefinition ${deviceDef.vendor} ${deviceDef.model}` );
822
+ console.log(`Wrong expose devicedefinition ${deviceDef.vendor} ${deviceDef.model}`);
798
823
  }
799
824
  }
800
825
  }