iobroker.zigbee 1.8.0 → 1.8.3
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.
- package/.eslintignore +2 -0
- package/.eslintrc.json +37 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/auto-merge.yml +17 -0
- package/.github/dependabot.yml +24 -0
- package/.github/stale.yml +13 -0
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/dependabot-automerge.yml +22 -0
- package/.github/workflows/test-and-release.yml +149 -0
- package/.releaseconfig.json +3 -0
- package/.travis/wiki.sh +28 -0
- package/.travis.yml +41 -0
- package/README.md +32 -9
- package/admin/admin.js +466 -482
- package/admin/i18n/de/translations.json +2 -2
- package/admin/index_m.html +1 -1
- package/admin/tab_m.html +3 -44
- package/admin/words.js +2 -2
- package/gulpfile.js +464 -0
- package/io-package.json +19 -26
- package/lib/backup.js +2 -2
- package/lib/binding.js +24 -23
- package/lib/colors.js +14 -16
- package/lib/commands.js +82 -89
- package/lib/developer.js +7 -6
- package/lib/devices.js +153 -144
- package/lib/exclude.js +36 -30
- package/lib/exposes.js +111 -106
- package/lib/groups.js +54 -53
- package/lib/json.js +4 -3
- package/lib/networkmap.js +2 -2
- package/lib/ota.js +15 -23
- package/lib/rgb.js +44 -47
- package/lib/seriallist.js +16 -21
- package/lib/states.js +496 -482
- package/lib/statescontroller.js +164 -170
- package/lib/utils.js +21 -22
- package/lib/zbBaseExtension.js +4 -4
- package/lib/zbDelayedAction.js +13 -5
- package/lib/zbDeviceAvailability.js +44 -47
- package/lib/zbDeviceConfigure.js +19 -7
- package/lib/zbDeviceEvent.js +4 -3
- package/lib/zigbeecontroller.js +96 -88
- package/main.js +133 -149
- package/package.json +15 -29
- package/test/integration.js +5 -0
- package/test/mocha.custom.opts +2 -0
- package/test/mocha.setup.js +14 -0
- package/test/package.js +5 -0
- package/test/unit.js +5 -0
- package/docs/de/img/CC2531.png +0 -0
- package/docs/de/img/CC2538_CC2592_PA.PNG +0 -0
- package/docs/de/img/CC2591.png +0 -0
- package/docs/de/img/boards.jpg +0 -0
- package/docs/de/img/cc26x2r.PNG +0 -0
- package/docs/de/img/results.jpg +0 -0
- package/docs/de/img/sku_429478_2.png +0 -0
- package/docs/de/img/sku_429601_2.png +0 -0
- package/docs/de/readme.md +0 -27
- package/docs/en/img/CC2531.png +0 -0
- package/docs/en/img/CC2591.png +0 -0
- package/docs/en/img/deconz.png +0 -0
- package/docs/en/img/sku_429478_2.png +0 -0
- package/docs/en/img/sku_429601_2.png +0 -0
- package/docs/en/readme.md +0 -30
- package/docs/flashing_via_arduino_(en).md +0 -110
- package/docs/ru/img/CC2531.png +0 -0
- package/docs/ru/img/CC2591.png +0 -0
- package/docs/ru/img/sku_429478_2.png +0 -0
- package/docs/ru/img/sku_429601_2.png +0 -0
- package/docs/ru/readme.md +0 -28
- package/docs/tutorial/CC2530_20190425.zip +0 -0
- package/docs/tutorial/CC2530_CC2591_20190515.zip +0 -0
- package/docs/tutorial/CC2530_CC2592_20190515.zip +0 -0
- package/docs/tutorial/CC2531_20190425.zip +0 -0
- package/docs/tutorial/adm5_1.PNG +0 -0
- package/docs/tutorial/adm5_2.PNG +0 -0
- package/docs/tutorial/cat.PNG +0 -0
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/inst.PNG +0 -0
- package/docs/tutorial/reflash-finish.PNG +0 -0
- package/docs/tutorial/reflash-step0.png +0 -0
- package/docs/tutorial/reflash-step1.PNG +0 -0
- package/docs/tutorial/reflash-step2.PNG +0 -0
- package/docs/tutorial/settings.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/docs/tutorial/zigbee.png +0 -0
- package/docs/tutorial/zigbee15.png +0 -0
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('
|
|
5
|
-
const rgb = require('
|
|
6
|
-
const utils = require('
|
|
7
|
-
const colors = require('
|
|
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');
|
|
8
8
|
const ea = zigbeeHerdsmanConverters.exposes.access;
|
|
9
9
|
|
|
10
10
|
function genState(expose, role, name, desc) {
|
|
@@ -32,7 +32,7 @@ function genState(expose, role, name, desc) {
|
|
|
32
32
|
state.getter = payload => (payload[propName] === (expose.value_on || 'ON'));
|
|
33
33
|
}
|
|
34
34
|
else {
|
|
35
|
-
state.getter = payload => undefined;
|
|
35
|
+
state.getter = payload => ( undefined);
|
|
36
36
|
}
|
|
37
37
|
if (writable) {
|
|
38
38
|
state.setter = (value) => (value) ? (expose.value_on || 'ON') : ((expose.value_off != undefined) ? expose.value_off : 'OFF');
|
|
@@ -72,7 +72,7 @@ function genState(expose, role, name, desc) {
|
|
|
72
72
|
write: writable,
|
|
73
73
|
read: true,
|
|
74
74
|
type: 'string',
|
|
75
|
-
states: expose.values.map(item => `${item}:${item}`).join(';'),
|
|
75
|
+
states: expose.values.map((item) => `${item}:${item}`).join(';'),
|
|
76
76
|
};
|
|
77
77
|
if (expose.endpoint) {
|
|
78
78
|
state.epname = expose.endpoint;
|
|
@@ -103,6 +103,8 @@ function genState(expose, role, name, desc) {
|
|
|
103
103
|
return state;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
|
|
107
|
+
|
|
106
108
|
function createFromExposes(model, def) {
|
|
107
109
|
const states = [];
|
|
108
110
|
// make the different (set and get) part of state is updatable if different exposes is used for get and set
|
|
@@ -119,24 +121,22 @@ function createFromExposes(model, def) {
|
|
|
119
121
|
if (state === undefined) {
|
|
120
122
|
return 0;
|
|
121
123
|
}
|
|
122
|
-
if (access === undefined)
|
|
123
|
-
access = ea.ALL;
|
|
124
|
-
}
|
|
124
|
+
if (access === undefined) access = ea.ALL;
|
|
125
125
|
state.readable = (access & ea.STATE) > 0;
|
|
126
126
|
state.writable = (access & ea.SET) > 0;
|
|
127
|
-
const stateExists = states.findIndex( (element, index, array) => element.id === state.id);
|
|
128
|
-
if (stateExists < 0) {
|
|
127
|
+
const stateExists = states.findIndex( (element, index, array) => (element.id === state.id ));
|
|
128
|
+
if (stateExists < 0 ) {
|
|
129
129
|
state.write = state.writable;
|
|
130
|
-
if (!state.writable) {
|
|
131
|
-
if (state.hasOwnProperty('setter')) {
|
|
130
|
+
if (! state.writable) {
|
|
131
|
+
if ( state.hasOwnProperty('setter') ) {
|
|
132
132
|
delete state.setter;
|
|
133
133
|
}
|
|
134
|
-
if (state.hasOwnProperty('setattr')) {
|
|
134
|
+
if ( state.hasOwnProperty('setattr') ) {
|
|
135
135
|
delete state.setattr;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
if (!state.readable) {
|
|
139
|
-
if (state.hasOwnProperty('getter')) {
|
|
138
|
+
if (! state.readable) {
|
|
139
|
+
if (state.hasOwnProperty('getter') ) {
|
|
140
140
|
//to awid some worning on unprocessed data
|
|
141
141
|
state.getter = payload => ( undefined );
|
|
142
142
|
}
|
|
@@ -144,7 +144,7 @@ function createFromExposes(model, def) {
|
|
|
144
144
|
return states.push(state);
|
|
145
145
|
}
|
|
146
146
|
else {
|
|
147
|
-
if ((state.readable) && (!states[stateExists].readable)) {
|
|
147
|
+
if ( (state.readable) && (! states[stateExists].readable ) ) {
|
|
148
148
|
states[stateExists].read = state.read;
|
|
149
149
|
// as state is readable, it can't be button or event
|
|
150
150
|
if (states[stateExists].role === 'button') {
|
|
@@ -160,58 +160,58 @@ function createFromExposes(model, def) {
|
|
|
160
160
|
// trying to remove the `prop` property, as main key for get and set,
|
|
161
161
|
// as it can be different in new and old states, and leave only:
|
|
162
162
|
// setattr for old and id for new
|
|
163
|
-
if ((state.hasOwnProperty('prop')) && (state.prop === state.id)) {
|
|
163
|
+
if (( state.hasOwnProperty('prop') ) && (state.prop === state.id)) {
|
|
164
164
|
if ( states[stateExists].hasOwnProperty('prop') ) {
|
|
165
165
|
if (states[stateExists].prop !== states[stateExists].id) {
|
|
166
|
-
if (!states[stateExists].hasOwnProperty('setattr')) {
|
|
166
|
+
if (! states[stateExists].hasOwnProperty('setattr')) {
|
|
167
167
|
states[stateExists].setattr = states[stateExists].prop;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
delete states[stateExists].prop;
|
|
171
171
|
}
|
|
172
|
-
}
|
|
172
|
+
}
|
|
173
|
+
else if ( state.hasOwnProperty('prop') ) {
|
|
173
174
|
states[stateExists].prop = state.prop;
|
|
174
175
|
}
|
|
175
176
|
states[stateExists].readable = true;
|
|
176
177
|
}
|
|
177
|
-
if ((state.writable) && (!states[stateExists].writable)) {
|
|
178
|
+
if ( (state.writable) && (! states[stateExists].writable ) ) {
|
|
178
179
|
states[stateExists].write = state.writable;
|
|
179
180
|
// use new state `setter`
|
|
180
|
-
if (state.hasOwnProperty('setter')) {
|
|
181
|
+
if ( state.hasOwnProperty('setter') ) {
|
|
181
182
|
states[stateExists].setter = state.setter;
|
|
182
183
|
}
|
|
183
184
|
// use new state `setterOpt`
|
|
184
|
-
if (state.hasOwnProperty('setterOpt')) {
|
|
185
|
+
if ( state.hasOwnProperty('setterOpt') ) {
|
|
185
186
|
states[stateExists].setterOpt = state.setterOpt;
|
|
186
187
|
}
|
|
187
188
|
// use new state `inOptions`
|
|
188
|
-
if (state.hasOwnProperty('inOptions')) {
|
|
189
|
+
if ( state.hasOwnProperty('inOptions') ) {
|
|
189
190
|
states[stateExists].inOptions = state.inOptions;
|
|
190
191
|
}
|
|
191
192
|
// as we have new state, responsible for set, we have to use new `isOption`
|
|
192
193
|
// or remove it
|
|
193
|
-
if (((!state.hasOwnProperty('isOption')) || (state.isOptions === false))
|
|
194
|
+
if (((! state.hasOwnProperty('isOption') ) || (state.isOptions === false))
|
|
194
195
|
&& (states[stateExists].hasOwnProperty('isOption'))) {
|
|
195
196
|
delete states[stateExists].isOption;
|
|
196
|
-
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
197
199
|
states[stateExists].isOption = state.isOption;
|
|
198
200
|
}
|
|
199
|
-
|
|
200
201
|
// use new `setattr` or `prop` as `setattr`
|
|
201
|
-
if (state.hasOwnProperty('setattr')) {
|
|
202
|
+
if ( state.hasOwnProperty('setattr') ) {
|
|
202
203
|
states[stateExists].setattr = state.setattr;
|
|
203
|
-
}
|
|
204
|
+
}
|
|
205
|
+
else if ( state.hasOwnProperty('prop') ) {
|
|
204
206
|
states[stateExists].setattr = state.prop;
|
|
205
207
|
}
|
|
206
|
-
|
|
207
208
|
// remove `prop` equal to if, due to prop is uses as key in set and get
|
|
208
|
-
if (states[stateExists].prop === states[stateExists].id) {
|
|
209
|
+
if ( states[stateExists].prop === states[stateExists].id) {
|
|
209
210
|
delete states[stateExists].prop;
|
|
210
211
|
}
|
|
211
|
-
if (state.hasOwnProperty('epname')) {
|
|
212
|
+
if ( state.hasOwnProperty('epname') ) {
|
|
212
213
|
states[stateExists].epname = state.epname;
|
|
213
214
|
}
|
|
214
|
-
|
|
215
215
|
states[stateExists].writable = true;
|
|
216
216
|
}
|
|
217
217
|
return states.length;
|
|
@@ -242,7 +242,6 @@ function createFromExposes(model, def) {
|
|
|
242
242
|
}, prop.access);
|
|
243
243
|
break;
|
|
244
244
|
}
|
|
245
|
-
|
|
246
245
|
case 'brightness': {
|
|
247
246
|
const stateNameB = expose.endpoint ? `brightness_${expose.endpoint}` : 'brightness';
|
|
248
247
|
pushToStates({
|
|
@@ -256,8 +255,12 @@ function createFromExposes(model, def) {
|
|
|
256
255
|
min: 0, // ignore expose.value_min
|
|
257
256
|
max: 100, // ignore expose.value_max
|
|
258
257
|
inOptions: true,
|
|
259
|
-
getter: payload =>
|
|
260
|
-
|
|
258
|
+
getter: payload => {
|
|
259
|
+
return utils.bulbLevelToAdapterLevel(payload[stateNameB]);
|
|
260
|
+
},
|
|
261
|
+
setter: (value) => {
|
|
262
|
+
return utils.adapterLevelToBulbLevel(value);
|
|
263
|
+
},
|
|
261
264
|
setterOpt: (value, options) => {
|
|
262
265
|
const hasTransitionTime = options && options.hasOwnProperty('transition_time');
|
|
263
266
|
const transitionTime = hasTransitionTime ? options.transition_time : 0;
|
|
@@ -265,7 +268,7 @@ function createFromExposes(model, def) {
|
|
|
265
268
|
preparedOptions.brightness = utils.adapterLevelToBulbLevel(value);
|
|
266
269
|
return preparedOptions;
|
|
267
270
|
},
|
|
268
|
-
readResponse: resp => {
|
|
271
|
+
readResponse: (resp) => {
|
|
269
272
|
const respObj = resp[0];
|
|
270
273
|
if (respObj.status === 0 && respObj.attrData != undefined) {
|
|
271
274
|
return utils.bulbLevelToAdapterLevel(respObj.attrData);
|
|
@@ -279,30 +282,30 @@ function createFromExposes(model, def) {
|
|
|
279
282
|
}
|
|
280
283
|
case 'color_temp': {
|
|
281
284
|
const stateNameT = expose.endpoint ? `colortemp_${expose.endpoint}` : 'colortemp';
|
|
282
|
-
pushToStates(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
setterOpt: (value, options) => {
|
|
298
|
-
const hasTransitionTime = options && options.hasOwnProperty('transition_time');
|
|
299
|
-
const transitionTime = hasTransitionTime ? options.transition_time : 0;
|
|
300
|
-
return {...options, transition: transitionTime};
|
|
301
|
-
},
|
|
302
|
-
epname: expose.endpoint,
|
|
303
|
-
setattr: 'color_temp',
|
|
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);
|
|
304
300
|
},
|
|
305
|
-
|
|
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};
|
|
305
|
+
},
|
|
306
|
+
epname: expose.endpoint,
|
|
307
|
+
setattr: 'color_temp',
|
|
308
|
+
}, prop.access);
|
|
306
309
|
pushToStates(statesDefs.colortemp_move, prop.access);
|
|
307
310
|
break;
|
|
308
311
|
}
|
|
@@ -317,7 +320,7 @@ function createFromExposes(model, def) {
|
|
|
317
320
|
write: true,
|
|
318
321
|
read: true,
|
|
319
322
|
type: 'string',
|
|
320
|
-
setter: value => {
|
|
323
|
+
setter: (value) => {
|
|
321
324
|
// convert RGB to XY for set
|
|
322
325
|
/*
|
|
323
326
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(value);
|
|
@@ -339,8 +342,9 @@ function createFromExposes(model, def) {
|
|
|
339
342
|
xy = rgb.rgb_to_cie(rgbcolor.r, rgbcolor.g, rgbcolor.b);
|
|
340
343
|
return {
|
|
341
344
|
x: xy[0],
|
|
342
|
-
y: xy[1]
|
|
345
|
+
y: xy[1]
|
|
343
346
|
};
|
|
347
|
+
|
|
344
348
|
},
|
|
345
349
|
setterOpt: (value, options) => {
|
|
346
350
|
const hasTransitionTime = options && options.hasOwnProperty('transition_time');
|
|
@@ -350,7 +354,7 @@ function createFromExposes(model, def) {
|
|
|
350
354
|
getter: payload => {
|
|
351
355
|
if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
|
|
352
356
|
const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
|
|
353
|
-
return
|
|
357
|
+
return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
|
|
354
358
|
} else {
|
|
355
359
|
return undefined;
|
|
356
360
|
}
|
|
@@ -371,13 +375,14 @@ function createFromExposes(model, def) {
|
|
|
371
375
|
write: true,
|
|
372
376
|
read: true,
|
|
373
377
|
type: 'string',
|
|
374
|
-
setter: value => {
|
|
378
|
+
setter: (value) => {
|
|
375
379
|
const _rgb = colors.ParseColor(value);
|
|
376
380
|
const hsv = rgb.rgbToHSV(_rgb.r, _rgb.g, _rgb.b, true);
|
|
377
381
|
return {
|
|
378
382
|
hue: Math.min(Math.max(hsv.h,1),359),
|
|
379
383
|
saturation: hsv.s,
|
|
380
384
|
// brightness: Math.floor(hsv.v * 2.55),
|
|
385
|
+
|
|
381
386
|
};
|
|
382
387
|
},
|
|
383
388
|
setterOpt: (value, options) => {
|
|
@@ -391,7 +396,7 @@ function createFromExposes(model, def) {
|
|
|
391
396
|
pushToStates({
|
|
392
397
|
id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
|
|
393
398
|
prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
394
|
-
name: `Hue ${expose.endpoint
|
|
399
|
+
name: `Hue ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
395
400
|
icon: undefined,
|
|
396
401
|
role: 'level.color.hue',
|
|
397
402
|
write: true,
|
|
@@ -418,12 +423,11 @@ function createFromExposes(model, def) {
|
|
|
418
423
|
const hue_correction_table = [];
|
|
419
424
|
options.hue_calibration.split(',').forEach(element => {
|
|
420
425
|
const match = /([0-9]+):([0-9]+)/.exec(element);
|
|
421
|
-
if (match && match.length
|
|
422
|
-
hue_correction_table.push({in: Number(match[1]), out: Number(match[2])});
|
|
426
|
+
if (match && match.length ==3)
|
|
427
|
+
hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
|
|
423
428
|
});
|
|
424
|
-
if (hue_correction_table.length > 0)
|
|
429
|
+
if (hue_correction_table.length > 0)
|
|
425
430
|
return {...options, transition: transitionTime, hue_correction: hue_correction_table};
|
|
426
|
-
}
|
|
427
431
|
}
|
|
428
432
|
return {...options, transition: transitionTime};
|
|
429
433
|
},
|
|
@@ -441,10 +445,12 @@ function createFromExposes(model, def) {
|
|
|
441
445
|
min: 0,
|
|
442
446
|
max: 100,
|
|
443
447
|
inOptions: true,
|
|
444
|
-
setter: (value, options) =>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
+
setter: (value, options) => {
|
|
449
|
+
return {
|
|
450
|
+
hue: options.hue,
|
|
451
|
+
saturation: value,
|
|
452
|
+
};
|
|
453
|
+
},
|
|
448
454
|
setterOpt: (value, options) => {
|
|
449
455
|
const hasTransitionTime = options && options.hasOwnProperty('transition_time');
|
|
450
456
|
const transitionTime = hasTransitionTime ? options.transition_time : 0;
|
|
@@ -457,12 +463,11 @@ function createFromExposes(model, def) {
|
|
|
457
463
|
const hue_correction_table = [];
|
|
458
464
|
options.hue_calibration.split(',').forEach(element => {
|
|
459
465
|
const match = /([0-9]+):([0-9]+)/.exec(element);
|
|
460
|
-
if (match && match.length
|
|
466
|
+
if (match && match.length ==3)
|
|
461
467
|
hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
|
|
462
468
|
});
|
|
463
|
-
if (hue_correction_table.length > 0)
|
|
469
|
+
if (hue_correction_table.length > 0)
|
|
464
470
|
return {...options, transition: transitionTime, hue_correction: hue_correction_table};
|
|
465
|
-
}
|
|
466
471
|
}
|
|
467
472
|
return {...options, transition: transitionTime};
|
|
468
473
|
},
|
|
@@ -480,10 +485,12 @@ function createFromExposes(model, def) {
|
|
|
480
485
|
read: false,
|
|
481
486
|
type: 'string',
|
|
482
487
|
inOptions: true,
|
|
483
|
-
setter: (value, options) =>
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
488
|
+
setter: (value, options) => {
|
|
489
|
+
return {
|
|
490
|
+
hue: options.hue,
|
|
491
|
+
saturation: options.saturation,
|
|
492
|
+
};
|
|
493
|
+
},
|
|
487
494
|
setterOpt: (value, options) => {
|
|
488
495
|
const hasTransitionTime = options && options.hasOwnProperty('transition_time');
|
|
489
496
|
const transitionTime = hasTransitionTime ? options.transition_time : 0;
|
|
@@ -491,20 +498,20 @@ function createFromExposes(model, def) {
|
|
|
491
498
|
if (hasHueCalibrationTable)
|
|
492
499
|
try {
|
|
493
500
|
return {...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration)};
|
|
494
|
-
}
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
495
503
|
const hue_correction_table = [];
|
|
496
504
|
options.hue_calibration.split(',').forEach(element => {
|
|
497
505
|
const match = /([0-9]+):([0-9]+)/.exec(element);
|
|
498
|
-
if (match && match.length
|
|
506
|
+
if (match && match.length ==3)
|
|
499
507
|
hue_correction_table.push({ in: Number(match[1]), out: Number(match[2])});
|
|
500
|
-
}
|
|
501
508
|
});
|
|
502
|
-
if (hue_correction_table.length > 0)
|
|
509
|
+
if (hue_correction_table.length > 0)
|
|
503
510
|
return {...options, transition: transitionTime, hue_correction: hue_correction_table};
|
|
504
|
-
}
|
|
505
511
|
}
|
|
506
512
|
return {...options, transition: transitionTime};
|
|
507
513
|
},
|
|
514
|
+
|
|
508
515
|
}, prop.access);
|
|
509
516
|
break;
|
|
510
517
|
}
|
|
@@ -575,20 +582,19 @@ function createFromExposes(model, def) {
|
|
|
575
582
|
break;
|
|
576
583
|
}
|
|
577
584
|
}
|
|
578
|
-
if (state)
|
|
579
|
-
pushToStates(state, expose.access);
|
|
580
|
-
}
|
|
585
|
+
if (state) pushToStates(state, expose.access);
|
|
581
586
|
break;
|
|
582
587
|
|
|
583
588
|
case 'enum':
|
|
584
589
|
switch (expose.name) {
|
|
585
590
|
case 'action': {
|
|
586
|
-
// Ansatz:
|
|
587
591
|
|
|
588
|
-
//
|
|
589
|
-
// Action (bekommt text ausser hold und release, auto reset nach 250 ms)
|
|
590
|
-
// Hold: wird gesetzt bei hold, gelöscht bei passendem Release
|
|
592
|
+
// Ansatz:
|
|
591
593
|
|
|
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
|
+
|
|
592
598
|
if (!Array.isArray(expose.values)) break;
|
|
593
599
|
const hasHold = expose.values.find((actionName) => actionName.includes('hold'));
|
|
594
600
|
const hasRelease = expose.values.find((actionName) => actionName.includes('release'));
|
|
@@ -607,7 +613,7 @@ function createFromExposes(model, def) {
|
|
|
607
613
|
write: false,
|
|
608
614
|
read: true,
|
|
609
615
|
type: 'boolean',
|
|
610
|
-
getter: payload => payload.action === actionName ? true : (payload.action === releaseActionName ? false : undefined
|
|
616
|
+
getter: payload => (payload.action === actionName) ? true : (payload.action === releaseActionName) ? false : undefined,
|
|
611
617
|
};
|
|
612
618
|
} else {
|
|
613
619
|
state = {
|
|
@@ -619,7 +625,7 @@ function createFromExposes(model, def) {
|
|
|
619
625
|
write: false,
|
|
620
626
|
read: true,
|
|
621
627
|
type: 'boolean',
|
|
622
|
-
getter: payload => payload.action === actionName ? true : undefined,
|
|
628
|
+
getter: payload => (payload.action === actionName) ? true : undefined,
|
|
623
629
|
isEvent: true,
|
|
624
630
|
};
|
|
625
631
|
}
|
|
@@ -670,9 +676,7 @@ function createFromExposes(model, def) {
|
|
|
670
676
|
break;
|
|
671
677
|
}
|
|
672
678
|
}
|
|
673
|
-
if (state)
|
|
674
|
-
pushToStates(state, expose.access);
|
|
675
|
-
}
|
|
679
|
+
if (state) pushToStates(state, expose.access);
|
|
676
680
|
break;
|
|
677
681
|
|
|
678
682
|
case 'text':
|
|
@@ -735,7 +739,7 @@ function createFromExposes(model, def) {
|
|
|
735
739
|
return result;
|
|
736
740
|
};
|
|
737
741
|
st.setattr = expose.property;
|
|
738
|
-
}
|
|
742
|
+
};
|
|
739
743
|
// if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
|
|
740
744
|
if (prop.access & ea.STATE) {
|
|
741
745
|
st.getter = payload => {
|
|
@@ -746,10 +750,11 @@ function createFromExposes(model, def) {
|
|
|
746
750
|
return undefined;
|
|
747
751
|
}
|
|
748
752
|
};
|
|
749
|
-
} else {
|
|
750
|
-
st.getter = payload => undefined;
|
|
751
753
|
}
|
|
752
|
-
|
|
754
|
+
else {
|
|
755
|
+
st.getter = payload => { return undefined };
|
|
756
|
+
}
|
|
757
|
+
;
|
|
753
758
|
pushToStates(st, prop.access);
|
|
754
759
|
}
|
|
755
760
|
break;
|
|
@@ -759,8 +764,8 @@ function createFromExposes(model, def) {
|
|
|
759
764
|
}
|
|
760
765
|
const newDev = {
|
|
761
766
|
models: [model],
|
|
762
|
-
icon,
|
|
763
|
-
states,
|
|
767
|
+
icon: icon,
|
|
768
|
+
states: states,
|
|
764
769
|
exposed: true,
|
|
765
770
|
};
|
|
766
771
|
// make the function code printable in log
|
|
@@ -770,11 +775,11 @@ function createFromExposes(model, def) {
|
|
|
770
775
|
}
|
|
771
776
|
|
|
772
777
|
function applyExposes(mappedDevices, byModel, allExcludesObj) {
|
|
773
|
-
// for
|
|
778
|
+
// for exlude search
|
|
774
779
|
const allExcludesStr = JSON.stringify(allExcludesObj);
|
|
775
780
|
// create or update device from exposes
|
|
776
781
|
for (const deviceDef of zigbeeHerdsmanConverters.definitions) {
|
|
777
|
-
const strippedModel = (deviceDef.model) ? deviceDef.model.replace(
|
|
782
|
+
const strippedModel = (deviceDef.model) ? deviceDef.model.replace(/\0.*$/g, '').trim() : '';
|
|
778
783
|
// check if device is mapped
|
|
779
784
|
const existsMap = byModel.get(strippedModel);
|
|
780
785
|
|
|
@@ -789,7 +794,7 @@ function applyExposes(mappedDevices, byModel, allExcludesObj) {
|
|
|
789
794
|
existsMap.exposed = true;
|
|
790
795
|
}
|
|
791
796
|
} catch (e) {
|
|
792
|
-
console.log(`Wrong expose devicedefinition ${deviceDef.vendor} ${deviceDef.model}`);
|
|
797
|
+
console.log(`Wrong expose devicedefinition ${deviceDef.vendor} ${deviceDef.model}` );
|
|
793
798
|
}
|
|
794
799
|
}
|
|
795
800
|
}
|