zigbee-herdsman-converters 14.0.393 → 14.0.397

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.
@@ -1042,7 +1042,7 @@ const converters = {
1042
1042
  cluster: 'genScenes',
1043
1043
  type: 'commandRecall',
1044
1044
  convert: (model, msg, publish, options, meta) => {
1045
- if (hasAlreadyProcessedMessage(msg)) return;
1045
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1046
1046
  const payload = {action: postfixWithEndpointName(`recall_${msg.data.sceneid}`, msg, model)};
1047
1047
  addActionGroup(payload, msg, model);
1048
1048
  return payload;
@@ -1052,7 +1052,7 @@ const converters = {
1052
1052
  cluster: 'ssIasAce',
1053
1053
  type: 'commandPanic',
1054
1054
  convert: (model, msg, publish, options, meta) => {
1055
- if (hasAlreadyProcessedMessage(msg)) return;
1055
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1056
1056
  const payload = {action: postfixWithEndpointName(`panic`, msg, model)};
1057
1057
  addActionGroup(payload, msg, model);
1058
1058
  return payload;
@@ -1062,7 +1062,7 @@ const converters = {
1062
1062
  cluster: 'ssIasAce',
1063
1063
  type: 'commandArm',
1064
1064
  convert: (model, msg, publish, options, meta) => {
1065
- if (hasAlreadyProcessedMessage(msg)) return;
1065
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1066
1066
  const payload = {
1067
1067
  action: postfixWithEndpointName(constants.armMode[msg.data['armmode']], msg, model),
1068
1068
  action_code: msg.data.code,
@@ -1076,6 +1076,7 @@ const converters = {
1076
1076
  cluster: 'ssIasAce',
1077
1077
  type: 'commandArm',
1078
1078
  convert: (model, msg, publish, options, meta) => {
1079
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1079
1080
  const payload = converters.command_arm.convert(model, msg, publish, options, meta);
1080
1081
  if (!payload) return;
1081
1082
  payload.action_transaction = msg.meta.zclTransactionSequenceNumber;
@@ -1086,7 +1087,7 @@ const converters = {
1086
1087
  cluster: 'closuresWindowCovering',
1087
1088
  type: 'commandStop',
1088
1089
  convert: (model, msg, publish, options, meta) => {
1089
- if (hasAlreadyProcessedMessage(msg)) return;
1090
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1090
1091
  const payload = {action: postfixWithEndpointName('stop', msg, model)};
1091
1092
  addActionGroup(payload, msg, model);
1092
1093
  return payload;
@@ -1096,7 +1097,7 @@ const converters = {
1096
1097
  cluster: 'closuresWindowCovering',
1097
1098
  type: 'commandUpOpen',
1098
1099
  convert: (model, msg, publish, options, meta) => {
1099
- if (hasAlreadyProcessedMessage(msg)) return;
1100
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1100
1101
  const payload = {action: postfixWithEndpointName('open', msg, model)};
1101
1102
  addActionGroup(payload, msg, model);
1102
1103
  return payload;
@@ -1106,7 +1107,7 @@ const converters = {
1106
1107
  cluster: 'closuresWindowCovering',
1107
1108
  type: 'commandDownClose',
1108
1109
  convert: (model, msg, publish, options, meta) => {
1109
- if (hasAlreadyProcessedMessage(msg)) return;
1110
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1110
1111
  const payload = {action: postfixWithEndpointName('close', msg, model)};
1111
1112
  addActionGroup(payload, msg, model);
1112
1113
  return payload;
@@ -1116,7 +1117,7 @@ const converters = {
1116
1117
  cluster: 'genOnOff',
1117
1118
  type: 'commandOn',
1118
1119
  convert: (model, msg, publish, options, meta) => {
1119
- if (hasAlreadyProcessedMessage(msg)) return;
1120
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1120
1121
  const payload = {action: postfixWithEndpointName('on', msg, model)};
1121
1122
  addActionGroup(payload, msg, model);
1122
1123
  return payload;
@@ -1126,7 +1127,7 @@ const converters = {
1126
1127
  cluster: 'genOnOff',
1127
1128
  type: 'commandOff',
1128
1129
  convert: (model, msg, publish, options, meta) => {
1129
- if (hasAlreadyProcessedMessage(msg)) return;
1130
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1130
1131
  const payload = {action: postfixWithEndpointName('off', msg, model)};
1131
1132
  addActionGroup(payload, msg, model);
1132
1133
  return payload;
@@ -1136,7 +1137,7 @@ const converters = {
1136
1137
  cluster: 'genOnOff',
1137
1138
  type: 'commandOffWithEffect',
1138
1139
  convert: (model, msg, publish, options, meta) => {
1139
- if (hasAlreadyProcessedMessage(msg)) return;
1140
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1140
1141
  const payload = {action: postfixWithEndpointName(`off`, msg, model)};
1141
1142
  addActionGroup(payload, msg, model);
1142
1143
  return payload;
@@ -1146,7 +1147,7 @@ const converters = {
1146
1147
  cluster: 'genOnOff',
1147
1148
  type: 'commandToggle',
1148
1149
  convert: (model, msg, publish, options, meta) => {
1149
- if (hasAlreadyProcessedMessage(msg)) return;
1150
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1150
1151
  const payload = {action: postfixWithEndpointName('toggle', msg, model)};
1151
1152
  addActionGroup(payload, msg, model);
1152
1153
  return payload;
@@ -1157,7 +1158,7 @@ const converters = {
1157
1158
  type: ['commandMoveToLevel', 'commandMoveToLevelWithOnOff'],
1158
1159
  options: [exposes.options.simulated_brightness()],
1159
1160
  convert: (model, msg, publish, options, meta) => {
1160
- if (hasAlreadyProcessedMessage(msg)) return;
1161
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1161
1162
  const payload = {
1162
1163
  action: postfixWithEndpointName(`brightness_move_to_level`, msg, model),
1163
1164
  action_level: msg.data.level,
@@ -1179,7 +1180,7 @@ const converters = {
1179
1180
  type: ['commandMove', 'commandMoveWithOnOff'],
1180
1181
  options: [exposes.options.simulated_brightness()],
1181
1182
  convert: (model, msg, publish, options, meta) => {
1182
- if (hasAlreadyProcessedMessage(msg)) return;
1183
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1183
1184
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1184
1185
  const action = postfixWithEndpointName(`brightness_move_${direction}`, msg, model);
1185
1186
  const payload = {action, action_rate: msg.data.rate};
@@ -1215,7 +1216,7 @@ const converters = {
1215
1216
  type: ['commandStep', 'commandStepWithOnOff'],
1216
1217
  options: [exposes.options.simulated_brightness()],
1217
1218
  convert: (model, msg, publish, options, meta) => {
1218
- if (hasAlreadyProcessedMessage(msg)) return;
1219
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1219
1220
  const direction = msg.data.stepmode === 1 ? 'down' : 'up';
1220
1221
  const payload = {
1221
1222
  action: postfixWithEndpointName(`brightness_step_${direction}`, msg, model),
@@ -1242,7 +1243,7 @@ const converters = {
1242
1243
  type: ['commandStop', 'commandStopWithOnOff'],
1243
1244
  options: [exposes.options.simulated_brightness()],
1244
1245
  convert: (model, msg, publish, options, meta) => {
1245
- if (hasAlreadyProcessedMessage(msg)) return;
1246
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1246
1247
  if (options.simulated_brightness) {
1247
1248
  clearInterval(globalStore.getValue(msg.endpoint, 'simulated_brightness_timer'));
1248
1249
  globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', undefined);
@@ -1257,7 +1258,7 @@ const converters = {
1257
1258
  cluster: 'lightingColorCtrl',
1258
1259
  type: ['commandMoveColorTemp'],
1259
1260
  convert: (model, msg, publish, options, meta) => {
1260
- if (hasAlreadyProcessedMessage(msg)) return;
1261
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1261
1262
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1262
1263
  const action = postfixWithEndpointName(`color_temperature_move_${direction}`, msg, model);
1263
1264
  const payload = {action, action_rate: msg.data.rate, action_minimum: msg.data.minimum, action_maximum: msg.data.maximum};
@@ -1269,7 +1270,7 @@ const converters = {
1269
1270
  cluster: 'lightingColorCtrl',
1270
1271
  type: 'commandStepColorTemp',
1271
1272
  convert: (model, msg, publish, options, meta) => {
1272
- if (hasAlreadyProcessedMessage(msg)) return;
1273
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1273
1274
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1274
1275
  const payload = {
1275
1276
  action: postfixWithEndpointName(`color_temperature_step_${direction}`, msg, model),
@@ -1288,7 +1289,7 @@ const converters = {
1288
1289
  cluster: 'lightingColorCtrl',
1289
1290
  type: 'commandEnhancedMoveToHueAndSaturation',
1290
1291
  convert: (model, msg, publish, options, meta) => {
1291
- if (hasAlreadyProcessedMessage(msg)) return;
1292
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1292
1293
  const payload = {
1293
1294
  action: postfixWithEndpointName(`enhanced_move_to_hue_and_saturation`, msg, model),
1294
1295
  action_enhanced_hue: msg.data.enhancehue,
@@ -1305,7 +1306,7 @@ const converters = {
1305
1306
  cluster: 'lightingColorCtrl',
1306
1307
  type: ['commandStepHue'],
1307
1308
  convert: (model, msg, publish, options, meta) => {
1308
- if (hasAlreadyProcessedMessage(msg)) return;
1309
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1309
1310
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1310
1311
  const payload = {
1311
1312
  action: postfixWithEndpointName(`color_hue_step_${direction}`, msg, model),
@@ -1320,7 +1321,7 @@ const converters = {
1320
1321
  cluster: 'lightingColorCtrl',
1321
1322
  type: ['commandStepSaturation'],
1322
1323
  convert: (model, msg, publish, options, meta) => {
1323
- if (hasAlreadyProcessedMessage(msg)) return;
1324
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1324
1325
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1325
1326
  const payload = {
1326
1327
  action: postfixWithEndpointName(`color_saturation_step_${direction}`, msg, model),
@@ -1335,7 +1336,7 @@ const converters = {
1335
1336
  cluster: 'lightingColorCtrl',
1336
1337
  type: 'commandColorLoopSet',
1337
1338
  convert: (model, msg, publish, options, meta) => {
1338
- if (hasAlreadyProcessedMessage(msg)) return;
1339
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1339
1340
  const updateFlags = msg.data.updateflags;
1340
1341
  const actionLookup = {
1341
1342
  0x00: 'deactivate',
@@ -1365,7 +1366,7 @@ const converters = {
1365
1366
  cluster: 'lightingColorCtrl',
1366
1367
  type: 'commandMoveToColorTemp',
1367
1368
  convert: (model, msg, publish, options, meta) => {
1368
- if (hasAlreadyProcessedMessage(msg)) return;
1369
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1369
1370
  const payload = {
1370
1371
  action: postfixWithEndpointName(`color_temperature_move`, msg, model),
1371
1372
  action_color_temperature: msg.data.colortemp,
@@ -1379,7 +1380,7 @@ const converters = {
1379
1380
  cluster: 'lightingColorCtrl',
1380
1381
  type: 'commandMoveToColor',
1381
1382
  convert: (model, msg, publish, options, meta) => {
1382
- if (hasAlreadyProcessedMessage(msg)) return;
1383
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1383
1384
  const payload = {
1384
1385
  action: postfixWithEndpointName(`color_move`, msg, model),
1385
1386
  action_color: {
@@ -1396,7 +1397,7 @@ const converters = {
1396
1397
  cluster: 'lightingColorCtrl',
1397
1398
  type: 'commandMoveHue',
1398
1399
  convert: (model, msg, publish, options, meta) => {
1399
- if (hasAlreadyProcessedMessage(msg)) return;
1400
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1400
1401
  const movestop = msg.data.movemode == 1 ? 'move' : 'stop';
1401
1402
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
1402
1403
  const payload = {action, action_rate: msg.data.rate};
@@ -1408,7 +1409,7 @@ const converters = {
1408
1409
  cluster: 'lightingColorCtrl',
1409
1410
  type: 'commandMoveToSaturation',
1410
1411
  convert: (model, msg, publish, options, meta) => {
1411
- if (hasAlreadyProcessedMessage(msg)) return;
1412
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1412
1413
  const payload = {
1413
1414
  action: postfixWithEndpointName('move_to_saturation', msg, model),
1414
1415
  action_saturation: msg.data.saturation,
@@ -1422,7 +1423,7 @@ const converters = {
1422
1423
  cluster: 'lightingColorCtrl',
1423
1424
  type: 'commandMoveToHue',
1424
1425
  convert: (model, msg, publish, options, meta) => {
1425
- if (hasAlreadyProcessedMessage(msg)) return;
1426
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1426
1427
  const payload = {
1427
1428
  action: postfixWithEndpointName(`move_to_hue`, msg, model),
1428
1429
  action_hue: msg.data.hue,
@@ -1437,7 +1438,7 @@ const converters = {
1437
1438
  cluster: 'ssIasAce',
1438
1439
  type: 'commandEmergency',
1439
1440
  convert: (model, msg, publish, options, meta) => {
1440
- if (hasAlreadyProcessedMessage(msg)) return;
1441
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1441
1442
  const payload = {action: postfixWithEndpointName(`emergency`, msg, model)};
1442
1443
  addActionGroup(payload, msg, model);
1443
1444
  return payload;
@@ -1447,7 +1448,7 @@ const converters = {
1447
1448
  cluster: 'genOnOff',
1448
1449
  type: 'commandOn',
1449
1450
  convert: (model, msg, publish, options, meta) => {
1450
- if (hasAlreadyProcessedMessage(msg)) return;
1451
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1451
1452
  const property = postfixWithEndpointName('state', msg, model);
1452
1453
  return {[property]: 'ON'};
1453
1454
  },
@@ -1456,7 +1457,7 @@ const converters = {
1456
1457
  cluster: 'genOnOff',
1457
1458
  type: 'commandOff',
1458
1459
  convert: (model, msg, publish, options, meta) => {
1459
- if (hasAlreadyProcessedMessage(msg)) return;
1460
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
1460
1461
  const property = postfixWithEndpointName('state', msg, model);
1461
1462
  return {[property]: 'OFF'};
1462
1463
  },
@@ -2181,7 +2182,7 @@ const converters = {
2181
2182
  cluster: 'ssIasZone',
2182
2183
  type: 'commandStatusChangeNotification',
2183
2184
  convert: (model, msg, publish, options, meta) => {
2184
- if (hasAlreadyProcessedMessage(msg)) return;
2185
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
2185
2186
  const lookup = {1: 'pressed'};
2186
2187
  const zoneStatus = msg.data.zonestatus;
2187
2188
  return {
@@ -4515,7 +4516,7 @@ const converters = {
4515
4516
  cluster: 'genScenes',
4516
4517
  type: 'commandTradfriArrowSingle',
4517
4518
  convert: (model, msg, publish, options, meta) => {
4518
- if (hasAlreadyProcessedMessage(msg)) return;
4519
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4519
4520
  if (msg.data.value === 2) {
4520
4521
  // This is send on toggle hold, ignore it as a toggle_hold is already handled above.
4521
4522
  return;
@@ -4529,7 +4530,7 @@ const converters = {
4529
4530
  cluster: 'genScenes',
4530
4531
  type: 'commandTradfriArrowHold',
4531
4532
  convert: (model, msg, publish, options, meta) => {
4532
- if (hasAlreadyProcessedMessage(msg)) return;
4533
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4533
4534
  const direction = msg.data.value === 3329 ? 'left' : 'right';
4534
4535
  globalStore.putValue(msg.endpoint, 'direction', direction);
4535
4536
  return {action: `arrow_${direction}_hold`};
@@ -4540,7 +4541,7 @@ const converters = {
4540
4541
  type: 'commandTradfriArrowRelease',
4541
4542
  options: [exposes.options.legacy()],
4542
4543
  convert: (model, msg, publish, options, meta) => {
4543
- if (hasAlreadyProcessedMessage(msg)) return;
4544
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
4544
4545
  const direction = globalStore.getValue(msg.endpoint, 'direction');
4545
4546
  if (direction) {
4546
4547
  globalStore.clearValue(msg.endpoint, 'direction');
@@ -5379,7 +5380,7 @@ const converters = {
5379
5380
  cluster: 'genMultistateInput',
5380
5381
  type: ['attributeReport'],
5381
5382
  convert: (model, msg, publish, options, meta) => {
5382
- if (hasAlreadyProcessedMessage(msg)) return;
5383
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5383
5384
  let actionLookup = {0: 'hold', 1: 'single', 2: 'double', 3: 'triple', 255: 'release'};
5384
5385
  if (model.model === 'WXKG12LM') {
5385
5386
  actionLookup = {...actionLookup, 16: 'hold', 17: 'release', 18: 'shake'};
@@ -5525,7 +5526,7 @@ const converters = {
5525
5526
  `increase it with this option (value is in ms).`),
5526
5527
  ],
5527
5528
  convert: (model, msg, publish, options, meta) => {
5528
- if (hasAlreadyProcessedMessage(msg)) return;
5529
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5529
5530
  const state = msg.data['onOff'];
5530
5531
 
5531
5532
  // 0 = click down, 1 = click up, else = multiple clicks
@@ -5831,7 +5832,7 @@ const converters = {
5831
5832
  cluster: 'genMultistateInput',
5832
5833
  type: ['attributeReport', 'readResponse'],
5833
5834
  convert: (model, msg, publish, options, meta) => {
5834
- if (hasAlreadyProcessedMessage(msg)) return;
5835
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5835
5836
  const actionLookup = {0: 'hold', 255: 'release', 1: 'single', 2: 'double', 3: 'triple', 5: 'quintuple', 6: 'many'};
5836
5837
  const button = msg.endpoint.ID;
5837
5838
  const value = msg.data.presentValue;
@@ -5854,7 +5855,7 @@ const converters = {
5854
5855
  cluster: 'genOnOff',
5855
5856
  type: 'commandOn',
5856
5857
  convert: (model, msg, publish, options, meta) => {
5857
- if (hasAlreadyProcessedMessage(msg)) return;
5858
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5858
5859
  return {action: 'button_2_single'};
5859
5860
  },
5860
5861
  },
@@ -5862,7 +5863,7 @@ const converters = {
5862
5863
  cluster: 'genOnOff',
5863
5864
  type: 'commandOff',
5864
5865
  convert: (model, msg, publish, options, meta) => {
5865
- if (hasAlreadyProcessedMessage(msg)) return;
5866
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5866
5867
  return {action: 'button_1_single'};
5867
5868
  },
5868
5869
  },
@@ -5870,7 +5871,7 @@ const converters = {
5870
5871
  cluster: 'genLevelCtrl',
5871
5872
  type: 'commandStep',
5872
5873
  convert: (model, msg, publish, options, meta) => {
5873
- if (hasAlreadyProcessedMessage(msg)) return;
5874
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5874
5875
  const button = msg.data.stepmode === 0 ? '4' : '3';
5875
5876
  return {action: `button_${button}_single`};
5876
5877
  },
@@ -5880,7 +5881,7 @@ const converters = {
5880
5881
  type: 'commandStop',
5881
5882
  options: [exposes.options.legacy()],
5882
5883
  convert: (model, msg, publish, options, meta) => {
5883
- if (hasAlreadyProcessedMessage(msg)) return;
5884
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5884
5885
  if (globalStore.hasValue(msg.endpoint, 'button')) {
5885
5886
  const value = globalStore.getValue(msg.endpoint, 'button');
5886
5887
  const duration = Date.now() - value.start;
@@ -5894,7 +5895,7 @@ const converters = {
5894
5895
  cluster: 'genLevelCtrl',
5895
5896
  type: 'commandMove',
5896
5897
  convert: (model, msg, publish, options, meta) => {
5897
- if (hasAlreadyProcessedMessage(msg)) return;
5898
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5898
5899
  const button = msg.data.movemode === 0 ? '4' : '3';
5899
5900
  globalStore.putValue(msg.endpoint, 'button', {button, start: Date.now()});
5900
5901
  return {action: `button_${button}_hold`};
@@ -5904,7 +5905,7 @@ const converters = {
5904
5905
  cluster: 'lightingColorCtrl',
5905
5906
  type: 'commandStepColorTemp',
5906
5907
  convert: (model, msg, publish, options, meta) => {
5907
- if (hasAlreadyProcessedMessage(msg)) return;
5908
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5908
5909
  let action;
5909
5910
  if (model.model === 'WXCJKG12LM') {
5910
5911
  // for WXCJKG12LM model it's double click event on buttons 3 and 4
@@ -5921,7 +5922,7 @@ const converters = {
5921
5922
  type: 'commandMoveColorTemp',
5922
5923
  options: [exposes.options.legacy()],
5923
5924
  convert: (model, msg, publish, options, meta) => {
5924
- if (hasAlreadyProcessedMessage(msg)) return;
5925
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
5925
5926
  const stop = msg.data.movemode === 0;
5926
5927
  let result = null;
5927
5928
  if (stop) {
@@ -7327,7 +7328,7 @@ const converters = {
7327
7328
  cluster: 'wiserDeviceInfo',
7328
7329
  type: 'attributeReport',
7329
7330
  convert: (model, msg, publish, options, meta) => {
7330
- if (hasAlreadyProcessedMessage(msg)) return;
7331
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
7331
7332
 
7332
7333
  const data = msg.data['deviceInfo'].split(',');
7333
7334
  if (data[0] === 'UI' && data[1]) {
@@ -7761,6 +7762,31 @@ const converters = {
7761
7762
  return result;
7762
7763
  },
7763
7764
  },
7765
+ matsee_garage_door_opener: {
7766
+ cluster: 'manuSpecificTuya',
7767
+ type: ['commandDataReport', 'raw'],
7768
+ convert: (model, msg, publish, options, meta) => {
7769
+ const result = {};
7770
+ for (const dpValue of msg.data.dpValues) {
7771
+ const value = tuya.getDataValue(dpValue);
7772
+ switch (dpValue.dp) {
7773
+ case tuya.dataPoints.garageDoorTrigger:
7774
+ result.action = 'trigger';
7775
+ break;
7776
+ case tuya.dataPoints.garageDoorContact:
7777
+ result.garage_door_contact = Boolean(!value);
7778
+ break;
7779
+ case tuya.dataPoints.garageDoorStatus:
7780
+ // This reports a garage door status (open, closed), but it is very naive and misleading
7781
+ break;
7782
+ default:
7783
+ meta.logger.debug(`zigbee-herdsman-converters:matsee_garage_door_opener: NOT RECOGNIZED ` +
7784
+ `DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
7785
+ }
7786
+ }
7787
+ return result;
7788
+ },
7789
+ },
7764
7790
  moes_thermostat_tv: {
7765
7791
  cluster: 'manuSpecificTuya',
7766
7792
  type: ['commandDataResponse', 'commandDataReport', 'raw'],
@@ -8080,7 +8106,7 @@ const converters = {
8080
8106
  convert: (model, msg, publish, options, meta) => {
8081
8107
  // commandStopMove without params
8082
8108
  if (msg.data[2] !== 71) return;
8083
- if (hasAlreadyProcessedMessage(msg)) return;
8109
+ if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
8084
8110
  const movestop = 'stop';
8085
8111
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
8086
8112
  const payload = {action};
@@ -2333,6 +2333,12 @@ const converters = {
2333
2333
  tuya.sendDataPointRaw(entity, tuya.dataPoints.lidlTimer, tuya.convertDecimalValueTo4ByteHexArray(value));
2334
2334
  },
2335
2335
  },
2336
+ matsee_garage_door_opener: {
2337
+ key: ['trigger'],
2338
+ convertSet: (entity, key, value, meta) => {
2339
+ tuya.sendDataPointBool(entity, tuya.dataPoints.garageDoorTrigger, true);
2340
+ },
2341
+ },
2336
2342
  SPZ01_power_outage_memory: {
2337
2343
  key: ['power_outage_memory'],
2338
2344
  convertSet: async (entity, key, value, meta) => {
@@ -5090,7 +5096,7 @@ const converters = {
5090
5096
  await tuya.sendDataPointEnum(
5091
5097
  entity,
5092
5098
  tuya.dataPoints.neoAOVolume,
5093
- {'low': 2, 'medium': 1, 'high': 0}[value]);
5099
+ {'low': 0, 'medium': 1, 'high': 2}[value]);
5094
5100
  break;
5095
5101
  case 'duration':
5096
5102
  await tuya.sendDataPointValue(entity, tuya.dataPoints.neoAODuration, value);
@@ -332,4 +332,25 @@ module.exports = [
332
332
  },
333
333
  exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
334
334
  },
335
+ {
336
+ zigbeeModel: ['EFEKTA_PWS_MaxPro'],
337
+ model: 'EFEKTA_PWS_MaxPro',
338
+ vendor: 'Custom devices (DiY)',
339
+ description: '[Plant watering sensor EFEKTA PWS Max Pro, long battery life](http://efektalab.com/PWS_MaxPro)',
340
+ fromZigbee: [fz.temperature, fz.humidity, fz.illuminance, fz.soil_moisture, fz.battery],
341
+ toZigbee: [tz.factory_reset],
342
+ configure: async (device, coordinatorEndpoint, logger) => {
343
+ const firstEndpoint = device.getEndpoint(1);
344
+ await reporting.bind(firstEndpoint, coordinatorEndpoint, [
345
+ 'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity', 'msIlluminanceMeasurement', 'msSoilMoisture']);
346
+ const overides = {min: 0, max: 21600, change: 0};
347
+ await reporting.batteryVoltage(firstEndpoint, overides);
348
+ await reporting.batteryPercentageRemaining(firstEndpoint, overides);
349
+ await reporting.temperature(firstEndpoint, overides);
350
+ await reporting.humidity(firstEndpoint, overides);
351
+ await reporting.illuminance(firstEndpoint, overides);
352
+ await reporting.soil_moisture(firstEndpoint, overides);
353
+ },
354
+ exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
355
+ },
335
356
  ];
package/devices/ecodim.js CHANGED
@@ -98,7 +98,6 @@ module.exports = [
98
98
  model: 'ED-10014',
99
99
  vendor: 'EcoDim',
100
100
  description: 'Zigbee 8 button wall switch - white',
101
- supports: '',
102
101
  fromZigbee: [fz.command_on, fz.command_off, fz.command_move, fz.command_stop, fz.battery],
103
102
  exposes: [e.battery(), e.action(['on_1', 'off_1', 'brightness_move_up_1', 'brightness_move_down_1', 'brightness_stop_1',
104
103
  'on_2', 'off_2', 'brightness_move_up_2', 'brightness_move_down_2', 'brightness_stop_2', 'on_3', 'off_3',
@@ -112,7 +111,6 @@ module.exports = [
112
111
  model: 'ED-10015',
113
112
  vendor: 'EcoDim',
114
113
  description: 'Zigbee 8 button wall switch - black',
115
- supports: '',
116
114
  fromZigbee: [fz.command_on, fz.command_off, fz.command_move, fz.command_stop, fz.battery],
117
115
  exposes: [e.battery(), e.action(['on_1', 'off_1', 'brightness_move_up_1', 'brightness_move_down_1', 'brightness_stop_1',
118
116
  'on_2', 'off_2', 'brightness_move_up_2', 'brightness_move_down_2', 'brightness_stop_2', 'on_3', 'off_3', 'brightness_move_up_3',
package/devices/jxuan.js CHANGED
@@ -38,7 +38,6 @@ module.exports = [
38
38
  model: 'SPZ01',
39
39
  vendor: 'J.XUAN',
40
40
  description: 'plug',
41
- supports: 'plug',
42
41
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
43
42
  exposes: [e.switch(), e.power(), e.power_outage_memory().withAccess(ea.STATE_SET)],
44
43
  toZigbee: [tz.on_off, tz.SPZ01_power_outage_memory],
@@ -5,6 +5,7 @@ const reporting = require('../lib/reporting');
5
5
  const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
7
  const ea = exposes.access;
8
+ const ota = require('../lib/ota');
8
9
 
9
10
  const readInitialBatteryState = async (type, data, device) => {
10
11
  if (['deviceAnnounce'].includes(type)) {
@@ -63,6 +64,7 @@ module.exports = [
63
64
  fromZigbee: [fz.identify, fz.ignore_basic_report, fz.command_cover_open, fz.command_cover_close, fz.command_cover_stop, fz.battery,
64
65
  fz.legrand_binary_input_moving],
65
66
  toZigbee: [],
67
+ ota: ota.zigbeeOTA,
66
68
  exposes: [e.battery(), e.action(['identify', 'open', 'close', 'stop', 'moving', 'stopped'])],
67
69
  configure: async (device, coordinatorEndpoint, logger) => {
68
70
  const endpoint = device.getEndpoint(1);
@@ -109,7 +111,7 @@ module.exports = [
109
111
  exposes: [e.battery(), e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up',
110
112
  'brightness_move_down', 'brightness_stop'])],
111
113
  toZigbee: [],
112
- meta: {battery: {voltageToPercentage: '3V_2500'}},
114
+ meta: {handleDuplicateTransaction: true, battery: {voltageToPercentage: '3V_2500'}},
113
115
  configure: async (device, coordinatorEndpoint, logger) => {
114
116
  const endpoint = device.getEndpoint(1);
115
117
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
@@ -125,7 +127,7 @@ module.exports = [
125
127
  exposes: [e.battery(),
126
128
  e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up', 'brightness_move_down', 'brightness_stop'])],
127
129
  toZigbee: [],
128
- meta: {multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}},
130
+ meta: {handleDuplicateTransaction: true, multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}},
129
131
  configure: async (device, coordinatorEndpoint, logger) => {
130
132
  const endpoint = device.getEndpoint(1);
131
133
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
@@ -182,6 +184,7 @@ module.exports = [
182
184
  zigbeeModel: [' Connected outlet\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
183
185
  model: '067775/741811',
184
186
  vendor: 'Legrand',
187
+ ota: ota.zigbeeOTA,
185
188
  description: 'Power socket with power consumption monitoring',
186
189
  fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
187
190
  toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_identify],
@@ -200,6 +203,7 @@ module.exports = [
200
203
  vendor: 'Legrand',
201
204
  description: 'Wired micromodule switch',
202
205
  extend: extend.switch(),
206
+ ota: ota.zigbeeOTA,
203
207
  fromZigbee: [fz.identify, fz.on_off],
204
208
  toZigbee: [tz.on_off, tz.legrand_identify],
205
209
  configure: async (device, coordinatorEndpoint, logger) => {
package/devices/lidl.js CHANGED
@@ -394,7 +394,7 @@ module.exports = [
394
394
  },
395
395
  {
396
396
  fingerprint: [{modelID: 'TY0202', manufacturerName: '_TZ1800_fcdjzz3s'}],
397
- model: 'HG06335',
397
+ model: 'HG06335/HG07310',
398
398
  vendor: 'Lidl',
399
399
  description: 'Silvercrest smart motion sensor',
400
400
  fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery],
@@ -0,0 +1,31 @@
1
+ const fz = require('../converters/fromZigbee');
2
+ const exposes = require('../lib/exposes');
3
+ const reporting = require('../lib/reporting');
4
+ const extend = require('../lib/extend');
5
+ const e = exposes.presets;
6
+ const ea = exposes.access;
7
+
8
+
9
+ module.exports = [
10
+ {
11
+ zigbeeModel: ['SZ1000'],
12
+ model: 'ZB250',
13
+ vendor: 'Micro Matic Norge AS',
14
+ description: 'Zigbee dimmer for LED',
15
+ fromZigbee: extend.light_onoff_brightness().fromZigbee.concat([fz.electrical_measurement, fz.metering]),
16
+ toZigbee: extend.light_onoff_brightness().toZigbee,
17
+ configure: async (device, coordinatorEndpoint, logger) => {
18
+ await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
19
+ const endpoint = device.getEndpoint(1);
20
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'haElectricalMeasurement', 'seMetering']);
21
+ await reporting.brightness(endpoint);
22
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
23
+ await reporting.rmsVoltage(endpoint, {min: 10, change: 20}); // Voltage - Min change of 2V
24
+ await reporting.rmsCurrent(endpoint, {min: 10, change: 10}); // A - z2m displays only the first decimals, change of 10 / 0,01A
25
+ await reporting.activePower(endpoint, {min: 10, change: 15}); // W - Min change of 1,5W
26
+ await reporting.currentSummDelivered(endpoint, {min: 300}); // Report KWH every 5min
27
+ },
28
+ exposes: [e.light_brightness(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
29
+ },
30
+ ];
31
+
package/devices/moes.js CHANGED
@@ -303,7 +303,6 @@ module.exports = [
303
303
  model: 'MS-108ZR',
304
304
  vendor: 'Moes',
305
305
  description: 'Zigbee + RF curtain switch module',
306
- supports: 'open, close, stop, position',
307
306
  fromZigbee: [fz.tuya_cover_options, fz.cover_position_tilt],
308
307
  toZigbee: [tz.cover_state, tz.moes_cover_calibration, tz.cover_position_tilt, tz.tuya_cover_reversal],
309
308
  exposes: [e.cover_position(), exposes.numeric('calibration_time', ea.ALL).withValueMin(0).withValueMax(100),
package/devices/owon.js CHANGED
@@ -27,7 +27,6 @@ module.exports = [
27
27
  model: 'CB432',
28
28
  vendor: 'OWON',
29
29
  description: '32A/63A power circuit breaker',
30
- supports: 'on/off, power measurement',
31
30
  fromZigbee: [fz.on_off, fz.metering, fz.electrical_measurement],
32
31
  toZigbee: [tz.on_off],
33
32
  exposes: [e.switch(), e.power(), e.energy()],