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.
- package/README.md +6 -0
- package/admin/adapter-settings.js +244 -0
- package/admin/admin.js +520 -494
- package/admin/index_m.html +1171 -1001
- package/admin/tab_m.html +44 -2
- 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 +27 -0
- 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 +30 -0
- package/docs/flashing_via_arduino_(en).md +110 -0
- 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 +28 -0
- 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/io-package.json +34 -33
- package/lib/backup.js +2 -2
- package/lib/binding.js +32 -37
- package/lib/colors.js +163 -158
- package/lib/commands.js +100 -91
- package/lib/developer.js +9 -12
- package/lib/devices.js +168 -178
- package/lib/exclude.js +30 -36
- package/lib/exposes.js +168 -143
- package/lib/groups.js +81 -83
- package/lib/json.js +5 -6
- package/lib/networkmap.js +2 -3
- package/lib/ota.js +34 -18
- package/lib/rgb.js +114 -72
- package/lib/seriallist.js +25 -20
- package/lib/statescontroller.js +206 -183
- package/lib/utils.js +29 -23
- package/lib/zbBaseExtension.js +4 -4
- package/lib/zbDelayedAction.js +5 -13
- package/lib/zbDeviceAvailability.js +69 -65
- package/lib/zbDeviceConfigure.js +9 -21
- package/lib/zbDeviceEvent.js +3 -4
- package/lib/zigbeecontroller.js +133 -128
- package/main.js +169 -154
- package/package.json +28 -14
- package/.eslintignore +0 -2
- package/.eslintrc.json +0 -37
- package/.github/FUNDING.yml +0 -3
- package/.github/auto-merge.yml +0 -17
- package/.github/dependabot.yml +0 -24
- package/.github/stale.yml +0 -13
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-automerge.yml +0 -22
- package/.github/workflows/test-and-release.yml +0 -149
- package/.releaseconfig.json +0 -3
- package/.travis/wiki.sh +0 -28
- package/.travis.yml +0 -41
- package/gulpfile.js +0 -464
- package/test/integration.js +0 -5
- package/test/mocha.custom.opts +0 -2
- package/test/mocha.setup.js +0 -14
- package/test/package.js +0 -5
- 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(
|
|
5
|
-
const rgb = require(
|
|
6
|
-
const utils = require(
|
|
7
|
-
const colors = require(
|
|
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 =>
|
|
33
|
-
}
|
|
34
|
-
|
|
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(
|
|
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)
|
|
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(
|
|
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 (!
|
|
131
|
-
if (
|
|
129
|
+
if (!state.writable) {
|
|
130
|
+
if (state.hasOwnProperty('setter')) {
|
|
132
131
|
delete state.setter;
|
|
133
132
|
}
|
|
134
|
-
if (
|
|
133
|
+
if (state.hasOwnProperty('setattr')) {
|
|
135
134
|
delete state.setattr;
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
|
-
if (!
|
|
139
|
-
if (state.hasOwnProperty('getter')
|
|
140
|
-
//to
|
|
141
|
-
state.getter = payload =>
|
|
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
|
-
|
|
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 (
|
|
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 ((
|
|
164
|
-
if (
|
|
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 (!
|
|
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 (
|
|
175
|
+
if ((state.writable) && (!states[stateExists].writable)) {
|
|
179
176
|
states[stateExists].write = state.writable;
|
|
180
177
|
// use new state `setter`
|
|
181
|
-
if (
|
|
178
|
+
if (state.hasOwnProperty('setter')) {
|
|
182
179
|
states[stateExists].setter = state.setter;
|
|
183
180
|
}
|
|
184
181
|
// use new state `setterOpt`
|
|
185
|
-
if (
|
|
182
|
+
if (state.hasOwnProperty('setterOpt')) {
|
|
186
183
|
states[stateExists].setterOpt = state.setterOpt;
|
|
187
184
|
}
|
|
188
185
|
// use new state `inOptions`
|
|
189
|
-
if (
|
|
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 (((!
|
|
195
|
-
|
|
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 (
|
|
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 (
|
|
206
|
+
if (states[stateExists].prop === states[stateExists].id) {
|
|
210
207
|
delete states[stateExists].prop;
|
|
211
208
|
}
|
|
212
|
-
if (
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
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:
|
|
324
|
-
|
|
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
|
|
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:
|
|
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
|
|
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 {
|
|
421
|
-
|
|
422
|
-
|
|
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
|
|
427
|
-
hue_correction_table.push({
|
|
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 {
|
|
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
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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 {
|
|
461
|
-
|
|
462
|
-
|
|
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
|
|
467
|
-
hue_correction_table.push({
|
|
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 {
|
|
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
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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 {
|
|
501
|
-
|
|
502
|
-
|
|
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
|
|
507
|
-
hue_correction_table.push({
|
|
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 {
|
|
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)
|
|
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
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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 =>
|
|
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 =>
|
|
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)
|
|
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 (
|
|
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
|
-
|
|
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
|
|
768
|
-
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
|
|
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
|
-
|
|
806
|
+
|
|
807
|
+
const stripModel = utils.getModelRegEx(deviceDef.model);
|
|
783
808
|
// check if device is mapped
|
|
784
|
-
const existsMap = byModel.get(
|
|
809
|
+
const existsMap = byModel.get(stripModel);
|
|
785
810
|
|
|
786
|
-
if ((deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) || allExcludesStr.indexOf(
|
|
811
|
+
if ((deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) || allExcludesStr.indexOf(stripModel) > 0) {
|
|
787
812
|
try {
|
|
788
|
-
const newDevice = createFromExposes(
|
|
813
|
+
const newDevice = createFromExposes(stripModel, deviceDef);
|
|
789
814
|
if (!existsMap) {
|
|
790
815
|
mappedDevices.push(newDevice);
|
|
791
|
-
byModel.set(
|
|
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
|
}
|