zigbee-herdsman-converters 14.0.400 → 14.0.404

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.
@@ -719,6 +719,7 @@ const converters = {
719
719
  {key: 'rmsVoltage', name: 'voltage', factor: 'acVoltage'},
720
720
  {key: 'rmsVoltagePhB', name: 'voltage_phase_b', factor: 'acVoltage'},
721
721
  {key: 'rmsVoltagePhC', name: 'voltage_phase_c', factor: 'acVoltage'},
722
+ {key: 'acFrequency', name: 'ac_frequency', factor: 'acFrequency'},
722
723
  ];
723
724
 
724
725
  const payload = {};
@@ -730,6 +731,9 @@ const converters = {
730
731
  payload[property] = calibrateAndPrecisionRoundOptions(value, options, entry.name);
731
732
  }
732
733
  }
734
+ if (msg.data.hasOwnProperty('powerFactor')) {
735
+ payload.power_factor = precisionRound(msg.data['powerFactor'] / 100, 2);
736
+ }
733
737
  return payload;
734
738
  },
735
739
  },
@@ -1042,7 +1046,7 @@ const converters = {
1042
1046
  cluster: 'genScenes',
1043
1047
  type: 'commandRecall',
1044
1048
  convert: (model, msg, publish, options, meta) => {
1045
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1049
+ if (hasAlreadyProcessedMessage(msg)) return;
1046
1050
  const payload = {action: postfixWithEndpointName(`recall_${msg.data.sceneid}`, msg, model)};
1047
1051
  addActionGroup(payload, msg, model);
1048
1052
  return payload;
@@ -1052,7 +1056,7 @@ const converters = {
1052
1056
  cluster: 'ssIasAce',
1053
1057
  type: 'commandPanic',
1054
1058
  convert: (model, msg, publish, options, meta) => {
1055
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1059
+ if (hasAlreadyProcessedMessage(msg)) return;
1056
1060
  const payload = {action: postfixWithEndpointName(`panic`, msg, model)};
1057
1061
  addActionGroup(payload, msg, model);
1058
1062
  return payload;
@@ -1062,7 +1066,7 @@ const converters = {
1062
1066
  cluster: 'ssIasAce',
1063
1067
  type: 'commandArm',
1064
1068
  convert: (model, msg, publish, options, meta) => {
1065
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1069
+ if (hasAlreadyProcessedMessage(msg)) return;
1066
1070
  const payload = {
1067
1071
  action: postfixWithEndpointName(constants.armMode[msg.data['armmode']], msg, model),
1068
1072
  action_code: msg.data.code,
@@ -1086,7 +1090,7 @@ const converters = {
1086
1090
  cluster: 'closuresWindowCovering',
1087
1091
  type: 'commandStop',
1088
1092
  convert: (model, msg, publish, options, meta) => {
1089
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1093
+ if (hasAlreadyProcessedMessage(msg)) return;
1090
1094
  const payload = {action: postfixWithEndpointName('stop', msg, model)};
1091
1095
  addActionGroup(payload, msg, model);
1092
1096
  return payload;
@@ -1096,7 +1100,7 @@ const converters = {
1096
1100
  cluster: 'closuresWindowCovering',
1097
1101
  type: 'commandUpOpen',
1098
1102
  convert: (model, msg, publish, options, meta) => {
1099
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1103
+ if (hasAlreadyProcessedMessage(msg)) return;
1100
1104
  const payload = {action: postfixWithEndpointName('open', msg, model)};
1101
1105
  addActionGroup(payload, msg, model);
1102
1106
  return payload;
@@ -1106,7 +1110,7 @@ const converters = {
1106
1110
  cluster: 'closuresWindowCovering',
1107
1111
  type: 'commandDownClose',
1108
1112
  convert: (model, msg, publish, options, meta) => {
1109
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1113
+ if (hasAlreadyProcessedMessage(msg)) return;
1110
1114
  const payload = {action: postfixWithEndpointName('close', msg, model)};
1111
1115
  addActionGroup(payload, msg, model);
1112
1116
  return payload;
@@ -1116,7 +1120,7 @@ const converters = {
1116
1120
  cluster: 'genOnOff',
1117
1121
  type: 'commandOn',
1118
1122
  convert: (model, msg, publish, options, meta) => {
1119
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1123
+ if (hasAlreadyProcessedMessage(msg)) return;
1120
1124
  const payload = {action: postfixWithEndpointName('on', msg, model)};
1121
1125
  addActionGroup(payload, msg, model);
1122
1126
  return payload;
@@ -1126,7 +1130,7 @@ const converters = {
1126
1130
  cluster: 'genOnOff',
1127
1131
  type: 'commandOff',
1128
1132
  convert: (model, msg, publish, options, meta) => {
1129
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1133
+ if (hasAlreadyProcessedMessage(msg)) return;
1130
1134
  const payload = {action: postfixWithEndpointName('off', msg, model)};
1131
1135
  addActionGroup(payload, msg, model);
1132
1136
  return payload;
@@ -1136,7 +1140,7 @@ const converters = {
1136
1140
  cluster: 'genOnOff',
1137
1141
  type: 'commandOffWithEffect',
1138
1142
  convert: (model, msg, publish, options, meta) => {
1139
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1143
+ if (hasAlreadyProcessedMessage(msg)) return;
1140
1144
  const payload = {action: postfixWithEndpointName(`off`, msg, model)};
1141
1145
  addActionGroup(payload, msg, model);
1142
1146
  return payload;
@@ -1146,7 +1150,7 @@ const converters = {
1146
1150
  cluster: 'genOnOff',
1147
1151
  type: 'commandToggle',
1148
1152
  convert: (model, msg, publish, options, meta) => {
1149
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1153
+ if (hasAlreadyProcessedMessage(msg)) return;
1150
1154
  const payload = {action: postfixWithEndpointName('toggle', msg, model)};
1151
1155
  addActionGroup(payload, msg, model);
1152
1156
  return payload;
@@ -1157,7 +1161,7 @@ const converters = {
1157
1161
  type: ['commandMoveToLevel', 'commandMoveToLevelWithOnOff'],
1158
1162
  options: [exposes.options.simulated_brightness()],
1159
1163
  convert: (model, msg, publish, options, meta) => {
1160
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1164
+ if (hasAlreadyProcessedMessage(msg)) return;
1161
1165
  const payload = {
1162
1166
  action: postfixWithEndpointName(`brightness_move_to_level`, msg, model),
1163
1167
  action_level: msg.data.level,
@@ -1179,7 +1183,7 @@ const converters = {
1179
1183
  type: ['commandMove', 'commandMoveWithOnOff'],
1180
1184
  options: [exposes.options.simulated_brightness()],
1181
1185
  convert: (model, msg, publish, options, meta) => {
1182
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1186
+ if (hasAlreadyProcessedMessage(msg)) return;
1183
1187
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1184
1188
  const action = postfixWithEndpointName(`brightness_move_${direction}`, msg, model);
1185
1189
  const payload = {action, action_rate: msg.data.rate};
@@ -1215,7 +1219,7 @@ const converters = {
1215
1219
  type: ['commandStep', 'commandStepWithOnOff'],
1216
1220
  options: [exposes.options.simulated_brightness()],
1217
1221
  convert: (model, msg, publish, options, meta) => {
1218
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1222
+ if (hasAlreadyProcessedMessage(msg)) return;
1219
1223
  const direction = msg.data.stepmode === 1 ? 'down' : 'up';
1220
1224
  const payload = {
1221
1225
  action: postfixWithEndpointName(`brightness_step_${direction}`, msg, model),
@@ -1242,7 +1246,7 @@ const converters = {
1242
1246
  type: ['commandStop', 'commandStopWithOnOff'],
1243
1247
  options: [exposes.options.simulated_brightness()],
1244
1248
  convert: (model, msg, publish, options, meta) => {
1245
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1249
+ if (hasAlreadyProcessedMessage(msg)) return;
1246
1250
  if (options.simulated_brightness) {
1247
1251
  clearInterval(globalStore.getValue(msg.endpoint, 'simulated_brightness_timer'));
1248
1252
  globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', undefined);
@@ -1257,7 +1261,7 @@ const converters = {
1257
1261
  cluster: 'lightingColorCtrl',
1258
1262
  type: ['commandMoveColorTemp'],
1259
1263
  convert: (model, msg, publish, options, meta) => {
1260
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1264
+ if (hasAlreadyProcessedMessage(msg)) return;
1261
1265
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1262
1266
  const action = postfixWithEndpointName(`color_temperature_move_${direction}`, msg, model);
1263
1267
  const payload = {action, action_rate: msg.data.rate, action_minimum: msg.data.minimum, action_maximum: msg.data.maximum};
@@ -1269,7 +1273,7 @@ const converters = {
1269
1273
  cluster: 'lightingColorCtrl',
1270
1274
  type: 'commandStepColorTemp',
1271
1275
  convert: (model, msg, publish, options, meta) => {
1272
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1276
+ if (hasAlreadyProcessedMessage(msg)) return;
1273
1277
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1274
1278
  const payload = {
1275
1279
  action: postfixWithEndpointName(`color_temperature_step_${direction}`, msg, model),
@@ -1288,7 +1292,7 @@ const converters = {
1288
1292
  cluster: 'lightingColorCtrl',
1289
1293
  type: 'commandEnhancedMoveToHueAndSaturation',
1290
1294
  convert: (model, msg, publish, options, meta) => {
1291
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1295
+ if (hasAlreadyProcessedMessage(msg)) return;
1292
1296
  const payload = {
1293
1297
  action: postfixWithEndpointName(`enhanced_move_to_hue_and_saturation`, msg, model),
1294
1298
  action_enhanced_hue: msg.data.enhancehue,
@@ -1305,7 +1309,7 @@ const converters = {
1305
1309
  cluster: 'lightingColorCtrl',
1306
1310
  type: ['commandStepHue'],
1307
1311
  convert: (model, msg, publish, options, meta) => {
1308
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1312
+ if (hasAlreadyProcessedMessage(msg)) return;
1309
1313
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1310
1314
  const payload = {
1311
1315
  action: postfixWithEndpointName(`color_hue_step_${direction}`, msg, model),
@@ -1320,7 +1324,7 @@ const converters = {
1320
1324
  cluster: 'lightingColorCtrl',
1321
1325
  type: ['commandStepSaturation'],
1322
1326
  convert: (model, msg, publish, options, meta) => {
1323
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1327
+ if (hasAlreadyProcessedMessage(msg)) return;
1324
1328
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1325
1329
  const payload = {
1326
1330
  action: postfixWithEndpointName(`color_saturation_step_${direction}`, msg, model),
@@ -1335,7 +1339,7 @@ const converters = {
1335
1339
  cluster: 'lightingColorCtrl',
1336
1340
  type: 'commandColorLoopSet',
1337
1341
  convert: (model, msg, publish, options, meta) => {
1338
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1342
+ if (hasAlreadyProcessedMessage(msg)) return;
1339
1343
  const updateFlags = msg.data.updateflags;
1340
1344
  const actionLookup = {
1341
1345
  0x00: 'deactivate',
@@ -1365,7 +1369,7 @@ const converters = {
1365
1369
  cluster: 'lightingColorCtrl',
1366
1370
  type: 'commandMoveToColorTemp',
1367
1371
  convert: (model, msg, publish, options, meta) => {
1368
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1372
+ if (hasAlreadyProcessedMessage(msg)) return;
1369
1373
  const payload = {
1370
1374
  action: postfixWithEndpointName(`color_temperature_move`, msg, model),
1371
1375
  action_color_temperature: msg.data.colortemp,
@@ -1379,7 +1383,7 @@ const converters = {
1379
1383
  cluster: 'lightingColorCtrl',
1380
1384
  type: 'commandMoveToColor',
1381
1385
  convert: (model, msg, publish, options, meta) => {
1382
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1386
+ if (hasAlreadyProcessedMessage(msg)) return;
1383
1387
  const payload = {
1384
1388
  action: postfixWithEndpointName(`color_move`, msg, model),
1385
1389
  action_color: {
@@ -1396,7 +1400,7 @@ const converters = {
1396
1400
  cluster: 'lightingColorCtrl',
1397
1401
  type: 'commandMoveHue',
1398
1402
  convert: (model, msg, publish, options, meta) => {
1399
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1403
+ if (hasAlreadyProcessedMessage(msg)) return;
1400
1404
  const movestop = msg.data.movemode == 1 ? 'move' : 'stop';
1401
1405
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
1402
1406
  const payload = {action, action_rate: msg.data.rate};
@@ -1408,7 +1412,7 @@ const converters = {
1408
1412
  cluster: 'lightingColorCtrl',
1409
1413
  type: 'commandMoveToSaturation',
1410
1414
  convert: (model, msg, publish, options, meta) => {
1411
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1415
+ if (hasAlreadyProcessedMessage(msg)) return;
1412
1416
  const payload = {
1413
1417
  action: postfixWithEndpointName('move_to_saturation', msg, model),
1414
1418
  action_saturation: msg.data.saturation,
@@ -1422,7 +1426,7 @@ const converters = {
1422
1426
  cluster: 'lightingColorCtrl',
1423
1427
  type: 'commandMoveToHue',
1424
1428
  convert: (model, msg, publish, options, meta) => {
1425
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1429
+ if (hasAlreadyProcessedMessage(msg)) return;
1426
1430
  const payload = {
1427
1431
  action: postfixWithEndpointName(`move_to_hue`, msg, model),
1428
1432
  action_hue: msg.data.hue,
@@ -1437,7 +1441,7 @@ const converters = {
1437
1441
  cluster: 'ssIasAce',
1438
1442
  type: 'commandEmergency',
1439
1443
  convert: (model, msg, publish, options, meta) => {
1440
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1444
+ if (hasAlreadyProcessedMessage(msg)) return;
1441
1445
  const payload = {action: postfixWithEndpointName(`emergency`, msg, model)};
1442
1446
  addActionGroup(payload, msg, model);
1443
1447
  return payload;
@@ -1447,7 +1451,7 @@ const converters = {
1447
1451
  cluster: 'genOnOff',
1448
1452
  type: 'commandOn',
1449
1453
  convert: (model, msg, publish, options, meta) => {
1450
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1454
+ if (hasAlreadyProcessedMessage(msg)) return;
1451
1455
  const property = postfixWithEndpointName('state', msg, model);
1452
1456
  return {[property]: 'ON'};
1453
1457
  },
@@ -1456,7 +1460,7 @@ const converters = {
1456
1460
  cluster: 'genOnOff',
1457
1461
  type: 'commandOff',
1458
1462
  convert: (model, msg, publish, options, meta) => {
1459
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1463
+ if (hasAlreadyProcessedMessage(msg)) return;
1460
1464
  const property = postfixWithEndpointName('state', msg, model);
1461
1465
  return {[property]: 'OFF'};
1462
1466
  },
@@ -2181,7 +2185,7 @@ const converters = {
2181
2185
  cluster: 'ssIasZone',
2182
2186
  type: 'commandStatusChangeNotification',
2183
2187
  convert: (model, msg, publish, options, meta) => {
2184
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
2188
+ if (hasAlreadyProcessedMessage(msg)) return;
2185
2189
  const lookup = {1: 'pressed'};
2186
2190
  const zoneStatus = msg.data.zonestatus;
2187
2191
  return {
@@ -3811,19 +3815,21 @@ const converters = {
3811
3815
  return {open_window_temperature: (value / 10).toFixed(1)};
3812
3816
  case tuya.dataPoints.tvErrorStatus:
3813
3817
  return {fault_alarm: value};
3814
- case tuya.dataPoints.tvHolidayMode:
3815
- return {holiday_mode_date: value};
3816
-
3818
+ case tuya.dataPoints.tvHolidayMode: {
3819
+ const sy = value.slice(0, 4); const sm = value.slice(4, 6); const sd = value.slice(6, 8);
3820
+ const sh = value.slice(8, 10); const smi = value.slice(10, 12); const ey = value.slice(12, 16);
3821
+ const em = value.slice(16, 18); const ed = value.slice(18, 20); const eh = value.slice(20, 22);
3822
+ const emi = value.slice(22, 24);
3823
+ const hMode = 'start --> ' + sy + ' - ' + sm + ' - ' + sd + ' ' + sh + ' : ' + smi +
3824
+ ' stop --> ' + ey + ' - ' + em + ' - ' + ed + ' ' + eh + ' : ' + emi;
3825
+ return {holiday_start_stop: hMode};
3826
+ }
3817
3827
  case tuya.dataPoints.tvBoostMode:
3818
- // Online ?
3828
+ // 115 online / Is the device online
3819
3829
  return {online: value ? 'ON' : 'OFF'};
3820
3830
  case tuya.dataPoints.tvWorkingDay:
3821
- // tvWorkingDay: 31,
3831
+ // DP-31, Send and Report, ENUM, Week select 0 - 5 days, 1 - 6 days, 2 - 7 days
3822
3832
  return {working_day: value};
3823
- case tuya.dataPoints.tvWeekSchedule:
3824
- // tvWeekSchedule: 106, Week select 0 - 5 days, 1 - 6 days, 2 - 7 days
3825
- return {week_schedule: value};
3826
-
3827
3833
  case tuya.dataPoints.tvMondaySchedule:
3828
3834
  return {schedule_monday:
3829
3835
  ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
@@ -4518,7 +4524,7 @@ const converters = {
4518
4524
  cluster: 'genScenes',
4519
4525
  type: 'commandTradfriArrowSingle',
4520
4526
  convert: (model, msg, publish, options, meta) => {
4521
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4527
+ if (hasAlreadyProcessedMessage(msg)) return;
4522
4528
  if (msg.data.value === 2) {
4523
4529
  // This is send on toggle hold, ignore it as a toggle_hold is already handled above.
4524
4530
  return;
@@ -4532,7 +4538,7 @@ const converters = {
4532
4538
  cluster: 'genScenes',
4533
4539
  type: 'commandTradfriArrowHold',
4534
4540
  convert: (model, msg, publish, options, meta) => {
4535
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4541
+ if (hasAlreadyProcessedMessage(msg)) return;
4536
4542
  const direction = msg.data.value === 3329 ? 'left' : 'right';
4537
4543
  globalStore.putValue(msg.endpoint, 'direction', direction);
4538
4544
  return {action: `arrow_${direction}_hold`};
@@ -4543,7 +4549,7 @@ const converters = {
4543
4549
  type: 'commandTradfriArrowRelease',
4544
4550
  options: [exposes.options.legacy()],
4545
4551
  convert: (model, msg, publish, options, meta) => {
4546
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4552
+ if (hasAlreadyProcessedMessage(msg)) return;
4547
4553
  const direction = globalStore.getValue(msg.endpoint, 'direction');
4548
4554
  if (direction) {
4549
4555
  globalStore.clearValue(msg.endpoint, 'direction');
@@ -5253,7 +5259,7 @@ const converters = {
5253
5259
  else if (index === 5) {
5254
5260
  if (['JT-BZ-01AQ/A'].includes(model.model)) payload.power_outage_count = value;
5255
5261
  } else if (index === 100) {
5256
- if (['QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
5262
+ if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
5257
5263
  const mapping = model.model === 'QBCZ15LM' ? 'relay' : 'left';
5258
5264
  payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
5259
5265
  } else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
@@ -5262,13 +5268,15 @@ const converters = {
5262
5268
  payload.state = value === 1 ? 'ON' : 'OFF';
5263
5269
  }
5264
5270
  } else if (index === 101) {
5265
- if (['QBKG19LM', 'QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
5271
+ if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
5266
5272
  const mapping = model.model === 'QBCZ15LM' ? 'usb' : 'right';
5267
5273
  payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
5268
5274
  } else if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
5269
5275
  payload.state_center = value === 1 ? 'ON' : 'OFF';
5270
5276
  } else if (['RTCGQ12LM'].includes(model.model)) {
5271
5277
  payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
5278
+ } else if (['ZNJLBL01LM'].includes(model.model)) {
5279
+ payload.battery = value;
5272
5280
  }
5273
5281
  } else if (index ===102 ) {
5274
5282
  if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
@@ -5299,6 +5307,7 @@ const converters = {
5299
5307
  }
5300
5308
  if (msg.data.hasOwnProperty('4')) payload.mode_switch = {4: 'anti_flicker_mode', 1: 'quick_mode'}[msg.data['4']];
5301
5309
  if (msg.data.hasOwnProperty('10')) payload.switch_type = {1: 'toggle', 2: 'momentary'}[msg.data['10']];
5310
+ if (msg.data.hasOwnProperty('240')) payload.flip_indicator_light = msg.data['240'] === 1 ? 'ON' : 'OFF';
5302
5311
  if (msg.data.hasOwnProperty('258')) payload.detection_interval = msg.data['258'];
5303
5312
  if (msg.data.hasOwnProperty('268')) {
5304
5313
  if (['RTCGQ13LM'].includes(model.model)) {
@@ -5329,6 +5338,7 @@ const converters = {
5329
5338
  if (msg.data.hasOwnProperty('523')) payload.overload_protection = precisionRound(msg.data['523'], 2);
5330
5339
  if (msg.data.hasOwnProperty('550')) payload.button_switch_mode = msg.data['550'] === 1 ? 'relay_and_usb' : 'relay';
5331
5340
  if (msg.data['mode'] !== undefined) payload.operation_mode = ['command', 'event'][msg.data['mode']];
5341
+ if (msg.data.hasOwnProperty('1289')) payload.dimmer_mode = {3: 'rgbw', 1: 'dual_ct'}[msg.data['1289']];
5332
5342
  return payload;
5333
5343
  },
5334
5344
  },
@@ -5391,14 +5401,15 @@ const converters = {
5391
5401
  cluster: 'genMultistateInput',
5392
5402
  type: ['attributeReport'],
5393
5403
  convert: (model, msg, publish, options, meta) => {
5394
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5404
+ if (hasAlreadyProcessedMessage(msg)) return;
5395
5405
  let actionLookup = {0: 'hold', 1: 'single', 2: 'double', 3: 'triple', 255: 'release'};
5396
5406
  if (model.model === 'WXKG12LM') {
5397
5407
  actionLookup = {...actionLookup, 16: 'hold', 17: 'release', 18: 'shake'};
5398
5408
  }
5399
5409
 
5400
5410
  let buttonLookup = null;
5401
- if (['WXKG02LM_rev2', 'WXKG07LM', 'WXKG17LM'].includes(model.model)) buttonLookup = {1: 'left', 2: 'right', 3: 'both'};
5411
+ if (['WXKG02LM_rev2', 'WXKG07LM', 'WXKG15LM', 'WXKG17LM',
5412
+ 'WRS-R02'].includes(model.model)) buttonLookup = {1: 'left', 2: 'right', 3: 'both'};
5402
5413
  if (['QBKG12LM', 'QBKG24LM'].includes(model.model)) buttonLookup = {5: 'left', 6: 'right', 7: 'both'};
5403
5414
  if (['QBKG39LM', 'QBKG41LM', 'WS-EUK02', 'WS-EUK04', 'QBKG20LM', 'QBKG31LM'].includes(model.model)) {
5404
5415
  buttonLookup = {41: 'left', 42: 'right', 51: 'both'};
@@ -5537,7 +5548,7 @@ const converters = {
5537
5548
  `increase it with this option (value is in ms).`),
5538
5549
  ],
5539
5550
  convert: (model, msg, publish, options, meta) => {
5540
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5551
+ if (hasAlreadyProcessedMessage(msg)) return;
5541
5552
  const state = msg.data['onOff'];
5542
5553
 
5543
5554
  // 0 = click down, 1 = click up, else = multiple clicks
@@ -5801,6 +5812,40 @@ const converters = {
5801
5812
  }
5802
5813
  },
5803
5814
  },
5815
+ xiaomi_curtain_acn002_position: {
5816
+ cluster: 'genAnalogOutput',
5817
+ type: ['attributeReport', 'readResponse'],
5818
+ options: [exposes.options.invert_cover()],
5819
+ convert: (model, msg, publish, options, meta) => {
5820
+ let position = precisionRound(msg.data['presentValue'], 2);
5821
+ position = options.invert_cover ? 100 - position : position;
5822
+ return {position: position};
5823
+ },
5824
+ },
5825
+ xiaomi_curtain_acn002_status: {
5826
+ cluster: 'genMultistateOutput',
5827
+ type: ['attributeReport', 'readResponse'],
5828
+ convert: (model, msg, publish, options, meta) => {
5829
+ let running = false;
5830
+ const data = msg.data;
5831
+ const lookup = {
5832
+ 0: 'declining',
5833
+ 1: 'rising',
5834
+ 2: 'pause',
5835
+ 3: 'blocked',
5836
+ };
5837
+ if (data && data.hasOwnProperty('presentValue')) {
5838
+ const value = data['presentValue'];
5839
+ if (value < 2) {
5840
+ running = true;
5841
+ }
5842
+ return {
5843
+ motor_state: lookup[value],
5844
+ running: running,
5845
+ };
5846
+ }
5847
+ },
5848
+ },
5804
5849
  xiaomi_operation_mode_basic: {
5805
5850
  cluster: 'genBasic',
5806
5851
  type: ['attributeReport', 'readResponse'],
@@ -5843,7 +5888,7 @@ const converters = {
5843
5888
  cluster: 'genMultistateInput',
5844
5889
  type: ['attributeReport', 'readResponse'],
5845
5890
  convert: (model, msg, publish, options, meta) => {
5846
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5891
+ if (hasAlreadyProcessedMessage(msg)) return;
5847
5892
  const actionLookup = {0: 'hold', 255: 'release', 1: 'single', 2: 'double', 3: 'triple', 5: 'quintuple', 6: 'many'};
5848
5893
  const button = msg.endpoint.ID;
5849
5894
  const value = msg.data.presentValue;
@@ -5866,7 +5911,7 @@ const converters = {
5866
5911
  cluster: 'genOnOff',
5867
5912
  type: 'commandOn',
5868
5913
  convert: (model, msg, publish, options, meta) => {
5869
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5914
+ if (hasAlreadyProcessedMessage(msg)) return;
5870
5915
  return {action: 'button_2_single'};
5871
5916
  },
5872
5917
  },
@@ -5874,7 +5919,7 @@ const converters = {
5874
5919
  cluster: 'genOnOff',
5875
5920
  type: 'commandOff',
5876
5921
  convert: (model, msg, publish, options, meta) => {
5877
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5922
+ if (hasAlreadyProcessedMessage(msg)) return;
5878
5923
  return {action: 'button_1_single'};
5879
5924
  },
5880
5925
  },
@@ -5882,7 +5927,7 @@ const converters = {
5882
5927
  cluster: 'genLevelCtrl',
5883
5928
  type: 'commandStep',
5884
5929
  convert: (model, msg, publish, options, meta) => {
5885
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5930
+ if (hasAlreadyProcessedMessage(msg)) return;
5886
5931
  const button = msg.data.stepmode === 0 ? '4' : '3';
5887
5932
  return {action: `button_${button}_single`};
5888
5933
  },
@@ -5892,7 +5937,7 @@ const converters = {
5892
5937
  type: 'commandStop',
5893
5938
  options: [exposes.options.legacy()],
5894
5939
  convert: (model, msg, publish, options, meta) => {
5895
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5940
+ if (hasAlreadyProcessedMessage(msg)) return;
5896
5941
  if (globalStore.hasValue(msg.endpoint, 'button')) {
5897
5942
  const value = globalStore.getValue(msg.endpoint, 'button');
5898
5943
  const duration = Date.now() - value.start;
@@ -5906,7 +5951,7 @@ const converters = {
5906
5951
  cluster: 'genLevelCtrl',
5907
5952
  type: 'commandMove',
5908
5953
  convert: (model, msg, publish, options, meta) => {
5909
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5954
+ if (hasAlreadyProcessedMessage(msg)) return;
5910
5955
  const button = msg.data.movemode === 0 ? '4' : '3';
5911
5956
  globalStore.putValue(msg.endpoint, 'button', {button, start: Date.now()});
5912
5957
  return {action: `button_${button}_hold`};
@@ -5916,7 +5961,7 @@ const converters = {
5916
5961
  cluster: 'lightingColorCtrl',
5917
5962
  type: 'commandStepColorTemp',
5918
5963
  convert: (model, msg, publish, options, meta) => {
5919
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5964
+ if (hasAlreadyProcessedMessage(msg)) return;
5920
5965
  let action;
5921
5966
  if (model.model === 'WXCJKG12LM') {
5922
5967
  // for WXCJKG12LM model it's double click event on buttons 3 and 4
@@ -5933,7 +5978,7 @@ const converters = {
5933
5978
  type: 'commandMoveColorTemp',
5934
5979
  options: [exposes.options.legacy()],
5935
5980
  convert: (model, msg, publish, options, meta) => {
5936
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5981
+ if (hasAlreadyProcessedMessage(msg)) return;
5937
5982
  const stop = msg.data.movemode === 0;
5938
5983
  let result = null;
5939
5984
  if (stop) {
@@ -7359,7 +7404,7 @@ const converters = {
7359
7404
  cluster: 'wiserDeviceInfo',
7360
7405
  type: 'attributeReport',
7361
7406
  convert: (model, msg, publish, options, meta) => {
7362
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
7407
+ if (hasAlreadyProcessedMessage(msg)) return;
7363
7408
 
7364
7409
  const data = msg.data['deviceInfo'].split(',');
7365
7410
  if (data[0] === 'UI' && data[1]) {
@@ -8137,7 +8182,7 @@ const converters = {
8137
8182
  convert: (model, msg, publish, options, meta) => {
8138
8183
  // commandStopMove without params
8139
8184
  if (msg.data[2] !== 71) return;
8140
- if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
8185
+ if (hasAlreadyProcessedMessage(msg)) return;
8141
8186
  const movestop = 'stop';
8142
8187
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
8143
8188
  const payload = {action};