zigbee-herdsman-converters 14.0.396 → 14.0.400
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/converters/fromZigbee.js +79 -47
- package/converters/toZigbee.js +23 -0
- package/devices/custom_devices_diy.js +22 -0
- package/devices/ecodim.js +0 -2
- package/devices/edp.js +3 -1
- package/devices/ikea.js +2 -2
- package/devices/jxuan.js +0 -1
- package/devices/legrand.js +2 -2
- package/devices/moes.js +0 -1
- package/devices/owon.js +0 -1
- package/devices/perenio.js +0 -1
- package/devices/philips.js +9 -0
- package/devices/prolight.js +7 -0
- package/devices/schneider_electric.js +43 -0
- package/devices/sprut.js +92 -12
- package/devices/sunricher.js +2 -1
- package/devices/tuya.js +40 -7
- package/devices/xiaomi.js +7 -22
- package/lib/tuya.js +3 -0
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -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,
|
|
@@ -1086,7 +1086,7 @@ const converters = {
|
|
|
1086
1086
|
cluster: 'closuresWindowCovering',
|
|
1087
1087
|
type: 'commandStop',
|
|
1088
1088
|
convert: (model, msg, publish, options, meta) => {
|
|
1089
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1089
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1090
1090
|
const payload = {action: postfixWithEndpointName('stop', msg, model)};
|
|
1091
1091
|
addActionGroup(payload, msg, model);
|
|
1092
1092
|
return payload;
|
|
@@ -1096,7 +1096,7 @@ const converters = {
|
|
|
1096
1096
|
cluster: 'closuresWindowCovering',
|
|
1097
1097
|
type: 'commandUpOpen',
|
|
1098
1098
|
convert: (model, msg, publish, options, meta) => {
|
|
1099
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1099
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1100
1100
|
const payload = {action: postfixWithEndpointName('open', msg, model)};
|
|
1101
1101
|
addActionGroup(payload, msg, model);
|
|
1102
1102
|
return payload;
|
|
@@ -1106,7 +1106,7 @@ const converters = {
|
|
|
1106
1106
|
cluster: 'closuresWindowCovering',
|
|
1107
1107
|
type: 'commandDownClose',
|
|
1108
1108
|
convert: (model, msg, publish, options, meta) => {
|
|
1109
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1109
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1110
1110
|
const payload = {action: postfixWithEndpointName('close', msg, model)};
|
|
1111
1111
|
addActionGroup(payload, msg, model);
|
|
1112
1112
|
return payload;
|
|
@@ -1116,7 +1116,7 @@ const converters = {
|
|
|
1116
1116
|
cluster: 'genOnOff',
|
|
1117
1117
|
type: 'commandOn',
|
|
1118
1118
|
convert: (model, msg, publish, options, meta) => {
|
|
1119
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1119
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1120
1120
|
const payload = {action: postfixWithEndpointName('on', msg, model)};
|
|
1121
1121
|
addActionGroup(payload, msg, model);
|
|
1122
1122
|
return payload;
|
|
@@ -1126,7 +1126,7 @@ const converters = {
|
|
|
1126
1126
|
cluster: 'genOnOff',
|
|
1127
1127
|
type: 'commandOff',
|
|
1128
1128
|
convert: (model, msg, publish, options, meta) => {
|
|
1129
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1129
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1130
1130
|
const payload = {action: postfixWithEndpointName('off', msg, model)};
|
|
1131
1131
|
addActionGroup(payload, msg, model);
|
|
1132
1132
|
return payload;
|
|
@@ -1136,7 +1136,7 @@ const converters = {
|
|
|
1136
1136
|
cluster: 'genOnOff',
|
|
1137
1137
|
type: 'commandOffWithEffect',
|
|
1138
1138
|
convert: (model, msg, publish, options, meta) => {
|
|
1139
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1139
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1140
1140
|
const payload = {action: postfixWithEndpointName(`off`, msg, model)};
|
|
1141
1141
|
addActionGroup(payload, msg, model);
|
|
1142
1142
|
return payload;
|
|
@@ -1146,7 +1146,7 @@ const converters = {
|
|
|
1146
1146
|
cluster: 'genOnOff',
|
|
1147
1147
|
type: 'commandToggle',
|
|
1148
1148
|
convert: (model, msg, publish, options, meta) => {
|
|
1149
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1149
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1150
1150
|
const payload = {action: postfixWithEndpointName('toggle', msg, model)};
|
|
1151
1151
|
addActionGroup(payload, msg, model);
|
|
1152
1152
|
return payload;
|
|
@@ -1157,7 +1157,7 @@ const converters = {
|
|
|
1157
1157
|
type: ['commandMoveToLevel', 'commandMoveToLevelWithOnOff'],
|
|
1158
1158
|
options: [exposes.options.simulated_brightness()],
|
|
1159
1159
|
convert: (model, msg, publish, options, meta) => {
|
|
1160
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1160
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1161
1161
|
const payload = {
|
|
1162
1162
|
action: postfixWithEndpointName(`brightness_move_to_level`, msg, model),
|
|
1163
1163
|
action_level: msg.data.level,
|
|
@@ -1179,7 +1179,7 @@ const converters = {
|
|
|
1179
1179
|
type: ['commandMove', 'commandMoveWithOnOff'],
|
|
1180
1180
|
options: [exposes.options.simulated_brightness()],
|
|
1181
1181
|
convert: (model, msg, publish, options, meta) => {
|
|
1182
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1182
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1183
1183
|
const direction = msg.data.movemode === 1 ? 'down' : 'up';
|
|
1184
1184
|
const action = postfixWithEndpointName(`brightness_move_${direction}`, msg, model);
|
|
1185
1185
|
const payload = {action, action_rate: msg.data.rate};
|
|
@@ -1215,7 +1215,7 @@ const converters = {
|
|
|
1215
1215
|
type: ['commandStep', 'commandStepWithOnOff'],
|
|
1216
1216
|
options: [exposes.options.simulated_brightness()],
|
|
1217
1217
|
convert: (model, msg, publish, options, meta) => {
|
|
1218
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1218
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1219
1219
|
const direction = msg.data.stepmode === 1 ? 'down' : 'up';
|
|
1220
1220
|
const payload = {
|
|
1221
1221
|
action: postfixWithEndpointName(`brightness_step_${direction}`, msg, model),
|
|
@@ -1242,7 +1242,7 @@ const converters = {
|
|
|
1242
1242
|
type: ['commandStop', 'commandStopWithOnOff'],
|
|
1243
1243
|
options: [exposes.options.simulated_brightness()],
|
|
1244
1244
|
convert: (model, msg, publish, options, meta) => {
|
|
1245
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1245
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1246
1246
|
if (options.simulated_brightness) {
|
|
1247
1247
|
clearInterval(globalStore.getValue(msg.endpoint, 'simulated_brightness_timer'));
|
|
1248
1248
|
globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', undefined);
|
|
@@ -1257,7 +1257,7 @@ const converters = {
|
|
|
1257
1257
|
cluster: 'lightingColorCtrl',
|
|
1258
1258
|
type: ['commandMoveColorTemp'],
|
|
1259
1259
|
convert: (model, msg, publish, options, meta) => {
|
|
1260
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1260
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1261
1261
|
const direction = msg.data.movemode === 1 ? 'down' : 'up';
|
|
1262
1262
|
const action = postfixWithEndpointName(`color_temperature_move_${direction}`, msg, model);
|
|
1263
1263
|
const payload = {action, action_rate: msg.data.rate, action_minimum: msg.data.minimum, action_maximum: msg.data.maximum};
|
|
@@ -1269,7 +1269,7 @@ const converters = {
|
|
|
1269
1269
|
cluster: 'lightingColorCtrl',
|
|
1270
1270
|
type: 'commandStepColorTemp',
|
|
1271
1271
|
convert: (model, msg, publish, options, meta) => {
|
|
1272
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1272
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1273
1273
|
const direction = msg.data.stepmode === 1 ? 'up' : 'down';
|
|
1274
1274
|
const payload = {
|
|
1275
1275
|
action: postfixWithEndpointName(`color_temperature_step_${direction}`, msg, model),
|
|
@@ -1288,7 +1288,7 @@ const converters = {
|
|
|
1288
1288
|
cluster: 'lightingColorCtrl',
|
|
1289
1289
|
type: 'commandEnhancedMoveToHueAndSaturation',
|
|
1290
1290
|
convert: (model, msg, publish, options, meta) => {
|
|
1291
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1291
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1292
1292
|
const payload = {
|
|
1293
1293
|
action: postfixWithEndpointName(`enhanced_move_to_hue_and_saturation`, msg, model),
|
|
1294
1294
|
action_enhanced_hue: msg.data.enhancehue,
|
|
@@ -1305,7 +1305,7 @@ const converters = {
|
|
|
1305
1305
|
cluster: 'lightingColorCtrl',
|
|
1306
1306
|
type: ['commandStepHue'],
|
|
1307
1307
|
convert: (model, msg, publish, options, meta) => {
|
|
1308
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1308
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1309
1309
|
const direction = msg.data.stepmode === 1 ? 'up' : 'down';
|
|
1310
1310
|
const payload = {
|
|
1311
1311
|
action: postfixWithEndpointName(`color_hue_step_${direction}`, msg, model),
|
|
@@ -1320,7 +1320,7 @@ const converters = {
|
|
|
1320
1320
|
cluster: 'lightingColorCtrl',
|
|
1321
1321
|
type: ['commandStepSaturation'],
|
|
1322
1322
|
convert: (model, msg, publish, options, meta) => {
|
|
1323
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1323
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1324
1324
|
const direction = msg.data.stepmode === 1 ? 'up' : 'down';
|
|
1325
1325
|
const payload = {
|
|
1326
1326
|
action: postfixWithEndpointName(`color_saturation_step_${direction}`, msg, model),
|
|
@@ -1335,7 +1335,7 @@ const converters = {
|
|
|
1335
1335
|
cluster: 'lightingColorCtrl',
|
|
1336
1336
|
type: 'commandColorLoopSet',
|
|
1337
1337
|
convert: (model, msg, publish, options, meta) => {
|
|
1338
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1338
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1339
1339
|
const updateFlags = msg.data.updateflags;
|
|
1340
1340
|
const actionLookup = {
|
|
1341
1341
|
0x00: 'deactivate',
|
|
@@ -1365,7 +1365,7 @@ const converters = {
|
|
|
1365
1365
|
cluster: 'lightingColorCtrl',
|
|
1366
1366
|
type: 'commandMoveToColorTemp',
|
|
1367
1367
|
convert: (model, msg, publish, options, meta) => {
|
|
1368
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1368
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1369
1369
|
const payload = {
|
|
1370
1370
|
action: postfixWithEndpointName(`color_temperature_move`, msg, model),
|
|
1371
1371
|
action_color_temperature: msg.data.colortemp,
|
|
@@ -1379,7 +1379,7 @@ const converters = {
|
|
|
1379
1379
|
cluster: 'lightingColorCtrl',
|
|
1380
1380
|
type: 'commandMoveToColor',
|
|
1381
1381
|
convert: (model, msg, publish, options, meta) => {
|
|
1382
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1382
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1383
1383
|
const payload = {
|
|
1384
1384
|
action: postfixWithEndpointName(`color_move`, msg, model),
|
|
1385
1385
|
action_color: {
|
|
@@ -1396,7 +1396,7 @@ const converters = {
|
|
|
1396
1396
|
cluster: 'lightingColorCtrl',
|
|
1397
1397
|
type: 'commandMoveHue',
|
|
1398
1398
|
convert: (model, msg, publish, options, meta) => {
|
|
1399
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1399
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1400
1400
|
const movestop = msg.data.movemode == 1 ? 'move' : 'stop';
|
|
1401
1401
|
const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
|
|
1402
1402
|
const payload = {action, action_rate: msg.data.rate};
|
|
@@ -1408,7 +1408,7 @@ const converters = {
|
|
|
1408
1408
|
cluster: 'lightingColorCtrl',
|
|
1409
1409
|
type: 'commandMoveToSaturation',
|
|
1410
1410
|
convert: (model, msg, publish, options, meta) => {
|
|
1411
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1411
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1412
1412
|
const payload = {
|
|
1413
1413
|
action: postfixWithEndpointName('move_to_saturation', msg, model),
|
|
1414
1414
|
action_saturation: msg.data.saturation,
|
|
@@ -1422,7 +1422,7 @@ const converters = {
|
|
|
1422
1422
|
cluster: 'lightingColorCtrl',
|
|
1423
1423
|
type: 'commandMoveToHue',
|
|
1424
1424
|
convert: (model, msg, publish, options, meta) => {
|
|
1425
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1425
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1426
1426
|
const payload = {
|
|
1427
1427
|
action: postfixWithEndpointName(`move_to_hue`, msg, model),
|
|
1428
1428
|
action_hue: msg.data.hue,
|
|
@@ -1437,7 +1437,7 @@ const converters = {
|
|
|
1437
1437
|
cluster: 'ssIasAce',
|
|
1438
1438
|
type: 'commandEmergency',
|
|
1439
1439
|
convert: (model, msg, publish, options, meta) => {
|
|
1440
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1440
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1441
1441
|
const payload = {action: postfixWithEndpointName(`emergency`, msg, model)};
|
|
1442
1442
|
addActionGroup(payload, msg, model);
|
|
1443
1443
|
return payload;
|
|
@@ -1447,7 +1447,7 @@ const converters = {
|
|
|
1447
1447
|
cluster: 'genOnOff',
|
|
1448
1448
|
type: 'commandOn',
|
|
1449
1449
|
convert: (model, msg, publish, options, meta) => {
|
|
1450
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1450
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1451
1451
|
const property = postfixWithEndpointName('state', msg, model);
|
|
1452
1452
|
return {[property]: 'ON'};
|
|
1453
1453
|
},
|
|
@@ -1456,7 +1456,7 @@ const converters = {
|
|
|
1456
1456
|
cluster: 'genOnOff',
|
|
1457
1457
|
type: 'commandOff',
|
|
1458
1458
|
convert: (model, msg, publish, options, meta) => {
|
|
1459
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
1459
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
1460
1460
|
const property = postfixWithEndpointName('state', msg, model);
|
|
1461
1461
|
return {[property]: 'OFF'};
|
|
1462
1462
|
},
|
|
@@ -2181,7 +2181,7 @@ const converters = {
|
|
|
2181
2181
|
cluster: 'ssIasZone',
|
|
2182
2182
|
type: 'commandStatusChangeNotification',
|
|
2183
2183
|
convert: (model, msg, publish, options, meta) => {
|
|
2184
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
2184
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
2185
2185
|
const lookup = {1: 'pressed'};
|
|
2186
2186
|
const zoneStatus = msg.data.zonestatus;
|
|
2187
2187
|
return {
|
|
@@ -4045,7 +4045,8 @@ const converters = {
|
|
|
4045
4045
|
exposes.options.precision('humidity'), exposes.options.calibration('humidity'),
|
|
4046
4046
|
exposes.options.precision('co2'), exposes.options.calibration('co2'),
|
|
4047
4047
|
exposes.options.precision('voc'), exposes.options.calibration('voc'),
|
|
4048
|
-
exposes.options.precision('formaldehyd'), exposes.options.calibration('formaldehyd')
|
|
4048
|
+
exposes.options.precision('formaldehyd'), exposes.options.calibration('formaldehyd'),
|
|
4049
|
+
exposes.options.precision('pm25'), exposes.options.calibration('pm25')],
|
|
4049
4050
|
convert: (model, msg, publish, options, meta) => {
|
|
4050
4051
|
const dpValue = tuya.firstDpValue(msg, meta, 'tuya_air_quality');
|
|
4051
4052
|
const dp = dpValue.dp;
|
|
@@ -4062,6 +4063,8 @@ const converters = {
|
|
|
4062
4063
|
case tuya.dataPoints.tuyaSabFormaldehyd:
|
|
4063
4064
|
// Not sure which unit this is, supposedly mg/m³, but the value seems way too high.
|
|
4064
4065
|
return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd')};
|
|
4066
|
+
case tuya.dataPoints.tuyaSahkMP25:
|
|
4067
|
+
return {pm25: calibrateAndPrecisionRoundOptions(value, options, 'pm25')};
|
|
4065
4068
|
default:
|
|
4066
4069
|
meta.logger.warn(`zigbee-herdsman-converters:TuyaSmartAirBox: Unrecognized DP #${
|
|
4067
4070
|
dp} with data ${JSON.stringify(dpValue)}`);
|
|
@@ -4515,7 +4518,7 @@ const converters = {
|
|
|
4515
4518
|
cluster: 'genScenes',
|
|
4516
4519
|
type: 'commandTradfriArrowSingle',
|
|
4517
4520
|
convert: (model, msg, publish, options, meta) => {
|
|
4518
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
4521
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
4519
4522
|
if (msg.data.value === 2) {
|
|
4520
4523
|
// This is send on toggle hold, ignore it as a toggle_hold is already handled above.
|
|
4521
4524
|
return;
|
|
@@ -4529,7 +4532,7 @@ const converters = {
|
|
|
4529
4532
|
cluster: 'genScenes',
|
|
4530
4533
|
type: 'commandTradfriArrowHold',
|
|
4531
4534
|
convert: (model, msg, publish, options, meta) => {
|
|
4532
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
4535
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
4533
4536
|
const direction = msg.data.value === 3329 ? 'left' : 'right';
|
|
4534
4537
|
globalStore.putValue(msg.endpoint, 'direction', direction);
|
|
4535
4538
|
return {action: `arrow_${direction}_hold`};
|
|
@@ -4540,7 +4543,7 @@ const converters = {
|
|
|
4540
4543
|
type: 'commandTradfriArrowRelease',
|
|
4541
4544
|
options: [exposes.options.legacy()],
|
|
4542
4545
|
convert: (model, msg, publish, options, meta) => {
|
|
4543
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
4546
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
4544
4547
|
const direction = globalStore.getValue(msg.endpoint, 'direction');
|
|
4545
4548
|
if (direction) {
|
|
4546
4549
|
globalStore.clearValue(msg.endpoint, 'direction');
|
|
@@ -5250,9 +5253,11 @@ const converters = {
|
|
|
5250
5253
|
else if (index === 5) {
|
|
5251
5254
|
if (['JT-BZ-01AQ/A'].includes(model.model)) payload.power_outage_count = value;
|
|
5252
5255
|
} else if (index === 100) {
|
|
5253
|
-
if (['
|
|
5256
|
+
if (['QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5254
5257
|
const mapping = model.model === 'QBCZ15LM' ? 'relay' : 'left';
|
|
5255
5258
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5259
|
+
} else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
|
|
5260
|
+
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
5256
5261
|
} else {
|
|
5257
5262
|
payload.state = value === 1 ? 'ON' : 'OFF';
|
|
5258
5263
|
}
|
|
@@ -5260,10 +5265,17 @@ const converters = {
|
|
|
5260
5265
|
if (['QBKG19LM', 'QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5261
5266
|
const mapping = model.model === 'QBCZ15LM' ? 'usb' : 'right';
|
|
5262
5267
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5268
|
+
} else if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
|
|
5269
|
+
payload.state_center = value === 1 ? 'ON' : 'OFF';
|
|
5263
5270
|
} else if (['RTCGQ12LM'].includes(model.model)) {
|
|
5264
5271
|
payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
|
|
5265
5272
|
}
|
|
5266
|
-
} else if (index ===
|
|
5273
|
+
} else if (index ===102 ) {
|
|
5274
|
+
if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
|
|
5275
|
+
payload.state_right = value === 1 ? 'ON' : 'OFF';
|
|
5276
|
+
}
|
|
5277
|
+
} else if (index === 105) payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value]; // RTCGQ13LM
|
|
5278
|
+
else if (index === 149) {
|
|
5267
5279
|
payload.energy = precisionRound(value, 2); // 0x95
|
|
5268
5280
|
// Consumption is deprecated
|
|
5269
5281
|
payload.consumption = payload.energy;
|
|
@@ -5379,7 +5391,7 @@ const converters = {
|
|
|
5379
5391
|
cluster: 'genMultistateInput',
|
|
5380
5392
|
type: ['attributeReport'],
|
|
5381
5393
|
convert: (model, msg, publish, options, meta) => {
|
|
5382
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5394
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5383
5395
|
let actionLookup = {0: 'hold', 1: 'single', 2: 'double', 3: 'triple', 255: 'release'};
|
|
5384
5396
|
if (model.model === 'WXKG12LM') {
|
|
5385
5397
|
actionLookup = {...actionLookup, 16: 'hold', 17: 'release', 18: 'shake'};
|
|
@@ -5525,7 +5537,7 @@ const converters = {
|
|
|
5525
5537
|
`increase it with this option (value is in ms).`),
|
|
5526
5538
|
],
|
|
5527
5539
|
convert: (model, msg, publish, options, meta) => {
|
|
5528
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5540
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5529
5541
|
const state = msg.data['onOff'];
|
|
5530
5542
|
|
|
5531
5543
|
// 0 = click down, 1 = click up, else = multiple clicks
|
|
@@ -5831,7 +5843,7 @@ const converters = {
|
|
|
5831
5843
|
cluster: 'genMultistateInput',
|
|
5832
5844
|
type: ['attributeReport', 'readResponse'],
|
|
5833
5845
|
convert: (model, msg, publish, options, meta) => {
|
|
5834
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5846
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5835
5847
|
const actionLookup = {0: 'hold', 255: 'release', 1: 'single', 2: 'double', 3: 'triple', 5: 'quintuple', 6: 'many'};
|
|
5836
5848
|
const button = msg.endpoint.ID;
|
|
5837
5849
|
const value = msg.data.presentValue;
|
|
@@ -5854,7 +5866,7 @@ const converters = {
|
|
|
5854
5866
|
cluster: 'genOnOff',
|
|
5855
5867
|
type: 'commandOn',
|
|
5856
5868
|
convert: (model, msg, publish, options, meta) => {
|
|
5857
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5869
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5858
5870
|
return {action: 'button_2_single'};
|
|
5859
5871
|
},
|
|
5860
5872
|
},
|
|
@@ -5862,7 +5874,7 @@ const converters = {
|
|
|
5862
5874
|
cluster: 'genOnOff',
|
|
5863
5875
|
type: 'commandOff',
|
|
5864
5876
|
convert: (model, msg, publish, options, meta) => {
|
|
5865
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5877
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5866
5878
|
return {action: 'button_1_single'};
|
|
5867
5879
|
},
|
|
5868
5880
|
},
|
|
@@ -5870,7 +5882,7 @@ const converters = {
|
|
|
5870
5882
|
cluster: 'genLevelCtrl',
|
|
5871
5883
|
type: 'commandStep',
|
|
5872
5884
|
convert: (model, msg, publish, options, meta) => {
|
|
5873
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5885
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5874
5886
|
const button = msg.data.stepmode === 0 ? '4' : '3';
|
|
5875
5887
|
return {action: `button_${button}_single`};
|
|
5876
5888
|
},
|
|
@@ -5880,7 +5892,7 @@ const converters = {
|
|
|
5880
5892
|
type: 'commandStop',
|
|
5881
5893
|
options: [exposes.options.legacy()],
|
|
5882
5894
|
convert: (model, msg, publish, options, meta) => {
|
|
5883
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5895
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5884
5896
|
if (globalStore.hasValue(msg.endpoint, 'button')) {
|
|
5885
5897
|
const value = globalStore.getValue(msg.endpoint, 'button');
|
|
5886
5898
|
const duration = Date.now() - value.start;
|
|
@@ -5894,7 +5906,7 @@ const converters = {
|
|
|
5894
5906
|
cluster: 'genLevelCtrl',
|
|
5895
5907
|
type: 'commandMove',
|
|
5896
5908
|
convert: (model, msg, publish, options, meta) => {
|
|
5897
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5909
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5898
5910
|
const button = msg.data.movemode === 0 ? '4' : '3';
|
|
5899
5911
|
globalStore.putValue(msg.endpoint, 'button', {button, start: Date.now()});
|
|
5900
5912
|
return {action: `button_${button}_hold`};
|
|
@@ -5904,7 +5916,7 @@ const converters = {
|
|
|
5904
5916
|
cluster: 'lightingColorCtrl',
|
|
5905
5917
|
type: 'commandStepColorTemp',
|
|
5906
5918
|
convert: (model, msg, publish, options, meta) => {
|
|
5907
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5919
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5908
5920
|
let action;
|
|
5909
5921
|
if (model.model === 'WXCJKG12LM') {
|
|
5910
5922
|
// for WXCJKG12LM model it's double click event on buttons 3 and 4
|
|
@@ -5921,7 +5933,7 @@ const converters = {
|
|
|
5921
5933
|
type: 'commandMoveColorTemp',
|
|
5922
5934
|
options: [exposes.options.legacy()],
|
|
5923
5935
|
convert: (model, msg, publish, options, meta) => {
|
|
5924
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
5936
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
5925
5937
|
const stop = msg.data.movemode === 0;
|
|
5926
5938
|
let result = null;
|
|
5927
5939
|
if (stop) {
|
|
@@ -7228,6 +7240,26 @@ const converters = {
|
|
|
7228
7240
|
return {occupancy: (zoneStatus & 1) > 0, tamper: (zoneStatus & 4) > 0};
|
|
7229
7241
|
},
|
|
7230
7242
|
},
|
|
7243
|
+
ZM35HQ_attr: {
|
|
7244
|
+
cluster: 'ssIasZone',
|
|
7245
|
+
type: ['attributeReport', 'readResponse'],
|
|
7246
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7247
|
+
let result = {};
|
|
7248
|
+
const data = msg.data;
|
|
7249
|
+
if (data && data.hasOwnProperty('zoneStatus')) {
|
|
7250
|
+
result = converters.ias_occupancy_alarm_1_report.convert(model, msg, publish, options, meta);
|
|
7251
|
+
}
|
|
7252
|
+
if (data && data.hasOwnProperty('currentZoneSensitivityLevel')) {
|
|
7253
|
+
const senslookup = {'0': 'low', '1': 'medium', '2': 'high'};
|
|
7254
|
+
result.sensitivity = senslookup[data.currentZoneSensitivityLevel];
|
|
7255
|
+
}
|
|
7256
|
+
if (data && data.hasOwnProperty('61441')) {
|
|
7257
|
+
const keeptimelookup = {'0': 30, '1': 60, '2': 120};
|
|
7258
|
+
result.keep_time = keeptimelookup[data['61441']];
|
|
7259
|
+
}
|
|
7260
|
+
return result;
|
|
7261
|
+
},
|
|
7262
|
+
},
|
|
7231
7263
|
tuya_gas: {
|
|
7232
7264
|
cluster: 'manuSpecificTuya',
|
|
7233
7265
|
type: ['commandDataResponse'],
|
|
@@ -7327,7 +7359,7 @@ const converters = {
|
|
|
7327
7359
|
cluster: 'wiserDeviceInfo',
|
|
7328
7360
|
type: 'attributeReport',
|
|
7329
7361
|
convert: (model, msg, publish, options, meta) => {
|
|
7330
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
7362
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
7331
7363
|
|
|
7332
7364
|
const data = msg.data['deviceInfo'].split(',');
|
|
7333
7365
|
if (data[0] === 'UI' && data[1]) {
|
|
@@ -8105,7 +8137,7 @@ const converters = {
|
|
|
8105
8137
|
convert: (model, msg, publish, options, meta) => {
|
|
8106
8138
|
// commandStopMove without params
|
|
8107
8139
|
if (msg.data[2] !== 71) return;
|
|
8108
|
-
if (hasAlreadyProcessedMessage(msg)) return;
|
|
8140
|
+
if ((!model.meta || !model.meta.handleDuplicateTransaction) && hasAlreadyProcessedMessage(msg)) return;
|
|
8109
8141
|
const movestop = 'stop';
|
|
8110
8142
|
const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
|
|
8111
8143
|
const payload = {action};
|
package/converters/toZigbee.js
CHANGED
|
@@ -5961,6 +5961,29 @@ const converters = {
|
|
|
5961
5961
|
}
|
|
5962
5962
|
},
|
|
5963
5963
|
},
|
|
5964
|
+
ZM35HQ_attr: {
|
|
5965
|
+
key: [
|
|
5966
|
+
'sensitivity', 'keep_time',
|
|
5967
|
+
],
|
|
5968
|
+
convertSet: async (entity, key, value, meta) => {
|
|
5969
|
+
switch (key) {
|
|
5970
|
+
case 'sensitivity':
|
|
5971
|
+
await entity.write('ssIasZone', {currentZoneSensitivityLevel: {'low': 0, 'medium': 1, 'high': 2}[value]},
|
|
5972
|
+
{sendWhen: 'active'});
|
|
5973
|
+
break;
|
|
5974
|
+
case 'keep_time':
|
|
5975
|
+
await entity.write('ssIasZone', {61441: {value: {'30': 0, '60': 1, '120': 2}[value], type: 0x20}}, {sendWhen: 'active'});
|
|
5976
|
+
break;
|
|
5977
|
+
default: // Unknown key
|
|
5978
|
+
throw new Error(`Unhandled key ${key}`);
|
|
5979
|
+
}
|
|
5980
|
+
},
|
|
5981
|
+
convertGet: async (entity, key, meta) => {
|
|
5982
|
+
// Apparently, reading values may interfere with a commandStatusChangeNotification for changed occupancy.
|
|
5983
|
+
// Therefore, read "zoneStatus" as well.
|
|
5984
|
+
await entity.read('ssIasZone', ['currentZoneSensitivityLevel', 61441, 'zoneStatus'], {sendWhen: 'active'});
|
|
5985
|
+
},
|
|
5986
|
+
},
|
|
5964
5987
|
TS0210_sensitivity: {
|
|
5965
5988
|
key: ['sensitivity'],
|
|
5966
5989
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -353,4 +353,26 @@ module.exports = [
|
|
|
353
353
|
},
|
|
354
354
|
exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
|
|
355
355
|
},
|
|
356
|
+
{
|
|
357
|
+
zigbeeModel: ['EFEKTA_eON29wz'],
|
|
358
|
+
model: 'EFEKTA_eON29wz',
|
|
359
|
+
vendor: 'Custom devices (DiY)',
|
|
360
|
+
description: '[Mini weather station, barometer, forecast, charts, temperature, humidity, light](http://efektalab.com/eON290wz)',
|
|
361
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.pressure, fz.illuminance, fz.battery],
|
|
362
|
+
toZigbee: [tz.factory_reset],
|
|
363
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
364
|
+
const endpoint = device.getEndpoint(1);
|
|
365
|
+
await reporting.bind(endpoint, coordinatorEndpoint, [
|
|
366
|
+
'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity', 'msPressureMeasurement', 'msIlluminanceMeasurement']);
|
|
367
|
+
const overides = {min: 0, max: 21600, change: 0};
|
|
368
|
+
await reporting.batteryVoltage(endpoint, overides);
|
|
369
|
+
await reporting.batteryPercentageRemaining(endpoint, overides);
|
|
370
|
+
await reporting.temperature(endpoint, overides);
|
|
371
|
+
await reporting.humidity(endpoint, overides);
|
|
372
|
+
await reporting.illuminance(endpoint, overides);
|
|
373
|
+
await reporting.pressureExtended(endpoint, overides);
|
|
374
|
+
await endpoint.read('msPressureMeasurement', ['scale']);
|
|
375
|
+
},
|
|
376
|
+
exposes: [e.battery(), e.illuminance(), e.temperature(), e.humidity(), e.pressure()],
|
|
377
|
+
},
|
|
356
378
|
];
|
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/edp.js
CHANGED
|
@@ -16,8 +16,10 @@ module.exports = [
|
|
|
16
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
17
17
|
const endpoint = device.getEndpoint(85);
|
|
18
18
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
19
|
+
// await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
20
|
+
// Fix for UNSUPPORTED_ATTRIBUTE
|
|
21
|
+
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 1000, multiplier: 1});
|
|
19
22
|
await reporting.onOff(endpoint);
|
|
20
|
-
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
21
23
|
await reporting.instantaneousDemand(endpoint);
|
|
22
24
|
},
|
|
23
25
|
exposes: [e.switch(), e.power(), e.energy()],
|
package/devices/ikea.js
CHANGED
|
@@ -746,10 +746,10 @@ module.exports = [
|
|
|
746
746
|
extend: tradfriExtend.light_onoff_brightness_colortemp_color(),
|
|
747
747
|
},
|
|
748
748
|
{
|
|
749
|
-
zigbeeModel: ['TRADFRIbulbE14WWclear250lm'],
|
|
749
|
+
zigbeeModel: ['TRADFRIbulbE14WWclear250lm', 'TRADFRIbulbE12WWclear250lm'],
|
|
750
750
|
model: 'LED1935C3',
|
|
751
751
|
vendor: 'IKEA',
|
|
752
|
-
description: 'TRADFRI LED bulb E14 WW clear 250 lumen, dimmable',
|
|
752
|
+
description: 'TRADFRI LED bulb E12/E14 WW clear 250 lumen, dimmable',
|
|
753
753
|
extend: tradfriExtend.light_onoff_brightness(),
|
|
754
754
|
},
|
|
755
755
|
{
|
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],
|
package/devices/legrand.js
CHANGED
|
@@ -111,7 +111,7 @@ module.exports = [
|
|
|
111
111
|
exposes: [e.battery(), e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up',
|
|
112
112
|
'brightness_move_down', 'brightness_stop'])],
|
|
113
113
|
toZigbee: [],
|
|
114
|
-
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
114
|
+
meta: {handleDuplicateTransaction: true, battery: {voltageToPercentage: '3V_2500'}},
|
|
115
115
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
116
116
|
const endpoint = device.getEndpoint(1);
|
|
117
117
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
|
|
@@ -127,7 +127,7 @@ module.exports = [
|
|
|
127
127
|
exposes: [e.battery(),
|
|
128
128
|
e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up', 'brightness_move_down', 'brightness_stop'])],
|
|
129
129
|
toZigbee: [],
|
|
130
|
-
meta: {multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}},
|
|
130
|
+
meta: {handleDuplicateTransaction: true, multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}},
|
|
131
131
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
132
132
|
const endpoint = device.getEndpoint(1);
|
|
133
133
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
|
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()],
|
package/devices/perenio.js
CHANGED
|
@@ -40,7 +40,6 @@ module.exports = [
|
|
|
40
40
|
description: 'Motion sensor',
|
|
41
41
|
fromZigbee: [fz.battery, fz.ias_occupancy_alarm_1],
|
|
42
42
|
toZigbee: [],
|
|
43
|
-
meta: {battery: {dontDividePercentage: true}},
|
|
44
43
|
exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery()],
|
|
45
44
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
46
45
|
const endpoint = device.getEndpoint(1);
|
package/devices/philips.js
CHANGED
|
@@ -563,6 +563,15 @@ module.exports = [
|
|
|
563
563
|
extend: hueExtend.light_onoff_brightness(),
|
|
564
564
|
ota: ota.zigbeeOTA,
|
|
565
565
|
},
|
|
566
|
+
{
|
|
567
|
+
zigbeeModel: ['LWO002'],
|
|
568
|
+
model: '9290022415',
|
|
569
|
+
vendor: 'Philips',
|
|
570
|
+
description: 'Hue White G25 E26 Edison Filament Globe Bluetooth',
|
|
571
|
+
meta: {turnsOffAtBrightness1: true},
|
|
572
|
+
extend: hueExtend.light_onoff_brightness(),
|
|
573
|
+
ota: ota.zigbeeOTA,
|
|
574
|
+
},
|
|
566
575
|
{
|
|
567
576
|
zigbeeModel: ['LWA004'],
|
|
568
577
|
model: '8718699688820',
|
package/devices/prolight.js
CHANGED
|
@@ -15,6 +15,13 @@ module.exports = [
|
|
|
15
15
|
description: 'E27 filament bulb dimmable',
|
|
16
16
|
extend: extend.light_onoff_brightness(),
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
zigbeeModel: ['PROLIGHT E27 WARM WHITE'],
|
|
20
|
+
model: '5412748727364',
|
|
21
|
+
vendor: 'Prolight',
|
|
22
|
+
description: 'E27 bulb dimmable',
|
|
23
|
+
extend: extend.light_onoff_brightness(),
|
|
24
|
+
},
|
|
18
25
|
{
|
|
19
26
|
zigbeeModel: ['PROLIGHT GU10 WHITE AND COLOUR'],
|
|
20
27
|
model: '5412748727401',
|
|
@@ -186,6 +186,18 @@ module.exports = [
|
|
|
186
186
|
await reporting.brightness(endpoint);
|
|
187
187
|
},
|
|
188
188
|
},
|
|
189
|
+
{
|
|
190
|
+
zigbeeModel: ['CH2AX/SWITCH/1'],
|
|
191
|
+
model: '41E2PBSWMZ/356PB2MBTZ',
|
|
192
|
+
vendor: 'Schneider Electric',
|
|
193
|
+
description: 'Wiser 40/300-Series module switch 2A',
|
|
194
|
+
extend: extend.switch(),
|
|
195
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
196
|
+
const endpoint = device.getEndpoint(1);
|
|
197
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
198
|
+
await reporting.onOff(endpoint);
|
|
199
|
+
},
|
|
200
|
+
},
|
|
189
201
|
{
|
|
190
202
|
zigbeeModel: ['SMARTPLUG/1'],
|
|
191
203
|
model: 'CCT711119',
|
|
@@ -630,4 +642,35 @@ module.exports = [
|
|
|
630
642
|
await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
|
|
631
643
|
},
|
|
632
644
|
},
|
|
645
|
+
{
|
|
646
|
+
zigbeeModel: ['NHMOTION/SWITCH/1'],
|
|
647
|
+
model: '545D6306',
|
|
648
|
+
vendor: 'Schneider Electric',
|
|
649
|
+
description: 'LK FUGA Wiser wireless PIR with relay',
|
|
650
|
+
fromZigbee: [fz.on_off, fz.illuminance, fz.occupancy, fz.occupancy_timeout],
|
|
651
|
+
exposes: [e.switch().withEndpoint('l1'), e.occupancy(), e.illuminance_lux(), e.illuminance(),
|
|
652
|
+
exposes.numeric('occupancy_timeout', ea.ALL).withUnit('second').withValueMin(0).withValueMax(3600)
|
|
653
|
+
.withDescription('Time in seconds after which occupancy is cleared after detecting it')],
|
|
654
|
+
toZigbee: [tz.on_off, tz.occupancy_timeout],
|
|
655
|
+
endpoint: (device) => {
|
|
656
|
+
return {'default': 37, 'l1': 1, 'l2': 37};
|
|
657
|
+
},
|
|
658
|
+
meta: {multiEndpoint: true},
|
|
659
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
660
|
+
const endpoint1 = device.getEndpoint(1);
|
|
661
|
+
const binds1 = ['genBasic', 'genIdentify', 'genOnOff'];
|
|
662
|
+
await reporting.bind(endpoint1, coordinatorEndpoint, binds1);
|
|
663
|
+
await reporting.onOff(endpoint1);
|
|
664
|
+
// read switch state
|
|
665
|
+
await endpoint1.read('genOnOff', ['onOff']);
|
|
666
|
+
|
|
667
|
+
const endpoint37 = device.getEndpoint(37);
|
|
668
|
+
const binds37 = ['msIlluminanceMeasurement', 'msOccupancySensing'];
|
|
669
|
+
await reporting.bind(endpoint37, coordinatorEndpoint, binds37);
|
|
670
|
+
await reporting.occupancy(endpoint37);
|
|
671
|
+
await reporting.illuminance(endpoint37);
|
|
672
|
+
// read occupancy_timeout
|
|
673
|
+
await endpoint37.read('msOccupancySensing', ['pirOToUDelay']);
|
|
674
|
+
},
|
|
675
|
+
},
|
|
633
676
|
];
|
package/devices/sprut.js
CHANGED
|
@@ -2,14 +2,18 @@ const exposes = require('../lib/exposes');
|
|
|
2
2
|
const fz = require('../converters/fromZigbee');
|
|
3
3
|
const tz = require('../converters/toZigbee');
|
|
4
4
|
const reporting = require('../lib/reporting');
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const ota = require('../lib/ota');
|
|
6
|
+
const e = exposes;
|
|
7
|
+
const ep = exposes.presets;
|
|
8
|
+
const eo = exposes.options;
|
|
9
|
+
const ea = exposes.access;
|
|
10
|
+
const {calibrateAndPrecisionRoundOptions, getOptions} = require('../lib/utils');
|
|
7
11
|
|
|
8
12
|
const fzLocal = {
|
|
9
13
|
temperature: {
|
|
10
14
|
cluster: 'msTemperatureMeasurement',
|
|
11
15
|
type: ['attributeReport', 'readResponse'],
|
|
12
|
-
options: [
|
|
16
|
+
options: [eo.precision('temperature'), eo.calibration('temperature')],
|
|
13
17
|
convert: (model, msg, publish, options, meta) => {
|
|
14
18
|
const temperature = parseFloat(msg.data['measuredValue']) / 100.0;
|
|
15
19
|
return {temperature: calibrateAndPrecisionRoundOptions(temperature, options, 'temperature')};
|
|
@@ -46,11 +50,78 @@ const fzLocal = {
|
|
|
46
50
|
cluster: 'sprutNoise',
|
|
47
51
|
type: ['readResponse', 'attributeReport'],
|
|
48
52
|
convert: (model, msg, publish, options, meta) => {
|
|
49
|
-
if (msg.data.hasOwnProperty('
|
|
50
|
-
return {noise_detected: msg.data['
|
|
53
|
+
if (msg.data.hasOwnProperty('noiseDetected')) {
|
|
54
|
+
return {noise_detected: msg.data['noiseDetected'] === 1};
|
|
51
55
|
}
|
|
52
56
|
},
|
|
53
57
|
},
|
|
58
|
+
occupancy_timeout: {
|
|
59
|
+
cluster: 'msOccupancySensing',
|
|
60
|
+
type: ['readResponse', 'attributeReport'],
|
|
61
|
+
convert: (model, msg, publish, options, meta) => {
|
|
62
|
+
return {occupancy_timeout: msg.data.pirOToUDelay};
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
noise_timeout: {
|
|
66
|
+
cluster: 'sprutNoise',
|
|
67
|
+
type: ['readResponse', 'attributeReport'],
|
|
68
|
+
convert: (model, msg, publish, options, meta) => {
|
|
69
|
+
return {noise_timeout: msg.data.noiseAfterDetectDelay};
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const tzLocal = {
|
|
75
|
+
sprut_ir_remote: {
|
|
76
|
+
key: ['play_store', 'learn_start', 'learn_stop'],
|
|
77
|
+
convertSet: async (entity, key, value, meta) => {
|
|
78
|
+
const options = {
|
|
79
|
+
frameType: 0, manufacturerCode: 26214, disableDefaultResponse: true,
|
|
80
|
+
disableResponse: true, reservedBits: 0, direction: 0, writeUndiv: false,
|
|
81
|
+
transactionSequenceNumber: null,
|
|
82
|
+
};
|
|
83
|
+
switch (key) {
|
|
84
|
+
case 'play_store':
|
|
85
|
+
await entity.command('sprutIrBlaster', 'playStore',
|
|
86
|
+
{param: value['rom']}, options);
|
|
87
|
+
break;
|
|
88
|
+
case 'learn_start':
|
|
89
|
+
await entity.command('sprutIrBlaster', 'learnStart',
|
|
90
|
+
{value: value['rom']}, options);
|
|
91
|
+
break;
|
|
92
|
+
case 'learn_stop':
|
|
93
|
+
await entity.command('sprutIrBlaster', 'learnStop',
|
|
94
|
+
{value: value['rom']}, options);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
occupancy_timeout: {
|
|
100
|
+
key: ['occupancy_timeout'],
|
|
101
|
+
convertSet: async (entity, key, value, meta) => {
|
|
102
|
+
value *= 1;
|
|
103
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
104
|
+
await endpoint.write('msOccupancySensing', {pirOToUDelay: value}, getOptions(meta.mapped, entity));
|
|
105
|
+
return {state: {occupancy_timeout: value}};
|
|
106
|
+
},
|
|
107
|
+
convertGet: async (entity, key, meta) => {
|
|
108
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
109
|
+
await endpoint.read('msOccupancySensing', ['pirOToUDelay']);
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
noise_timeout: {
|
|
113
|
+
key: ['noise_timeout'],
|
|
114
|
+
convertSet: async (entity, key, value, meta) => {
|
|
115
|
+
value *= 1;
|
|
116
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
117
|
+
await endpoint.write('sprutNoise', {noiseAfterDetectDelay: value}, getOptions(meta.mapped, entity));
|
|
118
|
+
return {state: {noise_timeout: value}};
|
|
119
|
+
},
|
|
120
|
+
convertGet: async (entity, key, meta) => {
|
|
121
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
122
|
+
await endpoint.read('sprutNoise', ['noiseAfterDetectDelay']);
|
|
123
|
+
},
|
|
124
|
+
},
|
|
54
125
|
};
|
|
55
126
|
|
|
56
127
|
module.exports = [
|
|
@@ -60,15 +131,19 @@ module.exports = [
|
|
|
60
131
|
vendor: 'Sprut.device',
|
|
61
132
|
description: 'Wall-mounted Zigbee sensor',
|
|
62
133
|
fromZigbee: [fzLocal.temperature, fz.illuminance, fz.humidity, fz.occupancy, fzLocal.occupancy, fz.co2, fzLocal.voc,
|
|
63
|
-
fzLocal.noise, fzLocal.noise_detected, fz.on_off],
|
|
64
|
-
toZigbee: [tz.on_off],
|
|
65
|
-
exposes: [
|
|
66
|
-
|
|
67
|
-
|
|
134
|
+
fzLocal.noise, fzLocal.noise_detected, fz.on_off, fzLocal.occupancy_timeout, fzLocal.noise_timeout],
|
|
135
|
+
toZigbee: [tz.on_off, tzLocal.sprut_ir_remote, tzLocal.occupancy_timeout, tzLocal.noise_timeout],
|
|
136
|
+
exposes: [ep.temperature(), ep.illuminance(), ep.illuminance_lux(), ep.humidity(),
|
|
137
|
+
ep.occupancy(), ep.occupancy_level(), ep.co2(), ep.voc(), ep.noise(), ep.noise_detected(ea.STATE_GET),
|
|
138
|
+
ep.switch().withEndpoint('l1'), ep.switch().withEndpoint('l2'), ep.switch().withEndpoint('default'),
|
|
139
|
+
e.numeric('noise_timeout', ea.ALL).withValueMin(0).withValueMax(2000).withUnit('s')
|
|
140
|
+
.withDescription('Time in seconds after which noise is cleared after detecting it (default: 30)'),
|
|
141
|
+
e.numeric('occupancy_timeout', ea.ALL).withValueMin(0).withValueMax(2000).withUnit('s')
|
|
142
|
+
.withDescription('Time in seconds after which occupancy is cleared after detecting it (default: 30)')],
|
|
68
143
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
69
144
|
const endpoint1 = device.getEndpoint(1);
|
|
70
145
|
const binds = ['genBasic', 'msTemperatureMeasurement', 'msIlluminanceMeasurement', 'msRelativeHumidity',
|
|
71
|
-
'msOccupancySensing', 'msCO2', 'sprutVoc', 'sprutNoise'];
|
|
146
|
+
'msOccupancySensing', 'msCO2', 'sprutVoc', 'sprutNoise', 'sprutIrBlaster', 'genOta'];
|
|
72
147
|
await reporting.bind(endpoint1, coordinatorEndpoint, binds);
|
|
73
148
|
|
|
74
149
|
// led_red
|
|
@@ -80,17 +155,22 @@ module.exports = [
|
|
|
80
155
|
// buzzer
|
|
81
156
|
await device.getEndpoint(4).read('genOnOff', ['onOff']);
|
|
82
157
|
|
|
158
|
+
// Read settings at start
|
|
159
|
+
await endpoint1.read('msOccupancySensing', ['pirOToUDelay']);
|
|
160
|
+
await endpoint1.read('sprutNoise', ['noiseAfterDetectDelay']);
|
|
161
|
+
|
|
83
162
|
// Read data at start
|
|
84
163
|
await endpoint1.read('msTemperatureMeasurement', ['measuredValue']);
|
|
85
164
|
await endpoint1.read('msIlluminanceMeasurement', ['measuredValue']);
|
|
86
165
|
await endpoint1.read('msRelativeHumidity', ['measuredValue']);
|
|
87
166
|
await endpoint1.read('msOccupancySensing', ['occupancy']);
|
|
88
167
|
await endpoint1.read('sprutNoise', ['noise']);
|
|
89
|
-
await endpoint1.read('sprutNoise', ['
|
|
168
|
+
await endpoint1.read('sprutNoise', ['noiseDetected']);
|
|
90
169
|
},
|
|
91
170
|
endpoint: (device) => {
|
|
92
171
|
return {'system': 1, 'l1': 2, 'l2': 3, 'default': 4};
|
|
93
172
|
},
|
|
94
173
|
meta: {multiEndpoint: true},
|
|
174
|
+
ota: ota.zigbeeOTA,
|
|
95
175
|
},
|
|
96
176
|
];
|
package/devices/sunricher.js
CHANGED
|
@@ -260,7 +260,8 @@ module.exports = [
|
|
|
260
260
|
exposes: [e.action(['press_on', 'press_off', 'hold_on', 'hold_off', 'release'])],
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
|
-
fingerprint: [{modelID: 'GreenPower_2', ieeeAddr: /^0x000000005d5.....$/}
|
|
263
|
+
fingerprint: [{modelID: 'GreenPower_2', ieeeAddr: /^0x000000005d5.....$/},
|
|
264
|
+
{modelID: 'GreenPower_2', ieeeAddr: /^0x0000000057e.....$/}],
|
|
264
265
|
model: 'SR-ZGP2801K4-DIM',
|
|
265
266
|
vendor: 'Sunricher',
|
|
266
267
|
description: 'Pushbutton transmitter module',
|
package/devices/tuya.js
CHANGED
|
@@ -89,6 +89,15 @@ module.exports = [
|
|
|
89
89
|
toZigbee: [],
|
|
90
90
|
exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd()],
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_dwcarsat'}],
|
|
94
|
+
model: 'TS0601_smart_air_house_keeper',
|
|
95
|
+
vendor: 'TuYa',
|
|
96
|
+
description: 'Smart air house keeper',
|
|
97
|
+
fromZigbee: [fz.tuya_air_quality],
|
|
98
|
+
toZigbee: [],
|
|
99
|
+
exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd(), e.pm25()],
|
|
100
|
+
},
|
|
92
101
|
{
|
|
93
102
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_ggev5fsl'}],
|
|
94
103
|
model: 'TS0601_gas_sensor',
|
|
@@ -201,6 +210,13 @@ module.exports = [
|
|
|
201
210
|
toZigbee: utils.replaceInArray(extend.light_onoff_brightness_color().toZigbee, [tz.light_color], [tzLocal.TS0504B_color]),
|
|
202
211
|
meta: {applyRedFix: true},
|
|
203
212
|
},
|
|
213
|
+
{
|
|
214
|
+
fingerprint: [{modelID: 'TS0501A', manufacturerName: '_TZ3000_yeg1e5eh'}],
|
|
215
|
+
model: 'TS0501A',
|
|
216
|
+
description: 'Zigbee light',
|
|
217
|
+
vendor: 'TuYa',
|
|
218
|
+
extend: extend.light_onoff_brightness(),
|
|
219
|
+
},
|
|
204
220
|
{
|
|
205
221
|
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3000_4whigl8i'},
|
|
206
222
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
|
|
@@ -223,9 +239,7 @@ module.exports = [
|
|
|
223
239
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_mmtwjmaq'},
|
|
224
240
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_kmh5qpmb'},
|
|
225
241
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_zwvaj5wy'},
|
|
226
|
-
{modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
|
|
227
242
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_bsvqrxru'},
|
|
228
|
-
{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
|
|
229
243
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_tv3wxhcz'},
|
|
230
244
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
|
|
231
245
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_tiwq83wk'},
|
|
@@ -238,6 +252,19 @@ module.exports = [
|
|
|
238
252
|
toZigbee: [],
|
|
239
253
|
exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery()],
|
|
240
254
|
},
|
|
255
|
+
{
|
|
256
|
+
fingerprint: [{modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
|
|
257
|
+
{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'}],
|
|
258
|
+
model: 'ZM-35H-Q',
|
|
259
|
+
vendor: 'TuYa',
|
|
260
|
+
description: 'Motion Sensor',
|
|
261
|
+
fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ZM35HQ_attr],
|
|
262
|
+
toZigbee: [tz.ZM35HQ_attr],
|
|
263
|
+
exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery(),
|
|
264
|
+
exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
|
|
265
|
+
exposes.enum('keep_time', ea.ALL, ['30', '60', '120']).withDescription('PIR keep time in seconds'),
|
|
266
|
+
],
|
|
267
|
+
},
|
|
241
268
|
{
|
|
242
269
|
fingerprint: [{modelID: 'TS0207', manufacturerName: '_TZ3000_m0vaazab'},
|
|
243
270
|
{modelID: 'TS0207', manufacturerName: '_TZ3000_ufttklsz'},
|
|
@@ -319,8 +346,7 @@ module.exports = [
|
|
|
319
346
|
],
|
|
320
347
|
},
|
|
321
348
|
{
|
|
322
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'},
|
|
323
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_o1jzcxou'}],
|
|
349
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'}],
|
|
324
350
|
model: 'TS011F_socket_module',
|
|
325
351
|
vendor: 'TuYa',
|
|
326
352
|
description: 'Socket module',
|
|
@@ -329,12 +355,15 @@ module.exports = [
|
|
|
329
355
|
},
|
|
330
356
|
{
|
|
331
357
|
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_wxtp7c5y'},
|
|
332
|
-
{modelID: 'TS011F', manufacturerName: '_TYZB01_mtunwanm'}
|
|
358
|
+
{modelID: 'TS011F', manufacturerName: '_TYZB01_mtunwanm'},
|
|
359
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_o1jzcxou'}],
|
|
333
360
|
model: 'TS011F_wall_outlet',
|
|
334
361
|
vendor: 'TuYa',
|
|
335
362
|
description: 'In-wall outlet',
|
|
336
363
|
extend: extend.switch(),
|
|
337
|
-
whiteLabel: [{vendor: 'Teekar', model: 'SWP86-01OG'},
|
|
364
|
+
whiteLabel: [{vendor: 'Teekar', model: 'SWP86-01OG'},
|
|
365
|
+
{vendor: 'ClickSmart+', model: 'CMA30035'},
|
|
366
|
+
{vendor: 'BSEED', model: 'Zigbee Socket'}],
|
|
338
367
|
},
|
|
339
368
|
{
|
|
340
369
|
fingerprint: [{modelID: 'isltm67\u0000', manufacturerName: '_TYST11_pisltm67'}],
|
|
@@ -848,6 +877,7 @@ module.exports = [
|
|
|
848
877
|
{modelID: 'TS0601', manufacturerName: '_TZE200_fzo2pocs'},
|
|
849
878
|
{modelID: 'TS0601', manufacturerName: '_TZE200_5sbebbzs'},
|
|
850
879
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zuz7f94z'},
|
|
880
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_zyrdrmno'},
|
|
851
881
|
],
|
|
852
882
|
model: 'TS0601_cover',
|
|
853
883
|
vendor: 'TuYa',
|
|
@@ -867,6 +897,7 @@ module.exports = [
|
|
|
867
897
|
{vendor: 'Zemismart', model: 'M2805EGBZTN', description: 'Tubular motor'},
|
|
868
898
|
{vendor: 'Zemismart', model: 'BCM500DS-TYZ', description: 'Curtain motor'},
|
|
869
899
|
{vendor: 'A-OK', model: 'AM25', description: 'Tubular motor'},
|
|
900
|
+
{vendor: 'Alutech', model: 'AM/R-Sm', description: 'Tubular motor'},
|
|
870
901
|
],
|
|
871
902
|
fromZigbee: [fz.tuya_cover, fz.ignore_basic_report],
|
|
872
903
|
toZigbee: [tz.tuya_cover_control, tz.tuya_cover_options],
|
|
@@ -1434,7 +1465,8 @@ module.exports = [
|
|
|
1434
1465
|
{
|
|
1435
1466
|
fingerprint: [{modelID: 'TS0014', manufacturerName: '_TZ3000_jr2atpww'}, {modelID: 'TS0014', manufacturerName: '_TYZB01_dvakyzhd'},
|
|
1436
1467
|
{modelID: 'TS0014', manufacturerName: '_TZ3210_w3hl6rao'}, {modelID: 'TS0014', manufacturerName: '_TYZB01_bagt1e4o'},
|
|
1437
|
-
{modelID: 'TS0014', manufacturerName: '_TZ3000_r0pmi2p3'}, {modelID: 'TS0014', manufacturerName: '_TZ3000_fxjdcikv'}
|
|
1468
|
+
{modelID: 'TS0014', manufacturerName: '_TZ3000_r0pmi2p3'}, {modelID: 'TS0014', manufacturerName: '_TZ3000_fxjdcikv'},
|
|
1469
|
+
{modelID: 'TS0014', manufacturerName: '_TZ3000_q6vxaod1'}],
|
|
1438
1470
|
model: 'TS0014',
|
|
1439
1471
|
vendor: 'TuYa',
|
|
1440
1472
|
description: 'Smart light switch - 4 gang without neutral wire',
|
|
@@ -1580,6 +1612,7 @@ module.exports = [
|
|
|
1580
1612
|
vendor: 'TuYa',
|
|
1581
1613
|
description: 'Multiprise with 4 AC outlets and 2 USB super charging ports (16A)',
|
|
1582
1614
|
extend: extend.switch(),
|
|
1615
|
+
fromZigbee: [fz.on_off_skip_duplicate_transaction],
|
|
1583
1616
|
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
|
|
1584
1617
|
e.switch().withEndpoint('l4')],
|
|
1585
1618
|
whiteLabel: [{vendor: 'LEELKI', model: 'WP33-EU'}],
|
package/devices/xiaomi.js
CHANGED
|
@@ -736,9 +736,6 @@ module.exports = [
|
|
|
736
736
|
exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled'])
|
|
737
737
|
.withDescription('Decoupled mode for left button'),
|
|
738
738
|
],
|
|
739
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
740
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
741
|
-
},
|
|
742
739
|
onEvent: preventReset,
|
|
743
740
|
ota: ota.zigbeeOTA,
|
|
744
741
|
},
|
|
@@ -767,9 +764,6 @@ module.exports = [
|
|
|
767
764
|
.withDescription('Decoupled mode for right button')
|
|
768
765
|
.withEndpoint('right'),
|
|
769
766
|
],
|
|
770
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
771
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
772
|
-
},
|
|
773
767
|
onEvent: preventReset,
|
|
774
768
|
ota: ota.zigbeeOTA,
|
|
775
769
|
},
|
|
@@ -804,10 +798,8 @@ module.exports = [
|
|
|
804
798
|
.withDescription('Decoupled mode for right button')
|
|
805
799
|
.withEndpoint('right'),
|
|
806
800
|
],
|
|
807
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
808
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
809
|
-
},
|
|
810
801
|
onEvent: preventReset,
|
|
802
|
+
ota: ota.zigbeeOTA,
|
|
811
803
|
},
|
|
812
804
|
{
|
|
813
805
|
zigbeeModel: ['lumi.sens', 'lumi.sensor_ht'],
|
|
@@ -885,6 +877,7 @@ module.exports = [
|
|
|
885
877
|
await endpoint.read('genPowerCfg', ['batteryVoltage']);
|
|
886
878
|
await endpoint.read('aqaraOpple', [0x0102], {manufacturerCode: 0x115f});
|
|
887
879
|
},
|
|
880
|
+
ota: ota.zigbeeOTA,
|
|
888
881
|
},
|
|
889
882
|
{
|
|
890
883
|
zigbeeModel: ['lumi.motion.agl04'],
|
|
@@ -903,6 +896,7 @@ module.exports = [
|
|
|
903
896
|
await endpoint.read('aqaraOpple', [0x0102], {manufacturerCode: 0x115f});
|
|
904
897
|
await endpoint.read('aqaraOpple', [0x010c], {manufacturerCode: 0x115f});
|
|
905
898
|
},
|
|
899
|
+
ota: ota.zigbeeOTA,
|
|
906
900
|
},
|
|
907
901
|
{
|
|
908
902
|
zigbeeModel: ['lumi.sensor_magnet'],
|
|
@@ -995,7 +989,7 @@ module.exports = [
|
|
|
995
989
|
e.voltage().withAccess(ea.STATE), e.current(), e.consumer_connected(), e.led_disabled_night(),
|
|
996
990
|
e.power_outage_memory(), exposes.binary('auto_off', ea.STATE_SET, true, false)
|
|
997
991
|
.withDescription('Turn the device automatically off when attached device consumes less than 2W for 20 minutes'),
|
|
998
|
-
exposes.numeric('overload_protection', exposes.access.ALL).withValueMin(100).withValueMax(
|
|
992
|
+
exposes.numeric('overload_protection', exposes.access.ALL).withValueMin(100).withValueMax(2300).withUnit('W')
|
|
999
993
|
.withDescription('Maximum allowed load, turns off if exceeded')],
|
|
1000
994
|
ota: ota.zigbeeOTA,
|
|
1001
995
|
},
|
|
@@ -1689,7 +1683,7 @@ module.exports = [
|
|
|
1689
1683
|
zigbeeModel: ['lumi.plug.macn01'],
|
|
1690
1684
|
model: 'ZNCZ15LM',
|
|
1691
1685
|
vendor: 'Xiaomi',
|
|
1692
|
-
description: 'Aqara T1
|
|
1686
|
+
description: 'Aqara smart plug T1 (china standard)',
|
|
1693
1687
|
fromZigbee: [fz.on_off, fz.xiaomi_power, fz.aqara_opple],
|
|
1694
1688
|
toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_led_disabled_night,
|
|
1695
1689
|
tz.xiaomi_overload_protection, tz.xiaomi_socket_button_lock],
|
|
@@ -1698,9 +1692,6 @@ module.exports = [
|
|
|
1698
1692
|
e.power_outage_memory(), e.led_disabled_night(), e.button_lock(),
|
|
1699
1693
|
exposes.numeric('overload_protection', exposes.access.ALL).withValueMin(100).withValueMax(2500).withUnit('W')
|
|
1700
1694
|
.withDescription('Maximum allowed load, turns off if exceeded')],
|
|
1701
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1702
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
1703
|
-
},
|
|
1704
1695
|
ota: ota.zigbeeOTA,
|
|
1705
1696
|
},
|
|
1706
1697
|
{
|
|
@@ -1753,7 +1744,7 @@ module.exports = [
|
|
|
1753
1744
|
zigbeeModel: ['lumi.plug.sacn03'],
|
|
1754
1745
|
model: 'QBCZ15LM',
|
|
1755
1746
|
vendor: 'Xiaomi',
|
|
1756
|
-
description: 'Aqara smart wall outlet H1
|
|
1747
|
+
description: 'Aqara smart wall outlet H1 (USB)',
|
|
1757
1748
|
fromZigbee: [fz.on_off, fz.xiaomi_power, fz.aqara_opple],
|
|
1758
1749
|
toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_led_disabled_night,
|
|
1759
1750
|
tz.xiaomi_button_switch_mode, tz.xiaomi_overload_protection, tz.xiaomi_socket_button_lock],
|
|
@@ -1769,9 +1760,6 @@ module.exports = [
|
|
|
1769
1760
|
.withDescription('Control both relay and usb or only the relay with the physical switch button'),
|
|
1770
1761
|
exposes.numeric('overload_protection', exposes.access.ALL).withValueMin(100).withValueMax(2500).withUnit('W')
|
|
1771
1762
|
.withDescription('Maximum allowed load, turns off if exceeded')],
|
|
1772
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1773
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
1774
|
-
},
|
|
1775
1763
|
ota: ota.zigbeeOTA,
|
|
1776
1764
|
},
|
|
1777
1765
|
{
|
|
@@ -1803,9 +1791,6 @@ module.exports = [
|
|
|
1803
1791
|
e.current(), e.power_outage_memory(), e.led_disabled_night(), e.button_lock(),
|
|
1804
1792
|
exposes.numeric('overload_protection', exposes.access.ALL).withValueMin(100).withValueMax(2500).withUnit('W')
|
|
1805
1793
|
.withDescription('Maximum allowed load, turns off if exceeded')],
|
|
1806
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1807
|
-
await device.getEndpoint(1).write('aqaraOpple', {'mode': 1}, {manufacturerCode: 0x115f, disableResponse: true});
|
|
1808
|
-
},
|
|
1809
1794
|
ota: ota.zigbeeOTA,
|
|
1810
1795
|
},
|
|
1811
1796
|
{
|
|
@@ -1871,7 +1856,7 @@ module.exports = [
|
|
|
1871
1856
|
model: 'WXKG14LM',
|
|
1872
1857
|
vendor: 'Xiaomi',
|
|
1873
1858
|
description: 'Aqara wireless remote switch H1 (single rocker)',
|
|
1874
|
-
fromZigbee: [fz.xiaomi_multistate_action, fz.aqara_opple],
|
|
1859
|
+
fromZigbee: [fz.xiaomi_multistate_action, fz.aqara_opple, fz.command_toggle],
|
|
1875
1860
|
toZigbee: [tz.xiaomi_switch_click_mode, tz.aqara_opple_operation_mode],
|
|
1876
1861
|
exposes: [e.battery(), e.battery_voltage(), e.action(['single', 'double', 'triple', 'hold']),
|
|
1877
1862
|
exposes.enum('click_mode', ea.ALL, ['fast', 'multi'])
|
package/lib/tuya.js
CHANGED
|
@@ -418,6 +418,9 @@ const dataPoints = {
|
|
|
418
418
|
tuyaSabHumidity: 19,
|
|
419
419
|
tuyaSabVOC: 21,
|
|
420
420
|
tuyaSabFormaldehyd: 22,
|
|
421
|
+
// tuya Smart Air House Keeper, Multifunctionale air quality detector.
|
|
422
|
+
// CO2, Temp, Humidity, VOC and Formaldehyd same as Smart Air Box
|
|
423
|
+
tuyaSahkMP25: 20,
|
|
421
424
|
lidlTimer: 5,
|
|
422
425
|
// Moes MS-105 Dimmer
|
|
423
426
|
moes105DimmerState1: 1,
|
package/npm-shrinkwrap.json
CHANGED