iobroker.zigbee 3.3.1-alpha.0 → 3.3.2
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/LICENSE +1 -1
- package/README.md +49 -50
- package/admin/admin.js +39 -7
- package/admin/tab_m.html +19 -0
- package/io-package.json +26 -26
- package/lib/colors.js +182 -421
- package/lib/exposes.js +126 -202
- package/lib/groups.js +2 -5
- package/lib/legacy/devices.js +8 -5
- package/lib/models.js +101 -12
- package/lib/statescontroller.js +147 -134
- package/lib/zigbeecontroller.js +59 -10
- package/main.js +15 -20
- package/package.json +5 -5
package/lib/exposes.js
CHANGED
|
@@ -6,12 +6,16 @@ const utils = require('./utils');
|
|
|
6
6
|
const colors = require('./colors');
|
|
7
7
|
const ea = require('zigbee-herdsman-converters/lib/exposes').access;
|
|
8
8
|
|
|
9
|
-
const LocalData = { options:{} };
|
|
9
|
+
//const LocalData = { options:{ newCompositeMethod: true } };
|
|
10
|
+
//const LocalData = { options:{ } };
|
|
10
11
|
const __logger = undefined;
|
|
11
12
|
|
|
12
|
-
function genState(expose,
|
|
13
|
+
function genState(expose, overrides) {
|
|
14
|
+
const role = overrides?.role;
|
|
15
|
+
const name = overrides?.name;
|
|
16
|
+
const desc = overrides?.desc;
|
|
13
17
|
let state;
|
|
14
|
-
const readable = (expose.access & ea.
|
|
18
|
+
const readable = (expose.access & (ea.STATE_GET)) > 0;
|
|
15
19
|
const writable = (expose.access & ea.SET) > 0;
|
|
16
20
|
const stname = (name || expose.property);
|
|
17
21
|
if (typeof stname !== 'string') return;
|
|
@@ -26,10 +30,10 @@ function genState(expose, role, name, desc) {
|
|
|
26
30
|
prop: propName,
|
|
27
31
|
name: stateName,
|
|
28
32
|
icon: undefined,
|
|
29
|
-
role: role || 'state',
|
|
33
|
+
role: role || (readable ? 'state' : 'button'),
|
|
30
34
|
write: writable,
|
|
31
|
-
read:
|
|
32
|
-
type:
|
|
35
|
+
read: readable,
|
|
36
|
+
type: `boolean`,
|
|
33
37
|
};
|
|
34
38
|
if (readable) {
|
|
35
39
|
state.getter = payload => payload[propName] === (typeof expose.value_on == 'boolean' ? expose.value_on : expose.value_on || 'ON');
|
|
@@ -55,7 +59,7 @@ function genState(expose, role, name, desc) {
|
|
|
55
59
|
write: writable,
|
|
56
60
|
read: true,
|
|
57
61
|
type: 'number',
|
|
58
|
-
min: expose.value_min
|
|
62
|
+
min: expose.value_min,
|
|
59
63
|
max: expose.value_max,
|
|
60
64
|
unit: expose.unit,
|
|
61
65
|
};
|
|
@@ -130,13 +134,96 @@ function genState(expose, role, name, desc) {
|
|
|
130
134
|
break;
|
|
131
135
|
|
|
132
136
|
default:
|
|
133
|
-
|
|
137
|
+
return state;
|
|
138
|
+
}
|
|
139
|
+
if (overrides?.fromComposite) {
|
|
140
|
+
if (overrides?.channelID) {
|
|
141
|
+
state.compositeKey = overrides.channelID;
|
|
142
|
+
state.compositeTimeout = 250;
|
|
143
|
+
state.compositeState = overrides.channelID;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
state.inOptions = true;
|
|
147
|
+
state.setterOpt = (value, options) => {
|
|
148
|
+
const result = {};
|
|
149
|
+
options[expose.property] = value;
|
|
150
|
+
result[expose.property] = options;
|
|
151
|
+
return result;
|
|
152
|
+
};
|
|
153
|
+
if (expose.access & ea.SET) {
|
|
154
|
+
state.setter = (value, options) => {
|
|
155
|
+
const result = {};
|
|
156
|
+
options[expose.property] = value;
|
|
157
|
+
result[expose.property] = options;
|
|
158
|
+
return result;
|
|
159
|
+
};
|
|
160
|
+
state.setattr = expose.property;
|
|
161
|
+
};
|
|
162
|
+
if (expose.access & ea.STATE) {
|
|
163
|
+
expose.getter = payload => {
|
|
164
|
+
if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(expose.property)) {
|
|
165
|
+
return !isNaN(payload[expose.property][expose.property]) ? payload[expose.property][expose.property] : undefined;
|
|
166
|
+
} else {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
} else {
|
|
171
|
+
expose.getter = payload => undefined;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
134
174
|
}
|
|
135
175
|
|
|
176
|
+
|
|
136
177
|
return state;
|
|
137
178
|
}
|
|
138
179
|
|
|
139
|
-
|
|
180
|
+
|
|
181
|
+
function generateCompositeStates(expose, _channelID, options)
|
|
182
|
+
{
|
|
183
|
+
const states = [];
|
|
184
|
+
const stname = `${_channelID}${expose.property}`;
|
|
185
|
+
const stateId = stname.replace(/\*/g, '');
|
|
186
|
+
const stateName = (expose.description || expose.name);
|
|
187
|
+
const channelID = options.newCompositeMethod ? `c_${stateId}.` : '';
|
|
188
|
+
if (options.newCompositeMethod) {
|
|
189
|
+
|
|
190
|
+
if (typeof stname !== 'string') return undefined;;
|
|
191
|
+
states.push({
|
|
192
|
+
id: stateId,
|
|
193
|
+
name: stateName,
|
|
194
|
+
icon: undefined,
|
|
195
|
+
role: 'state',
|
|
196
|
+
write: Boolean (expose.access & ea.SET),
|
|
197
|
+
read: Boolean(expose.access & ea.GET),
|
|
198
|
+
type: 'string',
|
|
199
|
+
getter: (value) => {
|
|
200
|
+
const myval = value[stateId];
|
|
201
|
+
if (myval != undefined && typeof myval === 'object') return JSON.stringify(myval);
|
|
202
|
+
return myval;
|
|
203
|
+
},
|
|
204
|
+
setter: (value) => {
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(value);
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return { error: error.message }
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
}
|
|
215
|
+
if (expose?.features?.[Symbol.iterator]) for (const prop of expose.features) {
|
|
216
|
+
if (prop.type === 'composite' || prop.type === 'list') {
|
|
217
|
+
states.push(...generateCompositeStates(prop, channelID, options))
|
|
218
|
+
}
|
|
219
|
+
else
|
|
220
|
+
states.push(genState(prop, options.newCompositeMethod ? { fromComposite: true, name: `${channelID}${prop.name}` , channelID: stateId }: { fromComposite: true }))
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return states;
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
function createFromExposes(model, def, device, options, log) {
|
|
140
227
|
const { getStateDefinition } = require('./models');
|
|
141
228
|
const states = [];
|
|
142
229
|
// make the different (set and get) part of state is updatable if different exposes is used for get and set
|
|
@@ -298,7 +385,7 @@ function createFromExposes(model, def, device, log) {
|
|
|
298
385
|
function definitionHasTZHandler(definition, id) {
|
|
299
386
|
const tz = definition?.herdsmanModel?.toZigbee;
|
|
300
387
|
for (const converter of tz) {
|
|
301
|
-
if (converter
|
|
388
|
+
if (converter?.key?.includes(id))
|
|
302
389
|
return true;
|
|
303
390
|
}
|
|
304
391
|
return false;
|
|
@@ -313,7 +400,7 @@ function createFromExposes(model, def, device, log) {
|
|
|
313
400
|
let colorXYprop = undefined;
|
|
314
401
|
let colorHSprop = undefined;
|
|
315
402
|
|
|
316
|
-
for (const prop of expose.features) {
|
|
403
|
+
if (expose?.features?.[Symbol.iterator]) for (const prop of expose.features) {
|
|
317
404
|
switch (prop.name) {
|
|
318
405
|
case 'state': {
|
|
319
406
|
const stateNameS = expose.endpoint ? `state_${expose.endpoint}` : 'state';
|
|
@@ -521,26 +608,8 @@ function createFromExposes(model, def, device, log) {
|
|
|
521
608
|
read: true,
|
|
522
609
|
type: 'string',
|
|
523
610
|
setter: value => {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const colorJSON = JSON.parse(value.replaceAll("'",'"'));
|
|
527
|
-
const numProp = Object.keys(colorJSON).length;
|
|
528
|
-
if (hasMultipleProperties(colorJSON, ['hsb'], numProp)) return colorJSON;
|
|
529
|
-
if (hasMultipleProperties(colorJSON, ['hsl'], numProp)) return colorJSON;
|
|
530
|
-
if (hasMultipleProperties(colorJSON, ['hsv'], numProp)) return colorJSON;
|
|
531
|
-
if (hasMultipleProperties(colorJSON, ['h','s','b'], numProp)) return colorJSON;
|
|
532
|
-
if (hasMultipleProperties(colorJSON, ['h','s','v'], numProp)) return colorJSON;
|
|
533
|
-
if (hasMultipleProperties(colorJSON, ['h','s','l'], numProp)) return colorJSON;
|
|
534
|
-
if (hasMultipleProperties(colorJSON, ['hue', 'saturation'], numProp)) return colorJSON;
|
|
535
|
-
if (hasMultipleProperties(colorJSON, ['hex'], numProp)) return colorJSON;
|
|
536
|
-
if (hasMultipleProperties(colorJSON, ['rgb'], numProp)) return colorJSON;
|
|
537
|
-
if (hasMultipleProperties(colorJSON, ['x', 'y'], numProp)) return colorJSON;
|
|
538
|
-
if (hasMultipleProperties(colorJSON, ['r', 'g', 'b'], numProp)) return colorJSON;
|
|
539
|
-
//return { json:colorJSON, numProp:numProp, value:value };
|
|
540
|
-
}
|
|
541
|
-
catch (error) {
|
|
542
|
-
//return { error: error.message };
|
|
543
|
-
};
|
|
611
|
+
const rv = colors.complexColor(value, true);
|
|
612
|
+
if (rv) return rv;
|
|
544
613
|
// hex or named color
|
|
545
614
|
const rgbcolor = colors.ParseColor(value);
|
|
546
615
|
return rgbcolor;
|
|
@@ -551,24 +620,7 @@ function createFromExposes(model, def, device, log) {
|
|
|
551
620
|
return {...options, transition: transitionTime};
|
|
552
621
|
},
|
|
553
622
|
getter: payload => {
|
|
554
|
-
|
|
555
|
-
const colorJSON = payload.color;
|
|
556
|
-
const color = JSON.stringify(colorJSON)
|
|
557
|
-
//const numProp = Object.keys(colorJSON).length;
|
|
558
|
-
if (hasMultipleProperties(colorJSON, ['hsb'])) return color;
|
|
559
|
-
if (hasMultipleProperties(colorJSON, ['hsl'])) return color;
|
|
560
|
-
if (hasMultipleProperties(colorJSON, ['hsv'])) return color;
|
|
561
|
-
if (hasMultipleProperties(colorJSON, ['h','s','b'])) return color;
|
|
562
|
-
if (hasMultipleProperties(colorJSON, ['h','s','v'])) return color;
|
|
563
|
-
if (hasMultipleProperties(colorJSON, ['h','s','l'])) return color;
|
|
564
|
-
if (hasMultipleProperties(colorJSON, ['hue', 'saturation'])) return color;
|
|
565
|
-
if (hasMultipleProperties(colorJSON, ['h', 's'])) return color;
|
|
566
|
-
if (hasMultipleProperties(colorJSON, ['hex'])) return color;
|
|
567
|
-
if (hasMultipleProperties(colorJSON, ['rgb'])) return color;
|
|
568
|
-
if (hasMultipleProperties(colorJSON, ['x', 'y'])) return color;
|
|
569
|
-
if (hasMultipleProperties(colorJSON, ['r', 'g', 'b'])) return color;
|
|
570
|
-
}
|
|
571
|
-
return undefined;
|
|
623
|
+
return colors.complexColor(payload, false);
|
|
572
624
|
},
|
|
573
625
|
epname: expose.endpoint,
|
|
574
626
|
setattr: 'color',
|
|
@@ -617,7 +669,6 @@ function createFromExposes(model, def, device, log) {
|
|
|
617
669
|
compositeKey: channelWithEp,
|
|
618
670
|
compositeTimeout: 500,
|
|
619
671
|
compositeState: 'color',
|
|
620
|
-
composites: [`${channelWithEp}.r`,`${channelWithEp}.g`]
|
|
621
672
|
}, colorXYprop.access);
|
|
622
673
|
pushToStates({
|
|
623
674
|
id: `${channelWithEp}.g`,
|
|
@@ -632,7 +683,6 @@ function createFromExposes(model, def, device, log) {
|
|
|
632
683
|
compositeKey: channelWithEp,
|
|
633
684
|
compositeTimeout: 500,
|
|
634
685
|
compositeState: 'color',
|
|
635
|
-
composites: [`${channelWithEp}.x`,`${channelWithEp}.y`]
|
|
636
686
|
});
|
|
637
687
|
pushToStates({
|
|
638
688
|
id: `${channelWithEp}.b`,
|
|
@@ -703,10 +753,10 @@ function createFromExposes(model, def, device, log) {
|
|
|
703
753
|
break;
|
|
704
754
|
}
|
|
705
755
|
case 'switch':
|
|
706
|
-
for (const prop of expose.features) {
|
|
756
|
+
if (expose?.features?.[Symbol.iterator]) for (const prop of expose.features) {
|
|
707
757
|
switch (prop.name) {
|
|
708
758
|
case 'state':
|
|
709
|
-
pushToStates(genState(prop, 'switch'), prop.access);
|
|
759
|
+
pushToStates(genState(prop, { role:'switch' }), prop.access);
|
|
710
760
|
break;
|
|
711
761
|
default:
|
|
712
762
|
pushToStates(genState(prop), prop.access);
|
|
@@ -725,44 +775,44 @@ function createFromExposes(model, def, device, log) {
|
|
|
725
775
|
break;
|
|
726
776
|
|
|
727
777
|
case 'battery':
|
|
728
|
-
state = modifyState(genState(expose, 'value.battery'), {
|
|
778
|
+
state = modifyState(genState(expose, {role:'value.battery'}), {
|
|
729
779
|
icon:'img/battery_p.png',
|
|
730
780
|
});
|
|
731
781
|
//state = getStateDefinition('battery');
|
|
732
782
|
break;
|
|
733
783
|
|
|
734
784
|
case 'voltage':
|
|
735
|
-
state = genState(expose, 'level.voltage');
|
|
785
|
+
state = genState(expose, {role:'level.voltage'});
|
|
736
786
|
// state = getStateDefinition('voltage')
|
|
737
787
|
break;
|
|
738
788
|
|
|
739
789
|
case 'temperature':
|
|
740
|
-
state = genState(expose, 'value.temperature');
|
|
790
|
+
state = genState(expose, {role:'value.temperature'});
|
|
741
791
|
//state = getStateDefinition('temperature');
|
|
742
792
|
break;
|
|
743
793
|
|
|
744
794
|
case 'humidity':
|
|
745
|
-
state = genState(expose, 'value.humidity');
|
|
795
|
+
state = genState(expose, {role:'value.humidity'});
|
|
746
796
|
//state = getStateDefinition('humidity');
|
|
747
797
|
break;
|
|
748
798
|
|
|
749
799
|
case 'pressure':
|
|
750
|
-
state = genState(expose, 'value.pressure');
|
|
800
|
+
state = genState(expose, {role:'value.pressure'});
|
|
751
801
|
//state = getStateDefinition('pressure');
|
|
752
802
|
break;
|
|
753
803
|
|
|
754
804
|
case 'illuminance':
|
|
755
|
-
state = genState(expose, 'value.brightness', 'illuminance_raw' )
|
|
805
|
+
state = genState(expose, {role:'value.brightness', name: 'illuminance_raw'} );
|
|
756
806
|
//state = getStateDefinition('illuminance_raw');
|
|
757
807
|
break;
|
|
758
808
|
|
|
759
809
|
case 'illuminance_lux':
|
|
760
|
-
state = genState(expose, 'value.brightness', 'illuminance');
|
|
810
|
+
state = genState(expose, {role:'value.brightness', name:'illuminance'});
|
|
761
811
|
//state = getStateDefinition('illuminance');
|
|
762
812
|
break;
|
|
763
813
|
|
|
764
814
|
case 'power':
|
|
765
|
-
state = genState(expose, 'value.power', 'load_power');
|
|
815
|
+
state = genState(expose, {role:'value.power', name:'load_power'});
|
|
766
816
|
//state = getStateDefinition('load_power');
|
|
767
817
|
break;
|
|
768
818
|
|
|
@@ -848,9 +898,9 @@ function createFromExposes(model, def, device, log) {
|
|
|
848
898
|
} else {
|
|
849
899
|
switch (expose.name) {
|
|
850
900
|
case 'contact': {
|
|
851
|
-
state = modifyState(genState(expose, 'sensor'), { getter: payload => payload.contact });
|
|
901
|
+
state = modifyState(genState(expose, {role:'sensor'}), { getter: payload => payload.contact });
|
|
852
902
|
// state = getStateDefinition('contact');
|
|
853
|
-
pushToStates(modifyState(genState(expose, 'sensor'), {
|
|
903
|
+
pushToStates(modifyState(genState(expose,{role: 'sensor'}), {
|
|
854
904
|
id:'opened',
|
|
855
905
|
name:'Is open',
|
|
856
906
|
role:'sensor.contact',
|
|
@@ -860,18 +910,18 @@ function createFromExposes(model, def, device, log) {
|
|
|
860
910
|
break;
|
|
861
911
|
}
|
|
862
912
|
case 'battery_low':
|
|
863
|
-
state = genState(expose,'indicator.lowbat', expose.name, 'Battery Status Low');
|
|
913
|
+
state = genState(expose, {role:'indicator.lowbat', name:expose.name, desc:'Battery Status Low'});
|
|
864
914
|
break;
|
|
865
915
|
|
|
866
916
|
case 'tamper':
|
|
867
|
-
state = modifyState(genState(expose, 'indicator', 'tampered'), {
|
|
917
|
+
state = modifyState(genState(expose, {role: 'indicator',name: 'tampered'}), {
|
|
868
918
|
prop:'tamper',
|
|
869
919
|
name:'Is tampered'
|
|
870
920
|
});
|
|
871
921
|
break;
|
|
872
922
|
|
|
873
923
|
case 'water_leak':
|
|
874
|
-
state = modifyState(genState(expose, 'indicator', 'detected'), {
|
|
924
|
+
state = modifyState(genState(expose, {role:'indicator', name:'detected'}), {
|
|
875
925
|
prop:'water_leak',
|
|
876
926
|
name:'Water leak detected'
|
|
877
927
|
})
|
|
@@ -879,7 +929,7 @@ function createFromExposes(model, def, device, log) {
|
|
|
879
929
|
break;
|
|
880
930
|
|
|
881
931
|
case 'lock':
|
|
882
|
-
state = modifyState(genState(expose, 'switch.lock'), {
|
|
932
|
+
state = modifyState(genState(expose, {role:'switch.lock'}), {
|
|
883
933
|
prop: 'child_lock',
|
|
884
934
|
name: 'Locked',
|
|
885
935
|
getter: payload => (payload.child_lock === 'LOCKED'),
|
|
@@ -889,7 +939,7 @@ function createFromExposes(model, def, device, log) {
|
|
|
889
939
|
break;
|
|
890
940
|
|
|
891
941
|
case 'occupancy':
|
|
892
|
-
state = genState(expose, 'sensor.motion');
|
|
942
|
+
state = genState(expose, {role:'sensor.motion'});
|
|
893
943
|
//state = getStateDefinition('occupancy');
|
|
894
944
|
break;
|
|
895
945
|
|
|
@@ -911,10 +961,10 @@ function createFromExposes(model, def, device, log) {
|
|
|
911
961
|
case 'lock':
|
|
912
962
|
case 'fan':
|
|
913
963
|
case 'cover':
|
|
914
|
-
for (const prop of expose.features) {
|
|
964
|
+
if (expose?.features?.[Symbol.iterator]) for (const prop of expose.features) {
|
|
915
965
|
switch (prop.name) {
|
|
916
966
|
case 'state':
|
|
917
|
-
pushToStates(genState(prop, 'switch'), prop.access);
|
|
967
|
+
pushToStates(genState(prop, {role:'switch'}), prop.access);
|
|
918
968
|
break;
|
|
919
969
|
default:
|
|
920
970
|
pushToStates(genState(prop), prop.access);
|
|
@@ -924,112 +974,16 @@ function createFromExposes(model, def, device, log) {
|
|
|
924
974
|
break;
|
|
925
975
|
|
|
926
976
|
case 'climate':
|
|
927
|
-
for (const prop of expose.features) {
|
|
977
|
+
if (expose?.features?.[Symbol.iterator]) for (const prop of expose.features) {
|
|
928
978
|
pushToStates(genState(prop), prop.access);
|
|
929
979
|
}
|
|
930
980
|
break;
|
|
931
981
|
|
|
932
982
|
case 'composite':
|
|
933
983
|
{
|
|
934
|
-
const
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
const channelID = LocalData.options.newCompositeMethod ? `${stateId}.` : '';
|
|
938
|
-
if (LocalData.options.newCompositeMethod) {
|
|
939
|
-
|
|
940
|
-
if (typeof stname !== 'string') break;
|
|
941
|
-
pushToStates({
|
|
942
|
-
id: stateId,
|
|
943
|
-
name: stateName,
|
|
944
|
-
icon: undefined,
|
|
945
|
-
role: 'state',
|
|
946
|
-
write: expose.access & ea.SET,
|
|
947
|
-
read: expose.access & ea.GET,
|
|
948
|
-
type: 'string',
|
|
949
|
-
}, expose.access)
|
|
950
|
-
|
|
951
|
-
}
|
|
952
|
-
for (const prop of expose.features) {
|
|
953
|
-
if (prop.type == 'numeric') {
|
|
954
|
-
const st = genState(prop, 'state', `${channelID}${prop.name}`);
|
|
955
|
-
st.prop = expose.property;
|
|
956
|
-
st.inOptions = true;
|
|
957
|
-
// I'm not fully sure, as it really needed, but
|
|
958
|
-
st.setterOpt = (value, options) => {
|
|
959
|
-
const result = {};
|
|
960
|
-
options[prop.property] = value;
|
|
961
|
-
result[expose.property] = options;
|
|
962
|
-
return result;
|
|
963
|
-
};
|
|
964
|
-
if (LocalData.options.newCompositeMethod) {
|
|
965
|
-
st.compositeKey = stateId;
|
|
966
|
-
st.compositeTimeout = 250;
|
|
967
|
-
st.compositeState = stateId;
|
|
968
|
-
} else
|
|
969
|
-
{
|
|
970
|
-
// if we have a composite expose, the value have to be an object {expose.property : {prop.property: value}}
|
|
971
|
-
if (prop.access & ea.SET) {
|
|
972
|
-
st.setter = (value, options) => {
|
|
973
|
-
const result = {};
|
|
974
|
-
options[prop.property] = value;
|
|
975
|
-
result[expose.property] = options;
|
|
976
|
-
return result;
|
|
977
|
-
};
|
|
978
|
-
st.setattr = expose.property;
|
|
979
|
-
}
|
|
980
|
-
// if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
|
|
981
|
-
if (prop.access & ea.STATE) {
|
|
982
|
-
st.getter = payload => {
|
|
983
|
-
if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
|
|
984
|
-
return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined;
|
|
985
|
-
} else {
|
|
986
|
-
return undefined;
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
} else {
|
|
990
|
-
st.getter = payload => undefined;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
pushToStates(st, prop.access);
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
if (prop.type == 'list') {
|
|
997
|
-
for (const propList of prop.item_type.features) {
|
|
998
|
-
const st = genState(propList);
|
|
999
|
-
st.prop = expose.property;
|
|
1000
|
-
st.inOptions = true;
|
|
1001
|
-
st.setterOpt = (value, options) => {
|
|
1002
|
-
const result = {};
|
|
1003
|
-
options[propList.property] = value;
|
|
1004
|
-
result[expose.property] = options;
|
|
1005
|
-
return result;
|
|
1006
|
-
};
|
|
1007
|
-
if (propList.access & ea.SET) {
|
|
1008
|
-
st.setter = (value, options) => {
|
|
1009
|
-
const result = {};
|
|
1010
|
-
options[propList.property] = value;
|
|
1011
|
-
result[expose.property] = options;
|
|
1012
|
-
return result;
|
|
1013
|
-
};
|
|
1014
|
-
st.setattr = expose.property;
|
|
1015
|
-
}
|
|
1016
|
-
if (propList.access & ea.STATE) {
|
|
1017
|
-
st.getter = payload => {
|
|
1018
|
-
if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(propList.property)) {
|
|
1019
|
-
return !isNaN(payload[expose.property][propList.property]) ? payload[expose.property][propList.property] : undefined;
|
|
1020
|
-
} else {
|
|
1021
|
-
return undefined;
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
1024
|
-
} else {
|
|
1025
|
-
st.getter = payload => undefined;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
st.id = st.prop + '_' + st.id;
|
|
1029
|
-
pushToStates(st, propList.access);
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
984
|
+
const cStates = generateCompositeStates(expose, '', options);
|
|
985
|
+
for (const state of cStates)
|
|
986
|
+
pushToStates(state, expose.access);
|
|
1033
987
|
break;
|
|
1034
988
|
}
|
|
1035
989
|
case 'list':
|
|
@@ -1047,20 +1001,9 @@ function createFromExposes(model, def, device, log) {
|
|
|
1047
1001
|
|
|
1048
1002
|
}
|
|
1049
1003
|
|
|
1050
|
-
async function
|
|
1051
|
-
if (options && typeof options == 'object') {
|
|
1052
|
-
LocalData.options = options;
|
|
1053
|
-
}
|
|
1054
|
-
const deviceDef = await zigbeeHerdsmanConverters.findByDevice(device);
|
|
1055
|
-
if (!deviceDef) {
|
|
1056
|
-
return undefined;
|
|
1057
|
-
}
|
|
1058
|
-
return applyDeviceDef(mappedDevices, byModel, deviceDef, device);
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
async function applyHerdsmanModel(modelDesc) {
|
|
1004
|
+
async function applyHerdsmanModel(modelDesc, options) {
|
|
1062
1005
|
try {
|
|
1063
|
-
const newModel = createFromExposes(modelDesc.key, modelDesc, modelDesc.device)
|
|
1006
|
+
const newModel = createFromExposes(modelDesc.key, modelDesc, modelDesc.device, options)
|
|
1064
1007
|
if (newModel) {
|
|
1065
1008
|
if (modelDesc.UUID) newModel.UUID = modelDesc.UUID;
|
|
1066
1009
|
}
|
|
@@ -1071,25 +1014,6 @@ async function applyHerdsmanModel(modelDesc) {
|
|
|
1071
1014
|
}
|
|
1072
1015
|
}
|
|
1073
1016
|
|
|
1074
|
-
|
|
1075
|
-
function applyDeviceDef(mappedDevices, byModel, deviceDef, device) {
|
|
1076
|
-
const stripModel = utils.getModelRegEx(deviceDef.model);
|
|
1077
|
-
const existsMap = byModel.get(stripModel);
|
|
1078
|
-
if (deviceDef.hasOwnProperty('exposes') && (!existsMap || !existsMap.hasOwnProperty('states'))) {
|
|
1079
|
-
try {
|
|
1080
|
-
const newDevice = createFromExposes(stripModel, deviceDef, device);
|
|
1081
|
-
mappedDevices.push(newDevice);
|
|
1082
|
-
byModel.set(stripModel, newDevice);
|
|
1083
|
-
return newDevice;
|
|
1084
|
-
|
|
1085
|
-
} catch (e) {
|
|
1086
|
-
return undefined;
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
return existsMap;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
1017
|
module.exports = {
|
|
1093
|
-
applyExposeForDevice: applyExposeForDevice,
|
|
1094
1018
|
applyHerdsmanModel: applyHerdsmanModel,
|
|
1095
1019
|
};
|
package/lib/groups.js
CHANGED
|
@@ -676,11 +676,8 @@ class Groups {
|
|
|
676
676
|
}, () => {
|
|
677
677
|
this.adapter.extendObject(id, {common: {name: name, type: 'group', icon: icon}});
|
|
678
678
|
// create writable states for groups from their devices
|
|
679
|
-
for (const
|
|
680
|
-
if (!
|
|
681
|
-
continue;
|
|
682
|
-
}
|
|
683
|
-
const statedesc = stateDefinitions.groupStates[stateInd];
|
|
679
|
+
for (const statedesc of stateDefinitions.groupStates) {
|
|
680
|
+
if (!statedesc) continue;
|
|
684
681
|
const common = {};
|
|
685
682
|
for (const prop in statedesc)
|
|
686
683
|
if (typeof statedesc[prop] != 'function')
|
package/lib/legacy/devices.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const states = require('./states.js').states;
|
|
4
4
|
const utils = require('../utils.js');
|
|
5
5
|
const rgb = require('../rgb.js');
|
|
6
|
-
const { applyExposeForDevice} = require('../exposes.js');
|
|
6
|
+
//const { applyExposeForDevice} = require('../exposes.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
// return list of changing states when incoming state is changed
|
|
@@ -3119,6 +3119,7 @@ function getByModel() {
|
|
|
3119
3119
|
|
|
3120
3120
|
removeEmptyStates(devices);
|
|
3121
3121
|
|
|
3122
|
+
/*
|
|
3122
3123
|
function fillStatesWithExposes(logger) {
|
|
3123
3124
|
if (DevicesByModel.size <1) getByModel();
|
|
3124
3125
|
return;
|
|
@@ -3133,7 +3134,7 @@ async function addExposeToDevices(device, logger, model) {
|
|
|
3133
3134
|
removeEmptyStates(devices);
|
|
3134
3135
|
return rv;
|
|
3135
3136
|
}
|
|
3136
|
-
|
|
3137
|
+
*/
|
|
3137
3138
|
// remove empty states
|
|
3138
3139
|
function removeEmptyStates(devices) {
|
|
3139
3140
|
for (const device of devices) {
|
|
@@ -3200,6 +3201,7 @@ function hasLegacyDevice(model) {
|
|
|
3200
3201
|
}
|
|
3201
3202
|
|
|
3202
3203
|
module.exports = {
|
|
3204
|
+
/*
|
|
3203
3205
|
devices,
|
|
3204
3206
|
legacy_devices,
|
|
3205
3207
|
commonStates,
|
|
@@ -3211,10 +3213,11 @@ module.exports = {
|
|
|
3211
3213
|
fillStatesWithExposes,
|
|
3212
3214
|
addExposeToDevices,
|
|
3213
3215
|
getByModel,
|
|
3216
|
+
*/
|
|
3214
3217
|
findModel,
|
|
3215
|
-
fillDevicesForLegacy,
|
|
3216
|
-
pairedLegacyDevices,
|
|
3217
|
-
setLegacyDevices,
|
|
3218
|
+
//fillDevicesForLegacy,
|
|
3219
|
+
//pairedLegacyDevices,
|
|
3220
|
+
//setLegacyDevices,
|
|
3218
3221
|
hasLegacyDevice,
|
|
3219
3222
|
getIconforLegacyModel,
|
|
3220
3223
|
};
|