iobroker.zigbee 1.5.6 → 1.6.8
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/.devcontainer/devcontainer.json +35 -35
- package/.devcontainer/docker-compose.yml +51 -51
- package/.devcontainer/iobroker/Dockerfile +1 -1
- package/.devcontainer/nginx/nginx.conf +32 -32
- package/.devcontainer/parcel/Dockerfile +8 -8
- package/.devcontainer/parcel/run.sh +6 -6
- package/.eslintignore +1 -1
- package/.eslintrc.json +36 -36
- package/.github/FUNDING.yml +3 -3
- package/.github/stale.yml +13 -13
- package/.github/workflows/test-and-release.yml +151 -151
- package/.travis/wiki.sh +27 -27
- package/LICENSE +21 -21
- package/README.md +385 -353
- package/admin/adapter-settings.js +244 -208
- package/admin/admin.js +2704 -2714
- package/admin/img/R7060.png +0 -0
- package/admin/img/WHD02.png +0 -0
- package/admin/img/ikea_E1812.png +0 -0
- package/admin/img/philips_hue_lom001.png +0 -0
- package/admin/img/tuya_rb280.png +0 -0
- package/admin/index.html +159 -159
- package/admin/index_m.html +1055 -965
- package/admin/moment.min.js +1 -1
- package/admin/shuffle.min.js +2 -2
- package/admin/tab_m.html +1025 -934
- package/admin/vis-network.min.js +26 -26
- package/admin/words.js +106 -106
- package/docs/de/readme.md +27 -27
- package/docs/en/readme.md +30 -30
- package/docs/flashing_via_arduino_(en).md +110 -110
- package/docs/ru/readme.md +28 -28
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/docs/tutorial/zigbee.png +0 -0
- package/io-package.json +317 -290
- package/lib/backup.js +132 -132
- package/lib/binding.js +325 -325
- package/lib/colors.js +460 -460
- package/lib/commands.js +435 -434
- package/lib/developer.js +148 -144
- package/lib/devices.js +3119 -3109
- package/lib/exclude.js +168 -168
- package/lib/exposes.js +204 -51
- package/lib/groups.js +316 -316
- package/lib/json.js +60 -60
- package/lib/networkmap.js +56 -56
- package/lib/ota.js +153 -153
- package/lib/rgb.js +225 -225
- package/lib/seriallist.js +37 -37
- package/lib/states.js +6381 -6322
- package/lib/statescontroller.js +502 -495
- package/lib/tools.js +54 -54
- package/lib/utils.js +151 -132
- package/lib/zbBaseExtension.js +31 -27
- package/lib/zbDelayedAction.js +151 -146
- package/lib/zbDeviceAvailability.js +306 -304
- package/lib/zbDeviceConfigure.js +148 -143
- package/lib/zbDeviceEvent.js +43 -43
- package/lib/zigbeecontroller.js +856 -822
- package/main.js +113 -39
- package/package.json +74 -73
- package/support/docgen.js +93 -93
package/lib/exposes.js
CHANGED
|
@@ -5,12 +5,15 @@ const statesDefs = require(__dirname + '/states.js').states;
|
|
|
5
5
|
const rgb = require(__dirname + '/rgb.js');
|
|
6
6
|
const utils = require(__dirname + '/utils.js');
|
|
7
7
|
const colors = require(__dirname + '/colors.js');
|
|
8
|
+
const ea = zigbeeHerdsmanConverters.exposes.access;
|
|
8
9
|
|
|
9
10
|
function genState(expose, role, name, desc) {
|
|
10
11
|
let state;
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
12
|
+
const readable = (expose.access & ea.STATE) > 0;
|
|
13
|
+
const writable = (expose.access & ea.SET) > 0;
|
|
14
|
+
const stname = (name || expose.property);
|
|
15
|
+
if (typeof stname !== 'string') return;
|
|
16
|
+
const stateId = stname.replace(/\*/g, '');
|
|
14
17
|
const stateName = (desc || expose.description || expose.name);
|
|
15
18
|
const propName = expose.property;
|
|
16
19
|
switch (expose.type) {
|
|
@@ -21,13 +24,20 @@ function genState(expose, role, name, desc) {
|
|
|
21
24
|
name: stateName,
|
|
22
25
|
icon: undefined,
|
|
23
26
|
role: role || 'state',
|
|
24
|
-
write:
|
|
27
|
+
write: writable,
|
|
25
28
|
read: true,
|
|
26
29
|
type: 'boolean',
|
|
27
|
-
getter: payload => (payload[propName] === (expose.value_on || 'ON')),
|
|
28
|
-
setter: (value) => (value) ? (expose.value_on || 'ON') : ((expose.value_off != undefined) ? expose.value_off : 'OFF'),
|
|
29
|
-
setattr: expose.name,
|
|
30
30
|
};
|
|
31
|
+
if (readable) {
|
|
32
|
+
state.getter = payload => (payload[propName] === (expose.value_on || 'ON'));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
state.getter = payload => ( undefined);
|
|
36
|
+
}
|
|
37
|
+
if (writable) {
|
|
38
|
+
state.setter = (value) => (value) ? (expose.value_on || 'ON') : ((expose.value_off != undefined) ? expose.value_off : 'OFF');
|
|
39
|
+
state.setattr = expose.name;
|
|
40
|
+
}
|
|
31
41
|
if (expose.endpoint) {
|
|
32
42
|
state.epname = expose.endpoint;
|
|
33
43
|
}
|
|
@@ -40,7 +50,7 @@ function genState(expose, role, name, desc) {
|
|
|
40
50
|
name: stateName,
|
|
41
51
|
icon: undefined,
|
|
42
52
|
role: role || 'state',
|
|
43
|
-
write:
|
|
53
|
+
write: writable,
|
|
44
54
|
read: true,
|
|
45
55
|
type: 'number',
|
|
46
56
|
min: expose.value_min || 0,
|
|
@@ -59,13 +69,14 @@ function genState(expose, role, name, desc) {
|
|
|
59
69
|
name: stateName,
|
|
60
70
|
icon: undefined,
|
|
61
71
|
role: role || 'state',
|
|
62
|
-
write:
|
|
72
|
+
write: writable,
|
|
63
73
|
read: true,
|
|
64
74
|
type: 'string',
|
|
65
75
|
states: expose.values.map((item) => `${item}:${item}`).join(';'),
|
|
66
76
|
};
|
|
67
77
|
if (expose.endpoint) {
|
|
68
78
|
state.epname = expose.endpoint;
|
|
79
|
+
state.setattr = expose.name;
|
|
69
80
|
}
|
|
70
81
|
break;
|
|
71
82
|
|
|
@@ -76,7 +87,7 @@ function genState(expose, role, name, desc) {
|
|
|
76
87
|
name: stateName,
|
|
77
88
|
icon: undefined,
|
|
78
89
|
role: role || 'state',
|
|
79
|
-
write:
|
|
90
|
+
write: writable,
|
|
80
91
|
read: true,
|
|
81
92
|
type: 'string',
|
|
82
93
|
};
|
|
@@ -92,9 +103,121 @@ function genState(expose, role, name, desc) {
|
|
|
92
103
|
return state;
|
|
93
104
|
}
|
|
94
105
|
|
|
106
|
+
|
|
107
|
+
|
|
95
108
|
function createFromExposes(model, def) {
|
|
96
109
|
const states = [];
|
|
97
|
-
|
|
110
|
+
// make the different (set and get) part of state is updatable if different exposes is used for get and set
|
|
111
|
+
// as example:
|
|
112
|
+
// ...
|
|
113
|
+
// exposes.binary('some_option', ea.STATE, true, false).withDescription('Some Option'),
|
|
114
|
+
// exposes.composite('options', 'options')
|
|
115
|
+
// .withDescription('Some composite Options')
|
|
116
|
+
// .withFeature(exposes.binary('some_option', ea.SET, true, false).withDescription('Some Option'))
|
|
117
|
+
//in this case one state - `some_option` has two different exposes for set an get, we have to combine it ...
|
|
118
|
+
//
|
|
119
|
+
|
|
120
|
+
function pushToStates(state, access) {
|
|
121
|
+
if (state === undefined) {
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
if (access === undefined) access = ea.ALL;
|
|
125
|
+
state.readable = (access & ea.STATE) > 0;
|
|
126
|
+
state.writable = (access & ea.SET) > 0;
|
|
127
|
+
const stateExists = states.findIndex( (element, index, array) => (element.id === state.id ));
|
|
128
|
+
if (stateExists < 0 ) {
|
|
129
|
+
state.write = state.writable;
|
|
130
|
+
if (! state.writable) {
|
|
131
|
+
if ( state.hasOwnProperty('setter') ) {
|
|
132
|
+
delete state.setter;
|
|
133
|
+
}
|
|
134
|
+
if ( state.hasOwnProperty('setattr') ) {
|
|
135
|
+
delete state.setattr;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (! state.readable) {
|
|
139
|
+
if (state.hasOwnProperty('getter') ) {
|
|
140
|
+
//to awid some worning on unprocessed data
|
|
141
|
+
state.getter = payload => ( undefined );
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return states.push(state);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
if ( (state.readable) && (! states[stateExists].readable ) ) {
|
|
148
|
+
states[stateExists].read = state.read;
|
|
149
|
+
// as state is readable, it can't be button or event
|
|
150
|
+
if (states[stateExists].role === 'button') {
|
|
151
|
+
states[stateExists].role = state.role;
|
|
152
|
+
}
|
|
153
|
+
if (states[stateExists].hasOwnProperty('isEvent')) {
|
|
154
|
+
delete states[stateExists].isEvent;
|
|
155
|
+
}
|
|
156
|
+
// we have to use the getter from "new" state
|
|
157
|
+
if ( state.hasOwnProperty('getter') ) {
|
|
158
|
+
states[stateExists].getter = state.getter;
|
|
159
|
+
}
|
|
160
|
+
// trying to remove the `prop` property, as main key for get and set,
|
|
161
|
+
// as it can be different in new and old states, and leave only:
|
|
162
|
+
// setattr for old and id for new
|
|
163
|
+
if (( state.hasOwnProperty('prop') ) && (state.prop === state.id)) {
|
|
164
|
+
if ( states[stateExists].hasOwnProperty('prop') ) {
|
|
165
|
+
if (states[stateExists].prop !== states[stateExists].id) {
|
|
166
|
+
if (! states[stateExists].hasOwnProperty('setattr')) {
|
|
167
|
+
states[stateExists].setattr = states[stateExists].prop;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
delete states[stateExists].prop;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if ( state.hasOwnProperty('prop') ) {
|
|
174
|
+
states[stateExists].prop = state.prop;
|
|
175
|
+
}
|
|
176
|
+
states[stateExists].readable = true;
|
|
177
|
+
}
|
|
178
|
+
if ( (state.writable) && (! states[stateExists].writable ) ) {
|
|
179
|
+
states[stateExists].write = state.writable;
|
|
180
|
+
// use new state `setter`
|
|
181
|
+
if ( state.hasOwnProperty('setter') ) {
|
|
182
|
+
states[stateExists].setter = state.setter;
|
|
183
|
+
}
|
|
184
|
+
// use new state `setterOpt`
|
|
185
|
+
if ( state.hasOwnProperty('setterOpt') ) {
|
|
186
|
+
states[stateExists].setterOpt = state.setterOpt;
|
|
187
|
+
}
|
|
188
|
+
// use new state `inOptions`
|
|
189
|
+
if ( state.hasOwnProperty('inOptions') ) {
|
|
190
|
+
states[stateExists].inOptions = state.inOptions;
|
|
191
|
+
}
|
|
192
|
+
// as we have new state, responsible for set, we have to use new `isOption`
|
|
193
|
+
// or remove it
|
|
194
|
+
if (((! state.hasOwnProperty('isOption') ) || (state.isOptions === false))
|
|
195
|
+
&& (states[stateExists].hasOwnProperty('isOption'))) {
|
|
196
|
+
delete states[stateExists].isOption;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
states[stateExists].isOption = state.isOption;
|
|
200
|
+
}
|
|
201
|
+
// use new `setattr` or `prop` as `setattr`
|
|
202
|
+
if ( state.hasOwnProperty('setattr') ) {
|
|
203
|
+
states[stateExists].setattr = state.setattr;
|
|
204
|
+
}
|
|
205
|
+
else if ( state.hasOwnProperty('prop') ) {
|
|
206
|
+
states[stateExists].setattr = state.prop;
|
|
207
|
+
}
|
|
208
|
+
// remove `prop` equal to if, due to prop is uses as key in set and get
|
|
209
|
+
if ( states[stateExists].prop === states[stateExists].id) {
|
|
210
|
+
delete states[stateExists].prop;
|
|
211
|
+
}
|
|
212
|
+
if ( state.hasOwnProperty('epname') ) {
|
|
213
|
+
states[stateExists].epname = state.epname;
|
|
214
|
+
}
|
|
215
|
+
states[stateExists].writable = true;
|
|
216
|
+
}
|
|
217
|
+
return states.length;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const icon = utils.getDeviceIcon(def);
|
|
98
221
|
for (const expose of def.exposes) {
|
|
99
222
|
let state;
|
|
100
223
|
|
|
@@ -104,7 +227,7 @@ function createFromExposes(model, def) {
|
|
|
104
227
|
switch (prop.name) {
|
|
105
228
|
case 'state': {
|
|
106
229
|
const stateNameS = expose.endpoint ? `state_${expose.endpoint}` : 'state';
|
|
107
|
-
|
|
230
|
+
pushToStates({
|
|
108
231
|
id: stateNameS,
|
|
109
232
|
name: `Switch state ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
110
233
|
icon: undefined,
|
|
@@ -116,12 +239,12 @@ function createFromExposes(model, def) {
|
|
|
116
239
|
setter: (value) => (value) ? prop.value_on || 'ON' : ((prop.value_off != undefined) ? prop.value_off : 'OFF'),
|
|
117
240
|
epname: expose.endpoint,
|
|
118
241
|
setattr: 'state',
|
|
119
|
-
});
|
|
242
|
+
}, prop.access);
|
|
120
243
|
break;
|
|
121
244
|
}
|
|
122
245
|
case 'brightness': {
|
|
123
246
|
const stateNameB = expose.endpoint ? `brightness_${expose.endpoint}` : 'brightness';
|
|
124
|
-
|
|
247
|
+
pushToStates({
|
|
125
248
|
id: stateNameB,
|
|
126
249
|
name: `Brightness ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
127
250
|
icon: undefined,
|
|
@@ -153,13 +276,13 @@ function createFromExposes(model, def) {
|
|
|
153
276
|
},
|
|
154
277
|
epname: expose.endpoint,
|
|
155
278
|
setattr: 'brightness',
|
|
156
|
-
});
|
|
157
|
-
|
|
279
|
+
}, prop.access);
|
|
280
|
+
pushToStates(statesDefs.brightness_move, prop.access);
|
|
158
281
|
break;
|
|
159
282
|
}
|
|
160
283
|
case 'color_temp': {
|
|
161
284
|
const stateNameT = expose.endpoint ? `colortemp_${expose.endpoint}` : 'colortemp';
|
|
162
|
-
|
|
285
|
+
pushToStates({
|
|
163
286
|
id: stateNameT,
|
|
164
287
|
prop: expose.endpoint ? `color_temp_${expose.endpoint}` : 'color_temp',
|
|
165
288
|
name: `Color temperature ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
@@ -179,13 +302,13 @@ function createFromExposes(model, def) {
|
|
|
179
302
|
return {...options, transition: transitionTime};
|
|
180
303
|
},
|
|
181
304
|
epname: expose.endpoint,
|
|
182
|
-
});
|
|
183
|
-
|
|
305
|
+
}, prop.access);
|
|
306
|
+
pushToStates(statesDefs.colortemp_move, prop.access);
|
|
184
307
|
break;
|
|
185
308
|
}
|
|
186
309
|
case 'color_xy': {
|
|
187
310
|
const stateNameC = expose.endpoint ? `color_${expose.endpoint}` : 'color';
|
|
188
|
-
|
|
311
|
+
pushToStates({
|
|
189
312
|
id: stateNameC,
|
|
190
313
|
prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
191
314
|
name: `Color ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
@@ -235,12 +358,12 @@ function createFromExposes(model, def) {
|
|
|
235
358
|
},
|
|
236
359
|
epname: expose.endpoint,
|
|
237
360
|
setattr: 'color',
|
|
238
|
-
});
|
|
361
|
+
}, prop.access);
|
|
239
362
|
break;
|
|
240
363
|
}
|
|
241
364
|
case 'color_hs': {
|
|
242
365
|
const stateNameH = expose.endpoint ? `color_${expose.endpoint}` : 'color';
|
|
243
|
-
|
|
366
|
+
pushToStates({
|
|
244
367
|
id: stateNameH,
|
|
245
368
|
prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
246
369
|
name: `Color ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
@@ -266,8 +389,8 @@ function createFromExposes(model, def) {
|
|
|
266
389
|
},
|
|
267
390
|
epname: expose.endpoint,
|
|
268
391
|
setattr: 'color',
|
|
269
|
-
});
|
|
270
|
-
|
|
392
|
+
}, prop.access);
|
|
393
|
+
pushToStates({
|
|
271
394
|
id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
|
|
272
395
|
prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
273
396
|
name: `Hue ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
@@ -306,8 +429,8 @@ function createFromExposes(model, def) {
|
|
|
306
429
|
return {...options, transition: transitionTime};
|
|
307
430
|
},
|
|
308
431
|
|
|
309
|
-
});
|
|
310
|
-
|
|
432
|
+
}, prop.access);
|
|
433
|
+
pushToStates({
|
|
311
434
|
id: expose.endpoint ? `saturation_${expose.endpoint}` : 'saturation',
|
|
312
435
|
prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
313
436
|
name: `Saturation ${expose.endpoint ? expose.endpoint : ''}`.trim(),
|
|
@@ -346,10 +469,10 @@ function createFromExposes(model, def) {
|
|
|
346
469
|
return {...options, transition: transitionTime};
|
|
347
470
|
},
|
|
348
471
|
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
472
|
+
}, prop.access);
|
|
473
|
+
pushToStates(statesDefs.hue_move, prop.access);
|
|
474
|
+
pushToStates(statesDefs.saturation_move, prop.access);
|
|
475
|
+
pushToStates({
|
|
353
476
|
id: 'hue_calibration',
|
|
354
477
|
prop: 'color',
|
|
355
478
|
name: 'Hue color calibration table',
|
|
@@ -386,25 +509,25 @@ function createFromExposes(model, def) {
|
|
|
386
509
|
return {...options, transition: transitionTime};
|
|
387
510
|
},
|
|
388
511
|
|
|
389
|
-
});
|
|
512
|
+
}, prop.access);
|
|
390
513
|
break;
|
|
391
514
|
}
|
|
392
515
|
default:
|
|
393
|
-
|
|
516
|
+
pushToStates(genState(prop), prop.access);
|
|
394
517
|
break;
|
|
395
518
|
}
|
|
396
519
|
}
|
|
397
|
-
|
|
520
|
+
pushToStates(statesDefs.transition_time, ea.STATE_SET);
|
|
398
521
|
break;
|
|
399
522
|
|
|
400
523
|
case 'switch':
|
|
401
524
|
for (const prop of expose.features) {
|
|
402
525
|
switch (prop.name) {
|
|
403
526
|
case 'state':
|
|
404
|
-
|
|
527
|
+
pushToStates(genState(prop, 'switch'), prop.access);
|
|
405
528
|
break;
|
|
406
529
|
default:
|
|
407
|
-
|
|
530
|
+
pushToStates(genState(prop), prop.access);
|
|
408
531
|
break;
|
|
409
532
|
}
|
|
410
533
|
}
|
|
@@ -456,7 +579,7 @@ function createFromExposes(model, def) {
|
|
|
456
579
|
break;
|
|
457
580
|
}
|
|
458
581
|
}
|
|
459
|
-
if (state)
|
|
582
|
+
if (state) pushToStates(state, expose.access);
|
|
460
583
|
break;
|
|
461
584
|
|
|
462
585
|
case 'enum':
|
|
@@ -496,7 +619,7 @@ function createFromExposes(model, def) {
|
|
|
496
619
|
isEvent: true,
|
|
497
620
|
};
|
|
498
621
|
}
|
|
499
|
-
|
|
622
|
+
pushToStates(state, expose.access);
|
|
500
623
|
}
|
|
501
624
|
state = null;
|
|
502
625
|
break;
|
|
@@ -505,7 +628,7 @@ function createFromExposes(model, def) {
|
|
|
505
628
|
state = genState(expose);
|
|
506
629
|
break;
|
|
507
630
|
}
|
|
508
|
-
if (state)
|
|
631
|
+
if (state) pushToStates(state, expose.access);
|
|
509
632
|
break;
|
|
510
633
|
|
|
511
634
|
case 'binary':
|
|
@@ -515,7 +638,7 @@ function createFromExposes(model, def) {
|
|
|
515
638
|
switch (expose.name) {
|
|
516
639
|
case 'contact':
|
|
517
640
|
state = statesDefs.contact;
|
|
518
|
-
|
|
641
|
+
pushToStates(statesDefs.opened, ea.STATE);
|
|
519
642
|
break;
|
|
520
643
|
|
|
521
644
|
case 'battery_low':
|
|
@@ -543,12 +666,12 @@ function createFromExposes(model, def) {
|
|
|
543
666
|
break;
|
|
544
667
|
}
|
|
545
668
|
}
|
|
546
|
-
if (state)
|
|
669
|
+
if (state) pushToStates(state, expose.access);
|
|
547
670
|
break;
|
|
548
671
|
|
|
549
672
|
case 'text':
|
|
550
673
|
state = genState(expose);
|
|
551
|
-
|
|
674
|
+
pushToStates(state, expose.access);
|
|
552
675
|
break;
|
|
553
676
|
|
|
554
677
|
case 'lock':
|
|
@@ -557,10 +680,10 @@ function createFromExposes(model, def) {
|
|
|
557
680
|
for (const prop of expose.features) {
|
|
558
681
|
switch (prop.name) {
|
|
559
682
|
case 'state':
|
|
560
|
-
|
|
683
|
+
pushToStates(genState(prop, 'switch'), prop.access);
|
|
561
684
|
break;
|
|
562
685
|
default:
|
|
563
|
-
|
|
686
|
+
pushToStates(genState(prop), prop.access);
|
|
564
687
|
break;
|
|
565
688
|
}
|
|
566
689
|
}
|
|
@@ -570,16 +693,16 @@ function createFromExposes(model, def) {
|
|
|
570
693
|
for (const prop of expose.features) {
|
|
571
694
|
switch (prop.name) {
|
|
572
695
|
case 'away_mode':
|
|
573
|
-
|
|
696
|
+
pushToStates(statesDefs.climate_away_mode, prop.access);
|
|
574
697
|
break;
|
|
575
698
|
case 'system_mode':
|
|
576
|
-
|
|
699
|
+
pushToStates(statesDefs.climate_system_mode, prop.access);
|
|
577
700
|
break;
|
|
578
701
|
case 'running_mode':
|
|
579
|
-
|
|
702
|
+
pushToStates(statesDefs.climate_running_mode, prop.access);
|
|
580
703
|
break;
|
|
581
704
|
default:
|
|
582
|
-
|
|
705
|
+
pushToStates(genState(prop), prop.access);
|
|
583
706
|
break;
|
|
584
707
|
}
|
|
585
708
|
}
|
|
@@ -588,14 +711,41 @@ function createFromExposes(model, def) {
|
|
|
588
711
|
case 'composite':
|
|
589
712
|
for (const prop of expose.features) {
|
|
590
713
|
const st = genState(prop);
|
|
714
|
+
st.prop = expose.property;
|
|
591
715
|
st.inOptions = true;
|
|
716
|
+
// I'm not fully sure, as it really needed, but
|
|
592
717
|
st.setterOpt = (value, options) => {
|
|
593
718
|
const result = {};
|
|
594
|
-
|
|
719
|
+
options[prop.property] = value;
|
|
720
|
+
result[expose.property] = options;
|
|
595
721
|
return result;
|
|
596
722
|
};
|
|
597
|
-
|
|
598
|
-
|
|
723
|
+
// if we have a composite expose, the value have to be an object {expose.property : {prop.property: value}}
|
|
724
|
+
if (prop.access & ea.SET) {
|
|
725
|
+
st.setter = (value, options) => {
|
|
726
|
+
const result = {};
|
|
727
|
+
options[prop.property] = value;
|
|
728
|
+
result[expose.property] = options;
|
|
729
|
+
return result;
|
|
730
|
+
};
|
|
731
|
+
st.setattr = expose.property;
|
|
732
|
+
};
|
|
733
|
+
// if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
|
|
734
|
+
if (prop.access & ea.STATE) {
|
|
735
|
+
st.getter = payload => {
|
|
736
|
+
if ( (payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
|
|
737
|
+
return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
return undefined;
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
st.getter = payload => { return undefined };
|
|
746
|
+
}
|
|
747
|
+
;
|
|
748
|
+
pushToStates(st, prop.access);
|
|
599
749
|
}
|
|
600
750
|
break;
|
|
601
751
|
default:
|
|
@@ -608,7 +758,9 @@ function createFromExposes(model, def) {
|
|
|
608
758
|
states: states,
|
|
609
759
|
exposed: true,
|
|
610
760
|
};
|
|
611
|
-
//
|
|
761
|
+
// make the function code printable in log
|
|
762
|
+
//console.log(`Created mapping for device ${model}: ${JSON.stringify(newDev, function(key, value) {
|
|
763
|
+
// if (typeof value === 'function') {return value.toString() } else { return value } }, ' ')}`);
|
|
612
764
|
return newDev;
|
|
613
765
|
}
|
|
614
766
|
|
|
@@ -620,6 +772,7 @@ function applyExposes(mappedDevices, byModel, allExcludesObj) {
|
|
|
620
772
|
const strippedModel = (deviceDef.model) ? deviceDef.model.replace(/\0.*$/g, '').trim() : '';
|
|
621
773
|
// check if device is mapped
|
|
622
774
|
const existsMap = byModel.get(strippedModel);
|
|
775
|
+
|
|
623
776
|
if ((deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) || allExcludesStr.indexOf(strippedModel) > 0) {
|
|
624
777
|
const newDevice = createFromExposes(strippedModel, deviceDef);
|
|
625
778
|
if (!existsMap) {
|