iobroker.zigbee2mqtt 3.0.9 → 3.0.13

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/lib/exposes.js CHANGED
@@ -1,5 +1,5 @@
1
- /* eslint-disable no-prototype-builtins */
2
- // @ts-nocheck
1
+
2
+
3
3
  'use strict';
4
4
 
5
5
  const statesDefs = require('./states').states;
@@ -11,28 +11,28 @@ const getNonGenDevStatesDefs = require('./nonGenericDevicesExtension').getStateD
11
11
  // https://www.zigbee2mqtt.io/guide/usage/exposes.html#access
12
12
  const z2mAccess = {
13
13
  /**
14
- * Bit 0: The property can be found in the published state of this device
15
- */
14
+ * Bit 0: The property can be found in the published state of this device
15
+ */
16
16
  STATE: 1,
17
17
  /**
18
- * Bit 1: The property can be set with a /set command
19
- */
18
+ * Bit 1: The property can be set with a /set command
19
+ */
20
20
  SET: 2,
21
21
  /**
22
- * Bit 2: The property can be retrieved with a /get command
23
- */
22
+ * Bit 2: The property can be retrieved with a /get command
23
+ */
24
24
  GET: 4,
25
25
  /**
26
- * Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
27
- */
26
+ * Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
27
+ */
28
28
  STATE_SET: 3,
29
29
  /**
30
- * Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
31
- */
30
+ * Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
31
+ */
32
32
  STATE_GET: 5,
33
33
  /**
34
- * Bitwise inclusive OR of STATE and GET and SET : 0b001 | 0b100 | 0b010
35
- */
34
+ * Bitwise inclusive OR of STATE and GET and SET : 0b001 | 0b100 | 0b010
35
+ */
36
36
  ALL: 7,
37
37
  };
38
38
 
@@ -174,6 +174,11 @@ function genState(expose, role, name, desc) {
174
174
  return state;
175
175
  }
176
176
 
177
+ /**
178
+ *
179
+ * @param devicesMessag
180
+ * @param adapter
181
+ */
177
182
  async function createDeviceFromExposes(devicesMessag, adapter) {
178
183
  const states = [];
179
184
  let scenes = [];
@@ -189,7 +194,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
189
194
  if (state === undefined) {
190
195
  return 0;
191
196
  }
192
- if (access === undefined) access = z2mAccess.ALL;
197
+ if (access === undefined) {
198
+ access = z2mAccess.ALL;
199
+ }
193
200
  state.readable = (access & z2mAccess.STATE) > 0;
194
201
  state.writable = (access & z2mAccess.SET) > 0;
195
202
  const stateExists = states.findIndex((x, _index, _array) => x.id === state.id);
@@ -214,7 +221,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
214
221
  }
215
222
 
216
223
  return states.push(state);
217
- } else {
224
+ }
218
225
  if (state.readable && !states[stateExists].readable) {
219
226
  states[stateExists].read = state.read;
220
227
  // as state is readable, it can't be button or event
@@ -269,9 +276,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
269
276
  // as we have new state, responsible for set, we have to use new `isOption`
270
277
  // or remove it
271
278
  if (
272
- (!state.hasOwnProperty('isOption') || state.isOptions === false) &&
273
- states[stateExists].hasOwnProperty('isOption')
274
- ) {
279
+ (!state.hasOwnProperty('isOption') || state.isOption === false) && states[stateExists].hasOwnProperty('isOption')) {
275
280
  delete states[stateExists].isOption;
276
281
  } else {
277
282
  states[stateExists].isOption = state.isOption;
@@ -296,7 +301,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
296
301
  }
297
302
 
298
303
  return states.length;
299
- }
304
+
300
305
  }
301
306
 
302
307
  // search for scenes in the endpoints and build them into an array
@@ -442,17 +447,17 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
442
447
  read: true,
443
448
  type: 'number',
444
449
  min:
445
- config.useKelvin == true
446
- ? utils.miredKelvinConversion(prop.value_max)
447
- : prop.value_min,
450
+ config.useKelvin == true
451
+ ? utils.miredKelvinConversion(prop.value_max)
452
+ : prop.value_min,
448
453
  max:
449
- config.useKelvin == true
450
- ? utils.miredKelvinConversion(prop.value_min)
451
- : prop.value_max,
454
+ config.useKelvin == true
455
+ ? utils.miredKelvinConversion(prop.value_min)
456
+ : prop.value_max,
452
457
  def:
453
- config.useKelvin == true
454
- ? utils.miredKelvinConversion(prop.value_min)
455
- : prop.value_max,
458
+ config.useKelvin == true
459
+ ? utils.miredKelvinConversion(prop.value_min)
460
+ : prop.value_max,
456
461
  unit: config.useKelvin == true ? 'K' : 'mired',
457
462
  setter: (value) => {
458
463
  return utils.toMired(value);
@@ -463,9 +468,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
463
468
  }
464
469
  if (config.useKelvin == true) {
465
470
  return utils.miredKelvinConversion(payload[propName]);
466
- } else {
471
+ }
467
472
  return payload[propName];
468
- }
473
+
469
474
  },
470
475
  },
471
476
  prop.access
@@ -490,21 +495,21 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
490
495
  break;
491
496
  }
492
497
  case 'color_temp_startup': {
493
- const stateName = expose.endpoint
494
- ? `colortempstartup_${expose.endpoint}`
495
- : 'colortempstartup';
498
+ //const stateName = expose.endpoint
499
+ // ? `colortempstartup_${expose.endpoint}`
500
+ // : 'colortempstartup';
496
501
  const propName = expose.endpoint
497
502
  ? `color_temp_startup_${expose.endpoint}`
498
503
  : 'color_temp_startup';
499
504
  //const colorMode = expose.endpoint ? `color_mode_${expose.endpoint}` : 'color_mode';
500
505
  pushToStates(
501
506
  {
502
- id: stateName,
507
+ id: propName,
503
508
  prop: propName,
504
509
  name: `${prop.description} ${expose.endpoint ? `(${expose.endpoint})` : ''}`.trim(),
505
510
  //options: ['transition'],
506
511
  icon: undefined,
507
- role: 'level.color.temperature',
512
+ role: 'level', // Changed role to level to avoid double level.temperature in one device
508
513
  write: true,
509
514
  read: true,
510
515
  type: 'number',
@@ -521,9 +526,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
521
526
  //}
522
527
  if (config.useKelvin == true) {
523
528
  return utils.miredKelvinConversion(payload[propName]);
524
- } else {
529
+ }
525
530
  return payload[propName];
526
- }
531
+
527
532
  },
528
533
  },
529
534
  prop.access
@@ -560,22 +565,22 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
560
565
  }
561
566
  if (
562
567
  payload[stateName] &&
563
- payload[stateName].hasOwnProperty('x') &&
564
- payload[stateName].hasOwnProperty('y')
568
+ payload[stateName].hasOwnProperty('x') &&
569
+ payload[stateName].hasOwnProperty('y')
565
570
  ) {
566
571
  const colorval = rgb.cie_to_rgb(
567
572
  payload[stateName].x,
568
573
  payload[stateName].y
569
574
  );
570
575
  return (
571
- '#' +
572
- utils.decimalToHex(colorval[0]) +
573
- utils.decimalToHex(colorval[1]) +
574
- utils.decimalToHex(colorval[2])
576
+ `#${
577
+ utils.decimalToHex(colorval[0])
578
+ }${utils.decimalToHex(colorval[1])
579
+ }${utils.decimalToHex(colorval[2])}`
575
580
  );
576
- } else {
581
+ }
577
582
  return undefined;
578
- }
583
+
579
584
  },
580
585
  epname: expose.endpoint,
581
586
  },
@@ -637,10 +642,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
637
642
  payload[stateName].y
638
643
  );
639
644
  return (
640
- '#' +
641
- utils.decimalToHex(colorval[0]) +
642
- utils.decimalToHex(colorval[1]) +
643
- utils.decimalToHex(colorval[2])
645
+ `#${
646
+ utils.decimalToHex(colorval[0])
647
+ }${utils.decimalToHex(colorval[1])
648
+ }${utils.decimalToHex(colorval[2])}`
644
649
  );
645
650
  }
646
651
  return undefined;
@@ -751,12 +756,19 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
751
756
  break;
752
757
  }
753
758
  }
754
- if (state) pushToStates(state, expose.access);
759
+ if (state) {
760
+ pushToStates(state, expose.access);
761
+ }
755
762
  break;
756
763
 
757
- case 'enum':
764
+ case 'enum': {
758
765
  switch (expose.name) {
759
766
  case 'action': {
767
+ //generate an 'action' state\
768
+ state = genState(expose);
769
+ state.isEvent = true;
770
+ pushToStates(state, expose.access);
771
+
760
772
  if (!Array.isArray(expose.values)) {
761
773
  break;
762
774
  }
@@ -794,8 +806,8 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
794
806
  // is release -> hold state? - skip
795
807
  if (
796
808
  config.simpleHoldReleaseState == true &&
797
- actionName.endsWith('release') &&
798
- expose.values.find((x) => x == actionName.replace('release', 'hold'))
809
+ actionName.endsWith('release') &&
810
+ expose.values.find((x) => x == actionName.replace('release', 'hold'))
799
811
  ) {
800
812
  continue;
801
813
  }
@@ -803,8 +815,8 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
803
815
  // is stop - move state? - skip
804
816
  if (
805
817
  config.simpleMoveStopState == true &&
806
- actionName.endsWith('stop') &&
807
- expose.values.find((x) => x.includes(actionName.replace('stop', 'move')))
818
+ actionName.endsWith('stop') &&
819
+ expose.values.find((x) => x.includes(actionName.replace('stop', 'move')))
808
820
  ) {
809
821
  continue;
810
822
  }
@@ -812,17 +824,16 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
812
824
  // is release -> press state? - skip
813
825
  if (
814
826
  config.simplePressReleaseState == true &&
815
- actionName.endsWith('release') &&
816
- expose.values.find((x) => x == actionName.replace('release', 'press'))
827
+ actionName.endsWith('release') &&
828
+ expose.values.find((x) => x == actionName.replace('release', 'press'))
817
829
  ) {
818
830
  continue;
819
831
  }
820
832
 
821
833
  // is hold -> release state ?
822
- if (
823
- config.simpleHoldReleaseState == true &&
824
- actionName.endsWith('hold') &&
825
- expose.values.find((x) => x == actionName.replace('hold', 'release'))
834
+ if (config.simpleHoldReleaseState == true &&
835
+ actionName.endsWith('hold') &&
836
+ expose.values.find((x) => x == actionName.replace('hold', 'release'))
826
837
  ) {
827
838
  pushToStates(
828
839
  {
@@ -850,12 +861,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
850
861
  },
851
862
  expose.access
852
863
  );
853
- }
854
- // is move -> stop state ?
855
- else if (
864
+ } else if ( // is move -> stop state ?
856
865
  config.simpleMoveStopState == true &&
857
- actionName.includes('move') &&
858
- expose.values.find((x) => x == `${actionName.split('_')[0]}_stop`)
866
+ actionName.includes('move') &&
867
+ expose.values.find((x) => x == `${actionName.split('_')[0]}_stop`)
859
868
  ) {
860
869
  pushToStates(
861
870
  {
@@ -880,12 +889,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
880
889
  },
881
890
  expose.access
882
891
  );
883
- }
884
- // is press -> release state ?
885
- else if (
892
+ } else if ( // is press -> release state ?
886
893
  config.simplePressReleaseState == true &&
887
- actionName.endsWith('press') &&
888
- expose.values.find((x) => x == actionName.replace('press', 'release'))
894
+ actionName.endsWith('press') &&
895
+ expose.values.find((x) => x == actionName.replace('press', 'release'))
889
896
  ) {
890
897
  pushToStates(
891
898
  {
@@ -936,9 +943,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
936
943
  return utils.miredKelvinConversion(
937
944
  payload.action_color_temperature
938
945
  );
939
- } else {
946
+ }
940
947
  return payload.action_color_temperature;
941
- }
948
+
942
949
  }
943
950
  },
944
951
  },
@@ -964,22 +971,22 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
964
971
 
965
972
  if (
966
973
  payload.action_color &&
967
- payload.action_color.hasOwnProperty('x') &&
968
- payload.action_color.hasOwnProperty('y')
974
+ payload.action_color.hasOwnProperty('x') &&
975
+ payload.action_color.hasOwnProperty('y')
969
976
  ) {
970
977
  const colorval = rgb.cie_to_rgb(
971
978
  payload.action_color.x,
972
979
  payload.action_color.y
973
980
  );
974
981
  return (
975
- '#' +
976
- utils.decimalToHex(colorval[0]) +
977
- utils.decimalToHex(colorval[1]) +
978
- utils.decimalToHex(colorval[2])
982
+ `#${
983
+ utils.decimalToHex(colorval[0])
984
+ }${utils.decimalToHex(colorval[1])
985
+ }${utils.decimalToHex(colorval[2])}`
979
986
  );
980
- } else {
987
+ }
981
988
  return undefined;
982
- }
989
+
983
990
  },
984
991
  },
985
992
  expose.access
@@ -1006,9 +1013,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1006
1013
 
1007
1014
  if (payload.action_level) {
1008
1015
  return utils.bulbLevelToAdapterLevel(payload.action_level);
1009
- } else {
1016
+ }
1010
1017
  return undefined;
1011
- }
1018
+
1012
1019
  },
1013
1020
  },
1014
1021
  expose.access
@@ -1034,9 +1041,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1034
1041
 
1035
1042
  if (payload.action_level) {
1036
1043
  return payload.action_saturation;
1037
- } else {
1044
+ }
1038
1045
  return undefined;
1039
- }
1046
+
1040
1047
  },
1041
1048
  },
1042
1049
  expose.access
@@ -1063,41 +1070,14 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1063
1070
 
1064
1071
  if (payload.action_enhanced_hue) {
1065
1072
  return payload.action_enhanced_hue;
1066
- } else {
1073
+ }
1067
1074
  return undefined;
1068
- }
1075
+
1069
1076
  },
1070
1077
  },
1071
1078
  expose.access
1072
1079
  );
1073
- }
1074
- // else if (actionName == 'hue_move') {
1075
- // pushToStates({
1076
- // id: 'hue_move',
1077
- // name: 'Hue move rate',
1078
- // icon: undefined,
1079
- // role: 'level.color.hue',
1080
- // write: false,
1081
- // read: true,
1082
- // type: 'number',
1083
- // min: 0,
1084
- // max: 360,
1085
- // def: 0,
1086
- // isEvent: true,
1087
- // getter: (payload) => {
1088
- // if (payload.action != 'hue_move') {
1089
- // return undefined;
1090
- // }
1091
-
1092
- // if (payload.action_level) {
1093
- // return payload.action_level;
1094
- // } else {
1095
- // return undefined;
1096
- // }
1097
- // }
1098
- // }, expose.access);
1099
- // }
1100
- else {
1080
+ } else {
1101
1081
  pushToStates(
1102
1082
  {
1103
1083
  id: actionName.replace(/\*/g, ''),
@@ -1119,7 +1099,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1119
1099
  // Can the device simulated_brightness?
1120
1100
  if (
1121
1101
  definition.options &&
1122
- definition.options.find((x) => x.property == 'simulated_brightness')
1102
+ definition.options.find((x) => x.property == 'simulated_brightness')
1123
1103
  ) {
1124
1104
  pushToStates(statesDefs.simulated_brightness, z2mAccess.STATE);
1125
1105
  }
@@ -1130,9 +1110,11 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1130
1110
  state = genState(expose);
1131
1111
  break;
1132
1112
  }
1133
- if (state) pushToStates(state, expose.access);
1113
+ if (state) {
1114
+ pushToStates(state, expose.access);
1115
+ }
1134
1116
  break;
1135
-
1117
+ }
1136
1118
  case 'binary':
1137
1119
  if (expose.endpoint) {
1138
1120
  state = genState(expose);
@@ -1168,7 +1150,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1168
1150
  break;
1169
1151
  }
1170
1152
  }
1171
- if (state) pushToStates(state, expose.access);
1153
+ if (state) {
1154
+ pushToStates(state, expose.access);
1155
+ }
1172
1156
  break;
1173
1157
 
1174
1158
  case 'text':
@@ -1238,64 +1222,46 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1238
1222
  }
1239
1223
  break;
1240
1224
 
1241
- case 'composite':
1225
+ case 'composite': {
1226
+ const options = [];
1242
1227
  for (const prop of expose.features) {
1243
- // let state;
1244
- // if (prop.type == 'list' && prop.features) {
1245
- // const listName = prop.name;
1246
-
1247
- // for (const feature of prop.features) {
1248
- // genState(feature, 'state', `${listName}_${feature.name}`, prop.description);
1249
- // }
1250
- // }
1228
+ prop.type = 'text'; // to avoid problems with numbers, booleans, etc.
1251
1229
 
1252
1230
  const state = genState(prop);
1253
1231
  // Workaround for FP1 new state (region_upsert)
1254
1232
  if (!state) {
1255
1233
  break;
1256
1234
  }
1257
- state.prop = expose.property;
1258
- state.inOptions = true;
1259
- // I'm not fully sure, as it really needed, but
1260
- state.setterOpt = (value, options) => {
1261
- const result = {};
1262
- options[prop.property] = value;
1263
- result[expose.property] = options;
1264
- return result;
1265
- };
1266
- // if we have a composite expose, the value have to be an object {expose.property : {prop.property: value}}
1267
- if (prop.access & z2mAccess.SET) {
1268
- state.setter = (value, options) => {
1269
- const result = {};
1270
- options[prop.property] = value;
1271
- result[expose.property] = options;
1272
- return result;
1273
- };
1274
- state.setattr = expose.property;
1275
- }
1276
- // if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
1277
- if (prop.access & z2mAccess.STATE) {
1235
+
1236
+ state.prop = expose.property;
1237
+ state.inOptions = true;
1238
+ state.isOption = true;
1239
+
1240
+ if (expose.access & z2mAccess.STATE) {
1278
1241
  state.getter = (payload) => {
1279
1242
  if (
1280
1243
  payload.hasOwnProperty(expose.property) &&
1281
- payload[expose.property] !== null &&
1282
- payload[expose.property].hasOwnProperty(prop.property)
1244
+ payload[expose.property] !== null &&
1245
+ payload[expose.property].hasOwnProperty(prop.property)
1283
1246
  ) {
1284
1247
  return !isNaN(payload[expose.property][prop.property])
1285
1248
  ? payload[expose.property][prop.property]
1286
1249
  : undefined;
1287
- } else {
1250
+ }
1288
1251
  return undefined;
1289
- }
1252
+
1290
1253
  };
1291
1254
  } else {
1292
- state.getter = (_payload) => {
1293
- return undefined;
1255
+ state.getter = (payload) => {
1256
+ return payload[expose.property][prop.property];
1294
1257
  };
1295
1258
  }
1296
- pushToStates(state, prop.access);
1259
+
1260
+ pushToStates(state, z2mAccess.STATE);
1297
1261
  }
1262
+
1298
1263
  break;
1264
+ }
1299
1265
  default:
1300
1266
  console.log(`Unhandled expose type ${expose.type} for device ${deviceID}`);
1301
1267
  }