zigbee-herdsman-converters 14.0.633 → 14.0.635
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/devices/tuya.js +23 -3
- package/lib/tuya.js +129 -0
- package/package.json +2 -2
package/devices/tuya.js
CHANGED
|
@@ -908,7 +908,8 @@ module.exports = [
|
|
|
908
908
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_6amjviba'},
|
|
909
909
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_xr5m6kfg'},
|
|
910
910
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_xr5m6kfg'},
|
|
911
|
-
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bf175wi4'}
|
|
911
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bf175wi4'},
|
|
912
|
+
{modelID: 'TS0505B', manufacturerName: '_TZB210_3zfp8mki'}],
|
|
912
913
|
model: 'TS0505B',
|
|
913
914
|
vendor: 'TuYa',
|
|
914
915
|
description: 'Zigbee RGB+CCT light',
|
|
@@ -1138,8 +1139,6 @@ module.exports = [
|
|
|
1138
1139
|
{modelID: 'TS0601', manufacturerName: '_TZE200_ojzhk75b'},
|
|
1139
1140
|
{modelID: 'TS0601', manufacturerName: '_TZE200_swaamsoy'},
|
|
1140
1141
|
{modelID: 'TS0601', manufacturerName: '_TZE200_3p5ydos3'},
|
|
1141
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_1agwnems'},
|
|
1142
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_ip2akl4w'},
|
|
1143
1142
|
],
|
|
1144
1143
|
model: 'TS0601_dimmer',
|
|
1145
1144
|
vendor: 'TuYa',
|
|
@@ -1163,6 +1162,27 @@ module.exports = [
|
|
|
1163
1162
|
{vendor: 'Moes', model: 'EDM-1ZBB-EU'},
|
|
1164
1163
|
],
|
|
1165
1164
|
},
|
|
1165
|
+
{
|
|
1166
|
+
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_ip2akl4w', '_TZE200_1agwnems']),
|
|
1167
|
+
model: 'TS0601_dimmer_1',
|
|
1168
|
+
vendor: 'TuYa',
|
|
1169
|
+
description: 'Zigbee smart dimmer',
|
|
1170
|
+
fromZigbee: [tuya.fzDataPoints],
|
|
1171
|
+
toZigbee: [tuya.tzDataPoints],
|
|
1172
|
+
configure: tuya.configureMagicPacket,
|
|
1173
|
+
exposes: [tuya.exposes.lightBrightnessWithMinMax, tuya.exposes.powerOnBehavior, tuya.exposes.countdown, tuya.exposes.lightType],
|
|
1174
|
+
meta: {
|
|
1175
|
+
tuyaDatapoints: [
|
|
1176
|
+
[1, 'state', tuya.valueConverter.onOff, {skip: tuya.skip.stateOnAndBrightnessPresent}],
|
|
1177
|
+
[2, 'brightness', tuya.valueConverter.scale0_254to0_1000],
|
|
1178
|
+
[3, 'min_brightness', tuya.valueConverter.scale0_254to0_1000],
|
|
1179
|
+
[4, 'light_type', tuya.valueConverter.lightType],
|
|
1180
|
+
[5, 'max_brightness', tuya.valueConverter.scale0_254to0_1000],
|
|
1181
|
+
[6, 'countdown', tuya.valueConverter.countdown],
|
|
1182
|
+
[14, 'power_on_behavior', tuya.valueConverter.powerOnBehavior],
|
|
1183
|
+
],
|
|
1184
|
+
},
|
|
1185
|
+
},
|
|
1166
1186
|
{
|
|
1167
1187
|
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'}],
|
|
1168
1188
|
model: 'TS011F_socket_module',
|
package/lib/tuya.js
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const constants = require('./constants');
|
|
4
4
|
const globalStore = require('./store');
|
|
5
|
+
const exposes = require('./exposes');
|
|
6
|
+
const utils = require('./utils');
|
|
7
|
+
const e = exposes.presets;
|
|
8
|
+
const ea = exposes.access;
|
|
5
9
|
|
|
6
10
|
const dataTypes = {
|
|
7
11
|
raw: 0, // [ bytes ]
|
|
@@ -1131,7 +1135,132 @@ async function sendDataPointStringBuffer(entity, dp, value, cmd, seq=undefined)
|
|
|
1131
1135
|
);
|
|
1132
1136
|
}
|
|
1133
1137
|
|
|
1138
|
+
const tuyaExposes = {
|
|
1139
|
+
powerOnBehavior: exposes.enum('power_on_behavior', ea.STATE_SET, ['off', 'on', 'previous'])
|
|
1140
|
+
.withDescription('Controls the behavior when the device is powered on'),
|
|
1141
|
+
lightType: exposes.enum('light_type', ea.STATE_SET, ['led', 'incandescent', 'halogen'])
|
|
1142
|
+
.withDescription('Type of light attached to the device'),
|
|
1143
|
+
lightBrightnessWithMinMax: e.light_brightness().withMinBrightness().withMaxBrightness().setAccess(
|
|
1144
|
+
'state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).setAccess(
|
|
1145
|
+
'min_brightness', ea.STATE_SET).setAccess('max_brightness', ea.STATE_SET),
|
|
1146
|
+
countdown: exposes.numeric('countdown', ea.STATE_SET).withValueMin(0).withValueMax(43200).withValueStep(1).withUnit('s')
|
|
1147
|
+
.withDescription('Countdown to turn device off after a certain time'),
|
|
1148
|
+
};
|
|
1149
|
+
|
|
1150
|
+
const skip = {
|
|
1151
|
+
// Prevent state from being published when already ON and brightness is also published.
|
|
1152
|
+
// This prevents 100% -> X% brightness jumps when the switch is already on
|
|
1153
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/13800#issuecomment-1263592783
|
|
1154
|
+
stateOnAndBrightnessPresent: (meta) => meta.message.hasOwnProperty('brightness') && meta.state.state === 'ON',
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
const configureMagicPacket = async (device, coordinatorEndpoint, logger) => {
|
|
1158
|
+
const endpoint = device.endpoints[0];
|
|
1159
|
+
await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
const fingerprint = (modelID, manufacturerNames) => {
|
|
1163
|
+
return manufacturerNames.map((manufacturerName) => {
|
|
1164
|
+
return {modelID, manufacturerName};
|
|
1165
|
+
});
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const valueConverterBasic = {
|
|
1169
|
+
lookup: (map) => {
|
|
1170
|
+
return {
|
|
1171
|
+
to: (v) => {
|
|
1172
|
+
if (map[v] === undefined) throw new Error(`Value '${v}' is not allowed, expected one of ${Object.keys(map)}`);
|
|
1173
|
+
return map[v];
|
|
1174
|
+
},
|
|
1175
|
+
from: (v) => {
|
|
1176
|
+
const value = Object.entries(map).find((i) => i[1] === v);
|
|
1177
|
+
if (!value) throw new Error(`Value '${v}' is not allowed, expected one of ${Object.values(map)}`);
|
|
1178
|
+
return value[0];
|
|
1179
|
+
},
|
|
1180
|
+
};
|
|
1181
|
+
},
|
|
1182
|
+
scale: (min1, max1, min2, max2) => {
|
|
1183
|
+
return {to: (v) => utils.mapNumberRange(v, min1, max1, min2, max2), from: (v) => utils.mapNumberRange(v, min2, max2, min1, max1)};
|
|
1184
|
+
},
|
|
1185
|
+
raw: () => {
|
|
1186
|
+
return {to: (v) => v, from: (v) => v};
|
|
1187
|
+
},
|
|
1188
|
+
divideBy: (value) => {
|
|
1189
|
+
return {to: (v) => v * value, from: (v) => v / value};
|
|
1190
|
+
},
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
const valueConverter = {
|
|
1194
|
+
trueFalse: valueConverterBasic.lookup({1: true, 0: false}),
|
|
1195
|
+
onOff: valueConverterBasic.lookup({'ON': true, 'OFF': false}),
|
|
1196
|
+
powerOnBehavior: valueConverterBasic.lookup({'off': 0, 'on': 1, 'previous': 2}),
|
|
1197
|
+
lightType: valueConverterBasic.lookup({'led': 0, 'incandescent': 1, 'halogen': 2}),
|
|
1198
|
+
countdown: valueConverterBasic.raw(),
|
|
1199
|
+
scale0_254to0_1000: valueConverterBasic.scale(0, 254, 0, 1000),
|
|
1200
|
+
scale0_1to0_1000: valueConverterBasic.scale(0, 1, 0, 1000),
|
|
1201
|
+
divideBy100: valueConverterBasic.divideBy(100),
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
const tzDataPoints = {
|
|
1205
|
+
key: ['state', 'brightness', 'min_brightness', 'max_brightness', 'power_on_behavior', 'countdown', 'light_type'],
|
|
1206
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1207
|
+
// A set converter is only called once; therefore we need to loop
|
|
1208
|
+
const state = {};
|
|
1209
|
+
if (!meta.mapped.meta || !meta.mapped.meta.tuyaDatapoints) throw new Error('No datapoints map defined');
|
|
1210
|
+
const datapoints = meta.mapped.meta.tuyaDatapoints;
|
|
1211
|
+
for (const [key, value] of Object.entries(meta.message)) {
|
|
1212
|
+
const convertedKey = meta.mapped.meta.multiEndpoint ? `${key}_${meta.endpoint_name}` : key;
|
|
1213
|
+
const dpEntry = datapoints.find((d) => d[1] === convertedKey);
|
|
1214
|
+
if (!dpEntry || !dpEntry[1]) {
|
|
1215
|
+
throw new Error(`No datapoint defined for '${key}'`);
|
|
1216
|
+
}
|
|
1217
|
+
if (dpEntry[3] && dpEntry[3].skip && dpEntry[3].skip(meta)) continue;
|
|
1218
|
+
const dpId = dpEntry[0];
|
|
1219
|
+
const convertedValue = dpEntry[2].to(value);
|
|
1220
|
+
if (typeof convertedValue === 'boolean') {
|
|
1221
|
+
await sendDataPointBool(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1222
|
+
} else if (typeof convertedValue === 'number') {
|
|
1223
|
+
await sendDataPointValue(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1224
|
+
} else {
|
|
1225
|
+
throw new Error(`Don't know how to send type '${typeof convertedValue}'`);
|
|
1226
|
+
}
|
|
1227
|
+
state[convertedKey] = value;
|
|
1228
|
+
}
|
|
1229
|
+
return {state};
|
|
1230
|
+
},
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
const fzDataPoints = {
|
|
1234
|
+
cluster: 'manuSpecificTuya',
|
|
1235
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
1236
|
+
convert: (model, msg, publish, options, meta) => {
|
|
1237
|
+
const result = {};
|
|
1238
|
+
if (!model.meta || !model.meta.tuyaDatapoints) throw new Error('No datapoints map defined');
|
|
1239
|
+
const datapoints = model.meta.tuyaDatapoints;
|
|
1240
|
+
for (const dpValue of msg.data.dpValues) {
|
|
1241
|
+
const dpId = dpValue.dp;
|
|
1242
|
+
const dpEntry = datapoints.find((d) => d[0] === dpId);
|
|
1243
|
+
if (dpEntry) {
|
|
1244
|
+
const value = getDataValue(dpValue);
|
|
1245
|
+
result[dpEntry[1]] = dpEntry[2].from(value);
|
|
1246
|
+
} else {
|
|
1247
|
+
meta.logger.warn(`Datapoint ${dpId} not defined for '${meta.device.manufacturerName}' ` +
|
|
1248
|
+
`with data ${JSON.stringify(dpValue)}`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return result;
|
|
1252
|
+
},
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1134
1255
|
module.exports = {
|
|
1256
|
+
exposes: tuyaExposes,
|
|
1257
|
+
skip,
|
|
1258
|
+
configureMagicPacket,
|
|
1259
|
+
fingerprint,
|
|
1260
|
+
valueConverterBasic,
|
|
1261
|
+
valueConverter,
|
|
1262
|
+
tzDataPoints,
|
|
1263
|
+
fzDataPoints,
|
|
1135
1264
|
sendDataPoint,
|
|
1136
1265
|
sendDataPoints,
|
|
1137
1266
|
sendDataPointValue,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-herdsman-converters",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.635",
|
|
4
4
|
"description": "Collection of device converters to be used with zigbee-herdsman",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"buffer-crc32": "^0.2.13",
|
|
39
39
|
"https-proxy-agent": "^5.0.1",
|
|
40
40
|
"tar-stream": "^2.2.0",
|
|
41
|
-
"zigbee-herdsman": "^0.14.
|
|
41
|
+
"zigbee-herdsman": "^0.14.62"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"eslint": "*",
|