zigbee-herdsman-converters 14.0.654 → 14.0.655

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.
@@ -782,7 +782,7 @@ const converters = {
782
782
  // Device sends multiple messages with the same transactionSequenceNumber,
783
783
  // prevent that multiple messages get send.
784
784
  // https://github.com/Koenkk/zigbee2mqtt/issues/3687
785
- if (msg.data.hasOwnProperty('onOff') && !hasAlreadyProcessedMessage(msg)) {
785
+ if (msg.data.hasOwnProperty('onOff') && !hasAlreadyProcessedMessage(msg, model)) {
786
786
  const property = postfixWithEndpointName('state', msg, model, meta);
787
787
  return {[property]: msg.data['onOff'] === 1 ? 'ON' : 'OFF'};
788
788
  }
@@ -1084,7 +1084,7 @@ const converters = {
1084
1084
  cluster: 'genScenes',
1085
1085
  type: 'commandStore',
1086
1086
  convert: (model, msg, publish, options, meta) => {
1087
- if (hasAlreadyProcessedMessage(msg)) return;
1087
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1088
1088
  const payload = {action: postfixWithEndpointName(`store_${msg.data.sceneid}`, msg, model, meta)};
1089
1089
  addActionGroup(payload, msg, model);
1090
1090
  return payload;
@@ -1094,7 +1094,7 @@ const converters = {
1094
1094
  cluster: 'genScenes',
1095
1095
  type: 'commandRecall',
1096
1096
  convert: (model, msg, publish, options, meta) => {
1097
- if (hasAlreadyProcessedMessage(msg)) return;
1097
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1098
1098
  const payload = {action: postfixWithEndpointName(`recall_${msg.data.sceneid}`, msg, model, meta)};
1099
1099
  addActionGroup(payload, msg, model);
1100
1100
  return payload;
@@ -1104,7 +1104,7 @@ const converters = {
1104
1104
  cluster: 'ssIasAce',
1105
1105
  type: 'commandPanic',
1106
1106
  convert: (model, msg, publish, options, meta) => {
1107
- if (hasAlreadyProcessedMessage(msg)) return;
1107
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1108
1108
  const payload = {action: postfixWithEndpointName(`panic`, msg, model, meta)};
1109
1109
  addActionGroup(payload, msg, model);
1110
1110
  return payload;
@@ -1114,7 +1114,7 @@ const converters = {
1114
1114
  cluster: 'ssIasAce',
1115
1115
  type: 'commandArm',
1116
1116
  convert: (model, msg, publish, options, meta) => {
1117
- if (hasAlreadyProcessedMessage(msg)) return;
1117
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1118
1118
  const payload = {
1119
1119
  action: postfixWithEndpointName(constants.armMode[msg.data['armmode']], msg, model, meta),
1120
1120
  action_code: msg.data.code,
@@ -1138,7 +1138,7 @@ const converters = {
1138
1138
  cluster: 'closuresWindowCovering',
1139
1139
  type: 'commandStop',
1140
1140
  convert: (model, msg, publish, options, meta) => {
1141
- if (hasAlreadyProcessedMessage(msg)) return;
1141
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1142
1142
  const payload = {action: postfixWithEndpointName('stop', msg, model, meta)};
1143
1143
  addActionGroup(payload, msg, model);
1144
1144
  return payload;
@@ -1148,7 +1148,7 @@ const converters = {
1148
1148
  cluster: 'closuresWindowCovering',
1149
1149
  type: 'commandUpOpen',
1150
1150
  convert: (model, msg, publish, options, meta) => {
1151
- if (hasAlreadyProcessedMessage(msg)) return;
1151
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1152
1152
  const payload = {action: postfixWithEndpointName('open', msg, model, meta)};
1153
1153
  addActionGroup(payload, msg, model);
1154
1154
  return payload;
@@ -1158,7 +1158,7 @@ const converters = {
1158
1158
  cluster: 'closuresWindowCovering',
1159
1159
  type: 'commandDownClose',
1160
1160
  convert: (model, msg, publish, options, meta) => {
1161
- if (hasAlreadyProcessedMessage(msg)) return;
1161
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1162
1162
  const payload = {action: postfixWithEndpointName('close', msg, model, meta)};
1163
1163
  addActionGroup(payload, msg, model);
1164
1164
  return payload;
@@ -1168,7 +1168,7 @@ const converters = {
1168
1168
  cluster: 'genOnOff',
1169
1169
  type: 'commandOn',
1170
1170
  convert: (model, msg, publish, options, meta) => {
1171
- if (hasAlreadyProcessedMessage(msg)) return;
1171
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1172
1172
  const payload = {action: postfixWithEndpointName('on', msg, model, meta)};
1173
1173
  addActionGroup(payload, msg, model);
1174
1174
  return payload;
@@ -1178,7 +1178,7 @@ const converters = {
1178
1178
  cluster: 'genOnOff',
1179
1179
  type: 'commandOff',
1180
1180
  convert: (model, msg, publish, options, meta) => {
1181
- if (hasAlreadyProcessedMessage(msg)) return;
1181
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1182
1182
  const payload = {action: postfixWithEndpointName('off', msg, model, meta)};
1183
1183
  addActionGroup(payload, msg, model);
1184
1184
  return payload;
@@ -1188,7 +1188,7 @@ const converters = {
1188
1188
  cluster: 'genOnOff',
1189
1189
  type: 'commandOffWithEffect',
1190
1190
  convert: (model, msg, publish, options, meta) => {
1191
- if (hasAlreadyProcessedMessage(msg)) return;
1191
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1192
1192
  const payload = {action: postfixWithEndpointName(`off`, msg, model, meta)};
1193
1193
  addActionGroup(payload, msg, model);
1194
1194
  return payload;
@@ -1198,7 +1198,7 @@ const converters = {
1198
1198
  cluster: 'genOnOff',
1199
1199
  type: 'commandToggle',
1200
1200
  convert: (model, msg, publish, options, meta) => {
1201
- if (hasAlreadyProcessedMessage(msg)) return;
1201
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1202
1202
  const payload = {action: postfixWithEndpointName('toggle', msg, model, meta)};
1203
1203
  addActionGroup(payload, msg, model);
1204
1204
  return payload;
@@ -1209,7 +1209,7 @@ const converters = {
1209
1209
  type: ['commandMoveToLevel', 'commandMoveToLevelWithOnOff'],
1210
1210
  options: [exposes.options.simulated_brightness()],
1211
1211
  convert: (model, msg, publish, options, meta) => {
1212
- if (hasAlreadyProcessedMessage(msg)) return;
1212
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1213
1213
  const payload = {
1214
1214
  action: postfixWithEndpointName(`brightness_move_to_level`, msg, model, meta),
1215
1215
  action_level: msg.data.level,
@@ -1231,7 +1231,7 @@ const converters = {
1231
1231
  type: ['commandMove', 'commandMoveWithOnOff'],
1232
1232
  options: [exposes.options.simulated_brightness()],
1233
1233
  convert: (model, msg, publish, options, meta) => {
1234
- if (hasAlreadyProcessedMessage(msg)) return;
1234
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1235
1235
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1236
1236
  const action = postfixWithEndpointName(`brightness_move_${direction}`, msg, model, meta);
1237
1237
  const payload = {action, action_rate: msg.data.rate};
@@ -1267,7 +1267,7 @@ const converters = {
1267
1267
  type: ['commandStep', 'commandStepWithOnOff'],
1268
1268
  options: [exposes.options.simulated_brightness()],
1269
1269
  convert: (model, msg, publish, options, meta) => {
1270
- if (hasAlreadyProcessedMessage(msg)) return;
1270
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1271
1271
  const direction = msg.data.stepmode === 1 ? 'down' : 'up';
1272
1272
  const payload = {
1273
1273
  action: postfixWithEndpointName(`brightness_step_${direction}`, msg, model, meta),
@@ -1294,7 +1294,7 @@ const converters = {
1294
1294
  type: ['commandStop', 'commandStopWithOnOff'],
1295
1295
  options: [exposes.options.simulated_brightness()],
1296
1296
  convert: (model, msg, publish, options, meta) => {
1297
- if (hasAlreadyProcessedMessage(msg)) return;
1297
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1298
1298
  if (options.simulated_brightness) {
1299
1299
  clearInterval(globalStore.getValue(msg.endpoint, 'simulated_brightness_timer'));
1300
1300
  globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', undefined);
@@ -1309,7 +1309,7 @@ const converters = {
1309
1309
  cluster: 'lightingColorCtrl',
1310
1310
  type: ['commandMoveColorTemp'],
1311
1311
  convert: (model, msg, publish, options, meta) => {
1312
- if (hasAlreadyProcessedMessage(msg)) return;
1312
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1313
1313
  const direction = msg.data.movemode === 1 ? 'down' : 'up';
1314
1314
  const action = postfixWithEndpointName(`color_temperature_move_${direction}`, msg, model, meta);
1315
1315
  const payload = {action, action_rate: msg.data.rate, action_minimum: msg.data.minimum, action_maximum: msg.data.maximum};
@@ -1321,7 +1321,7 @@ const converters = {
1321
1321
  cluster: 'lightingColorCtrl',
1322
1322
  type: 'commandStepColorTemp',
1323
1323
  convert: (model, msg, publish, options, meta) => {
1324
- if (hasAlreadyProcessedMessage(msg)) return;
1324
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1325
1325
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1326
1326
  const payload = {
1327
1327
  action: postfixWithEndpointName(`color_temperature_step_${direction}`, msg, model, meta),
@@ -1340,7 +1340,7 @@ const converters = {
1340
1340
  cluster: 'lightingColorCtrl',
1341
1341
  type: 'commandEnhancedMoveToHueAndSaturation',
1342
1342
  convert: (model, msg, publish, options, meta) => {
1343
- if (hasAlreadyProcessedMessage(msg)) return;
1343
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1344
1344
  const payload = {
1345
1345
  action: postfixWithEndpointName(`enhanced_move_to_hue_and_saturation`, msg, model, meta),
1346
1346
  action_enhanced_hue: msg.data.enhancehue,
@@ -1357,7 +1357,7 @@ const converters = {
1357
1357
  cluster: 'lightingColorCtrl',
1358
1358
  type: ['commandStepHue'],
1359
1359
  convert: (model, msg, publish, options, meta) => {
1360
- if (hasAlreadyProcessedMessage(msg)) return;
1360
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1361
1361
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1362
1362
  const payload = {
1363
1363
  action: postfixWithEndpointName(`color_hue_step_${direction}`, msg, model, meta),
@@ -1372,7 +1372,7 @@ const converters = {
1372
1372
  cluster: 'lightingColorCtrl',
1373
1373
  type: ['commandStepSaturation'],
1374
1374
  convert: (model, msg, publish, options, meta) => {
1375
- if (hasAlreadyProcessedMessage(msg)) return;
1375
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1376
1376
  const direction = msg.data.stepmode === 1 ? 'up' : 'down';
1377
1377
  const payload = {
1378
1378
  action: postfixWithEndpointName(`color_saturation_step_${direction}`, msg, model, meta),
@@ -1387,7 +1387,7 @@ const converters = {
1387
1387
  cluster: 'lightingColorCtrl',
1388
1388
  type: 'commandColorLoopSet',
1389
1389
  convert: (model, msg, publish, options, meta) => {
1390
- if (hasAlreadyProcessedMessage(msg)) return;
1390
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1391
1391
  const updateFlags = msg.data.updateflags;
1392
1392
  const actionLookup = {
1393
1393
  0x00: 'deactivate',
@@ -1417,7 +1417,7 @@ const converters = {
1417
1417
  cluster: 'lightingColorCtrl',
1418
1418
  type: 'commandMoveToColorTemp',
1419
1419
  convert: (model, msg, publish, options, meta) => {
1420
- if (hasAlreadyProcessedMessage(msg)) return;
1420
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1421
1421
  const payload = {
1422
1422
  action: postfixWithEndpointName(`color_temperature_move`, msg, model, meta),
1423
1423
  action_color_temperature: msg.data.colortemp,
@@ -1431,7 +1431,7 @@ const converters = {
1431
1431
  cluster: 'lightingColorCtrl',
1432
1432
  type: 'commandMoveToColor',
1433
1433
  convert: (model, msg, publish, options, meta) => {
1434
- if (hasAlreadyProcessedMessage(msg)) return;
1434
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1435
1435
  const payload = {
1436
1436
  action: postfixWithEndpointName(`color_move`, msg, model, meta),
1437
1437
  action_color: {
@@ -1448,7 +1448,7 @@ const converters = {
1448
1448
  cluster: 'lightingColorCtrl',
1449
1449
  type: 'commandMoveHue',
1450
1450
  convert: (model, msg, publish, options, meta) => {
1451
- if (hasAlreadyProcessedMessage(msg)) return;
1451
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1452
1452
  const movestop = msg.data.movemode == 1 ? 'move' : 'stop';
1453
1453
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model, meta);
1454
1454
  const payload = {action, action_rate: msg.data.rate};
@@ -1460,7 +1460,7 @@ const converters = {
1460
1460
  cluster: 'lightingColorCtrl',
1461
1461
  type: 'commandMoveToSaturation',
1462
1462
  convert: (model, msg, publish, options, meta) => {
1463
- if (hasAlreadyProcessedMessage(msg)) return;
1463
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1464
1464
  const payload = {
1465
1465
  action: postfixWithEndpointName('move_to_saturation', msg, model, meta),
1466
1466
  action_saturation: msg.data.saturation,
@@ -1474,7 +1474,7 @@ const converters = {
1474
1474
  cluster: 'lightingColorCtrl',
1475
1475
  type: 'commandMoveToHue',
1476
1476
  convert: (model, msg, publish, options, meta) => {
1477
- if (hasAlreadyProcessedMessage(msg)) return;
1477
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1478
1478
  const payload = {
1479
1479
  action: postfixWithEndpointName(`move_to_hue`, msg, model, meta),
1480
1480
  action_hue: msg.data.hue,
@@ -1489,7 +1489,7 @@ const converters = {
1489
1489
  cluster: 'ssIasAce',
1490
1490
  type: 'commandEmergency',
1491
1491
  convert: (model, msg, publish, options, meta) => {
1492
- if (hasAlreadyProcessedMessage(msg)) return;
1492
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1493
1493
  const payload = {action: postfixWithEndpointName(`emergency`, msg, model, meta)};
1494
1494
  addActionGroup(payload, msg, model);
1495
1495
  return payload;
@@ -1499,7 +1499,7 @@ const converters = {
1499
1499
  cluster: 'genOnOff',
1500
1500
  type: 'commandOn',
1501
1501
  convert: (model, msg, publish, options, meta) => {
1502
- if (hasAlreadyProcessedMessage(msg)) return;
1502
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1503
1503
  const property = postfixWithEndpointName('state', msg, model, meta);
1504
1504
  return {[property]: 'ON'};
1505
1505
  },
@@ -1508,7 +1508,7 @@ const converters = {
1508
1508
  cluster: 'genOnOff',
1509
1509
  type: 'commandOff',
1510
1510
  convert: (model, msg, publish, options, meta) => {
1511
- if (hasAlreadyProcessedMessage(msg)) return;
1511
+ if (hasAlreadyProcessedMessage(msg, model)) return;
1512
1512
  const property = postfixWithEndpointName('state', msg, model, meta);
1513
1513
  return {[property]: 'OFF'};
1514
1514
  },
@@ -2335,7 +2335,7 @@ const converters = {
2335
2335
  cluster: 'ssIasZone',
2336
2336
  type: 'commandStatusChangeNotification',
2337
2337
  convert: (model, msg, publish, options, meta) => {
2338
- if (hasAlreadyProcessedMessage(msg)) return;
2338
+ if (hasAlreadyProcessedMessage(msg, model)) return;
2339
2339
  const lookup = {1: 'pressed'};
2340
2340
  const zoneStatus = msg.data.zonestatus;
2341
2341
  return {
@@ -2818,7 +2818,7 @@ const converters = {
2818
2818
  cluster: 'genOnOff',
2819
2819
  type: 'raw',
2820
2820
  convert: (model, msg, publish, options, meta) => {
2821
- if (hasAlreadyProcessedMessage(msg, msg.data[1])) return;
2821
+ if (hasAlreadyProcessedMessage(msg, model, msg.data[1])) return;
2822
2822
  const clickMapping = {0: 'single', 1: 'double', 2: 'hold'};
2823
2823
  let buttonMapping = null;
2824
2824
  if (model.model === 'TS0042') {
@@ -4784,7 +4784,7 @@ const converters = {
4784
4784
  cluster: 'genScenes',
4785
4785
  type: 'commandTradfriArrowSingle',
4786
4786
  convert: (model, msg, publish, options, meta) => {
4787
- if (hasAlreadyProcessedMessage(msg)) return;
4787
+ if (hasAlreadyProcessedMessage(msg, model)) return;
4788
4788
  if (msg.data.value === 2) {
4789
4789
  // This is send on toggle hold, ignore it as a toggle_hold is already handled above.
4790
4790
  return;
@@ -4798,7 +4798,7 @@ const converters = {
4798
4798
  cluster: 'genScenes',
4799
4799
  type: 'commandTradfriArrowHold',
4800
4800
  convert: (model, msg, publish, options, meta) => {
4801
- if (hasAlreadyProcessedMessage(msg)) return;
4801
+ if (hasAlreadyProcessedMessage(msg, model)) return;
4802
4802
  const direction = msg.data.value === 3329 ? 'left' : 'right';
4803
4803
  globalStore.putValue(msg.endpoint, 'direction', direction);
4804
4804
  return {action: `arrow_${direction}_hold`};
@@ -4809,7 +4809,7 @@ const converters = {
4809
4809
  type: 'commandTradfriArrowRelease',
4810
4810
  options: [exposes.options.legacy()],
4811
4811
  convert: (model, msg, publish, options, meta) => {
4812
- if (hasAlreadyProcessedMessage(msg)) return;
4812
+ if (hasAlreadyProcessedMessage(msg, model)) return;
4813
4813
  const direction = globalStore.getValue(msg.endpoint, 'direction');
4814
4814
  if (direction) {
4815
4815
  globalStore.clearValue(msg.endpoint, 'direction');
@@ -4880,7 +4880,7 @@ const converters = {
4880
4880
  type: ['commandNotification', 'commandCommisioningNotification'],
4881
4881
  convert: (model, msg, publish, options, meta) => {
4882
4882
  const commandID = msg.data.commandID;
4883
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4883
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4884
4884
  if (commandID === 224) return; // Skip commisioning command.
4885
4885
 
4886
4886
  // Button 1: A0 (top left)
@@ -4902,7 +4902,7 @@ const converters = {
4902
4902
  type: ['commandNotification', 'commandCommisioningNotification'],
4903
4903
  convert: (model, msg, publish, options, meta) => {
4904
4904
  const commandID = msg.data.commandID;
4905
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4905
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4906
4906
  if (commandID === 224) return;
4907
4907
 
4908
4908
  // Button 1: A0 (top left)
@@ -4930,7 +4930,7 @@ const converters = {
4930
4930
  type: ['commandNotification', 'commandCommisioningNotification'],
4931
4931
  convert: (model, msg, publish, options, meta) => {
4932
4932
  const commandID = msg.data.commandID;
4933
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4933
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
4934
4934
  if (commandID === 224) return;
4935
4935
 
4936
4936
  // Button 1: A0 (top left)
@@ -5342,7 +5342,7 @@ const converters = {
5342
5342
  type: ['commandNotification', 'commandCommisioningNotification'],
5343
5343
  convert: (model, msg, publish, options, meta) => {
5344
5344
  const commandID = msg.data.commandID;
5345
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
5345
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
5346
5346
  if (commandID === 224) return;
5347
5347
  const lookup = {0x14: 'press_1', 0x15: 'press_2', 0x16: 'press_3', 0x17: 'press_4'};
5348
5348
  if (!lookup.hasOwnProperty(commandID)) {
@@ -5357,7 +5357,7 @@ const converters = {
5357
5357
  type: ['commandNotification', 'commandCommisioningNotification'],
5358
5358
  convert: (model, msg, publish, options, meta) => {
5359
5359
  const commandID = msg.data.commandID;
5360
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
5360
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
5361
5361
  if (commandID === 224) return;
5362
5362
  const lookup = {0x22: 'press_once', 0x20: 'press_twice'};
5363
5363
  if (!lookup.hasOwnProperty(commandID)) {
@@ -5476,7 +5476,7 @@ const converters = {
5476
5476
  cluster: 'genMultistateInput',
5477
5477
  type: ['attributeReport'],
5478
5478
  convert: (model, msg, publish, options, meta) => {
5479
- if (hasAlreadyProcessedMessage(msg)) return;
5479
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5480
5480
  let actionLookup = {0: 'hold', 1: 'single', 2: 'double', 3: 'triple', 255: 'release'};
5481
5481
  if (model.model === 'WXKG12LM') {
5482
5482
  actionLookup = {...actionLookup, 16: 'hold', 17: 'release', 18: 'shake'};
@@ -5613,7 +5613,7 @@ const converters = {
5613
5613
  `increase it with this option (value is in ms).`),
5614
5614
  ],
5615
5615
  convert: (model, msg, publish, options, meta) => {
5616
- if (hasAlreadyProcessedMessage(msg)) return;
5616
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5617
5617
  const state = msg.data['onOff'];
5618
5618
 
5619
5619
  // 0 = click down, 1 = click up, else = multiple clicks
@@ -5894,7 +5894,7 @@ const converters = {
5894
5894
  cluster: 'genMultistateInput',
5895
5895
  type: ['attributeReport', 'readResponse'],
5896
5896
  convert: (model, msg, publish, options, meta) => {
5897
- if (hasAlreadyProcessedMessage(msg)) return;
5897
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5898
5898
  const actionLookup = {0: 'hold', 255: 'release', 1: 'single', 2: 'double', 3: 'triple', 5: 'quintuple', 6: 'many'};
5899
5899
  const button = msg.endpoint.ID;
5900
5900
  const value = msg.data.presentValue;
@@ -5917,7 +5917,7 @@ const converters = {
5917
5917
  cluster: 'genOnOff',
5918
5918
  type: 'commandOn',
5919
5919
  convert: (model, msg, publish, options, meta) => {
5920
- if (hasAlreadyProcessedMessage(msg)) return;
5920
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5921
5921
  return {action: 'button_2_single'};
5922
5922
  },
5923
5923
  },
@@ -5925,7 +5925,7 @@ const converters = {
5925
5925
  cluster: 'genOnOff',
5926
5926
  type: 'commandOff',
5927
5927
  convert: (model, msg, publish, options, meta) => {
5928
- if (hasAlreadyProcessedMessage(msg)) return;
5928
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5929
5929
  return {action: 'button_1_single'};
5930
5930
  },
5931
5931
  },
@@ -5933,7 +5933,7 @@ const converters = {
5933
5933
  cluster: 'genLevelCtrl',
5934
5934
  type: 'commandStep',
5935
5935
  convert: (model, msg, publish, options, meta) => {
5936
- if (hasAlreadyProcessedMessage(msg)) return;
5936
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5937
5937
  const button = msg.data.stepmode === 0 ? '4' : '3';
5938
5938
  return {action: `button_${button}_single`};
5939
5939
  },
@@ -5943,7 +5943,7 @@ const converters = {
5943
5943
  type: 'commandStop',
5944
5944
  options: [exposes.options.legacy()],
5945
5945
  convert: (model, msg, publish, options, meta) => {
5946
- if (hasAlreadyProcessedMessage(msg)) return;
5946
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5947
5947
  if (globalStore.hasValue(msg.endpoint, 'button')) {
5948
5948
  const value = globalStore.getValue(msg.endpoint, 'button');
5949
5949
  const duration = Date.now() - value.start;
@@ -5957,7 +5957,7 @@ const converters = {
5957
5957
  cluster: 'genLevelCtrl',
5958
5958
  type: 'commandMove',
5959
5959
  convert: (model, msg, publish, options, meta) => {
5960
- if (hasAlreadyProcessedMessage(msg)) return;
5960
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5961
5961
  const button = msg.data.movemode === 0 ? '4' : '3';
5962
5962
  globalStore.putValue(msg.endpoint, 'button', {button, start: Date.now()});
5963
5963
  return {action: `button_${button}_hold`};
@@ -5967,7 +5967,7 @@ const converters = {
5967
5967
  cluster: 'lightingColorCtrl',
5968
5968
  type: 'commandStepColorTemp',
5969
5969
  convert: (model, msg, publish, options, meta) => {
5970
- if (hasAlreadyProcessedMessage(msg)) return;
5970
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5971
5971
  let action;
5972
5972
  if (model.model === 'WXCJKG12LM') {
5973
5973
  // for WXCJKG12LM model it's double click event on buttons 3 and 4
@@ -5984,7 +5984,7 @@ const converters = {
5984
5984
  type: 'commandMoveColorTemp',
5985
5985
  options: [exposes.options.legacy()],
5986
5986
  convert: (model, msg, publish, options, meta) => {
5987
- if (hasAlreadyProcessedMessage(msg)) return;
5987
+ if (hasAlreadyProcessedMessage(msg, model)) return;
5988
5988
  const stop = msg.data.movemode === 0;
5989
5989
  let result = null;
5990
5990
  if (stop) {
@@ -7132,7 +7132,7 @@ const converters = {
7132
7132
  type: ['commandNotification', 'commandCommisioningNotification'],
7133
7133
  convert: (model, msg, publish, options, meta) => {
7134
7134
  const commandID = msg.data.commandID;
7135
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
7135
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
7136
7136
  if (commandID === 224) return;
7137
7137
  const lookup = {0x22: 'press_1', 0x10: 'press_2', 0x11: 'press_3', 0x12: 'press_4'};
7138
7138
  if (!lookup.hasOwnProperty(commandID)) {
@@ -7410,7 +7410,7 @@ const converters = {
7410
7410
  cluster: 'wiserDeviceInfo',
7411
7411
  type: 'attributeReport',
7412
7412
  convert: (model, msg, publish, options, meta) => {
7413
- if (hasAlreadyProcessedMessage(msg)) return;
7413
+ if (hasAlreadyProcessedMessage(msg, model)) return;
7414
7414
 
7415
7415
  const data = msg.data['deviceInfo'].split(',');
7416
7416
  if (data[0] === 'UI' && data[1]) {
@@ -7623,7 +7623,7 @@ const converters = {
7623
7623
  cluster: 'ssIasZone',
7624
7624
  type: 'commandStatusChangeNotification',
7625
7625
  convert: (model, msg, publish, options, meta) => {
7626
- if (utils.hasAlreadyProcessedMessage(msg)) return;
7626
+ if (hasAlreadyProcessedMessage(msg, model)) return;
7627
7627
  const lookup = {32768: 'pressed'};
7628
7628
  const zoneStatus = msg.data.zonestatus;
7629
7629
  return {
@@ -7699,44 +7699,6 @@ const converters = {
7699
7699
  return result;
7700
7700
  },
7701
7701
  },
7702
- tuya_radar_sensor: {
7703
- cluster: 'manuSpecificTuya',
7704
- type: ['commandDataResponse', 'commandDataReport'],
7705
- convert: (model, msg, publish, options, meta) => {
7706
- const dpValue = tuya.firstDpValue(msg, meta, 'tuya_radar_sensor');
7707
- const dp = dpValue.dp;
7708
- const value = tuya.getDataValue(dpValue);
7709
- let result = null;
7710
- switch (dp) {
7711
- case tuya.dataPoints.trsPresenceState:
7712
- result = {presence: {0: false, 1: true}[value]};
7713
- break;
7714
- case tuya.dataPoints.trsMotionState:
7715
- result = {occupancy: {1: false, 2: true}[value]};
7716
- break;
7717
- case tuya.dataPoints.trsMotionSpeed:
7718
- result = {motion_speed: value};
7719
- break;
7720
- case tuya.dataPoints.trsMotionDirection:
7721
- result = {motion_direction: tuya.tuyaRadar.motionDirection[value]};
7722
- break;
7723
- case tuya.dataPoints.trsScene:
7724
- result = {radar_scene: tuya.tuyaRadar.radarScene[value]};
7725
- break;
7726
- case tuya.dataPoints.trsSensitivity:
7727
- result = {radar_sensitivity: value};
7728
- break;
7729
- case tuya.dataPoints.trsIlluminanceLux:
7730
- result = {illuminance_lux: value};
7731
- break;
7732
- case tuya.dataPoints.trsDetectionData: // Ignore this, function of this DP is unknown at the moment!
7733
- break;
7734
- default:
7735
- meta.logger.warn(`fromZigbee.tuya_radar_sensor: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
7736
- }
7737
- return result;
7738
- },
7739
- },
7740
7702
  tuya_radar_sensor_fall: {
7741
7703
  cluster: 'manuSpecificTuya',
7742
7704
  type: ['commandDataResponse', 'commandDataReport'],
@@ -8077,7 +8039,7 @@ const converters = {
8077
8039
  type: ['commandNotification', 'commandCommisioningNotification'],
8078
8040
  convert: (model, msg, publish, options, meta) => {
8079
8041
  const commandID = msg.data.commandID;
8080
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
8042
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
8081
8043
  if (commandID === 224) return;
8082
8044
  const lookup = {0x21: 'press_on', 0x20: 'press_off', 0x34: 'release', 0x35: 'hold_on', 0x36: 'hold_off'};
8083
8045
  if (!lookup.hasOwnProperty(commandID)) {
@@ -8092,7 +8054,7 @@ const converters = {
8092
8054
  type: ['commandNotification', 'commandCommisioningNotification'],
8093
8055
  convert: (model, msg, publish, options, meta) => {
8094
8056
  const commandID = msg.data.commandID;
8095
- if (hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
8057
+ if (hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
8096
8058
  if (commandID === 224) return;
8097
8059
  const lookup = {
8098
8060
  0x21: 'press_on',
@@ -8161,7 +8123,7 @@ const converters = {
8161
8123
  convert: (model, msg, publish, options, meta) => {
8162
8124
  // commandStopMove without params
8163
8125
  if (msg.data[2] !== 71) return;
8164
- if (hasAlreadyProcessedMessage(msg)) return;
8126
+ if (hasAlreadyProcessedMessage(msg, model)) return;
8165
8127
  const movestop = 'stop';
8166
8128
  const action = postfixWithEndpointName(`hue_${movestop}`, msg, model, meta);
8167
8129
  const payload = {action};
@@ -8173,7 +8135,7 @@ const converters = {
8173
8135
  cluster: 'genOnOff',
8174
8136
  type: 'raw',
8175
8137
  convert: (model, msg, publish, options, meta) => {
8176
- if (hasAlreadyProcessedMessage(msg, msg.data[1])) return;
8138
+ if (hasAlreadyProcessedMessage(msg, model, msg.data[1])) return;
8177
8139
  let action;
8178
8140
  if (msg.data[2] == 253) {
8179
8141
  action = {0: 'single', 1: 'double', 2: 'hold'}[msg.data[3]];
@@ -6869,21 +6869,6 @@ const converters = {
6869
6869
  }
6870
6870
  },
6871
6871
  },
6872
- tuya_radar_sensor: {
6873
- key: ['radar_scene', 'radar_sensitivity'],
6874
- convertSet: async (entity, key, value, meta) => {
6875
- switch (key) {
6876
- case 'radar_scene':
6877
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsScene, utils.getKey(tuya.tuyaRadar.radarScene, value));
6878
- break;
6879
- case 'radar_sensitivity':
6880
- await tuya.sendDataPointValue(entity, tuya.dataPoints.trsSensitivity, value);
6881
- break;
6882
- default: // Unknown Key
6883
- meta.logger.warn(`toZigbee.tuya_radar_sensor: Unhandled Key ${key}`);
6884
- }
6885
- },
6886
- },
6887
6872
  tuya_radar_sensor_fall: {
6888
6873
  key: ['radar_scene', 'radar_sensitivity', 'tumble_alarm_time', 'tumble_switch', 'fall_sensitivity'],
6889
6874
  convertSet: async (entity, key, value, meta) => {
package/devices/ikea.js CHANGED
@@ -92,7 +92,7 @@ const fzLocal = {
92
92
  cluster: 'genOnOff',
93
93
  type: 'commandOn',
94
94
  convert: (model, msg, publish, options, meta) => {
95
- if (utils.hasAlreadyProcessedMessage(msg)) return;
95
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
96
96
  const arrowReleaseAgo = Date.now() - globalStore.getValue(msg.endpoint, 'arrow_release', 0);
97
97
  if (arrowReleaseAgo > 700) {
98
98
  return {action: 'on'};
@@ -104,7 +104,7 @@ const fzLocal = {
104
104
  type: 'commandTradfriArrowRelease',
105
105
  options: [exposes.options.legacy()],
106
106
  convert: (model, msg, publish, options, meta) => {
107
- if (utils.hasAlreadyProcessedMessage(msg)) return;
107
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
108
108
  globalStore.putValue(msg.endpoint, 'arrow_release', Date.now());
109
109
  const direction = globalStore.getValue(msg.endpoint, 'direction');
110
110
  if (direction) {
@@ -10,7 +10,7 @@ const fzLocal = {
10
10
  type: ['commandNotification', 'commandCommisioningNotification'],
11
11
  convert: (model, msg, publish, options, meta) => {
12
12
  const commandID = msg.data.commandID;
13
- if (utils.hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
13
+ if (utils.hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
14
14
  if (commandID === 224) return;
15
15
  const lookup = {0x13: 'press_1', 0x14: 'press_2', 0x15: 'press_3', 0x16: 'press_4',
16
16
  0x1B: 'hold_1', 0x1C: 'hold_2', 0x1D: 'hold_3', 0x1E: 'hold_4'};
@@ -6,7 +6,6 @@ const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
7
  const ea = exposes.access;
8
8
  const ota = require('../lib/ota');
9
- const utils = require('../lib/utils');
10
9
 
11
10
  const readInitialBatteryState = async (type, data, device) => {
12
11
  if (['deviceAnnounce'].includes(type)) {
@@ -16,29 +15,6 @@ const readInitialBatteryState = async (type, data, device) => {
16
15
  }
17
16
  };
18
17
 
19
- const fzLocal = {
20
- command_off: {
21
- cluster: 'genOnOff',
22
- type: 'commandOff',
23
- convert: (model, msg, publish, options, meta) => {
24
- const payload = {action: utils.postfixWithEndpointName('off', msg, model, meta)};
25
- utils.addActionGroup(payload, msg, model);
26
- return payload;
27
- },
28
- },
29
- command_toggle: {
30
- cluster: 'genOnOff',
31
- type: 'commandToggle',
32
- convert: (model, msg, publish, options, meta) => {
33
- // Re-uses transactions sequence number so hasAlreadyProcessedMessage(msg) suppresess actions
34
- // https://github.com/Koenkk/zigbee2mqtt/issues/14256
35
- const payload = {action: utils.postfixWithEndpointName('toggle', msg, model, meta)};
36
- utils.addActionGroup(payload, msg, model);
37
- return payload;
38
- },
39
- },
40
- };
41
-
42
18
  module.exports = [
43
19
  {
44
20
  zigbeeModel: [' Contactor\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
@@ -133,12 +109,12 @@ module.exports = [
133
109
  vendor: 'Legrand',
134
110
  // led blink RED when battery is low
135
111
  description: 'Wireless remote switch',
136
- fromZigbee: [fz.identify, fz.command_on, fzLocal.command_off, fzLocal.command_toggle, fz.legacy.cmd_move, fz.legacy.cmd_stop,
112
+ fromZigbee: [fz.identify, fz.command_on, fz.command_off, fz.command_toggle, fz.legacy.cmd_move, fz.legacy.cmd_stop,
137
113
  fz.battery],
138
114
  exposes: [e.battery(), e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up',
139
115
  'brightness_move_down', 'brightness_stop'])],
140
116
  toZigbee: [],
141
- meta: {battery: {voltageToPercentage: '3V_2500'}},
117
+ meta: {battery: {voltageToPercentage: '3V_2500'}, publishDuplicateTransaction: true},
142
118
  configure: async (device, coordinatorEndpoint, logger) => {
143
119
  const endpoint = device.getEndpoint(1);
144
120
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
@@ -149,11 +125,11 @@ module.exports = [
149
125
  model: '067774',
150
126
  vendor: 'Legrand',
151
127
  description: 'Wireless double remote switch',
152
- fromZigbee: [fz.identify, fz.command_on, fzLocal.command_off, fzLocal.command_toggle, fz.command_move, fz.command_stop, fz.battery],
128
+ fromZigbee: [fz.identify, fz.command_on, fz.command_off, fz.command_toggle, fz.command_move, fz.command_stop, fz.battery],
153
129
  exposes: [e.battery(),
154
130
  e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up', 'brightness_move_down', 'brightness_stop'])],
155
131
  toZigbee: [],
156
- meta: {multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}},
132
+ meta: {multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}, publishDuplicateTransaction: true},
157
133
  configure: async (device, coordinatorEndpoint, logger) => {
158
134
  const endpoint = device.getEndpoint(1);
159
135
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
package/devices/lidl.js CHANGED
@@ -145,14 +145,14 @@ const fzLocal = {
145
145
  metering_skip_duplicate: {
146
146
  ...fz.metering,
147
147
  convert: (model, msg, publish, options, meta) => {
148
- if (utils.hasAlreadyProcessedMessage(msg)) return;
148
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
149
149
  return fz.metering.convert(model, msg, publish, options, meta);
150
150
  },
151
151
  },
152
152
  electrical_measurement_skip_duplicate: {
153
153
  ...fz.electrical_measurement,
154
154
  convert: (model, msg, publish, options, meta) => {
155
- if (utils.hasAlreadyProcessedMessage(msg)) return;
155
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
156
156
  return fz.electrical_measurement.convert(model, msg, publish, options, meta);
157
157
  },
158
158
  },
@@ -28,7 +28,7 @@ const fzLocal = {
28
28
  }
29
29
 
30
30
  const commandID = msg.data.commandID;
31
- if (utils.hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
31
+ if (utils.hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
32
32
 
33
33
  const rxAfterTx = (msg.data.options & (1<<11));
34
34
  const ret = {};
@@ -15,7 +15,7 @@ const fzLocal = {
15
15
  type: ['commandNotification', 'commandCommisioningNotification'],
16
16
  convert: (model, msg, publish, options, meta) => {
17
17
  const commandID = msg.data.commandID;
18
- if (utils.hasAlreadyProcessedMessage(msg, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
18
+ if (utils.hasAlreadyProcessedMessage(msg, model, msg.data.frameCounter, `${msg.device.ieeeAddr}_${commandID}`)) return;
19
19
  if (commandID === 224) return;
20
20
  const lookup = {
21
21
  0x21: 'press_on',
package/devices/tuya.js CHANGED
@@ -375,14 +375,14 @@ const fzLocal = {
375
375
  metering_skip_duplicate: {
376
376
  ...fz.metering,
377
377
  convert: (model, msg, publish, options, meta) => {
378
- if (utils.hasAlreadyProcessedMessage(msg)) return;
378
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
379
379
  return fz.metering.convert(model, msg, publish, options, meta);
380
380
  },
381
381
  },
382
382
  electrical_measurement_skip_duplicate: {
383
383
  ...fz.electrical_measurement,
384
384
  convert: (model, msg, publish, options, meta) => {
385
- if (utils.hasAlreadyProcessedMessage(msg)) return;
385
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
386
386
  return fz.electrical_measurement.convert(model, msg, publish, options, meta);
387
387
  },
388
388
  },
@@ -923,7 +923,8 @@ module.exports = [
923
923
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_xr5m6kfg'},
924
924
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_xr5m6kfg'},
925
925
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bf175wi4'},
926
- {modelID: 'TS0505B', manufacturerName: '_TZB210_3zfp8mki'}],
926
+ {modelID: 'TS0505B', manufacturerName: '_TZB210_3zfp8mki'},
927
+ {modelID: 'TS0505B', manufacturerName: '_TZ3000_y1vbo44x'}],
927
928
  model: 'TS0505B',
928
929
  vendor: 'TuYa',
929
930
  description: 'Zigbee RGB+CCT light',
@@ -3148,27 +3149,10 @@ module.exports = [
3148
3149
  ],
3149
3150
  },
3150
3151
  {
3151
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_vrfecyku'}],
3152
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_lu01t0zl'},
3153
+ {modelID: 'TS0601', manufacturerName: '_TZE200_vrfecyku'}],
3152
3154
  model: 'MIR-HE200-TY',
3153
3155
  vendor: 'TuYa',
3154
- description: 'Human presence sensor',
3155
- fromZigbee: [fz.tuya_radar_sensor],
3156
- toZigbee: [tz.tuya_radar_sensor],
3157
- exposes: [
3158
- e.illuminance_lux(), e.presence(), e.occupancy(),
3159
- exposes.numeric('motion_speed', ea.STATE).withDescription('Speed of movement'),
3160
- exposes.enum('motion_direction', ea.STATE, Object.values(tuya.tuyaRadar.motionDirection))
3161
- .withDescription('direction of movement from the point of view of the radar'),
3162
- exposes.numeric('radar_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1)
3163
- .withDescription('sensitivity of the radar'),
3164
- exposes.enum('radar_scene', ea.STATE_SET, Object.values(tuya.tuyaRadar.radarScene))
3165
- .withDescription('presets for sensitivity for presence and movement'),
3166
- ],
3167
- },
3168
- {
3169
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_lu01t0zl'}],
3170
- model: 'MIR-HE200-TY_fall',
3171
- vendor: 'TuYa',
3172
3156
  description: 'Human presence sensor with fall function',
3173
3157
  fromZigbee: [fz.tuya_radar_sensor_fall],
3174
3158
  toZigbee: [tz.tuya_radar_sensor_fall],
package/lib/legacy.js CHANGED
@@ -856,7 +856,7 @@ const fromZigbee = {
856
856
  type: 'commandToggle',
857
857
  options: [exposes.options.legacy()],
858
858
  convert: (model, msg, publish, options, meta) => {
859
- if (hasAlreadyProcessedMessage(msg)) return;
859
+ if (hasAlreadyProcessedMessage(msg, model)) return;
860
860
  if (isLegacyEnabled(options)) {
861
861
  return {action: 'play_pause'};
862
862
  } else {
@@ -869,7 +869,7 @@ const fromZigbee = {
869
869
  type: 'commandStep',
870
870
  options: [exposes.options.legacy()],
871
871
  convert: (model, msg, publish, options, meta) => {
872
- if (hasAlreadyProcessedMessage(msg)) return;
872
+ if (hasAlreadyProcessedMessage(msg, model)) return;
873
873
  if (isLegacyEnabled(options)) {
874
874
  const direction = msg.data.stepmode === 1 ? 'backward' : 'forward';
875
875
  return {
@@ -887,7 +887,7 @@ const fromZigbee = {
887
887
  type: 'commandMove',
888
888
  options: [exposes.options.legacy(), exposes.options.simulated_brightness(' Note: will only work when legacy: false is set.')],
889
889
  convert: (model, msg, publish, options, meta) => {
890
- if (hasAlreadyProcessedMessage(msg)) return;
890
+ if (hasAlreadyProcessedMessage(msg, model)) return;
891
891
  if (isLegacyEnabled(options)) {
892
892
  ictcg1(model, msg, publish, options, 'move');
893
893
  const direction = msg.data.movemode === 1 ? 'left' : 'right';
@@ -916,7 +916,7 @@ const fromZigbee = {
916
916
  type: 'commandStop',
917
917
  options: [exposes.options.legacy()],
918
918
  convert: (model, msg, publish, options, meta) => {
919
- if (hasAlreadyProcessedMessage(msg)) return;
919
+ if (hasAlreadyProcessedMessage(msg, model)) return;
920
920
  if (isLegacyEnabled(options)) {
921
921
  const value = ictcg1(model, msg, publish, options, 'stop');
922
922
  return {action: `rotate_stop`, brightness: value};
package/lib/utils.js CHANGED
@@ -66,7 +66,8 @@ function mapNumberRange(value, fromLow, fromHigh, toLow, toHigh, precision=0) {
66
66
  }
67
67
 
68
68
  const transactionStore = {};
69
- function hasAlreadyProcessedMessage(msg, ID=null, key=null) {
69
+ function hasAlreadyProcessedMessage(msg, model, ID=null, key=null) {
70
+ if (model.meta && model.meta.publishDuplicateTransaction) return false;
70
71
  const currentID = ID !== null ? ID : msg.meta.zclTransactionSequenceNumber;
71
72
  key = key || msg.device.ieeeAddr;
72
73
  if (transactionStore[key] === currentID) return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.654",
3
+ "version": "14.0.655",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [