zigbee-herdsman-converters
Version:
Collection of device converters to be used with zigbee-herdsman
17,969 lines • 838 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.definitions = void 0;
const node_util_1 = require("node:util");
const zigbee_herdsman_1 = require("zigbee-herdsman");
const fz = __importStar(require("../converters/fromZigbee"));
const tz = __importStar(require("../converters/toZigbee"));
const libColor = __importStar(require("../lib/color"));
const constants_1 = require("../lib/constants");
const exposes = __importStar(require("../lib/exposes"));
const legacy = __importStar(require("../lib/legacy"));
const logger_1 = require("../lib/logger");
const m = __importStar(require("../lib/modernExtend"));
const reporting = __importStar(require("../lib/reporting"));
const globalStore = __importStar(require("../lib/store"));
const tuya = __importStar(require("../lib/tuya"));
const utils = __importStar(require("../lib/utils"));
const utils_1 = require("../lib/utils");
const zosung = __importStar(require("../lib/zosung"));
const NS = "zhc:tuya";
const { tuyaLight, tuyaBase, tuyaMagicPacket, dpBinary, dpNumeric, dpEnumLookup } = tuya.modernExtend;
const e = exposes.presets;
const ea = exposes.access;
const fzZosung = zosung.fzZosung;
const tzZosung = zosung.tzZosung;
const ez = zosung.presetsZosung;
const storeLocal = {
getPrivatePJ1203A: (device) => {
let priv = globalStore.getValue(device, "private_state");
if (priv === undefined) {
//
// The PJ-1203A is sending quick sequences of messages containing a single datapoint.
// A sequence occurs every `update_frequency` seconds (10s by default)
//
// A typical sequence is composed of two identical groups for channel a and b.
//
// 102 energy_flow_a
// 112 voltage
// 113 current_a
// 101 power_a
// 110 power_factor_a
// 111 ac_frequency
// 115 power_ab
// ---
// 104 energy_flow_b
// 112 voltage
// 114 current_b
// 105 power_b
// 121 power_factor_b
// 111 ac_frequency
// 115 power_ab
//
// It should be noted that when no current is detected on channel x then
// energy_flow_x is not emitted and current_x==0, power_x==0 and power_factor_x==100.
//
// The other datapoints are emitted every few minutes.
//
// There is a known issue on the _TZE204_81yrt3lo (with appVersion 74, stackVersion 0 and hwVersion 1).
// The energy_flow datapoints are (incorrectly) emitted during the next update. This is quite problematic
// because that means that the direction can be inverted for up to update_frequency seconds.
//
// The features implemented here are
// - cache the datapoints for each channel and publish them together.
// - (OPTIONAL) solve the issue described above by waiting for the next energy flow datapoint
// before publishing the cached channel data.
// - (OPTIONAL) provide signed power instead of energy flow.
// - detect missing or reordered Zigbee message using the Tuya 'seq' attribute and invalidate
// cached data accordingly.
//
priv = {
// Cached values for both channels
sign_a: null,
sign_b: null,
power_a: null,
power_b: null,
current_a: null,
current_b: null,
power_factor_a: null,
power_factor_b: null,
timestamp_a: null,
timestamp_b: null,
// Used to detect missing or misordered messages.
last_seq: -99999,
// Do all PJ-1203A increment seq by 256? If not, then this is
// the value that will have to be customized.
seq_inc: 256,
// Also need to save the last published SIGNED values of
// power_a and power_b to recompute power_ab on the fly.
pub_power_a: null,
pub_power_b: null,
recompute_power_ab: function (result) {
let modified = false;
if ("power_a" in result) {
this.pub_power_a = result.power_a * (result.energy_flow_a === "producing" ? -1 : 1);
modified = true;
}
if ("power_b" in result) {
this.pub_power_b = result.power_b * (result.energy_flow_b === "producing" ? -1 : 1);
modified = true;
}
if (modified) {
if (this.pub_power_a !== null && this.pub_power_b !== null) {
// Cancel and reapply the scaling by 10 to avoid floating-point rounding errors
// such as 79.8 - 37.1 = 42.699999999999996
result.power_ab = Math.round(10 * this.pub_power_a + 10 * this.pub_power_b) / 10;
}
}
},
flush: function (result, channel, options) {
const sign = this[`sign_${channel}`];
const power = this[`power_${channel}`];
const current = this[`current_${channel}`];
const powerFactor = this[`power_factor_${channel}`];
this[`sign_${channel}`] = this[`power_${channel}`] = this[`current_${channel}`] = this[`power_factor_${channel}`] = null;
// Only publish if the set is complete otherwise discard everything.
if (sign !== null && power !== null && current !== null && powerFactor !== null) {
const signedPowerKey = `signed_power_${channel}`;
const signedPower = options[signedPowerKey] != null ? options[signedPowerKey] : false;
if (signedPower) {
result[`power_${channel}`] = sign * power;
result[`energy_flow_${channel}`] = "sign";
}
else {
result[`power_${channel}`] = power;
result[`energy_flow_${channel}`] = sign > 0 ? "consuming" : "producing";
}
result[`timestamp_${channel}`] = this[`timestamp_${channel}`];
result[`current_${channel}`] = current;
result[`power_factor_${channel}`] = powerFactor;
this.recompute_power_ab(result);
return true;
}
return false;
},
// When the device does not detect any flow, it stops sending
// the energy_flow datapoint (102 and 104) and always set
// current_x=0, power_x=0 and power_factor_x=100.
//
// So if we see a datapoint with current==0 or power==0
// then we can safely assume that we are in that zero energy state.
//
// Also, the publication of a zero energy state is not delayed
// when option late_energy_flow_a|b is set.
flushZero: function (result, channel, options) {
this[`sign_${channel}`] = +1;
this[`power_${channel}`] = 0;
this[`timestamp_${channel}`] = new Date().toISOString();
this[`current_${channel}`] = 0;
this[`power_factor_${channel}`] = 100;
this.flush(result, channel, options);
},
clear: () => {
priv.sign_a = null;
priv.sign_b = null;
priv.power_a = null;
priv.power_b = null;
priv.current_a = null;
priv.current_b = null;
priv.power_factor_a = null;
priv.power_factor_b = null;
},
};
globalStore.putValue(device, "private_state", priv);
}
return priv;
},
};
const convLocal = {
energyFlowPJ1203A: (channel) => {
return {
from: (v, meta, options) => {
const priv = storeLocal.getPrivatePJ1203A(meta.device);
const result = {};
priv[`sign_${channel}`] = v === 1 ? -1 : +1;
const lateEnergyFlowKey = `late_energy_flow_${channel}`;
const lateEnergyFlow = options[lateEnergyFlowKey] != null ? options[lateEnergyFlowKey] : false;
if (lateEnergyFlow) {
priv.flush(result, channel, options);
}
return result;
},
};
},
powerPJ1203A: (channel) => {
return {
from: (v, meta, options) => {
const priv = storeLocal.getPrivatePJ1203A(meta.device);
const result = {};
priv[`power_${channel}`] = v / 10;
priv[`timestamp_${channel}`] = new Date().toISOString();
if (v === 0) {
priv.flushZero(result, channel, options);
return result;
}
return result;
},
};
},
currentPJ1203A: (channel) => {
return {
from: (v, meta, options) => {
const priv = storeLocal.getPrivatePJ1203A(meta.device);
const result = {};
priv[`current_${channel}`] = v / 1000;
if (v === 0) {
priv.flushZero(result, channel, options);
return result;
}
return result;
},
};
},
powerFactorPJ1203A: (channel) => {
return {
from: (v, meta, options) => {
const priv = storeLocal.getPrivatePJ1203A(meta.device);
const result = {};
priv[`power_factor_${channel}`] = v;
const lateEnergyFlowKey = `late_energy_flow_${channel}`;
const lateEnergyFlow = options[lateEnergyFlowKey] != null ? options[lateEnergyFlowKey] : false;
if (!lateEnergyFlow) {
priv.flush(result, channel, options);
}
return result;
},
};
},
powerAbPJ1203A: () => {
return {
// power_ab datapoint is broken and will be recomputed so ignore it.
from: (v, meta, options) => {
return {};
},
};
},
sceneCubeAction: () => {
const lookup = ["side_1", "side_2", "side_3", "side_4", "knock", "shake"];
const expose = e.action(lookup);
return [
tuya.modernExtend.dpEnumLookup({
dp: 0x01,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { side_1: 0 },
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x02,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { side_2: 0 },
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x03,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { side_3: 0 },
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x04,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { side_4: 0 },
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x05,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { knock: 0 },
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x06,
name: "action",
type: tuya.dataTypes.bool,
readOnly: true,
expose: expose,
lookup: { shake: 0 },
}),
];
},
name: {
to: (v, meta) => {
const utf8bytes = new node_util_1.TextEncoder().encode(v);
return Array.from(utf8bytes, (utf8bytes) => utf8bytes.toString(16).padStart(4, "0")).join("");
},
from: (v, meta) => {
const bytes = [];
for (let i = 0; i < v.length; i += 4) {
bytes.push(Number.parseInt(v.slice(i, i + 4), 16));
}
const hexToBytes = Uint8Array.from(bytes);
return new node_util_1.TextDecoder("utf-8").decode(hexToBytes);
},
},
};
const tzLocal = {
ts110eCountdown: {
key: ["countdown"],
convertSet: async (entity, key, value, meta) => {
utils.assertNumber(value);
const data = Buffer.alloc(4);
data.writeUInt32LE(value);
await entity.command("genOnOff", "tuyaCountdown", { data });
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS030F_border: {
key: ["border"],
convertSet: async (entity, key, value, meta) => {
const lookup = { up: 0, down: 1, up_delete: 2, down_delete: 3 };
await entity.write(0xe001, {
57345: { value: utils.getFromLookup(value, lookup), type: 0x30 },
});
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0726_switch_mode: {
key: ["switch_mode"],
convertSet: async (entity, key, value, meta) => {
await entity.write(0xe001, {
53280: {
value: utils.getFromLookup(value, { switch: 0, scene: 1 }),
type: 0x30,
},
});
return { state: { switch_mode: value } };
},
},
led_control: {
key: ["brightness", "color", "color_temp", "transition"],
options: [exposes.options.color_sync()],
convertSet: async (entity, _key, _value, meta) => {
const newState = {};
// The color mode encodes whether the light is using its white LEDs or its color LEDs
let colorMode = meta.state.color_mode ?? constants_1.colorModeLookup[constants_1.ColorMode.ColorTemp];
// Color mode switching is done by setting color temperature (switch to white LEDs) or setting color (switch
// to color LEDs)
if ("color_temp" in meta.message)
colorMode = constants_1.colorModeLookup[constants_1.ColorMode.ColorTemp];
if ("color" in meta.message)
colorMode = constants_1.colorModeLookup[constants_1.ColorMode.HS];
if (colorMode !== meta.state.color_mode) {
newState.color_mode = colorMode;
// To switch between white mode and color mode, we have to send a special command:
const rgbMode = colorMode === constants_1.colorModeLookup[constants_1.ColorMode.HS];
await entity.command("lightingColorCtrl", "tuyaRgbMode", {
enable: rgbMode,
});
}
// A transition time of 0 would be treated as about 1 second, probably some kind of fallback/default
// transition time, so for "no transition" we use 1 (tenth of a second).
const transtime = typeof meta.message.transition === "number" ? meta.message.transition * 10 : 0.1;
if (colorMode === constants_1.colorModeLookup[constants_1.ColorMode.ColorTemp]) {
if ("brightness" in meta.message) {
const zclData = { level: Number(meta.message.brightness), transtime };
await entity.command("genLevelCtrl", "moveToLevel", zclData, utils.getOptions(meta.mapped, entity));
newState.brightness = meta.message.brightness;
}
if ("color_temp" in meta.message) {
const zclData = {
colortemp: meta.message.color_temp,
transtime: transtime,
};
await entity.command("lightingColorCtrl", "moveToColorTemp", zclData, utils.getOptions(meta.mapped, entity));
newState.color_temp = meta.message.color_temp;
}
}
else if (colorMode === constants_1.colorModeLookup[constants_1.ColorMode.HS]) {
if ("brightness" in meta.message || "color" in meta.message) {
// We ignore the brightness of the color and instead use the overall brightness setting of the lamp
// for the brightness because I think that's the expected behavior and also because the color
// conversion below always returns 100 as brightness ("value") even for very dark colors, except
// when the color is completely black/zero.
// Load current state or defaults
const newSettings = {
brightness: meta.state.brightness ?? 254, // full brightness
// @ts-expect-error ignore
hue: meta.state.color?.hue ?? 0, // red
// @ts-expect-error ignore
saturation: meta.state.color?.saturation ?? 100, // full saturation
};
// Apply changes
if ("brightness" in meta.message) {
newSettings.brightness = meta.message.brightness;
newState.brightness = meta.message.brightness;
}
if ("color" in meta.message) {
// The Z2M UI sends `{ hex:'#xxxxxx' }`.
// Home Assistant sends `{ h: xxx, s: xxx }`.
// We convert the former into the latter.
const c = libColor.Color.fromConverterArg(meta.message.color);
if (c.isRGB()) {
// https://github.com/Koenkk/zigbee2mqtt/issues/13421#issuecomment-1426044963
c.hsv = c.rgb.gammaCorrected().toXY().toHSV();
}
const color = c.hsv;
newSettings.hue = color.hue;
newSettings.saturation = color.saturation;
newState.color = {
hue: color.hue,
saturation: color.saturation,
};
}
// Convert to device specific format and send
const brightness = utils.toNumber(newSettings.brightness, "brightness");
const zclData = {
brightness: utils.mapNumberRange(brightness, 0, 254, 0, 1000),
hue: newSettings.hue,
saturation: utils.mapNumberRange(newSettings.saturation, 0, 100, 0, 1000),
};
// This command doesn't support a transition time
await entity.command("lightingColorCtrl", "tuyaMoveToHueAndSaturationBrightness2", zclData, utils.getOptions(meta.mapped, entity));
}
}
// If we're in white mode, calculate a matching display color for the set color temperature. This also kind
// of works in the other direction.
Object.assign(newState, libColor.syncColorState(newState, meta.state, entity, meta.options));
return { state: newState };
},
convertGet: async (entity, key, meta) => {
await entity.read("lightingColorCtrl", ["currentHue", "currentSaturation", "currentLevel", "tuyaRgbMode", "colorTemperature"]);
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0504B_color: {
key: ["color"],
convertSet: async (entity, key, value, meta) => {
const color = libColor.Color.fromConverterArg(value);
const enableWhite = (color.isRGB() && color.rgb.red === 1 && color.rgb.green === 1 && color.rgb.blue === 1) ||
// Zigbee2MQTT frontend white value
(color.isXY() && (color.xy.x === 0.3125 || color.xy.y === 0.32894736842105265)) ||
// Home Assistant white color picker value
(color.isXY() && (color.xy.x === 0.323 || color.xy.y === 0.329));
if (enableWhite) {
await entity.command("lightingColorCtrl", "tuyaRgbMode", {
enable: false,
});
const newState = { color_mode: "xy" };
if (color.isXY()) {
newState.color = color.xy;
}
else {
newState.color = color.rgb.gammaCorrected().toXY().rounded(4);
}
return {
state: libColor.syncColorState(newState, meta.state, entity, meta.options),
};
}
return await tz.light_color.convertSet(entity, key, value, meta);
},
convertGet: tz.light_color.convertGet,
},
TS0224: {
key: ["light", "duration", "volume"],
convertSet: async (entity, key, value, meta) => {
if (key === "light") {
utils.assertString(value, "light");
await entity.command("genOnOff", value.toLowerCase() === "on" ? "on" : "off", {}, utils.getOptions(meta.mapped, entity));
}
else if (key === "duration") {
await entity.write("ssIasWd", { maxDuration: value }, utils.getOptions(meta.mapped, entity));
}
else if (key === "volume") {
const lookup = { mute: 0, low: 10, medium: 30, high: 50 };
utils.assertString(value, "volume");
const lookupValue = lookup[value];
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
value = value.toLowerCase();
utils.validateValue(value, Object.keys(lookup));
await entity.write("ssIasWd", { 2: { value: lookupValue, type: 0x0a } }, utils.getOptions(meta.mapped, entity));
}
return { state: { [key]: value } };
},
},
temperature_unit: {
key: ["temperature_unit"],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case "temperature_unit": {
utils.assertString(value, "temperature_unit");
await entity.write("manuSpecificTuya_2", {
"57355": { value: { celsius: 0, fahrenheit: 1 }[value], type: 48 },
});
break;
}
default: // Unknown key
logger_1.logger.warning(`Unhandled key ${key}`, NS);
}
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS011F_threshold: {
key: [
"temperature_threshold",
"temperature_breaker",
"power_threshold",
"power_breaker",
"over_current_threshold",
"over_current_breaker",
"over_voltage_threshold",
"over_voltage_breaker",
"under_voltage_threshold",
"under_voltage_breaker",
],
convertSet: async (entity, key, value, meta) => {
const onOffLookup = { on: 1, off: 0 };
switch (key) {
case "temperature_threshold": {
const state = meta.state.temperature_breaker;
const buf = Buffer.from([5, utils.getFromLookup(state, onOffLookup), 0, utils.toNumber(value, "temperature_threshold")]);
await entity.command("manuSpecificTuya_3", "setOptions2", {
data: buf,
});
break;
}
case "temperature_breaker": {
const threshold = meta.state.temperature_threshold;
const number = utils.toNumber(threshold, "temperature_threshold");
const buf = Buffer.from([5, utils.getFromLookup(value, onOffLookup), 0, number]);
await entity.command("manuSpecificTuya_3", "setOptions2", {
data: buf,
});
break;
}
case "power_threshold": {
const state = meta.state.power_breaker;
const buf = Buffer.from([7, utils.getFromLookup(state, onOffLookup), 0, utils.toNumber(value, "power_breaker")]);
await entity.command("manuSpecificTuya_3", "setOptions2", {
data: buf,
});
break;
}
case "power_breaker": {
const threshold = meta.state.power_threshold;
const number = utils.toNumber(threshold, "power_breaker");
const buf = Buffer.from([7, utils.getFromLookup(value, onOffLookup), 0, number]);
await entity.command("manuSpecificTuya_3", "setOptions2", {
data: buf,
});
break;
}
case "over_current_threshold": {
const state = meta.state.over_current_breaker;
const buf = Buffer.from([1, utils.getFromLookup(state, onOffLookup), 0, utils.toNumber(value, "over_current_threshold")]);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
case "over_current_breaker": {
const threshold = meta.state.over_current_threshold;
const number = utils.toNumber(threshold, "over_current_threshold");
const buf = Buffer.from([1, utils.getFromLookup(value, onOffLookup), 0, number]);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
case "over_voltage_threshold": {
const state = meta.state.over_voltage_breaker;
const buf = Buffer.alloc(4);
buf.writeUInt8(3, 0);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 1);
buf.writeUInt16BE(utils.toNumber(value, "over_voltage_threshold"), 2);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
case "over_voltage_breaker": {
const threshold = meta.state.over_voltage_threshold;
const number = utils.toNumber(threshold, "over_voltage_threshold");
const buf = Buffer.from([3, utils.getFromLookup(value, onOffLookup), 0, number]);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
case "under_voltage_threshold": {
const state = meta.state.under_voltage_breaker;
const buf = Buffer.from([4, utils.getFromLookup(state, onOffLookup), 0, utils.toNumber(value, "under_voltage_threshold")]);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
case "under_voltage_breaker": {
const threshold = meta.state.under_voltage_threshold;
const number = utils.toNumber(threshold, "under_voltage_breaker");
const buf = Buffer.from([4, utils.getFromLookup(value, onOffLookup), 0, number]);
await entity.command("manuSpecificTuya_3", "setOptions3", {
data: buf,
});
break;
}
default: // Unknown key
logger_1.logger.warning(`Unhandled key ${key}`, NS);
}
},
},
invert_cover_percent_fix: {
key: ["state", "position"],
convertSet: async (entity, key, value, meta) => {
const shouldInvert = key === "position" && meta.options.cover_position_percent_fix;
const newValue = shouldInvert ? 100 - Number(value) : value;
return await legacy.toZigbee.tuya_cover_control.convertSet(entity, key, newValue, meta);
},
},
};
const fzLocal = {
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0726_action: {
cluster: "genOnOff",
type: ["commandTuyaAction"],
convert: (model, msg, publish, options, meta) => {
return { action: `scene_${msg.endpoint.ID}` };
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0222_humidity: {
...fz.humidity,
convert: (model, msg, publish, options, meta) => {
const result = fz.humidity.convert(model, msg, publish, options, meta);
if (result)
result.humidity *= 10;
return result;
},
},
scene_recall: {
cluster: "genScenes",
type: "commandRecall",
convert: (model, msg, publish, options, meta) => {
if ((0, utils_1.hasAlreadyProcessedMessage)(msg, model))
return;
const payload = {
action: (0, utils_1.postfixWithEndpointName)(`scene_${msg.data.sceneid}`, msg, model, meta),
};
(0, utils_1.addActionGroup)(payload, msg, model);
return payload;
},
},
scenes_recall_scene_65029: {
cluster: "65029",
type: ["raw", "attributeReport"],
convert: (model, msg, publish, options, meta) => {
const id = meta.device.modelID === "005f0c3b" ? msg.data[0] : msg.data[msg.data.length - 1];
return { action: `scene_${id}` };
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0201_battery: {
cluster: "genPowerCfg",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/11470
// https://github.com/Koenkk/zigbee-herdsman-converters/pull/8246
if (msg.data.batteryPercentageRemaining === 200 &&
msg.data.batteryVoltage < 30 &&
!["_TZ3000_lqmvrwa2"].includes(meta.device.manufacturerName))
return;
return fz.battery.convert(model, msg, publish, options, meta);
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS0201_humidity: {
...fz.humidity,
convert: (model, msg, publish, options, meta) => {
if (["_TZ3210_ncw88jfq", "_TZ3000_ywagc4rj"].includes(meta.device.manufacturerName)) {
msg.data.measuredValue *= 10;
}
return fz.humidity.convert(model, msg, publish, options, meta);
},
},
humidity10: {
cluster: "msRelativeHumidity",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const humidity = Number.parseFloat(msg.data.measuredValue) / 10.0;
if (humidity >= 0 && humidity <= 100) {
return { humidity };
}
},
},
temperature_unit: {
cluster: "manuSpecificTuya_2",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data["57355"] !== undefined) {
result.temperature_unit = utils.getFromLookup(msg.data["57355"], {
"0": "celsius",
"1": "fahrenheit",
});
}
return result;
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS011F_electrical_measurement: {
...fz.electrical_measurement,
convert: async (model, msg, publish, options, meta) => {
const result = fz.electrical_measurement.convert(model, msg, publish, options, meta) ?? {};
const lookup = {
power: "activePower",
current: "rmsCurrent",
voltage: "rmsVoltage",
};
// Wait 5 seconds before reporting a 0 value as this could be an invalid measurement.
// https://github.com/Koenkk/zigbee2mqtt/issues/16709#issuecomment-1509599046
if (result) {
for (const key of ["power", "current", "voltage"]) {
if (key in result) {
const value = result[key];
clearTimeout(globalStore.getValue(msg.endpoint, key));
if (value === 0) {
const configuredReporting = msg.endpoint.configuredReportings.find((c) => c.cluster.name === "haElectricalMeasurement" && c.attribute.name === lookup[key]);
const time = (configuredReporting ? configuredReporting.minimumReportInterval : 5) * 2 + 1;
globalStore.putValue(msg.endpoint, key, setTimeout(() => {
const payload = { [key]: value };
// Device takes a lot of time to report power 0 in some cases. When current == 0 we can assume power == 0
// https://github.com/Koenkk/zigbee2mqtt/discussions/19680#discussioncomment-7868445
if (key === "current") {
payload.power = 0;
}
publish(payload);
}, time * 1000));
delete result[key];
}
}
}
}
// Device takes a lot of time to report power 0 in some cases. When the state is OFF we can assume power == 0
// https://github.com/Koenkk/zigbee2mqtt/discussions/19680#discussioncomment-7868445
if (meta.state.state === "OFF") {
result.power = 0;
}
return result;
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
TS011F_threshold: {
cluster: "manuSpecificTuya_3",
type: "raw",
convert: (model, msg, publish, options, meta) => {
const splitToAttributes = (value) => {
const result = {};
const len = value.length;
let i = 0;
while (i < len) {
const key = value.readUInt8(i);
result[key] = [value.readUInt8(i + 1), value.readUInt16BE(i + 2)];
i += 4;
}
return result;
};
const lookup = { 0: "OFF", 1: "ON" };
const command = msg.data[2];
const data = msg.data.slice(3);
if (command === 0xe6) {
const value = splitToAttributes(data);
const result = {};
if (0x05 in value) {
result.temperature_threshold = value[0x05][1];
result.temperature_breaker = lookup[value[0x05][0]];
}
if (0x07 in value) {
result.power_threshold = value[0x07][1];
result.power_breaker = lookup[value[0x07][0]];
}
return result;
}
if (command === 0xe7) {
const value = splitToAttributes(data);
return {
over_current_threshold: value[0x01][1],
over_current_breaker: lookup[value[0x01][0]],
over_voltage_threshold: value[0x03][1],
over_voltage_breaker: lookup[value[0x03][0]],
under_voltage_threshold: value[0x04][1],
under_voltage_breaker: lookup[value[0x04][0]],
};
}
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
PJ1203A_sync_time_increase_seq: {
cluster: "manuSpecificTuya",
type: ["commandMcuSyncTime"],
convert: (model, msg, publish, options, meta) => {
const priv = storeLocal.getPrivatePJ1203A(meta.device);
priv.last_seq += priv.seq_inc;
},
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
PJ1203A_strict_fz_datapoints: {
...tuya.fz.datapoints,
convert: (model, msg, publish, options, meta) => {
// Uncomment the next line to test the behavior when random messages are lost
// if ( Math.random() < 0.05 ) return;
const priv = storeLocal.getPrivatePJ1203A(meta.device);
// Detect missing or re-ordered messages but allow duplicate messages (should we?).
const expectedSeq = (priv.last_seq + priv.seq_inc) & 0xffff;
if (msg.data.seq !== expectedSeq && msg.data.seq !== priv.last_seq) {
logger_1.logger.debug(`[PJ1203A] Missing or re-ordered message detected: Got seq=${msg.data.seq}, expected ${priv.next_seq}`, NS);
priv.clear();
}
priv.last_seq = msg.data.seq;
// And finally, process the datapoint using tuya.fz.datapoints
return tuya.fz.datapoints.convert(model, msg, publish, options, meta);
},
},
};
exports.definitions = [
{
zigbeeModel: ["TS0204"],
model: "TS0204",
vendor: "Tuya",
description: "Gas sensor",
whiteLabel: [{ vendor: "Tesla Smart", model: "TSL-SEN-GAS" }],
fromZigbee: [fz.ias_gas_alarm_1, fz.ignore_basic_report],
toZigbee: [],
exposes: [e.gas(), e.tamper()],
},
{
zigbeeModel: ["TS0205"],
model: "TS0205",
vendor: "Tuya",
description: "Smoke sensor",
whiteLabel: [
{ vendor: "Tesla Smart", model: "TSL-SEN-SMOKE" },
{ vendor: "Dongguan Daying Electornics Technology", model: "YG400A" },
tuya.whitelabel("Tuya", "TS0205_smoke_2", "Optical smoke sensor (model YG500A on the PCB)", ["_TZ3210_up3pngle"]),
tuya.whitelabel("Nedis", "ZBDS10WT", "Smoke sensor", ["_TYZB01_wqcac7lo"]),
],
// Configure battery % fails
// https://github.com/Koenkk/zigbee2mqtt/issues/22421
extend: [
m.battery({ percentageReporting: false }),
m.iasZoneAlarm({
zoneType: "smoke",
zoneAttributes: ["alarm_1", "tamper"],
}),
],
configure: async (device, coordinatorEndpoint) => {
if (device?.manufacturerName === "_TZ3210_up3pngle") {
// Required for this version
// https://github.com/Koenkk/zigbee-herdsman-converters/pull/8004
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
}
},
},
{
zigbeeModel: ["TS0111"],
model: "TS0111",
vendor: "Tuya",
description: "Socket",
extend: [tuya.modernExtend.tuyaOnOff()],
},
{
zigbeeModel: ["TS0218"],
model: "TS0218",
vendor: "Tuya",
description: "Button",
fromZigbee: [fz.command_emergency, fz.battery],
exposes: [e.battery(), e.action(["click"])],
toZigbee: [],
},
{
zigbeeModel: ["TS0203", "ZG-102Z"],
model: "TS0203",
vendor: "Tuya",
description: "Door/window sensor",
fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
toZigbee: [],
whiteLabel: [
{ vendor: "CR Smart Home", model: "TS0203" },
{ vendor: "Tuya", model: "iH-F001" },
{ vendor: "Tesla Smart", model: "TSL-SEN-DOOR" },
{ vendor: "Cleverio", model: "SS100" },
{ vendor: "HOBEIAN", model: "ZG-102ZA", fingerprint: [{ modelID: "ZG-102Z" }] },
tuya.whitelabel("Niceboy", "ORBIS Windows & Door Sensor", "Door sensor", ["_TZ3000_qrldbmfn"]),
tuya.whitelabel("Tuya", "ZD06", "Door window sensor", ["_TZ3000_rcuyhwe3"]),
tuya.whitelabel("Tuya", "ZD08", "Door sensor", ["_TZ3000_7d8yme6f"]),
tuya.whitelabel("Tuya", "MC500A", "Door sensor", ["_TZ3000_2mbfxlzr"]),
tuya.whitelabel("Tuya", "19DZT", "Door sensor", ["_TZ3000_n2egfsli"]),
tuya.whitelabel("Tuya", "DS04", "Door sensor", ["_TZ3000_yfekcy3n"]),
tuya.whitelabel("Moes", "ZSS-JM-GWM-C-MS", "Smart door and window sensor", ["_TZ3000_decxrtwa"]),
tuya.whitelabel("Moes", "ZSS-S01-GWM-C-MS", "Door/window alarm sensor", ["_TZ3000_8yhypbo7"]),
tuya.whitelabel("Moes", "ZSS-X-GWM-C", "Door/window magnetic sensor", ["_TZ3000_gntwytxo"]),
tuya.whitelabel("Luminea", "ZX-5232", "Smart door and window sensor", ["_TZ3000_4ugnzsli"]),
tuya.whitelabel("QA", "QASD1", "Door sensor", ["_TZ3000_udyjylt7"]),
tuya.whitelabel("Nous", "E3", "Door sensor", ["_TZ3000_v7chgqso"]),
tuya.whitelabel("Woox", "R7047", "Smart Door & Window Sensor", ["_TZ3000_timx9ivq"]),
],
exposes: (device, options) => {
const exps = [e.contact(), e.battery(), e.battery_voltage()];
const noTamperModels = [
// manufacturerName for models without a tamper sensor
"_TZ3000_rcuyhwe3", // Tuya ZD06
"_TZ3000_2mbfxlzr", // Tuya MC500A
"_TZ3000_n2egfsli", // Tuya 19DZT
"_TZ3000_yfekcy3n", // Tuya DS04
"_TZ3000_bpkijo14",
"_TZ3000_gntwytxo", // Moes ZSS-X-GWM-C
"_TZ3000_4ugnzsli", // Luminea ZX-5232
"_TZ3000_timx9ivq", //Woox R7047
];
if (!device || !noTamperModels.includes(device.manufacturerName)) {
exps.push(e.tamper());
}
const noBatteryLowModels = ["_TZ3000_26fmupbb", "_TZ3000_oxslv1c9", "_TZ3000_osu834un", "_TZ3000_timx9ivq"];
if (!device || !noBatteryLowModels.includes(device.manufacturerName)) {
exps.push(e.battery_low());
}
return exps;
},
meta: {
battery: {
// These sensors do send a Battery Percentage Remaining (0x0021)
// value, but is usually incorrect. For example, a coin battery tested
// with a load tester may show 80%, but report 2.5V / 1%. This voltage
// calculation matches what ZHA does by default.
// https://github.com/Koenkk/zigbee2mqtt/discussions/17337
// https://github.com/zigpy/zha-device-handlers/blob/c6ed94a52a469e72b32ece2a92d528060c7fd034/zhaquirks/__init__.py#L195-L228
voltageToPercentage: "3V_1500_2800",
},
},
configure: async (device, coordinatorEndpoint) => {
try {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
}
catch {
/* Fails for some*/
}
const endpoint = device.getEndpoint(1);
if (endpoint.binds.some((b) => b.cluster.name === "genPollCtrl")) {
await endpoint.unbind("genPollCtrl", coordinatorEndpoint);
}
},
},
{
fingerprint: tuya.fingerprint("TS0203", ["_TZ3210_jowhpxop"]),
model: "TS0203_1",
vendor: "Tuya",
description: "Door sensor with scene switch",
fromZigbee: [tuya.fz.datapoints, fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [e.action(["single", "double", "hold"]), e.contact(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage()],
meta: {
tuyaDatapoints: [[101, "action", tuya.valueConverterBasic.lookup({ single: 0, double: 1, hold: 2 })]],
},
whiteLabel: [tuya.whitelabel("Linkoze", "LKDSZ001", "Door sensor with scene switch", ["_TZ3210_jowhpxop"])],
},
{
fingerprint: tuya.fingerprint("TS0021", ["_TZ3210_3ulg9kpo"]),
model: "LKWSZ211",
vendor: "Linkoze",
description: "Scene remote with 2 keys",
fromZigbee: [tuya.fz.datapoints, fz.ignore_basic_report],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.action(["button_1_single", "button_1_double", "button_1_hold", "button_2_single", "button_2_double", "button_2_hold"]),
],
meta: {
tuyaDatapoints: [
[
1,
"action",
tuya.valueConverterBasic.lookup({
button_1_single: tuya.enum(0),
button_1_double: tuya.enum(1),
button_1_hold: tuya.enum(2),
}),
],
[
2,
"action",
tuya.valueConverterBasic.lookup({
button_2_single: tuya.enum(0),
button_2_double: tuya.enum(1),
button_2_hold: tuya.enum(2),
}),
],
[10, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_bq5c8xfe",
"_TZE200_bjawzodf",
"_TZE200_qyflbnbj",
"_TZE200_44af8vyi",
"_TZE200_zl1kmjqx",
"_TZE204_qyflbnbj",
"_TZE284_qyflbnbj",
]),
model: "TS0601_temperature_humidity_sensor_1",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [legacy.fromZigbee.tuya_temperature_humidity_sensor],
toZigbee: [],
exposes: (device, options) => {
const exps = [e.temperature(), e.humidity(), e.battery()];
if (!device ||
device.manufacturerName === "_TZE200_qyflbnbj" ||
device.manufacturerName === "_TZE204_qyflbnbj" ||
device.manufacturerName === "_TZE284_qyflbnbj") {
exps.push(e.battery_low());
exps.push(e.enum("battery_level", ea.STATE, ["low", "middle", "high"]).withDescription("Battery level state"));
}
return exps;
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_mfamvsdb"]),
model: "F00MB00-04-1",
vendor: "FORIA",
description: "4 scenes switch",
extend: [
tuya.modernExtend.tuyaMagicPacket(),
tuya.modernExtend.combineActions([
tuya.modernExtend.dpAction({ dp: 1, lookup: { scene_1: 0 } }),
tuya.modernExtend.dpAction({ dp: 2, lookup: { scene_2: 0 } }),
tuya.modernExtend.dpAction({ dp: 3, lookup: { scene_3: 0 } }),
tuya.modernExtend.dpAction({ dp: 4, lookup: { scene_4: 0 } }),
]),
tuya.modernExtend.dpBinary({
name: "vibration",
dp: 0x6c,
type: tuya.dataTypes.enum,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Enable vibration",
}),
tuya.modernExtend.dpBinary({
name: "approach",
dp: 0x6b,
type: tuya.dataTypes.enum,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Enable approach detection",
}),
tuya.modernExtend.dpBinary({
name: "illumination",
dp: 0x6a,
type: tuya.dataTypes.enum,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Enable illumination detection",
}),
tuya.modernExtend.dpBinary({
name: "backlight",
dp: 0x69,
type: tuya.dataTypes.enum,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Enable backlight",
}),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_dhke3p9w", "_TZE284_dhke3p9w"]),
model: "F00YK04-18-1",
vendor: "FORIA",
description: "18 scenes remote",
extend: [
tuya.modernExtend.tuyaMagicPacket(),
tuya.modernExtend.combineActions([
tuya.modernExtend.dpAction({ dp: 1, lookup: { scene_1: 0 } }),
tuya.modernExtend.dpAction({ dp: 2, lookup: { scene_2: 0 } }),
tuya.modernExtend.dpAction({ dp: 3, lookup: { scene_3: 0 } }),
tuya.modernExtend.dpAction({ dp: 4, lookup: { scene_4: 0 } }),
tuya.modernExtend.dpAction({ dp: 5, lookup: { scene_5: 0 } }),
tuya.modernExtend.dpAction({ dp: 6, lookup: { scene_6: 0 } }),
tuya.modernExtend.dpAction({ dp: 7, lookup: { scene_7: 0 } }),
tuya.modernExtend.dpAction({ dp: 8, lookup: { scene_8: 0 } }),
tuya.modernExtend.dpAction({ dp: 9, lookup: { scene_9: 0 } }),
tuya.modernExtend.dpAction({ dp: 10, lookup: { scene_10: 0 } }),
tuya.modernExtend.dpAction({ dp: 11, lookup: { scene_11: 0 } }),
tuya.modernExtend.dpAction({ dp: 12, lookup: { scene_12: 0 } }),
tuya.modernExtend.dpAction({ dp: 13, lookup: { scene_13: 0 } }),
tuya.modernExtend.dpAction({ dp: 14, lookup: { scene_14: 0 } }),
tuya.modernExtend.dpAction({ dp: 15, lookup: { scene_15: 0 } }),
tuya.modernExtend.dpAction({ dp: 16, lookup: { scene_16: 0 } }),
tuya.modernExtend.dpAction({ dp: 101, lookup: { scene_17: 0 } }),
tuya.modernExtend.dpAction({ dp: 102, lookup: { scene_18: 0 } }),
]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_yjjdcqsq",
"_TZE200_9yapgbuv",
"_TZE200_utkemkbs",
"_TZE204_utkemkbs",
"_TZE284_utkemkbs",
"_TZE204_9yapgbuv",
"_TZE204_upagmta9",
"_TZE200_cirvgep4",
"_TZE204_d7lpruvi",
"_TZE200_upagmta9",
"_TZE204_yjjdcqsq",
"_TZE204_jygvp6fk",
"_TZE204_cirvgep4",
"_TZE284_yjjdcqsq",
"_TZE284_hdyjyqjm",
"_TZE284_d7lpruvi",
]),
model: "TS0601_temperature_humidity_sensor_2",
vendor: "Tuya",
description: "Temperature and humidity sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent({ queryOnDeviceAnnounce: true }),
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
exposes: [e.temperature(), e.humidity(), tuya.exposes.batteryState(), tuya.exposes.temperatureUnit()],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[2, "humidity", tuya.valueConverter.raw],
[3, "battery_state", tuya.valueConverter.batteryState],
[9, "temperature_unit", tuya.valueConverter.temperatureUnitEnum],
],
},
whiteLabel: [
tuya.whitelabel("Tuya", "ZTH01", "Temperature and humidity sensor", ["_TZE200_yjjdcqsq", "_TZE204_yjjdcqsq", "_TZE284_yjjdcqsq"]),
tuya.whitelabel("Tuya", "SZTH02", "Temperature and humidity sensor", ["_TZE200_utkemkbs", "_TZE204_utkemkbs", "_TZE284_utkemkbs"]),
tuya.whitelabel("Tuya", "ZTH02", "Temperature and humidity sensor", ["_TZE200_9yapgbuv", "_TZE204_9yapgbuv"]),
tuya.whitelabel("Tuya", "ZTH05", "Temperature and humidity sensor", ["_TZE204_upagmta9", "_TZE200_upagmta9"]),
tuya.whitelabel("Tuya", "ZTH08-E", "Temperature and humidity sensor", ["_TZE200_cirvgep4", "_TZE204_cirvgep4"]),
tuya.whitelabel("Tuya", "ZTH08", "Temperature and humidity sensor", ["_TZE204_d7lpruvi", "_TZE284_d7lpruvi", "_TZE284_hdyjyqjm"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_s1xgth2u"]),
model: "TS0601_temperature_humidity_sensor_3",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [tuya.fz.datapoints],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting (-- Maybe needed? Copied this from another humidity sensor configuration)
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
exposes: [e.temperature(), e.humidity(), e.battery(), tuya.exposes.temperatureUnit()],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[2, "humidity", tuya.valueConverter.raw],
[4, "battery", tuya.valueConverter.raw], // maybe?
[9, "temperature_unit", tuya.valueConverter.temperatureUnitEnum],
[19, "temperature_sensitivity", tuya.valueConverter.raw], // maybe? commented this out for now
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_vvmbj46n", "_TZE284_vvmbj46n", "_TZE200_w6n8jeuu"]),
model: "ZTH05Z",
vendor: "Tuya",
description: "Temperature and humidity sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent({ queryOnDeviceAnnounce: true }),
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
exposes: [
e.temperature(),
e.humidity(),
e.battery(),
e.enum("temperature_unit", ea.STATE_SET, ["celsius", "fahrenheit"]).withDescription("Temperature unit"),
e
.numeric("max_temperature_alarm", ea.STATE_SET)
.withUnit("°C")
.withValueMin(-20)
.withValueMax(60)
.withDescription("Alarm temperature max"),
e
.numeric("min_temperature_alarm", ea.STATE_SET)
.withUnit("°C")
.withValueMin(-20)
.withValueMax(60)
.withDescription("Alarm temperature min"),
e.numeric("max_humidity_alarm", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Alarm humidity max"),
e.numeric("min_humidity_alarm", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Alarm humidity min"),
e.enum("temperature_alarm", ea.STATE, ["lower_alarm", "upper_alarm", "cancel"]).withDescription("Temperature alarm"),
e.enum("humidity_alarm", ea.STATE, ["lower_alarm", "upper_alarm", "cancel"]).withDescription("Humidity alarm"),
e
.numeric("temperature_periodic_report", ea.STATE_SET)
.withUnit("min")
.withValueMin(1)
.withValueMax(120)
.withDescription("Temp periodic report"),
e
.numeric("humidity_periodic_report", ea.STATE_SET)
.withUnit("min")
.withValueMin(1)
.withValueMax(120)
.withDescription("Humidity periodic report"),
e
.numeric("temperature_sensitivity", ea.STATE_SET)
.withUnit("°C")
.withValueMin(0.3)
.withValueMax(1)
.withValueStep(0.1)
.withDescription("Sensitivity of temperature"),
e
.numeric("humidity_sensitivity", ea.STATE_SET)
.withUnit("%")
.withValueMin(3)
.withValueMax(10)
.withValueStep(1)
.withDescription("Sensitivity of humidity"),
],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[2, "humidity", tuya.valueConverter.raw],
[4, "battery", tuya.valueConverter.raw],
[9, "temperature_unit", tuya.valueConverter.temperatureUnitEnum],
[10, "max_temperature_alarm", tuya.valueConverter.divideBy10],
[11, "min_temperature_alarm", tuya.valueConverter.divideBy10],
[12, "max_humidity_alarm", tuya.valueConverter.raw],
[13, "min_humidity_alarm", tuya.valueConverter.raw],
[
14,
"temperature_alarm",
tuya.valueConverterBasic.lookup({
lower_alarm: tuya.enum(0),
upper_alarm: tuya.enum(1),
cancel: tuya.enum(2),
}),
],
[
15,
"humidity_alarm",
tuya.valueConverterBasic.lookup({
lower_alarm: tuya.enum(0),
upper_alarm: tuya.enum(1),
cancel: tuya.enum(2),
}),
],
[17, "temperature_periodic_report", tuya.valueConverter.raw],
[18, "humidity_periodic_report", tuya.valueConverter.raw],
[19, "temperature_sensitivity", tuya.valueConverter.divideBy10],
[20, "humidity_sensitivity", tuya.valueConverter.raw],
],
},
whiteLabel: [tuya.whitelabel("ONENUO", "TH05Z", "Temperature & humidity sensor with clock and humidity display", ["_TZE200_vvmbj46n"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nvups4nh"]),
model: "TS0601_contact_temperature_humidity_sensor",
vendor: "Tuya",
description: "Contact, temperature and humidity sensor",
fromZigbee: [tuya.fz.datapoints, tuya.fz.gateway_connection_status],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.contact(), e.temperature(), e.humidity(), e.battery()],
meta: {
tuyaDatapoints: [
[1, "contact", tuya.valueConverter.trueFalseInvert],
[2, "battery", tuya.valueConverter.raw],
[7, "temperature", tuya.valueConverter.divideBy10],
[8, "humidity", tuya.valueConverter.raw],
],
},
whiteLabel: [tuya.whitelabel("Aubess", "1005005194831629", "Contact, temperature and humidity sensor", ["_TZE200_nvups4nh"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_vzqtvljm"]),
model: "TS0601_illuminance_temperature_humidity_sensor_1",
vendor: "Tuya",
description: "Illuminance, temperature & humidity sensor",
fromZigbee: [legacy.fromZigbee.tuya_illuminance_temperature_humidity_sensor],
toZigbee: [],
exposes: [e.temperature(), e.humidity(), e.illuminance(), e.battery()],
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_8ygsuhe1",
"_TZE200_yvx5lh6k",
"_TZE200_ryfmq5rl",
"_TZE200_c2fmom5z",
"_TZE200_mja3fuja",
"_TZE204_c2fmom5z",
"_TZE204_yvx5lh6k",
]),
model: "TS0601_air_quality_sensor",
vendor: "Tuya",
description: "Air quality sensor",
fromZigbee: [legacy.fromZigbee.tuya_air_quality],
toZigbee: [],
exposes: [e.temperature(), e.humidity(), e.co2(), e.voc().withUnit("ppm"), e.formaldehyd()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_rbbx5mfq"]),
model: "TS0601_illuminance_temperature_humidity_sensor_2",
vendor: "Tuya",
description: "Illuminance sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.illuminance().withUnit("lx"), e.temperature(), e.humidity()],
meta: {
tuyaDatapoints: [
[2, "illuminance", tuya.valueConverter.raw],
[6, "temperature", tuya.valueConverter.divideBy10],
[7, "humidity", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_dwcarsat", "_TZE204_dwcarsat"]),
model: "TS0601_smart_air_house_keeper",
vendor: "Tuya",
description: "Smart air house keeper",
fromZigbee: [legacy.fromZigbee.tuya_air_quality],
toZigbee: [],
exposes: [
e.temperature(),
e.humidity(),
e.co2(),
e.voc().withUnit("ppb"),
e.formaldehyd().withUnit("µg/m³"),
e.pm25().withValueMin(0).withValueMax(999).withValueStep(1),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ogkdpgy2", "_TZE200_3ejwxpmu", "_TZE204_3ejwxpmu"]),
model: "TS0601_temperature_humidity_co2_sensor",
vendor: "Tuya",
description: "NDIR co2 sensor",
fromZigbee: [legacy.fromZigbee.tuya_air_quality],
toZigbee: [],
exposes: [e.temperature(), e.humidity(), e.co2()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ogkdpgy2"]),
model: "TS0601_co2_sensor",
vendor: "Tuya",
description: "NDIR co2 sensor",
fromZigbee: [legacy.fromZigbee.tuya_air_quality],
toZigbee: [],
exposes: [e.co2()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_7bztmfm1", "_TZE204_7bztmfm1"]),
model: "DCR-CO",
vendor: "Tuya",
description: "Smart air box (carbon monoxide)",
fromZigbee: [legacy.fromZigbee.tuya_CO],
toZigbee: [],
exposes: [e.binary("carbon_monoxide", ea.STATE, "ON", "OFF").withDescription("Indicates if CO (carbon monoxide) is detected"), e.co()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ggev5fsl", "_TZE200_u319yc66", "_TZE200_kvpwq8z7"]),
model: "TS0601_gas_sensor_1",
vendor: "Tuya",
description: "Gas sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.gas(), tuya.exposes.selfTest(), tuya.exposes.selfTestResult(), tuya.exposes.faultAlarm(), tuya.exposes.silence()],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalse0],
[8, "self_test", tuya.valueConverter.raw],
[9, "self_test_result", tuya.valueConverter.selfTestResult],
[11, "fault_alarm", tuya.valueConverter.trueFalse1],
[16, "silence", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_yojqa8xn", "_TZE204_zougpkpy", "_TZE204_chbyv06x", "_TZE204_yojqa8xn", "_TZE284_chbyv06x"]),
model: "TS0601_gas_sensor_2",
vendor: "Tuya",
description: "Gas sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.gas(),
tuya.exposes.gasValue().withUnit("LEL"),
tuya.exposes.selfTest(),
tuya.exposes.selfTestResult(),
tuya.exposes.silence(),
e
.enum("alarm_ringtone", ea.STATE_SET, ["melody_1", "melody_2", "melody_3", "melody_4", "melody_5"])
.withDescription("Ringtone of the alarm"),
e.numeric("alarm_time", ea.STATE_SET).withValueMin(1).withValueMax(180).withValueStep(1).withUnit("s").withDescription("Alarm time"),
e.binary("preheat", ea.STATE, true, false).withDescription("Indicates sensor preheat is active"),
],
whiteLabel: [tuya.whitelabel("DYGSM", "DY-RQ500A", "Gas sensor", ["_TZE204_zougpkpy", "_TZE204_chbyv06x", "_TZE284_chbyv06x"])],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalseEnum0],
[2, "gas_value", tuya.valueConverter.divideBy10],
[
6,
"alarm_ringtone",
tuya.valueConverterBasic.lookup({
melody_1: tuya.enum(0),
melody_2: tuya.enum(1),
melody_3: tuya.enum(2),
melody_4: tuya.enum(3),
melody_5: tuya.enum(4),
}),
],
[7, "alarm_time", tuya.valueConverter.raw],
[8, "self_test", tuya.valueConverter.raw],
[9, "self_test_result", tuya.valueConverter.selfTestResult],
[10, "preheat", tuya.valueConverter.raw],
[13, null, null], // alarm_switch; ignore for now since it is unclear what it does
[16, "silence", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nus5kk3n"]),
model: "TS0601_gas_sensor_3",
vendor: "Tuya",
description: "Gas sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.gas(), tuya.exposes.selfTest(), tuya.exposes.selfTestResult(), tuya.exposes.faultAlarm(), tuya.exposes.silence()],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalse0],
[9, "self_test_result", tuya.valueConverter.selfTestResult],
[11, "fault_alarm", tuya.valueConverter.trueFalse1],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_mby4kbtq", "_TZE204_mby4kbtq", "_TZE204_uo8qcagc"]),
model: "TS0601_gas_sensor_4", // _TZE200_mby4kbtq looks like TS0601_gas_sensor_2
vendor: "Tuya",
description: "Gas sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.gas(),
tuya.exposes.gasValue().withUnit("LEL"),
e.binary("preheat", ea.STATE, true, false).withDescription("Indicates sensor preheat is active"),
tuya.exposes.faultAlarm(),
e.binary("alarm_switch", ea.STATE_SET, true, false),
tuya.exposes.silence(),
],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalse0],
[2, "gas_value", tuya.valueConverter.divideBy10],
[10, "preheat", tuya.valueConverter.raw],
[11, "fault_alarm", tuya.valueConverter.trueFalse1],
[13, "alarm_switch", tuya.valueConverter.raw],
[16, "silence", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-301Z"],
fingerprint: [
...tuya.fingerprint("TS0001", [
"_TZ3000_hktqahrq",
"_TZ3000_q6a3tepg",
"_TZ3000_skueekg3",
"_TZ3000_npzfdcof",
"_TZ3000_5ng23zjs",
"_TZ3000_rmjr4ufz",
"_TZ3000_v7gnj3ad",
"_TZ3000_3a9beq8a",
"_TZ3000_ark8nv4y",
"_TZ3000_mx3vgyea",
"_TZ3000_fdxihpp7",
"_TZ3000_qsp2pwtf",
"_TZ3000_kycczpw8",
"_TZ3000_46t1rvdu",
]),
...tuya.fingerprint("TS000F", [
"_TZ3000_hktqahrq",
"_TZ3000_m9af2l6g",
"_TZ3000_mx3vgyea",
"_TZ3000_skueekg3",
"_TZ3000_dlhhrhs8",
"_TZ3000_fdxihpp7",
]),
],
model: "WHD02",
vendor: "Tuya",
whiteLabel: [
{ vendor: "Tuya", model: "iHSW02" },
{
vendor: "HOBEIAN",
model: "ZG-301Z",
fingerprint: [{ modelID: "ZG-301Z" }],
},
tuya.whitelabel("Tuya", "QS-zigbee-S08-16A-RF", "Wall switch module", ["_TZ3000_dlhhrhs8"]),
],
description: "Wall switch module",
extend: [tuya.modernExtend.tuyaOnOff({ switchType: true, onOffCountdown: true })],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS011F", [
"_TZ3000_mvn6jl7x",
"_TZ3000_raviyuvk",
"_TYZB01_hlla45kx",
"_TZ3000_92qd4sqa",
"_TZ3000_zwaadvus",
"_TZ3000_k6fvknrr",
"_TZ3000_6s5dc9lx",
"_TZ3000_helyqdvs",
"_TZ3000_rgpqqmbj",
"_TZ3000_8nyaanzb",
"_TZ3000_iy2c3n6p",
"_TZ3000_qlmnxmac",
"_TZ3000_sgb0xhwn",
]),
model: "TS011F_2_gang_wall",
vendor: "Tuya",
description: "2 gang wall outlet",
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeLowMediumHigh: true,
childLock: true,
endpoints: ["l1", "l2"],
}),
],
whiteLabel: [
tuya.whitelabel("ClickSmart+", "CMA30036", "2 gang socket outlet", ["_TYZB01_hlla45kx"]),
tuya.whitelabel("Rylike", "RY-WS02Z", "2 gang socket outlet AU", ["_TZ3000_rgpqqmbj", "_TZ3000_8nyaanzb", "_TZ3000_iy2c3n6p"]),
tuya.whitelabel("Nova Digital", "NT-S2", "2 gang socket outlet BR", ["_TZ3000_sgb0xhwn"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true, multiEndpointSkip: ["power_on_behavior"] },
configure: tuya.configureMagicPacket,
},
{
fingerprint: [
...tuya.fingerprint("TS011F", ["_TZ3000_rk2yzt0u", "_TZ3000_o4cjetlm"]),
...tuya.fingerprint("TS0001", [
"_TZ3000_o4cjetlm",
"_TZ3000_iedbgyxt",
"_TZ3000_h3noz0a5",
"_TYZB01_4tlksk8a",
"_TZ3000_5ucujjts",
"_TZ3000_h8ngtlxy",
"_TZ3000_w0ypwa1f",
"_TZ3000_wpueorev",
"_TZ3000_cmcjbqup",
]),
...tuya.fingerprint("TS0011", ["_TYZB01_rifa0wlb"]),
],
model: "ZN231392",
vendor: "Tuya",
description: "Smart water/gas valve",
extend: [tuya.modernExtend.tuyaOnOff({ indicatorMode: true })],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await endpoint.read("genOnOff", ["onOff", "moesStartUpOnOff"]);
},
},
{
zigbeeModel: ["CK-BL702-AL-01(7009_Z102LG03-1)", "CK-BL702-AL-01(7009_Z102LG04-1)", "CK-BL702-AL-01(7009_Z102LG04-2)"],
model: "CK-BL702-AL-01",
vendor: "Tuya",
description: "Zigbee LED bulb",
extend: [
tuya.modernExtend.tuyaLight({
colorTemp: { range: [142, 500] },
color: true,
}),
],
},
{
zigbeeModel: ["SM0001"],
model: "SM0001",
vendor: "Tuya",
description: "Switch",
extend: [tuya.modernExtend.tuyaOnOff()],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [tuya.whitelabel("Zemismart", "ZM-H7", "Hand wave wall smart switch", ["_TZ3000_jcqs2mrv"])],
},
{
zigbeeModel: ["TS0505"],
model: "TS0505",
vendor: "Tuya",
description: " GU10 zbeacon Zigbee LED bulb",
extend: [
m.light({
colorTemp: { range: [153, 500] },
color: { modes: ["xy", "hs"] },
}),
],
},
{
zigbeeModel: ["TS0505B"],
model: "TS0505B_1",
vendor: "Tuya",
description: "Zigbee RGB+CCT light",
whiteLabel: [
{ vendor: "Mercator Ikuü", model: "SMD4106W-RGB-ZB" },
{ vendor: "Tuya", model: "A5C-21F7-01" },
{ vendor: "Mercator Ikuü", model: "S9E27LED9W-RGB-Z" },
{
vendor: "Aldi",
model: "L122CB63H11A9.0W",
description: "LIGHTWAY smart home LED-lamp - bulb",
},
{
vendor: "Lidl",
model: "14153706L",
description: "Livarno smart LED ceiling light",
},
{
vendor: "Zemismart",
model: "LXZB-ZB-09A",
description: "Zemismart LED Surface Mounted Downlight 9W RGBW",
},
{
vendor: "Feconn",
model: "FE-GU10-5W",
description: "Zigbee GU10 5W smart bulb",
},
{ vendor: "Nedis", model: "ZBLC1E14" },
tuya.whitelabel("Aldi", "L122FF63H11A5.0W", "LIGHTWAY smart home LED-lamp - spot", ["_TZ3000_j0gtlepx"]),
tuya.whitelabel("Aldi", "L122AA63H11A6.5W", "LIGHTWAY smart home LED-lamp - candle", ["_TZ3000_iivsrikg"]),
tuya.whitelabel("Aldi", "C422AC11D41H140.0W", "MEGOS LED panel RGB+CCT 40W 3600lm 62 x 62 cm", ["_TZ3000_v1srfw9x"]),
tuya.whitelabel("Aldi", "C422AC14D41H140.0W", "MEGOS LED panel RGB+CCT 40W 3600lm 30 x 120 cm", ["_TZ3000_gb5gaeca"]),
tuya.whitelabel("Lidl", "14156506L", "Livarno Lux smart LED mood light", ["_TZ3210_r0xgkft5"]),
tuya.whitelabel("Lidl", "HG08010", "Livarno Home outdoor spotlight", ["_TZ3210_umi6vbsz"]),
tuya.whitelabel("Lidl", "HG08008", "Livarno Home LED ceiling light", ["_TZ3210_p9ao60da"]),
tuya.whitelabel("Lidl", "14158704L", "Livarno Home LED floor lamp, RGBW", ["_TZ3210_z1vlyufu"]),
tuya.whitelabel("Lidl", "14158804L", "Livarno Home LED desk lamp RGBW", ["_TZ3210_hxtfthp5"]),
tuya.whitelabel("Lidl", "HG07834A/HG09155A/HG08131A", "Livarno Home GU10 spot RGB+CCT", ["_TZ3000_quqaeew6"]),
tuya.whitelabel("Lidl", "HG07834B/HG09155B/HG08131B", "Livarno Home E14 candle RGB+CCT", ["_TZ3000_th6zqqy6"]),
tuya.whitelabel("Lidl", "HG07834B", "Livarno Home E14 candle RGB+CCT", ["_TZ3000_wr6g6olr"]),
tuya.whitelabel("Lidl", "HG08131C", "Livarno Home outdoor E27 bulb in set with flare", ["_TZ3000_q50zhdsc"]),
tuya.whitelabel("Lidl", "HG07834C/HG09155C/HG08131C", "Livarno Home E27 bulb RGB+CCT", ["_TZ3000_qd7hej8u"]),
tuya.whitelabel("Lidl", "HG08383B", "Livarno outdoor LED light chain", ["_TZ3000_bwlvyjwk"]),
tuya.whitelabel("Lidl", "HG08383A", "Livarno outdoor LED light chain", ["_TZ3000_taspddvq"]),
tuya.whitelabel("Garza Smart", "Garza-Standard-A60", "Standard A60 bulb", ["_TZ3210_sln7ah6r"]),
tuya.whitelabel("UR Lighting", "TH008L10RGBCCT", "10W RGB+CCT downlight", ["_TZ3210_dn5higyl", "_TZ3210_hicxa0rh"]),
tuya.whitelabel("Lidl", "HG08007", "Livarno Home outdoor LED band", ["_TZ3210_zbabx9wh"]),
tuya.whitelabel("Lidl", "399629_2110", "Livarno Lux Ceiling Panel RGB+CCT", ["_TZ3210_c0s1xloa", "_TZ3210_x13bu7za"]),
tuya.whitelabel("Nous", "P3Z", "Smart light bulb", ["_TZ3210_cieijuw1"]),
tuya.whitelabel("Moes", "ZLD-RCW_1", "RGB+CCT Zigbee LED controller", ["_TZ3000_7hcgjxpc"]),
tuya.whitelabel("Moes", "ZB-TD5-RCW-GU10", "RGB+CCT 4.7W GU10 LED bulb", ["_TZ3210_rcggc0ys"]),
tuya.whitelabel("Moes", "ZB-TDA9-RCW-E27-MS", "RGB+CCT 9W E27 LED bulb", ["_TZ3210_wxa85bwk"]),
tuya.whitelabel("Moes", "ZB-LZD10-RCW", "10W RGB+CCT Smart Downlight", ["_TZ3210_s9lumfhn", "_TZ3210_jjqdqxfq", "_TZ3210_dwzfzfjc"]),
tuya.whitelabel("Moes", "ZB-TDC6-RCW-E14", "RGB+CCT 5W E14 LED bulb", ["_TZ3210_ifga63rg"]),
tuya.whitelabel("MiBoxer", "E3-ZR", "3 in 1 LED Controller", ["_TZB210_wy1pyu1q"]),
tuya.whitelabel("MiBoxer", "FUT037Z+", "RGB led controller", ["_TZB210_417ikxay", "_TZB210_wxazcmsh"]),
tuya.whitelabel("MiBoxer", "FUT039Z", "RGB+CCT LED controller", ["_TZ3210_jicmoite", "_TZB210_rs0ufzwg"]),
tuya.whitelabel("MiBoxer", "FUT066Z", "RGB+CCT LED Downlight", ["_TZ3210_zrvxvydd"]),
tuya.whitelabel("MiBoxer", "FUT103ZR", "GU10 RGB+CCT", ["_TZB210_6eed09b9"]),
tuya.whitelabel("MiBoxer", "FUT106ZR", "GU10 RGB+CCT", ["_TZB210_rwy5hexp", "_TZB210_lnnkh3f9"]),
tuya.whitelabel("Tuya", "TS0505B_1_1", "Zigbee 3.0 18W led light bulb E27 RGBCW", [
"_TZ3210_jd3z4yig",
"_TZ3210_r5afgmkl",
"_TZ3210_mja6r5ix",
]),
tuya.whitelabel("MiBoxer", "FUTC11ZR", "Outdoor light", ["_TZB210_zmppwawa"]),
tuya.whitelabel("TechToy", "_TZ3210_iw0zkcu8", "Smart bulb RGB 9W E27", ["_TZ3210_iw0zkcu8"]),
],
extend: [
tuya.modernExtend.tuyaLight({
colorTemp: { range: [153, 500] },
color: true,
}),
],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 29,
});
},
},
{
fingerprint: tuya.fingerprint("TS0505B", ["_TZ3210_iystcadi", "_TZ3210_it1u8ahz"]),
model: "TS0505B_2",
vendor: "Tuya",
description: "Zigbee RGB+CCT light",
whiteLabel: [
tuya.whitelabel("Lidl", "14149505L/14149506L_2", "Livarno Lux light bar RGB+CCT (black/white)", ["_TZ3210_iystcadi"]),
tuya.whitelabel("Tuya", "TS0505B_2_2", "Zigbee GU10/E14 5W smart bulb", ["_TZ3210_it1u8ahz"]),
],
toZigbee: [tz.on_off, tzLocal.led_control, tuya.tz.do_not_disturb],
fromZigbee: [fz.on_off, fz.tuya_led_controller, fz.brightness, fz.ignore_basic_report],
exposes: [e.light_brightness_colortemp_colorhs([143, 500]).removeFeature("color_temp_startup"), tuya.exposes.doNotDisturb()],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 29,
});
},
},
{
fingerprint: tuya.fingerprint("TS0505B", ["_TZB210_3zfp8mki", "_TZB210_gj0ccsar"]),
model: "TS0505B_3",
vendor: "Tuya",
description: "Zigbee RGB+CCT light",
whiteLabel: [
tuya.whitelabel("Skydance", "WZ5_dim_2", "Zigbee & RF 5 in 1 LED controller (DIM mode)", ["_TZB210_3zfp8mki"]),
tuya.whitelabel("QA", "QADZC5", "5 in 1 LED controller", ["_TZB210_gj0ccsar"]),
],
extend: [
m.light({
colorTemp: { range: [153, 500] },
color: { modes: ["hs"], applyRedFix: true, enhancedHue: false },
}),
],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 29,
});
},
},
{
fingerprint: tuya.fingerprint("TS0505B", ["_TZ3210_bfwvfyx1"]),
model: "CK-BL702-AL-01_1",
vendor: "eWeLink",
description: "Zigbee 3.0 15W led light bulb E27 RGBCW",
toZigbee: [tuya.tz.do_not_disturb],
extend: [m.light({ colorTemp: { range: [50, 500], startup: false }, effect: false, powerOnBehavior: false, color: { modes: ["xy", "hs"] } })],
exposes: [tuya.exposes.doNotDisturb()],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", { colorCapabilities: 29 });
},
},
{
zigbeeModel: ["TS0503B"],
model: "TS0503B",
vendor: "Tuya",
description: "Zigbee RGB light",
whiteLabel: [{ vendor: "BTF-Lighting", model: "C03Z" }, tuya.whitelabel("MiBoxer", "FUT037Z", "RGB led controller", ["_TZ3210_778drfdt"])],
extend: [tuya.modernExtend.tuyaLight({ color: true })],
},
{
zigbeeModel: ["TS0504B"],
model: "TS0504B",
vendor: "Tuya",
description: "Zigbee RGBW light",
toZigbee: [tzLocal.TS0504B_color],
extend: [tuya.modernExtend.tuyaLight({ color: true })],
},
{
zigbeeModel: ["TS0501A"],
model: "TS0501A",
description: "Zigbee light",
vendor: "Tuya",
extend: [tuyaLight()],
whiteLabel: [
tuya.whitelabel("Lidl", "HG06463A", "Livarno Lux E27 ST64 filament bulb", ["_TZ3000_j2w1dw29"]),
tuya.whitelabel("Lidl", "HG06463B", "Livarno Lux E27 G95 filament bulb", ["_TZ3000_nosnx7im"]),
tuya.whitelabel("Lidl", "HG06462A", "Livarno Lux E27 A60 filament bulb", ["_TZ3000_7dcddnye", "_TZ3000_nbnmw9nc"]),
],
},
{
fingerprint: tuya.fingerprint("TS0501B", ["_TZB210_rkgngb5o"]),
model: "TS0501B_dimmer",
description: "Zigbee dimmer",
vendor: "Tuya",
extend: [tuyaLight({ configureReporting: true, effect: false })],
whiteLabel: [tuya.whitelabel("Tuya", "L1(ZW)", "Light dimmer 0-10V", ["_TZB210_rkgngb5o"])],
},
{
fingerprint: tuya.fingerprint("TS0501B", ["_TZB210_g01ie5wu"]),
model: "TS0501B_dimmer_2",
description: "Zigbee dimmer",
vendor: "Tuya",
extend: [tuyaLight({ minBrightness: "command", effect: false })],
},
{
zigbeeModel: ["TS0501B"],
model: "TS0501B",
description: "Zigbee light",
vendor: "Tuya",
extend: [tuyaLight()],
whiteLabel: [
tuya.whitelabel("MiBoxer", "FUT036Z", "Single color LED controller", ["_TZ3210_dxroobu3", "_TZ3210_dbilpfqk"]),
tuya.whitelabel("Mercator Ikuü", "SMFL20W-ZB", "Ridley Floodlight", ["_TZ3000_juq7i1fr"]),
],
},
{
fingerprint: tuya.fingerprint("TS0202", ["_TYZB01_vwqnz1sn"]),
model: "TS0202_3",
vendor: "Tuya",
description: "Motion detector with illuminance",
fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_occupancy_alarm_1_report],
toZigbee: [],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [e.occupancy(), e.battery_low(), e.battery(), e.tamper()],
extend: [m.illuminance()],
},
{
fingerprint: tuya.fingerprint("TS0202", ["_TZ3210_cwamkvua"]),
model: "TS0202_2",
vendor: "Tuya",
description: "Motion sensor with scene switch",
fromZigbee: [tuya.fz.datapoints, fz.ias_occupancy_alarm_1, fz.battery],
toZigbee: [tuya.tz.datapoints],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
},
exposes: [
e.battery(),
e.battery_voltage(),
e.occupancy(),
e.action(["single", "double", "hold"]),
e.enum("light", ea.STATE, ["dark", "bright"]),
],
meta: {
tuyaDatapoints: [
[102, "light", tuya.valueConverterBasic.lookup({ dark: false, bright: true })],
[101, "action", tuya.valueConverterBasic.lookup({ single: 0, double: 1, hold: 2 })],
],
},
whiteLabel: [{ vendor: "Linkoze", model: "LKMSZ001" }],
},
{
fingerprint: tuya.fingerprint("TS0202", ["_TYZB01_jytabjkb", "_TZ3000_lltemgsf", "_TYZB01_5nr7ncpl", "_TZ3000_mg4dy6z6", "_TZ3000_bsvqrxru"]),
model: "TS0202_1",
vendor: "Tuya",
description: "Motion sensor",
// Requires alarm_1_with_timeout https://github.com/Koenkk/zigbee2mqtt/issues/2818#issuecomment-776119586
fromZigbee: [fz.ias_occupancy_alarm_1_with_timeout, fz.battery, fz.ignore_basic_report],
toZigbee: [],
exposes: [e.occupancy(), e.battery_low(), e.battery(), e.battery_voltage()],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
fingerprint: tuya.fingerprint("WHD02", ["_TZ3000_hktqahrq"]),
zigbeeModel: ["TS0202"],
model: "TS0202",
vendor: "Tuya",
description: "Motion sensor",
whiteLabel: [
{ vendor: "Mercator Ikuü", model: "SMA02P" },
{ vendor: "Tuya", model: "TY-ZPR06" },
{ vendor: "Tesla Smart", model: "TS0202" },
tuya.whitelabel("MiBoxer", "PIR1-ZB", "PIR sensor", ["_TZ3040_wqmtjsyk"]),
tuya.whitelabel("Tuya", "ZMS01", "Motion sensor", ["_TZ3000_otvn3lne"]),
tuya.whitelabel("Nous", "E2", "Motion sensor", ["_TZ3000_h4wnrtck"]),
tuya.whitelabel("Tuya", "809WZT", "Motion sensor", ["_TZ3040_bb6xaihh"]),
tuya.whitelabel("Niceboy", "ORBIS Motion Sensor", "Motion sensor", ["_TZ3000_qomxlryd"]),
tuya.whitelabel("Luminea", "ZX-5311", "Motion sensor", ["_TZ3000_jmrgyl7o"]),
tuya.whitelabel("Tuya", "ZP01", "Motion sensor", ["_TZ3000_lf56vpxj"]),
tuya.whitelabel("Tuya", "HW500A", "Motion sensor", ["_TZ3000_bsvqrxru"]),
tuya.whitelabel("Nedis", "ZBSM10WT", "Motion sensor", ["_TZ3000_nss8amz9"]),
],
fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_occupancy_alarm_1_report],
toZigbee: [],
exposes: (device, options) => {
const exps = [e.occupancy(), e.battery_low(), e.battery(), e.battery_voltage()];
if (!device || !["_TZ3000_bsvqrxru", "_TZ3000_nss8amz9"].includes(device.manufacturerName)) {
exps.push(e.tamper());
}
return exps;
},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
try {
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
}
catch {
/* Fails for some https://github.com/Koenkk/zigbee2mqtt/issues/13708 */
}
},
},
{
fingerprint: tuya.fingerprint("TS0202", ["_TZ3040_fwxuzcf4", "_TZ3040_msl6wxk9"]),
model: "ZM-35H-Q",
vendor: "Tuya",
description: "Motion sensor",
fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ZM35HQ_attr, legacy.fromZigbee.ZM35HQ_battery],
toZigbee: [tz.ZM35HQ_attr],
extend: [m.quirkCheckinInterval(15000)],
exposes: [
e.occupancy(),
e.battery_low(),
e.battery(),
e.enum("sensitivity", ea.ALL, ["low", "medium", "high"]).withDescription("PIR sensor sensitivity"),
e.enum("keep_time", ea.ALL, [30, 60, 120]).withDescription("PIR keep time in seconds"),
],
configure: tuya.configureMagicPacket,
whiteLabel: [tuya.whitelabel("Aubess", "40ZH-O", "Motion sensor", ["_TZ3040_msl6wxk9"])],
},
{
zigbeeModel: ["ZG-204Z"],
fingerprint: tuya.fingerprint("TS0202", ["_TZ3000_mcxw5ehu", "_TZ3000_6ygjfyll", "_TZ3040_6ygjfyll", "_TZ3000_msl6wxk9"]),
model: "IH012-RT01",
vendor: "Tuya",
description: "Motion sensor",
fromZigbee: [fz.ignore_basic_report, fz.ZM35HQ_attr, fz.battery],
toZigbee: [tz.ZM35HQ_attr],
extend: [
m.quirkCheckinInterval(15000),
// Occupancy reporting interval is 60s, so allow for one dropped update plus a small safety margin of 5s
m.iasZoneAlarm({
zoneType: "occupancy",
zoneAttributes: ["alarm_1", "battery_low"],
keepAliveTimeout: 125,
}),
],
exposes: [
e.battery(),
e.battery_voltage(),
e.enum("sensitivity", ea.ALL, ["low", "medium", "high"]).withDescription("PIR sensor sensitivity"),
e.enum("keep_time", ea.ALL, [30, 60, 120]).withDescription("PIR keep time in seconds"),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
},
whiteLabel: [
{
vendor: "HOBEIAN",
model: "ZG-204Z",
fingerprint: [{ modelID: "ZG-204Z" }],
},
tuya.whitelabel("Tuya", "ZMS-102", "Motion sensor", ["_TZ3000_msl6wxk9"]),
],
},
{
fingerprint: tuya.fingerprint("TS0202", ["_TZ3000_o4mkahkc"]),
model: "IH012-RT02",
vendor: "Tuya",
description: "Motion sensor",
fromZigbee: [fz.ias_occupancy_alarm_1, fz.ignore_basic_report, fz.ZM35HQ_attr, fz.battery],
toZigbee: [tz.ZM35HQ_attr],
extend: [m.quirkCheckinInterval(15000)],
exposes: [
e.occupancy(),
e.battery_low(),
e.tamper(),
e.battery(),
e.battery_voltage(),
e.enum("sensitivity", ea.ALL, ["low", "medium", "high"]).withDescription("PIR sensor sensitivity"),
e.enum("keep_time", ea.ALL, [30, 60, 120]).withDescription("PIR keep time in seconds"),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
},
},
{
fingerprint: [
...tuya.fingerprint("TS0207", [
"_TZ3000_m0vaazab",
"_TZ3000_ufttklsz",
"_TZ3000_nkkl7uzv",
"_TZ3000_misw04hq",
"_TZ3000_nlsszmzl",
"_TZ3000_gszjt2xx",
"_TZ3000_wlquqiiz",
"_TZ3000_5k5vh43t",
"_TZ3000_kxlmv9ag",
"_TZ3000_wmlc9p9z",
"_TZ3000_shopg9ss",
"_TZ3000_n0lphcok",
]),
...tuya.fingerprint("TS0001", ["_TZ3000_n0lphcok"]),
],
model: "TS0207_repeater",
vendor: "Tuya",
description: "Repeater",
fromZigbee: [fz.linkquality_from_basic],
toZigbee: [],
whiteLabel: [tuya.whitelabel("Tuya", "TS0001_repeater", "Zigbee signal repeater", ["_TZ3000_n0lphcok"])],
exposes: [],
},
{
zigbeeModel: ["TS0207", "FNB54-WTS08ML1.0", "ZG-222Z"],
model: "TS0207_water_leak_detector",
vendor: "Tuya",
description: "Water leak detector",
fromZigbee: [fz.ias_water_leak_alarm_1, fz.battery, fz.ignore_basic_report],
whiteLabel: [
{ vendor: "CR Smart Home", model: "TS0207" },
{
vendor: "HOBEIAN",
model: "ZG-222Z",
fingerprint: [{ modelID: "ZG-222Z" }],
},
tuya.whitelabel("Meian", "SW02", "Water leak sensor", ["_TZ3000_kyb656no"]),
tuya.whitelabel("Aubess", "IH-K665", "Water leak sensor", ["_TZ3000_kstbkt6a"]),
tuya.whitelabel("HOBEIAN", "ZG-222ZA", "Water leak sensor", ["_TZ3000_k4ej3ww2"]),
tuya.whitelabel("Tuya", "TS0207_water_leak_detector_1", "Zigbee water flood sensor + 1m probe cable", [
"_TZ3000_ocjlo4ea",
"_TZ3000_upgcbody",
]),
tuya.whitelabel("Tuya", "TS0207_water_leak_detector_3", "Zigbee water leak sensor", ["_TYZB01_sqmd19i1"]),
tuya.whitelabel("Moes", "ZSS-QY-WL-C-MS", "Zigbee water leak sensor", ["_TZ3000_t6jriawg"]),
tuya.whitelabel("Tuya", "899WZ", "Water leak detector with 80DB Alarm", ["_TZ3000_mugyhz0q"]),
tuya.whitelabel("Niceboy", "ORBIS Water Sensor", "Water leak sensor", ["_TZ3000_awvmkayh"]),
tuya.whitelabel("Nous", "E4", "Water Leakage Sensor)", ["_TZ3000_0s9gukzt"]),
],
toZigbee: [],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
},
exposes: (device, options) => {
const exps = [e.water_leak(), e.battery_low(), e.battery()];
const noTamperModels = [
// manufacturerName for models without a tamper sensor
"_TZ3000_mugyhz0q", // Tuya 899WZ
"_TZ3000_k4ej3ww2", // Aubess IH-K665
"_TZ3000_kstbkt6a", // Aubess IH-K665
"_TZ3000_upgcbody", // Zigbee water leak sensor
];
if (!device || !noTamperModels.includes(device.manufacturerName)) {
exps.push(e.tamper());
}
return exps;
},
},
{
fingerprint: tuya.fingerprint("TS0207", ["_TZ3210_tgvtvdoc"]),
model: "RB-SRAIN01",
vendor: "Tuya",
description: "Solar rain sensor",
fromZigbee: [tuya.fz.datapoints],
extend: [m.iasZoneAlarm({ zoneType: "rain", zoneAttributes: ["alarm_1"] }), m.battery({ percentageReporting: false })],
exposes: [
e.illuminance().withUnit("lx"),
e.numeric("illuminance_average_20min", ea.STATE).withUnit("lx").withDescription("Illuminance average for the last 20 minutes"),
e.numeric("illuminance_maximum_today", ea.STATE).withUnit("lx").withDescription("Illuminance maximum for the last 24 hours"),
e.binary("cleaning_reminder", ea.STATE, true, false).withDescription("Cleaning reminder"),
e.numeric("rain_intensity", ea.STATE).withUnit("mV").withDescription("Rainfall intensity"),
],
meta: {
tuyaDatapoints: [
[4, "battery", tuya.valueConverter.raw],
[101, "illuminance", tuya.valueConverter.raw],
[102, "illuminance_average_20min", tuya.valueConverter.raw],
[103, "illuminance_maximum_today", tuya.valueConverter.raw],
[104, "cleaning_reminder", tuya.valueConverter.trueFalse0],
[105, "rain_intensity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0101", ["_TYZB01_ijihzffk", "_TZ3210_tfxwxklq", "_TZ3210_2dfy6tol"]),
model: "TS0101",
vendor: "Tuya",
description: "Zigbee Socket",
whiteLabel: [
{ vendor: "Larkkey", model: "PS080" },
{ vendor: "Mercator Ikuü", model: "SPBS01G" },
tuya.whitelabel("Mercator Ikuü", "SISW01", "Inline Switch", ["_TZ3210_2dfy6tol"]),
],
extend: [tuya.modernExtend.tuyaOnOff()],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0108", ["_TYZB01_7yidyqxd"]),
model: "TS0108",
vendor: "Tuya",
description: "Socket with 2 USB",
whiteLabel: [{ vendor: "Larkkey", model: "PS580" }],
extend: [tuya.modernExtend.tuyaOnOff()],
exposes: [e.switch().withEndpoint("l1"), e.switch().withEndpoint("l2")],
endpoint: (device) => {
return { l1: 1, l2: 7 };
},
meta: { multiEndpoint: true, disableDefaultResponse: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(7), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_myd45weu",
"_TZE200_ga1maeof",
"_TZE200_2se8efxh",
"_TZE204_myd45weu",
"_TZE284_myd45weu",
"_TZE284_oitavov2",
]),
model: "TS0601_soil",
vendor: "Tuya",
description: "Soil sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.temperature(), e.soil_moisture(), tuya.exposes.temperatureUnit(), e.battery(), tuya.exposes.batteryState()],
meta: {
tuyaDatapoints: [
[3, "soil_moisture", tuya.valueConverter.raw],
[5, "temperature", tuya.valueConverter.raw],
[9, "temperature_unit", tuya.valueConverter.temperatureUnit],
[14, "battery_state", tuya.valueConverter.batteryState],
[15, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_g2e6cpnw", "_TZE284_sgabhwa6"]),
model: "TS0601_soil_2",
vendor: "Tuya",
description: "Soil sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.soil_moisture(),
e.numeric("temperature", ea.STATE).withUnit("°C").withValueMin(-10).withValueMax(60).withDescription("Soil temperature"),
e.numeric("temperature_f", ea.STATE).withUnit("°F").withValueMin(14).withValueMax(140).withDescription("Soil temperature"),
e
.numeric("temperature_sensitivity", ea.STATE_SET)
.withUnit("°C")
.withValueMin(0.3)
.withValueMax(1)
.withValueStep(0.1)
.withDescription("Temperature sensitivity"),
e.numeric("humidity_sensitivity", ea.STATE_SET).withUnit("%").withValueMin(1).withValueMax(5).withDescription("Humidity sensitivity"),
e.enum("temperature_alarm", ea.STATE, ["lower_alarm", "upper_alarm", "cancel"]).withDescription("Temperature alarm state"),
e.enum("humidity_alarm", ea.STATE, ["lower_alarm", "upper_alarm", "cancel"]).withDescription("Humidity alarm state"),
e
.numeric("max_temperature_alarm", ea.STATE_SET)
.withUnit("°C")
.withValueMin(0)
.withValueMax(60)
.withDescription("Upper temperature limit"),
e
.numeric("min_temperature_alarm", ea.STATE_SET)
.withUnit("°C")
.withValueMin(0)
.withValueMax(60)
.withDescription("Lower temperature limit"),
e.numeric("max_humidity_alarm", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Upper humidity limit"),
e.numeric("min_humidity_alarm", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Lower humidity limit"),
e.numeric("schedule_periodic", ea.STATE_SET).withUnit("min").withValueMin(5).withValueMax(60).withDescription("Report sensitivity"),
e.battery(),
tuya.exposes.batteryState(),
],
meta: {
tuyaDatapoints: [
[
101,
"temperature_alarm",
tuya.valueConverterBasic.lookup({
lower_alarm: tuya.enum(0),
upper_alarm: tuya.enum(1),
cancel: tuya.enum(2),
}),
],
[
102,
"humidity_alarm",
tuya.valueConverterBasic.lookup({
lower_alarm: tuya.enum(0),
upper_alarm: tuya.enum(1),
cancel: tuya.enum(2),
}),
],
[3, "soil_moisture", tuya.valueConverter.raw],
[5, "temperature", tuya.valueConverter.divideBy10],
[110, "temperature_f", tuya.valueConverter.divideBy10],
[107, "temperature_sensitivity", tuya.valueConverter.divideBy10],
[108, "humidity_sensitivity", tuya.valueConverter.raw],
[103, "max_temperature_alarm", tuya.valueConverter.divideBy10],
[104, "min_temperature_alarm", tuya.valueConverter.divideBy10],
[105, "max_humidity_alarm", tuya.valueConverter.raw],
[106, "min_humidity_alarm", tuya.valueConverter.raw],
[109, "schedule_periodic", tuya.valueConverter.raw],
[15, "battery", tuya.valueConverter.raw],
[14, "battery_state", tuya.valueConverter.batteryState],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_aao3yzhs", "_TZE284_nhgdf6qr", "_TZE284_ap9owrsa"]),
model: "TS0601_soil_3",
vendor: "Tuya",
description: "Soil sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.temperature(), e.soil_moisture(), tuya.exposes.temperatureUnit(), e.battery(), tuya.exposes.batteryState()],
meta: {
tuyaDatapoints: [
[3, "soil_moisture", tuya.valueConverter.raw],
[5, "temperature", tuya.valueConverter.divideBy10],
[9, "temperature_unit", tuya.valueConverter.temperatureUnit],
[14, "battery_state", tuya.valueConverter.batteryState],
[15, "battery", tuya.valueConverterBasic.scale(6, 60, 0, 100)], //device reports back false scaling
],
},
whiteLabel: [tuya.whitelabel("GIEX", "GX04", "Soil Moisture Sensor", ["_TZE284_nhgdf6qr"])],
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_ip2akl4w",
"_TZE200_1agwnems",
"_TZE200_la2c2uo9",
"_TZE200_579lguh2",
"_TZE200_vucankjx",
"_TZE200_4mh6tyyo",
"_TZE204_hlx9tnzb",
"_TZE204_n9ctkb6j",
"_TZE204_9qhuzgo0",
"_TZE200_9cxuhakf",
"_TZE200_a0syesf5",
"_TZE200_3p5ydos3",
"_TZE200_swaamsoy",
"_TZE200_ojzhk75b",
"_TZE200_w4cryh2i",
"_TZE200_dfxkcots",
"_TZE204_68utemio",
"_TZE200_9i9dt8is",
"_TZE200_ctq0k47x",
"_TZE200_ebwgzdqq",
"_TZE204_vevc4c6g",
"_TZE200_0nauxa0p",
"_TZE200_ykgar0ow",
"_TZE200_0hb4rdnp",
]),
model: "TS0601_dimmer_1_gang_1",
vendor: "Tuya",
description: "1 gang smart dimmer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: (device, options) => {
const exps = [
tuya.exposes.lightBrightnessWithMinMax(),
tuya.exposes.countdown(),
e.power_on_behavior().withAccess(ea.STATE_SET),
];
if (!device || !["_TZE200_ykgar0ow", "_TZE200_0hb4rdnp"].includes(device.manufacturerName)) {
exps.push(tuya.exposes.lightType(), tuya.exposes.backlightModeOffNormalInverted().withAccess(ea.STATE_SET));
}
return exps;
},
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "brightness", tuya.valueConverter.scale0_254to0_1000],
[3, "min_brightness", tuya.valueConverter.scale0_254to0_1000],
[4, "light_type", tuya.valueConverter.lightType],
[5, "max_brightness", tuya.valueConverter.scale0_254to0_1000],
[6, "countdown", tuya.valueConverter.countdown],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehavior],
[21, "backlight_mode", tuya.valueConverter.backlightModeOffNormalInverted],
],
},
whiteLabel: [
{ vendor: "Lerlink", model: "X706U" },
{ vendor: "Moes", model: "ZS-EUD_1gang" },
{ vendor: "Larkkey", model: "ZSTY-SM-1DMZG-EU" },
{ vendor: "Earda", model: "EDM-1ZAA-EU" },
{ vendor: "Earda", model: "EDM-1ZAB-EU" },
{ vendor: "Earda", model: "EDM-1ZBA-EU" },
{ vendor: "Mercator Ikuü", model: "SSWD01" },
{ vendor: "Moes", model: "ZS-USD" },
{ vendor: "Moes", model: "EDM-1ZBB-EU" },
tuya.whitelabel("Moes", "ZS-SR-EUD-1", "Star ring smart dimmer switch 1 gang", ["_TZE204_hlx9tnzb"]),
tuya.whitelabel("Moes", "MS-105Z", "Smart Dimmer module", ["_TZE200_la2c2uo9"]),
tuya.whitelabel("Mercator Ikuü", "SSWM-DIMZ", "Switch Mechanism", ["_TZE200_9cxuhakf"]),
tuya.whitelabel("Zemismart", "ZN2S-US1-SD", "Single gang dimmer", ["_TZE204_68utemio"]),
tuya.whitelabel("Mercator Ikuü", "SSWRM-ZB", "Rotary dimmer mechanism", ["_TZE200_a0syesf5"]),
tuya.whitelabel("Lonsonho", "EDM-1ZBB-EU", "Smart Dimmer Switch", ["_TZE200_0nauxa0p"]),
tuya.whitelabel("ION Industries", "ID200W-ZIGB", "LED Zigbee Dimmer", ["_TZE200_ykgar0ow"]),
tuya.whitelabel("ION Industries", "90.500.090", "Zigbee Dimmer Master/Slave set", ["_TZE200_0hb4rdnp"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_whpb9yts"]),
model: "TS0601_dimmer_1_gang_2",
vendor: "Tuya",
description: "1 gang smart dimmer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.lightBrightness(),
tuya.exposes.countdown(),
tuya.exposes.lightType(),
e.power_on_behavior().withAccess(ea.STATE_SET),
tuya.exposes.backlightModeOffNormalInverted().withAccess(ea.STATE_SET),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[3, "brightness", tuya.valueConverter.scale0_254to0_1000],
[4, "light_type", tuya.valueConverter.lightType],
[5, "max_brightness", tuya.valueConverter.scale0_254to0_1000],
[6, "countdown", tuya.valueConverter.countdown],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehavior],
[21, "backlight_mode", tuya.valueConverter.backlightModeOffNormalInverted],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_qzaing2g"]),
model: "TS0601_dimmer_1_gang_3",
vendor: "Tuya",
description: "1 gang smart dimmer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [tuya.exposes.lightBrightness(), e.voltage(), e.current(), e.power(), e.child_lock(), tuya.exposes.backlightModeOffOn()],
meta: {
tuyaDatapoints: [
[16, "backlight_mode", tuya.valueConverter.onOff],
[21, "current", tuya.valueConverter.divideBy1000],
[22, "power", tuya.valueConverter.divideBy10],
[23, "voltage", tuya.valueConverter.divideBy10],
[101, "child_lock", tuya.valueConverter.lockUnlock],
[141, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[142, "brightness", tuya.valueConverter.scale0_254to0_1000],
// Doesn't seem to work
// https://github.com/Koenkk/zigbee2mqtt/issues/26526#issuecomment-2749559071
// [143, "min_brightness", tuya.valueConverter.scale0_254to0_1000],
// [144, "max_brightness", tuya.valueConverter.scale0_254to0_1000],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_fjjbhx9d", "_TZE200_e3oitdyu", "_TZE200_gwkapsoq", "_TZE204_zenj4lxv"]),
model: "TS0601_dimmer_2",
vendor: "Tuya",
description: "2 gang smart dimmer",
whiteLabel: [
{ vendor: "Moes", model: "ZS-EUD_2gang" },
{ vendor: "Moes", model: "MS-105B" }, // _TZE200_e3oitdyu
tuya.whitelabel("Moes", "ZS-SR-EUD-2", "Star ring smart dimmer switch 2 gangs", ["_TZE204_zenj4lxv"]),
],
extend: [
tuya.modernExtend.tuyaMagicPacket(),
m.deviceEndpoints({ endpoints: { l1: 1, l2: 1 } }),
tuya.modernExtend.dpLight({
state: {
dp: 1,
type: tuya.dataTypes.bool,
valueOn: ["ON", true],
valueOff: ["OFF", false],
skip: tuya.skip.stateOnAndBrightnessPresent,
},
brightness: {
dp: 2,
type: tuya.dataTypes.number,
scale: [0, 254, 0, 1000],
},
min: { dp: 3, type: tuya.dataTypes.number, scale: [0, 254, 0, 1000] },
max: { dp: 5, type: tuya.dataTypes.number, scale: [0, 254, 0, 1000] },
endpoint: "l1",
}),
tuya.modernExtend.dpNumeric({
name: "countdown",
dp: 6,
type: tuya.dataTypes.number,
expose: tuya.exposes.countdown(),
endpoint: "l1",
}),
tuya.modernExtend.dpLight({
state: {
dp: 7,
type: tuya.dataTypes.bool,
valueOn: ["ON", true],
valueOff: ["OFF", false],
skip: tuya.skip.stateOnAndBrightnessPresent,
},
brightness: {
dp: 8,
type: tuya.dataTypes.number,
scale: [0, 254, 0, 1000],
},
min: { dp: 9, type: tuya.dataTypes.number, scale: [0, 254, 0, 1000] },
max: { dp: 11, type: tuya.dataTypes.number, scale: [0, 254, 0, 1000] },
endpoint: "l2",
}),
tuya.modernExtend.dpNumeric({
name: "countdown",
dp: 12,
type: tuya.dataTypes.number,
expose: tuya.exposes.countdown(),
endpoint: "l2",
}),
tuya.modernExtend.dpPowerOnBehavior({
dp: 14,
type: tuya.dataTypes.enum,
}),
tuya.modernExtend.dpBacklightMode({
dp: 21,
type: tuya.dataTypes.enum,
}),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_vm1gyrso", "_TZE204_1v1dxkck", "_TZE204_znvwzxkq", "_TZE284_znvwzxkq"]),
model: "TS0601_dimmer_3",
vendor: "Tuya",
description: "3 gang smart dimmer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.lightBrightnessWithMinMax().withEndpoint("l1"),
tuya.exposes.lightBrightnessWithMinMax().withEndpoint("l2"),
tuya.exposes.lightBrightnessWithMinMax().withEndpoint("l3"),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l3"),
e.power_on_behavior().withAccess(ea.STATE_SET),
tuya.exposes.backlightModeOffNormalInverted().withAccess(ea.STATE_SET),
],
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[3, "min_brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[5, "max_brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[6, "countdown_l1", tuya.valueConverter.countdown],
[7, "state_l2", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[8, "brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[9, "min_brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[11, "max_brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[12, "countdown_l2", tuya.valueConverter.countdown],
[15, "state_l3", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[16, "brightness_l3", tuya.valueConverter.scale0_254to0_1000],
[17, "min_brightness_l3", tuya.valueConverter.scale0_254to0_1000],
[19, "max_brightness_l3", tuya.valueConverter.scale0_254to0_1000],
[20, "countdown_l3", tuya.valueConverter.countdown],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[21, "backlight_mode", tuya.valueConverter.backlightModeOffNormalInverted],
],
},
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1 };
},
whiteLabel: [
{ vendor: "Moes", model: "ZS-EUD_3gang" },
tuya.whitelabel("Moes", "ZS-SR-EUD-3", "Star ring smart dimmer switch 3 gangs", ["_TZE204_1v1dxkck"]),
tuya.whitelabel("Zemismart", "ZN2S-RS3E-DH", "3 gang dimmer", ["_TZE204_znvwzxkq", "_TZE284_znvwzxkq"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_bxoo2swd", "_TZE200_tsxpl0d0"]),
model: "TS0601_dimmer_4",
vendor: "Tuya",
description: "2 gang smart dimmer module",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.lightBrightnessWithMinMax().withEndpoint("l1"),
tuya.exposes.lightBrightnessWithMinMax().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.lightType().withEndpoint("l1"),
tuya.exposes.lightType().withEndpoint("l2"),
e.enum("power_on_behavior", ea.STATE_SET, ["off", "on", "previous"]),
],
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[3, "min_brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[
4,
"light_type_l1",
tuya.valueConverterBasic.lookup({
led: tuya.enum(0),
incandescent: tuya.enum(1),
halogen: tuya.enum(2),
}),
],
[5, "max_brightness_l1", tuya.valueConverter.scale0_254to0_1000],
[6, "countdown_l1", tuya.valueConverter.countdown],
[7, "state_l2", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[8, "brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[9, "min_brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[
10,
"light_type_l2",
tuya.valueConverterBasic.lookup({
led: tuya.enum(0),
incandescent: tuya.enum(1),
halogen: tuya.enum(2),
}),
],
[11, "max_brightness_l2", tuya.valueConverter.scale0_254to0_1000],
[12, "countdown_l2", tuya.valueConverter.countdown],
[
14,
"power_on_behavior",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
on: tuya.enum(1),
previous: tuya.enum(2),
}),
],
],
},
endpoint: (device) => {
return { l1: 1, l2: 1 };
},
whiteLabel: [
tuya.whitelabel("Moes", "ZM-105B-M", "2 gang smart dimmer module", ["_TZE204_bxoo2swd"]),
tuya.whitelabel("KnockautX", "FMD2C018", "2 gang smart dimmer module", ["_TZE200_tsxpl0d0"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_dcnsggvz"]),
model: "TS0601_dimmer_5",
vendor: "Tuya",
description: "1 gang smart dimmer module",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.lightBrightnessWithMinMax(),
e.enum("power_on_behavior", ea.STATE_SET, ["off", "on", "previous"]),
tuya.exposes.countdown(),
tuya.exposes.lightType(),
tuya.exposes.switchType(),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "brightness", tuya.valueConverter.scale0_254to0_1000],
[3, "min_brightness", tuya.valueConverter.scale0_254to0_1000],
[
4,
"light_type",
tuya.valueConverterBasic.lookup({
led: tuya.enum(0),
incandescent: tuya.enum(1),
halogen: tuya.enum(2),
}),
],
[4, "light_type", tuya.valueConverter.lightType],
[5, "max_brightness", tuya.valueConverter.scale0_254to0_1000],
[6, "countdown", tuya.valueConverter.countdown],
[
14,
"power_on_behavior",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
on: tuya.enum(1),
previous: tuya.enum(2),
}),
],
[
57,
"switch_type",
tuya.valueConverterBasic.lookup({
toggle: tuya.enum(0),
state: tuya.enum(1),
momentary: tuya.enum(2),
}),
],
],
},
whiteLabel: [{ vendor: "Moes", model: "MS-105-M" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_p0gzbqct"]),
model: "TS0601_dimmer_knob",
vendor: "Tuya",
description: "Zigbee smart knob dimmer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.lightBrightness().withMinBrightness().setAccess("min_brightness", ea.STATE_SET),
tuya.exposes.lightType(),
tuya.exposes.indicatorModeNoneRelayPos(),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "brightness", tuya.valueConverter.scale0_254to0_1000],
[3, "min_brightness", tuya.valueConverter.scale0_254to0_1000],
[4, "light_type", tuya.valueConverter.lightType],
[21, "indicator_mode", tuya.valueConverterBasic.lookup({ none: 0, relay: 1, pos: 2 })],
],
},
whiteLabel: [
{ vendor: "Moes", model: "WS-SY-EURD" },
{ vendor: "Moes", model: "WS-SY-EURD-WH-MS" },
],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_oiymh3qu"]),
model: "TS011F_socket_module",
vendor: "Tuya",
description: "Socket module",
extend: [tuya.modernExtend.tuyaOnOff()],
whiteLabel: [
{ vendor: "LoraTap", model: "RR400ZB" },
{ vendor: "LoraTap", model: "SP400ZB" },
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_wxtp7c5y", "_TYZB01_mtunwanm"]),
model: "TS011F_wall_outlet",
vendor: "Tuya",
description: "In-wall outlet",
extend: [tuya.modernExtend.tuyaOnOff()],
whiteLabel: [
{ vendor: "Teekar", model: "SWP86-01OG" },
tuya.whitelabel("ClickSmart+", "CMA30035", "1 gang socket outlet", ["_TYZB01_mtunwanm"]),
{ vendor: "BSEED", model: "Zigbee Socket" },
],
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZ3210_fhx7lk3d"]),
model: "CMA30651",
vendor: "ClickSmart+",
description: "13A Smart Switched Fused Connection Unit",
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeLowMediumHigh: true,
childLock: true,
powerOnBehavior2: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0011", ["_TZ3000_uaa34g7v"]),
model: "CSP041",
vendor: "ClickSmart+",
description: "1 gang switch module without neutral wire",
extend: [m.onOff({ powerOnBehavior: false })],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TYZB01_u9kkqh5o"]),
model: "CSP043",
vendor: "ClickSmart+",
description: "1 gang switch module with neutral wire",
extend: [m.onOff({ powerOnBehavior: false })],
},
{
fingerprint: tuya.fingerprint("TS0012", ["_TZ3000_biakwrag"]),
model: "CSP042",
vendor: "ClickSmart+",
description: "2 gang switch module without neutral wire",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: false,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true, multiEndpointSkip: ["power_on_behavior"] },
},
{
fingerprint: tuya.fingerprint("TS110F", ["_TZ3000_estfrmup", "_TZ3000_ktuoyvt5"]),
model: "CSP051",
vendor: "ClickSmart+",
description: "1 gang smart dimmer switch module without neutral",
extend: [m.light()],
whiteLabel: [tuya.whitelabel("Lonsonho", "QS-Zigbee-D02-TRIAC-L", "1 gang smart dimmer switch module without neutral", ["_TZ3000_ktuoyvt5"])],
},
{
fingerprint: tuya.fingerprint("TS110F", ["_TZ3000_hexqj6ls"]),
model: "CSP052",
vendor: "ClickSmart+",
description: "2 gang smart dimmer switch module without neutral",
extend: [
m.deviceEndpoints({ endpoints: { l1: 1, l2: 2 } }),
m.light({
powerOnBehavior: false,
endpointNames: ["l1", "l2"],
configureReporting: true,
}),
],
meta: { multiEndpoint: true },
},
{
fingerprint: [...tuya.fingerprint("isltm67\u0000", ["_TYST11_pisltm67"]), ...tuya.fingerprint("TS0601", ["_TZE200_pisltm67"])],
model: "S-LUX-ZB",
vendor: "Tuya",
description: "Light sensor",
fromZigbee: [legacy.fromZigbee.SLUXZB],
toZigbee: [],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]);
},
exposes: [e.battery(), e.illuminance(), e.enum("brightness_level", ea.STATE, ["LOW", "MEDIUM", "HIGH"])],
},
{
zigbeeModel: ["TS130F"],
model: "TS130F",
vendor: "Tuya",
description: "Curtain/blind switch",
fromZigbee: [fz.cover_position_tilt, tuya.fz.indicator_mode, fz.tuya_cover_options, tuya.fz.backlight_mode_off_on],
toZigbee: [
tz.cover_state,
tz.cover_position_tilt,
tz.tuya_cover_calibration,
tz.tuya_cover_reversal,
tuya.tz.backlight_indicator_mode_2,
tuya.tz.backlight_indicator_mode_1,
],
meta: { coverInverted: true },
whiteLabel: [
tuya.whitelabel("Danor", "SK-Z802C-US", "Smart curtain/shutter switch", ["_TZ3000_8h7wgocw"]),
{ vendor: "LoraTap", model: "SC400" },
tuya.whitelabel("LoraTap", "SC500ZB", "Roller Shutter Blind Module", ["_TZ3000_e3vhyirx"]),
tuya.whitelabel("Nous", "B4Z", "Curtain switch", ["_TZ3000_yruungrl"]),
tuya.whitelabel("Nous", "L12Z", "Smart ZigBee Curtain Module L12Z", ["_TZ3000_jwv3cwak"]),
tuya.whitelabel("Zemismart", "ZN-LC1E", "Smart curtain/shutter switch", ["_TZ3000_74hsp7qy"]),
],
exposes: (device) => {
const exps = [
e.cover_position(),
e.enum("moving", ea.STATE, ["UP", "STOP", "DOWN"]),
e.binary("motor_reversal", ea.ALL, "ON", "OFF"),
];
if (device?.manufacturerName !== "_TZ3000_cet6ch1r") {
exps.push(e.binary("calibration", ea.ALL, "ON", "OFF"), e.numeric("calibration_time", ea.STATE).withUnit("s").withDescription("Calibration time"));
}
else {
exps.push(e.binary("calibration_up", ea.ALL, "ON", "OFF"), e.numeric("calibration_time_up", ea.STATE).withUnit("s").withDescription("Calibration time up"), e.binary("calibration_down", ea.ALL, "ON", "OFF"), e.numeric("calibration_time_down", ea.STATE).withUnit("s").withDescription("Calibration time down"));
}
if (device?.manufacturerName !== "_TZ3210_xbpt8ewc" && device?.manufacturerName !== "_TZ3000_e3vhyirx") {
exps.push(tuya.exposes.indicatorMode(), tuya.exposes.backlightModeOffOn());
}
return exps;
},
},
{
fingerprint: tuya.fingerprint("TS130F", ["_TZ3210_dwytrmda", "_TZ3000_1dd0d5yi"]),
model: "MS-108ZR",
vendor: "Moes",
description: "Zigbee + RF curtain switch module",
whiteLabel: [tuya.whitelabel("Girier", "TS130F_GIRIER", "Smart curtain switch", ["_TZ3210_dwytrmda"])],
ota: true,
meta: { coverInverted: true },
fromZigbee: [fz.tuya_cover_options, fz.cover_position_tilt],
toZigbee: [tz.cover_state, tz.moes_cover_calibration, tz.cover_position_tilt, tz.tuya_cover_reversal],
exposes: [
e.cover_position(),
e.numeric("calibration_time", ea.ALL).withValueMin(0).withValueMax(100),
e.enum("moving", ea.STATE, ["UP", "STOP", "DOWN"]),
e.binary("motor_reversal", ea.ALL, "ON", "OFF"),
],
},
{
zigbeeModel: ["qnazj70", "kjintbl"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_oisqyl4o", "_TZ3000_uim07oem", "_TZE200_js3mgbjb", "_TZE200_7deq70b8", "_TZE204_ptaqh9tk"]),
model: "TS0601_switch",
vendor: "Tuya",
description: "1, 2, 3 or 4 gang switch",
exposes: [
e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l3").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l4").setAccess("state", ea.STATE_SET),
],
fromZigbee: [fz.ignore_basic_report, legacy.fromZigbee.tuya_switch],
toZigbee: [legacy.toZigbee.tuya_switch_state],
meta: { multiEndpoint: true },
whiteLabel: [
{ vendor: "Norklmes", model: "MKS-CM-W5" },
{ vendor: "Somgoms", model: "ZSQB-SMB-ZB" },
{ vendor: "Moes", model: "WS-EUB1-ZG" },
{ vendor: "AVATTO", model: "ZGB-WS-EU" },
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
if (device.getEndpoint(2))
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
if (device.getEndpoint(3))
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
if (device.getEndpoint(4))
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
},
endpoint: (device) => {
// Endpoint selection is made in tuya_switch_state
return { l1: 1, l2: 1, l3: 1, l4: 1 };
},
},
{
zigbeeModel: ["TS0301"],
model: "TS0301",
vendor: "Tuya",
description: "Cover",
extend: [m.battery(), m.windowCovering({ controls: ["lift"] })],
whiteLabel: [tuya.whitelabel("Yookee", "D10110_1", "Smart blind", ["_TZE200_9caxna4s"])],
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_aqnazj70",
"_TZE200_di3tfv5b",
"_TZE200_mexisfik",
"_TZE204_mexisfik",
"_TZE204_6wi2mope",
"_TZE204_iik0pquw",
"_TZE204_aagrxlbd",
"_TZE204_f5efvtbv",
"_TZE284_f5efvtbv",
"_TZE204_lbhh5o6z",
]),
model: "TS0601_switch_4_gang_1",
vendor: "Tuya",
description: "4 gang switch",
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [
tuya.whitelabel("ZYXH", "TY-04Z", "4 gang switch", ["_TZE204_iik0pquw"]),
{ vendor: "Norklmes", model: "MKS-CM-W5" },
{ vendor: "Somgoms", model: "ZSQB-SMB-ZB" },
{ vendor: "Moes", model: "WS-EUB1-ZG" },
{ vendor: "AVATTO", model: "ZGB-WS-EU" },
tuya.whitelabel("AVATTO", "WSMD-4", "4 gang switch", ["_TZE204_f5efvtbv", "_TZE284_f5efvtbv"]),
tuya.whitelabel("AVATTO", "ZWSMD-4", "4 gang switch", ["_TZE204_lbhh5o6z"]),
tuya.whitelabel("Tuya", "MG-ZG04W", "4 gang switch", ["_TZE204_mexisfik"]),
],
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
],
},
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1 };
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_jwsjbxjs", "_TZE200_leaqthqq"]),
model: "TS0601_switch_5_gang",
vendor: "Tuya",
description: "5 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, l5: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_mwvfvw8g",
"_TZE200_wnp4d4va",
"_TZE200_cduqh1l0",
"_TZE200_emxxanvi",
"_TZE204_g4au0afs",
"_TZE204_w1wwxoja",
"_TZE204_lmgrbuwf",
"_TZE284_tdhnhhiy",
]),
model: "TS0601_switch_6_gang",
vendor: "Tuya",
description: "6 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
device.save();
},
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, l5: 1, l6: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
],
},
whiteLabel: [
tuya.whitelabel("Mercator Ikuü", "SSW06G", "6 Gang switch", ["_TZE200_wnp4d4va"]),
tuya.whitelabel("Nova Digital", "NTZB-04-W-B", "4 gang switch with 2 gang socket 4x4", ["_TZE204_lmgrbuwf"]),
tuya.whitelabel("Nova Digital", "SYZB-6W", "6 gang switch 4x4", ["_TZE284_tdhnhhiy"]),
],
},
{
zigbeeModel: ["ZG-302Z1"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ojtqawav", "_TZE204_gbagoilo", "_TZE200_ojtqawav"]),
model: "TS0601_switch_1_gang",
vendor: "Tuya",
description: "1 gang switch",
exposes: [e.switch().setAccess("state", ea.STATE_SET)],
fromZigbee: [fz.ignore_basic_report, legacy.fromZigbee.tuya_switch],
toZigbee: [legacy.toZigbee.tuya_switch_state],
whiteLabel: [tuya.whitelabel("Shawader", "SMKG-1KNL-US/TZB-W", "1 gang switch", ["_TZE204_ojtqawav"])],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_gbagoilo"]),
model: "MG-ZG01W",
vendor: "Tuya",
description: "1 gang switch with power meter",
exposes: [tuya.exposes.switch(), e.voltage(), e.current(), e.power()],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[21, "current", tuya.valueConverter.divideBy1000],
[22, "power", tuya.valueConverter.divideBy10],
[23, "voltage", tuya.valueConverter.divideBy10],
],
},
},
{
zigbeeModel: ["ZG-302Z2"],
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_nkjintbl",
"_TZE200_ji1gn7rw",
"_TZE200_3t91nb6k",
"_TZE204_wvovwe9h",
"_TZE200_wvovwe9h",
"_TZE204_3t91nb6k",
]),
model: "TS0601_switch_2_gang",
vendor: "Tuya",
description: "2 gang switch",
exposes: [e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET), e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET)],
fromZigbee: [fz.ignore_basic_report, legacy.fromZigbee.tuya_switch],
toZigbee: [legacy.toZigbee.tuya_switch_state],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
if (device.getEndpoint(2))
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
endpoint: (device) => {
// Endpoint selection is made in tuya_switch_state
return { l1: 1, l2: 1 };
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nh9m9emk"]),
model: "MG-ZG02W",
vendor: "Tuya",
description: "2 gang switch",
exposes: [e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET), e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET)],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
],
},
endpoint: (device) => {
return { l1: 1, l2: 1 };
},
},
{
zigbeeModel: ["ZG-302Z3"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_kyfqmmyl", "_TZE200_2hf7x9n3", "_TZE204_atpwqgml", "_TZE200_bynnczcb", "_TZE200_atpwqgml"]),
model: "TS0601_switch_3_gang",
vendor: "Tuya",
description: "3 gang switch",
whiteLabel: [
{
vendor: "Nova Digital",
model: "WS-US-ZB",
description: "Interruptor touch Zigbee 3 Teclas",
},
],
exposes: [
e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l3").setAccess("state", ea.STATE_SET),
],
fromZigbee: [fz.ignore_basic_report, legacy.fromZigbee.tuya_switch],
toZigbee: [legacy.toZigbee.tuya_switch_state],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
endpoint: (device) => {
// Endpoint selection is made in tuya_switch_state
return { l1: 1, l2: 1, l3: 1 };
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_go3tvswy", "_TZE204_2imwyigp", "_TZE200_2imwyigp"]),
model: "MG-ZG03W",
vendor: "Tuya",
description: "3 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l3").setAccess("state", ea.STATE_SET),
],
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
],
},
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1 };
},
},
{
fingerprint: tuya.fingerprint("TS0215A", [
"_TZ3000_4fsgukof",
"_TZ3000_wr2ucaj9",
"_TZ3000_zsh6uat3",
"_TZ3000_tj4pwzzm",
"_TZ3000_2izubafb",
"_TZ3000_pkfazisv",
"_TZ3000_0dumfk2z",
"_TZ3000_ssp0maqm",
"_TZ3000_p3fph1go",
"_TZ3000_9r5jaajv",
]),
model: "TS0215A_sos",
vendor: "Tuya",
description: "SOS button",
fromZigbee: [fz.command_emergency, fz.battery],
exposes: [e.battery(), e.battery_voltage(), e.action(["emergency"])],
toZigbee: [],
whiteLabel: [
tuya.whitelabel("Tuya", "BT400B", "Zigbee Panic Button", ["_TZ3000_0dumfk2z"]),
tuya.whitelabel("Woox", "R7052", "Smart SOS button", ["_TZ3000_ssp0maqm"]),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "genTime", "genBasic", "ssIasAce", "ssIasZone"]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.batteryVoltage(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0215A", [
"_TZ3000_p6ju8myv",
"_TZ3000_0zrccfgx",
"_TZ3000_fsiepnrh",
"_TZ3000_ug1vtuzn",
"_TZ3000_eo3dttwe",
"_TZ3000_jwcixnrz",
]),
model: "TS0215A_remote",
vendor: "Tuya",
description: "Security remote control",
fromZigbee: [fz.command_arm, fz.command_emergency, fz.battery],
exposes: [e.battery(), e.action(["disarm", "arm_day_zones", "arm_night_zones", "arm_all_zones", "exit_delay", "emergency"])],
toZigbee: [],
whiteLabel: [
{ vendor: "Woox", model: "R7054" },
{ vendor: "Nedis", model: "ZBRC10WT" },
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "genTime", "genBasic", "ssIasAce", "ssIasZone"]);
},
},
{
fingerprint: tuya.fingerprint("TS0503A", ["_TZ3000_obacbukl"]),
model: "TS0503A",
vendor: "Tuya",
description: "Led strip controller",
extend: [tuya.modernExtend.tuyaLight({ color: true })],
},
{
zigbeeModel: ["TS0503A"],
model: "TYZS1L",
vendor: "Tuya",
description: "Led strip controller HSB",
exposes: [e.light_colorhs()],
fromZigbee: [fz.on_off, fz.tuya_led_controller],
toZigbee: [tz.tuya_led_controller, tz.ignore_transition, tz.ignore_rate],
},
{
zigbeeModel: ["TS0502A"],
model: "TS0502A",
vendor: "Tuya",
description: "Light controller",
extend: [tuya.modernExtend.tuyaLight({ colorTemp: { range: [153, 500] } })],
whiteLabel: [
tuya.whitelabel("Lidl", "HG06492B/HG08130B", "Livarno Home E14 candle CCT", ["_TZ3000_oborybow"]),
tuya.whitelabel("Lidl", "HG06492A/HG08130A", "Livarno Lux GU10 spot CCT", ["_TZ3000_el5kt5im"]),
tuya.whitelabel("Lidl", "HG06492C/HG08130C/HG09154C", "Livarno Lux E27 bulb CCT", ["_TZ3000_49qchf10"]),
tuya.whitelabel("Lidl", "14147206L", "Livarno Lux ceiling light", ["_TZ3000_rylaozuc", "_TZ3000_5fkufhn1"]),
tuya.whitelabel("Lidl", "14153905L", "Livarno Home LED floor lamp", ["_TZ3000_8uaoilu9"]),
],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 16,
});
},
},
{
fingerprint: tuya.fingerprint("TS0503B", ["_TZB210_lmqquxus"]),
zigbeeModel: ["TS0502B"],
model: "TS0502B",
vendor: "Tuya",
description: "Light controller",
whiteLabel: [
tuya.whitelabel("Mercator Ikuü", "SMI7040", "Ford Batten Light", ["_TZ3000_zw7wr5uo"]),
{
vendor: "Mercator Ikuü",
model: "SMD9300",
description: "Donovan Panel Light",
},
tuya.whitelabel("Aldi", "F122SB62H22A4.5W", "LIGHTWAY smart home LED-lamp - filament", ["_TZ3000_g1glzzfk"]),
tuya.whitelabel("MiBoxer", "FUT035Z+", "Dual white LED controller", [
"_TZ3210_frm6149r",
"_TZ3210_jtifm80b",
"_TZ3210_xwqng7ol",
"_TZB210_lmqquxus",
]),
tuya.whitelabel("MiBoxer", "E2-ZR", "2 in 1 LED controller", ["_TZB210_ayx58ft5", "_TZB210_eiwanbeb"]),
tuya.whitelabel("MiBoxer", "PZ2", "2 in 1 LED controller", ["_TZB210_0bkzabht"]),
tuya.whitelabel("Lidl", "14156408L", "Livarno Lux smart LED ceiling light", ["_TZ3210_c2iwpxf1"]),
],
extend: [
tuya.modernExtend.tuyaLight({
colorTemp: { range: [153, 500] },
configureReporting: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 16,
});
await tuya.configureMagicPacket(device, coordinatorEndpoint);
},
},
{
zigbeeModel: ["TS0504A"],
model: "TS0504A",
vendor: "Tuya",
description: "RGBW LED controller",
extend: [
tuya.modernExtend.tuyaLight({
colorTemp: { range: undefined },
color: true,
}),
],
},
{
fingerprint: tuya.fingerprint("TS0505A", ["_TZ3000_sosdczdl"]),
model: "TS0505A_led",
vendor: "Tuya",
description: "RGB+CCT LED",
toZigbee: [tz.on_off, tz.tuya_led_control],
fromZigbee: [fz.on_off, fz.tuya_led_controller, fz.brightness, fz.ignore_basic_report],
exposes: [e.light_brightness_colortemp_colorhs([153, 500]).removeFeature("color_temp_startup")],
},
{
zigbeeModel: ["TS0505A"],
model: "TS0505A",
vendor: "Tuya",
description: "RGB+CCT light controller",
extend: [
tuya.modernExtend.tuyaLight({
colorTemp: { range: undefined },
color: true,
}),
],
whiteLabel: [
tuya.whitelabel("Lidl", "HG06106B", "Livarno Lux E14 candle RGB", ["_TZ3000_odygigth"]),
tuya.whitelabel("Lidl", "HG06106A", "Livarno Lux GU10 spot RGB", ["_TZ3000_kdpxju99"]),
tuya.whitelabel("Lidl", "HG06106C", "Livarno Lux E27 bulb RGB", ["_TZ3000_dbou1ap4"]),
tuya.whitelabel("Lidl", "14148906L", "Livarno Lux mood light RGB+CCT", ["_TZ3000_9cpuaca6"]),
tuya.whitelabel("Lidl", "14149505L/14149506L_1", "Livarno Lux light bar RGB+CCT (black/white)", ["_TZ3000_gek6snaj"]),
tuya.whitelabel("Mycket", "MS-SP-LE27WRGB", "E27 RGBW bulb", ["_TZ3000_evag0pvn"]),
tuya.whitelabel("Lidl", "HG06104A", "Livarno Home RGB+CCT LED light strip 2m", ["_TZ3000_riwp3k79", "_TZ3000_riwp3k79"]),
],
configure: (device, coordinatorEndpoint) => {
device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", {
colorCapabilities: 29,
});
},
},
{
zigbeeModel: ["TS0201", "SNTZ003", "TY0201"],
model: "TS0201",
vendor: "Tuya",
description: "Temperature & humidity sensor with display",
fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fzLocal.TS0201_humidity],
toZigbee: [],
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
configure: tuya.configureMagicPacket,
ota: true,
whiteLabel: [
{ vendor: "BlitzWolf", model: "BW-IS4" },
tuya.whitelabel("Tuya", "TS0201_1", "Zigbee 3.0 temperature humidity sensor with display", ["_TZ3210_alxkwn0h"]),
tuya.whitelabel("Tuya", "ZTH01/ZTH02", "Temperature and humidity sensor", ["_TZ3000_0s1izerx"]),
tuya.whitelabel("Tuya", "ZY-ZTH02", "Temperature and humidity sensor", ["_TZ3000_v1w2k9dd", "_TZ3000_rdhukkmi"]),
tuya.whitelabel("SEDEA", "eTH730", "Temperature and humidity sensor", ["_TZ3000_lqmvrwa2"]),
tuya.whitelabel("Moes", "ZSS-S01-TH", "Temperature and humidity sensor", ["_TZ3000_f2bw0b6k"]),
tuya.whitelabel("Danfoss", "014G2480", "Temperature and humidity sensor", ["_TZ3000_mxzo5rhf"]),
tuya.whitelabel("Tuya", "HS09", "Hanging temperature humidity sensor", ["_TZ3000_1twfmkcc"]),
tuya.whitelabel("Nedis", "ZBSC10WT", "Temperature and humidity sensor", ["_TZ3000_fie1dpkm"]),
],
},
{
fingerprint: tuya.fingerprint("TS0201", [
"_TZ3000_bguser20",
"_TZ3000_yd2e749y",
"_TZ3000_6uzkisv2",
"_TZ3000_xr3htd96",
"_TZ3000_fllyghyj",
"_TZ3000_saiqcn0y",
"_TZ3000_bjawzodf",
]),
model: "WSD500A",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
toZigbee: [],
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
configure: tuya.configureMagicPacket,
whiteLabel: [tuya.whitelabel("Tuya", "TH02Z", "Temperature and humidity sensor", ["_TZ3000_fllyghyj", "_TZ3000_saiqcn0y"])],
meta: {
battery: {
// These sensors do send a Battery Percentage Remaining (0x0021)
// value, but is usually incorrect. For example, a coin battery tested
// with a load tester may show 80%, but report 2.5V / 1%. This voltage
// calculation matches what ZHA does by default.
// https://github.com/Koenkk/zigbee2mqtt/discussions/17337
// https://github.com/zigpy/zha-device-handlers/blob/c6ed94a52a469e72b32ece2a92d528060c7fd034/zhaquirks/__init__.py#L195-L228
voltageToPercentage: "3V_1500_2800",
},
},
},
{
fingerprint: [
...tuya.fingerprint("TS0201", ["_TZ3000_dowj6gyi", "_TZ3000_8ybe88nf", "_TZ3000_akqdg6g7"]),
{ manufacturerName: "_TZ3000_zl1kmjqx" },
],
model: "IH-K009",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
toZigbee: [],
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
configure: tuya.configureMagicPacket,
whiteLabel: [tuya.whitelabel("Tuya", "RSH-HS06_1", "Temperature & humidity sensor", ["_TZ3000_zl1kmjqx"])],
},
{
fingerprint: tuya.fingerprint("SM0201", ["_TYZB01_cbiezpds", "_TYZB01_zqvwka4k"]),
model: "SM0201",
vendor: "Tuya",
description: "Temperature & humidity sensor with LED screen",
fromZigbee: [fz.battery, fz.temperature, fz.humidity],
toZigbee: [],
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_3zofvcaa", "_TZ3000_pvlvoxvt", "_TZ3000_lqb7lcq9", "_TZ3210_urjf5u18"]),
model: "TS011F_2_gang_2_usb_wall",
vendor: "Tuya",
description: "2 gang 2 usb wall outlet",
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeLowMediumHigh: true,
endpoints: ["l1", "l2", "l3", "l4"],
childLock: true,
}),
],
endpoint: () => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const endpointID of [1, 2, 3, 4]) {
const endpoint = device.getEndpoint(endpointID);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.onOff(endpoint);
}
},
whiteLabel: [
tuya.whitelabel("Nova Digital", "NTS2-W-B", "2 gang 2 usb wall outlet 4x2", ["_TZ3000_lqb7lcq9"]),
tuya.whitelabel("AVATTO", "ZWOT12", "2 gang 2 usb wall outlet 4x2", ["_TZ3210_urjf5u18"]),
],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_bep7ccew", "_TZ3000_gazjngjl"]),
model: "TS011F_2_gang_power",
vendor: "Tuya",
description: "2 gang socket with power monitoring and USB",
extend: [
tuyaMagicPacket(),
m.deviceEndpoints({
endpoints: { left: 1, right: 2 },
multiEndpointSkip: ["current", "voltage", "power", "energy"],
}),
m.onOff({ powerOnBehavior: false, endpointNames: ["left", "right"] }),
m.identify(),
m.electricityMeter(),
],
},
{
zigbeeModel: ["TS0041"],
model: "TS0041",
vendor: "Tuya",
description: "Wireless switch with 1 button",
whiteLabel: [
{ vendor: "Smart9", model: "S9TSZGB" },
{ vendor: "Lonsonho", model: "TS0041" },
{ vendor: "Benexmart", model: "ZM-sui1" },
tuya.whitelabel("Tuya", "SH-SC07", "Button scene switch", ["_TZ3000_mrpevh8p"]),
tuya.whitelabel("Tuya", "MINI-ZSB", "Smart button", ["_TZ3000_qgwcxxws"]),
tuya.whitelabel("Nous", "LZ4", "Wireless switch button", ["_TZ3000_6km7djcm"]),
tuya.whitelabel("Marmitek", "Push_LE", "Smart switch", ["_TZ3000_4upl1fcj"]),
],
exposes: [e.battery(), e.action(["single", "double", "hold"])],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
/*
* reporting.batteryPercentageRemaining removed as it was causing devices to fall of the network
* every 1 hour, with light flashing when it happened, extremely short battery life, 2 presses for
* action to register: https://github.com/Koenkk/zigbee2mqtt/issues/8072
* Initially wrapped in a try catch: https://github.com/Koenkk/zigbee2mqtt/issues/6313
*/
},
{
zigbeeModel: ["TS0041A"],
model: "TS0041A",
vendor: "Tuya",
description: "Wireless switch with 1 button",
whiteLabel: [
tuya.whitelabel("Cleverio", "SB100", "Wireless switch with 1 button", ["_TYZB01_4qw4rl1u"]),
tuya.whitelabel("Marmitek", "Push_ME", "Wireless switch with 1 button", ["_TYZB01_1xktopx6"]),
],
exposes: [e.battery(), e.battery_voltage(), e.action(["single", "double", "hold"])],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
/*
* reporting.batteryPercentageRemaining removed as it was causing devices to fall of the network
* every 1 hour, with light flashing when it happened, extremely short battery life, 2 presses for
* action to register: https://github.com/Koenkk/zigbee2mqtt/issues/8072
* Initially wrapped in a try catch: https://github.com/Koenkk/zigbee2mqtt/issues/6313
*/
},
{
zigbeeModel: ["TS0042"],
model: "TS0042",
vendor: "Tuya",
description: "Wireless switch with 2 buttons",
whiteLabel: [
{ vendor: "Smart9", model: "S9TSZGB" },
{ vendor: "Lonsonho", model: "TS0042" },
{ vendor: "ClickSmart+", model: "CSPGM2075PW" },
tuya.whitelabel("Marmitek", "Push_LO", "Smart switch", ["_TZ3000_dfgbtub0"]),
],
exposes: [e.battery(), e.action(["1_single", "1_double", "1_hold", "2_single", "2_double", "2_hold"])],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
/*
* reporting.batteryPercentageRemaining removed as it was causing devices to fall of the network
* every 1 hour, with light flashing when it happened, extremely short battery life, 2 presses for
* action to register: https://github.com/Koenkk/zigbee2mqtt/issues/8072
* Initially wrapped in a try catch: https://github.com/Koenkk/zigbee2mqtt/issues/6313
*/
},
{
zigbeeModel: ["TS0043"],
model: "TS0043",
vendor: "Tuya",
description: "Wireless switch with 3 buttons",
whiteLabel: [
{ vendor: "Smart9", model: "S9TSZGB" },
{ vendor: "Lonsonho", model: "TS0043" },
{ vendor: "LoraTap", model: "SS600ZB" },
],
exposes: [e.battery(), e.action(["1_single", "1_double", "1_hold", "2_single", "2_double", "2_hold", "3_single", "3_double", "3_hold"])],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
/*
* reporting.batteryPercentageRemaining removed as it was causing devices to fall of the network
* every 1 hour, with light flashing when it happened, extremely short battery life, 2 presses for
* action to register: https://github.com/Koenkk/zigbee2mqtt/issues/8072
* Initially wrapped in a try catch: https://github.com/Koenkk/zigbee2mqtt/issues/6313
*/
},
{
zigbeeModel: ["TS0044"],
model: "TS0044",
vendor: "Tuya",
description: "Wireless switch with 4 buttons",
whiteLabel: [
{ vendor: "Lonsonho", model: "TS0044" },
{ vendor: "Haozee", model: "ESW-OZAA-EU" },
{ vendor: "LoraTap", model: "SS6400ZB" },
{ vendor: "Moes", model: "ZT-SY-EU-G-4S-WH-MS" },
{ vendor: "Nedis", model: "ZBWS40WT" },
tuya.whitelabel("Moes", "ZT-SR-EU4", "Star Ring 4 Gang Scene Switch", ["_TZ3000_a4xycprs"]),
tuya.whitelabel("Tuya", "TS0044_1", "Zigbee 4 button remote - 12 scene", ["_TZ3000_dziaict4", "_TZ3000_mh9px7cq", "_TZ3000_j61x9rxn"]),
tuya.whitelabel("Tuya", "TM-YKQ004", "Zigbee 4 button remote - 12 scene", ["_TZ3000_u3nv1jwk"]),
],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
exposes: [
e.battery(),
e.action([
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
]),
],
toZigbee: [],
configure: tuya.configureMagicPacket,
/*
* reporting.batteryPercentageRemaining removed as it was causing devices to fall of the network
* every 1 hour, with light flashing when it happened, extremely short battery life, 2 presses for
* action to register: https://github.com/Koenkk/zigbee2mqtt/issues/8072
* Initially wrapped in a try catch: https://github.com/Koenkk/zigbee2mqtt/issues/6313
*/
},
{
fingerprint: tuya.fingerprint("TS004F", [
"_TZ3000_nuombroo",
"_TZ3000_xabckq1v",
"_TZ3000_czuyt8lz",
"_TZ3000_0ht8dnxj",
"_TZ3000_b3mgfu0d",
"_TZ3000_11pg3ima",
"_TZ3000_et7afzxz",
]),
model: "TS004F",
vendor: "Tuya",
description: "Wireless switch with 4 buttons",
exposes: [
e.battery(),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
.withDescription('Operation mode: "command" - for group control, "event" - for clicks'),
e.action([
"on",
"off",
"brightness_step_up",
"brightness_step_down",
"brightness_move_up",
"brightness_move_down",
"color_temperature_step_up",
"color_temperature_step_down",
"brightness_stop",
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
]),
],
fromZigbee: [
fz.battery,
tuya.fz.on_off_action,
fz.tuya_operation_mode,
fz.command_on,
fz.command_off,
fz.command_step,
fz.command_move,
fz.command_stop,
fz.command_step_color_temperature,
],
whiteLabel: [tuya.whitelabel("Zemismart", "ZMR4", "Wireless switch with 4 buttons", ["_TZ3000_11pg3ima", "_TZ3000_et7afzxz"])],
toZigbee: [tz.tuya_operation_mode],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("genBasic", [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe]);
await endpoint.write("genOnOff", { tuyaOperationMode: 1 });
await endpoint.read("genOnOff", ["tuyaOperationMode"]);
try {
await endpoint.read(0xe001, [0xd011]);
}
catch {
/* do nothing */
}
await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
for (const ep of [1, 2, 3, 4]) {
// Not all variants have all endpoints
// https://github.com/Koenkk/zigbee2mqtt/issues/15730#issuecomment-1364498358
if (device.getEndpoint(ep)) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
}
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS004F", ["_TZ3000_r0o2dahu"]),
model: "TS004F_6_button",
vendor: "Tuya",
description: "Wireless switch with 6 buttons",
exposes: [
e.battery(),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
.withDescription('Operation mode: "command" - for group control, "event" - for clicks'),
e.action([
"on",
"off",
"brightness_step_up",
"brightness_step_down",
"brightness_move_up",
"brightness_move_down",
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
"5_single",
"5_double",
"5_hold",
"6_single",
"6_double",
"6_hold",
]),
],
fromZigbee: [fz.battery, tuya.fz.on_off_action, fz.tuya_operation_mode, fz.command_on, fz.command_off, fz.command_step, fz.command_move],
toZigbee: [tz.tuya_operation_mode],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("genBasic", [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe]);
await endpoint.write("genOnOff", { tuyaOperationMode: 1 });
await endpoint.read("genOnOff", ["tuyaOperationMode"]);
try {
await endpoint.read(0xe001, [0xd011]);
}
catch {
/* do nothing */
}
await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
for (const ep of [1, 2, 3, 4, 5, 6]) {
// Not all variants have all endpoints
// https://github.com/Koenkk/zigbee2mqtt/issues/15730#issuecomment-1364498358
if (device.getEndpoint(ep)) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
}
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_dzuqwsyg", "_TZE204_dzuqwsyg"]),
model: "BAC-003",
vendor: "Tuya",
description: "FCU thermostat temperature controller",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
options: [
e
.enum("control_sequence_of_operation", ea.SET, ["cooling_only", "cooling_and_heating_4-pipes"])
.withDescription("Operating environment of the thermostat"),
e.binary("expose_device_state", ea.SET, true, false).withDescription("Expose device power state as a separate property when enabled."),
],
exposes: (device, options) => {
const system_modes = ["off", "cool", "heat", "fan_only"];
// Device can operate either in 2-pipe or 4-pipe configuration
// For 2-pipe configurations remove 'heat' mode
switch (options?.control_sequence_of_operation) {
case "cooling_only":
system_modes.splice(2, 1);
break;
}
const exposes = [
e
.climate()
.withLocalTemperature(ea.STATE)
.withSystemMode(system_modes, ea.STATE_SET)
.withFanMode(["low", "medium", "high", "auto"], ea.STATE_SET)
.withSetpoint("current_heating_setpoint", 5, 35, 1, ea.STATE_SET)
.withPreset(["auto", "manual"])
.withLocalTemperatureCalibration(-3, 3, 1, ea.STATE_SET),
e.child_lock(),
e
.composite("schedule", "schedule", ea.STATE_SET)
.withFeature(e.text("weekdays", ea.SET).withDescription('Schedule (1-5), 4 periods in format "hh:mm/tt".'))
.withFeature(e.text("saturday", ea.SET).withDescription('Schedule (6), 4 periods in format "hh:mm/tt".'))
.withFeature(e.text("sunday", ea.SET).withDescription('Schedule (7), 4 periods in format "hh:mm/tt".'))
.withDescription('Auto-mode schedule, 4 periods each per category. Example: "06:00/20 11:30/21 13:30/22 17:30/23.5".'),
e.max_temperature().withValueMin(35).withValueMax(45).withPreset("default", 35, "Default value"),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withUnit("°C")
.withValueMax(5)
.withValueMin(1)
.withValueStep(1)
.withPreset("default", 1, "Default value")
.withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity"),
];
if (options?.expose_device_state === true) {
exposes.unshift(e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON or OFF"));
}
return exposes;
},
meta: {
publishDuplicateTransaction: true,
tuyaDatapoints: [
[
1,
"state",
{
to: async (v, meta) => {
if (meta.options?.expose_device_state === true) {
await tuya.sendDataPointBool(meta.device.endpoints[0], 1, utils.getFromLookup(v, { on: true, off: false }), "dataRequest", 1);
}
},
from: (v, meta, options) => {
meta.state.system_mode = v === true ? (meta.state.system_mode_device ?? "cool") : "off";
if (options?.expose_device_state === true) {
return v === true ? "ON" : "OFF";
}
// biome-ignore lint/performance/noDelete: ignored using `--suppress`
delete meta.state.state;
},
},
],
[
2,
"system_mode",
{
// Extend system_mode to support 'off' in addition to 'cool', 'heat' and 'fan_only'
to: async (v, meta) => {
const entity = meta.device.endpoints[0];
// Power State
await tuya.sendDataPointBool(entity, 1, v !== "off", "dataRequest", 1);
switch (v) {
case "cool":
await tuya.sendDataPointEnum(entity, 2, 0, "dataRequest", 1);
break;
case "heat":
await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1);
break;
case "fan_only":
await tuya.sendDataPointEnum(entity, 2, 2, "dataRequest", 1);
break;
}
},
from: (v, meta) => {
const modes = ["cool", "heat", "fan_only"];
meta.state.system_mode_device = modes[v];
return modes[v];
},
},
],
[4, "preset", tuya.valueConverterBasic.lookup({ manual: true, auto: false })],
[16, "current_heating_setpoint", tuya.valueConverter.raw],
[19, "max_temperature", tuya.valueConverter.raw],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[26, "deadzone_temperature", tuya.valueConverter.raw],
[27, "local_temperature_calibration", tuya.valueConverter.localTemperatureCalibration],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
auto: tuya.enum(3),
}),
],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[
101,
"schedule",
{
to: (v, meta) => {
const periods = (value) => {
const regex = /((?<h>[01][0-9]|2[0-3]):(?<m>[0-5][0-9])\/(?<t>[0-3][0-9](\.[0,5]|)))/gm;
const matches = [...value.matchAll(regex)];
if (matches.length === 4) {
return matches.reduce((arr, m) => {
arr.push(Number.parseInt(m.groups.h));
arr.push(Number.parseInt(m.groups.m));
arr.push(Number.parseFloat(m.groups.t) * 2);
return arr;
}, []);
}
logger_1.logger.warning("Ignoring invalid or incomplete schedule", NS);
};
const schedule = [...periods(v.weekdays), ...periods(v.saturday), ...periods(v.sunday)];
return schedule;
},
from: (v, meta) => {
const format = (data) => {
return data.reduce((a, v, i) => {
switch (i % 3) {
// Hour
case 0:
return `${a}${i > 0 ? " " : ""}${v.toString().padStart(2, "0")}`;
// Minute
case 1:
return `${a}:${v.toString().padStart(2, "0")}`;
// Setpoint
case 2:
return `${a}/${v / 2}`;
}
}, "");
};
return {
weekdays: format(v.slice(0, 12)),
saturday: format(v.slice(1 * 12, 2 * 12)),
sunday: format(v.slice(2 * 12, 3 * 12)),
};
},
},
],
],
},
whiteLabel: [tuya.whitelabel("Tuya", "BAC-002-ALZB", "FCU thermostat temperature controller", ["_TZE200_dzuqwsyg"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_qq9mpfhw"]),
model: "TS0601_water_sensor",
vendor: "Tuya",
description: "Water leak sensor",
fromZigbee: [legacy.fromZigbee.tuya_water_leak, fz.ignore_basic_report],
exposes: [e.water_leak()],
toZigbee: [],
whiteLabel: [{ vendor: "Neo", model: "NAS-WS02B0" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_jthf7vb6"]),
model: "WLS-100z",
vendor: "Tuya",
description: "Water leak sensor",
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_raw, legacy.fromZigbee.wls100z_water_leak],
toZigbee: [],
onEvent: tuya.onEventSetTime,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]);
},
exposes: [e.battery(), e.water_leak()],
},
{
fingerprint: tuya.fingerprint("TS0001", [
"_TZ3000_xkap8wtb",
"_TZ3000_qnejhcsu",
"_TZ3000_x3ewpzyr",
"_TZ3000_mkhkxx1p",
"_TZ3000_tgddllx4",
"_TZ3000_kqvb5akv",
"_TZ3000_g92baclx",
"_TZ3000_qlai3277",
"_TZ3000_qaabwu5c",
"_TZ3000_ikuxinvo",
"_TZ3000_hzlsaltw",
"_TZ3000_jsfzkftc",
"_TZ3000_0ghwhypc",
]),
model: "TS0001_power",
description: "Switch with power monitoring",
vendor: "Tuya",
ota: true,
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, tuya.fz.power_outage_memory, tuya.fz.switch_type],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tuya.tz.switch_type],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
/*
https://github.com/Koenkk/zigbee2mqtt/issues/27090
INVALID_DATA_TYPE error for _TZ3000_xkap8wtb, appVersion:162 softwareBuildID: 0122052017
*/
if ("_TZ3000_xkap8wtb" === device.manufacturerName && [162, 100].includes(device.applicationVersion)) {
logger_1.logger.warning("Detected TS0001 _TZ3000_xkap8wtb switch with appVersion 100 or 162. Skip reporting for haElectricalMeasurement and seMeteringreporting in favor of polling.", NS);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
}
else {
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
await reporting.currentSummDelivered(endpoint);
}
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
exposes: [
e.switch(),
e.power(),
e.current(),
e.voltage(),
e.energy(),
tuya.exposes.switchType(),
e.enum("power_outage_memory", ea.ALL, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
],
whiteLabel: [
tuya.whitelabel("Nous", "B2Z", "1 gang switch with power monitoring", ["_TZ3000_qlai3277"]),
tuya.whitelabel("Colorock", "CR-MNZ1", "1 gang switch 30A with power monitoring", ["_TZ3000_tgddllx4"]),
tuya.whitelabel("Nous", "L6Z", "Switch with power monitoring", ["_TZ3000_qaabwu5c"]),
tuya.whitelabel("Tuya", "XSH01A", "1 gang switch", ["_TZ3000_x3ewpzyr"]),
],
onEvent: async (type, data, device, options) => {
if (["_TZ3000_x3ewpzyr"].includes(device.manufacturerName)) {
await tuya.onEventMeasurementPoll(type, data, device, options, true, true);
}
else if (["_TZ3000_xkap8wtb"].includes(device.manufacturerName) && [162, 100].includes(device.applicationVersion)) {
await tuya.onEventMeasurementPoll(type, data, device, options, true, true);
}
},
},
{
fingerprint: tuya.fingerprint("TS0002", ["_TZ3000_aaifmpuq", "_TZ3000_irrmjcgi", "_TZ3000_huvxrx4i"]),
model: "TS0002_power",
vendor: "Tuya",
description: "2 gang switch with power monitoring",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
endpoints: ["l1", "l2"],
electricalMeasurements: true,
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: {
multiEndpoint: true,
multiEndpointSkip: ["energy", "current", "voltage", "power"],
},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("genBasic", ["manufacturerName", "zclVersion", "appVersion", "modelId", "powerSource", 0xfffe]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
await reporting.currentSummDelivered(endpoint);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("Tuya", "XSH01B", "2 gang switch module with power monitoring", ["_TZ3000_irrmjcgi"]),
tuya.whitelabel("Nous", "B3Z", "2 gang switch module with power monitoring", ["_TZ3000_aaifmpuq"]),
],
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3000_xkap8wtb"]),
model: "TS000F_power",
description: "Switch with power monitoring",
vendor: "Tuya",
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, tuya.fz.power_on_behavior_1, tuya.fz.switch_type],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tuya.tz.switch_type],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.currentSummDelivered(endpoint);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
whiteLabel: [{ vendor: "Aubess", model: "WHD02" }],
exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.power_on_behavior(), tuya.exposes.switchType()],
},
{
zigbeeModel: ["TS0001"],
model: "TS0001",
vendor: "Tuya",
description: "1 gang switch",
extend: [tuya.modernExtend.tuyaOnOff()],
whiteLabel: [
{
vendor: "CR Smart Home",
model: "TS0001",
description: "Valve control",
},
{ vendor: "Lonsonho", model: "X701" },
{ vendor: "Bandi", model: "BDS03G1" },
tuya.whitelabel("Nous", "B1Z", "1 gang switch", ["_TZ3000_ctftgjwb"]),
tuya.whitelabel("Tuya", "XMSJ", "Zigbee USB power switch", ["_TZ3000_8n7lqbm0"]),
tuya.whitelabel("Tuya", "ZG-001", "Smart home relay module", ["_TZ3000_g8n1n7lg"]),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZ3000_myaaknbq", "_TZ3000_cpozgbrx"]),
model: "TS0001_switch_module_1",
vendor: "Tuya",
description: "1 gang switch module",
extend: [
tuya.modernExtend.tuyaOnOff({
indicatorMode: true,
backlightModeOffOn: true,
onOffCountdown: true,
}),
],
whiteLabel: [
tuya.whitelabel("PSMART", "T441", "1 gang switch module", ["_TZ3000_myaaknbq"]),
tuya.whitelabel("PSMART", "T461", "1 gang switch module", ["_TZ3000_cpozgbrx"]),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZ3000_gbshwgag"]),
model: "TS0001_switch_module_2",
vendor: "Tuya",
description: "1 gang switch with backlight",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
backlightModeOffOn: true,
indicatorMode: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
////////////////////////
// TS0002 DEFINITIONS //
////////////////////////
{
// TS0002 model with only on/off capability
fingerprint: tuya.fingerprint("TS0002", [
"_TZ3000_01gpyda5",
"_TZ3000_bvrlqyj7",
"_TZ3000_7ed9cqgi",
"_TZ3000_zmy4lslw",
"_TZ3000_ruxexjfz",
"_TZ3000_4xfqlgqo",
"_TZ3000_hojntt34",
"_TZ3000_eei0ubpy",
"_TZ3000_qaa59zqd",
"_TZ3000_lmlsduws",
"_TZ3000_lugaswf8",
"_TZ3000_nuenzetq",
"_TZ3000_ruldv5dt",
"_TZ3000_fbjdkph9",
]),
model: "TS0002_basic",
vendor: "Tuya",
description: "2 gang switch module",
whiteLabel: [
{ vendor: "OXT", model: "SWTZ22" },
tuya.whitelabel("Moes", "ZM-104B-M", "2 gang switch", ["_TZ3000_qaa59zqd"]),
tuya.whitelabel("pcblab.io", "RR620ZB", "2 gang Zigbee switch module", ["_TZ3000_4xfqlgqo"]),
tuya.whitelabel("Nous", "L13Z", "2 gang switch", ["_TZ3000_ruxexjfz", "_TZ3000_hojntt34"]),
tuya.whitelabel("Tuya", "ZG-2002-RF", "Three mode Zigbee Switch", ["_TZ3000_lugaswf8", "_TZ3000_nuenzetq", "_TZ3000_ruldv5dt"]),
tuya.whitelabel("Mercator Ikuü", "SSW02", "2 gang switch", ["_TZ3000_fbjdkph9"]),
tuya.whitelabel("Aubess", "TMZ02", "2 gang switch", ["_TZ3000_lmlsduws"]),
],
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
},
{
// TS0002 model with limited functionality available
fingerprint: tuya.fingerprint("TS0002", [
"_TZ3000_fisb3ajo",
"_TZ3000_5gey1ohx",
"_TZ3000_mtnpt6ws",
"_TZ3000_mufwv0ry",
"_TZ3000_54hjn4vs",
"_TZ3000_aa5t61rh",
"_TZ3000_in5qxhtt",
"_TZ3000_ogpla3lh",
"_TZ3000_i9w5mehz",
]),
model: "TS0002_limited",
vendor: "Tuya",
description: "2 gang switch module",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
onOffCountdown: true,
indicatorMode: true,
backlightModeOffOn: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("AVATTO", "ZWSM16-2-Zigbee", "2 gang switch module", ["_TZ3000_mtnpt6ws"]),
tuya.whitelabel("PSMART", "T442", "2 gang switch module", ["_TZ3000_mufwv0ry"]),
tuya.whitelabel("Lonsonho", "X702A", "2 gang switch with backlight", ["_TZ3000_54hjn4vs", "_TZ3000_aa5t61rh"]),
tuya.whitelabel("Homeetec", "37022463-1", "2 Gang switch with backlight", ["_TZ3000_in5qxhtt"]),
tuya.whitelabel("RoomsAI", "37022463-2", "2 Gang switch with backlight", ["_TZ3000_ogpla3lh"]),
],
},
{
// TS0002 2 gang switch module with all available features. This is the default for TS0002 devices.
model: "TS0002",
zigbeeModel: ["TS0002"],
vendor: "Tuya",
description: "2-Gang switch with backlight, countdown and inching",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
powerOnBehavior2: true,
backlightModeOffOn: true,
indicatorMode: true,
onOffCountdown: true,
inchingSwitch: true,
endpoints: ["l1", "l2"],
}),
tuya.clusters.addTuyaCommonPrivateCluster(),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("Zemismart", "TB26-2", "2 Gang switch with backlight, countdown, inching", ["_TZ3000_ywubfuvt"]),
{ vendor: "Zemismart", model: "ZM-CSW002-D_switch" },
{ vendor: "Lonsonho", model: "X702" },
{ vendor: "AVATTO", model: "ZTS02" },
tuya.whitelabel("PSMART", "T462", "2 Gang switch with backlight, countdown, inching", ["_TZ3000_wnzoyohq"]),
],
},
////////////////////////
// TS0003 DEFINITIONS //
////////////////////////
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_rhkfbfcv", "_TZ3000_empogkya", "_TZ3000_lubfc1t5", "_TZ3000_lsunm46z", "_TZ3000_v4l4b0lp"]),
model: "TS0003_switch_3_gang_with_backlight",
vendor: "Tuya",
description: "3-Gang switch with backlight",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
indicatorMode: true,
backlightModeOffOn: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("Lonsonho", "X703A", "3 Gang switch with backlight", ["_TZ3000_rhkfbfcv"]),
tuya.whitelabel("Zemismart", "ZM-L03E-Z", "3 gang switch with neutral", ["_TZ3000_empogkya", "_TZ3000_lsunm46z"]),
tuya.whitelabel("Tuya", "M10Z", "2 gang switch with 20A power socket", ["_TZ3000_lubfc1t5"]),
],
},
{
zigbeeModel: ["TS0003"],
model: "TS0003",
vendor: "Tuya",
description: "3 gang switch",
extend: [
m.deviceEndpoints({ endpoints: { left: 1, center: 2, right: 3 } }),
m.onOff({
endpointNames: ["left", "center", "right"],
powerOnBehavior: false,
}),
],
whiteLabel: [
{ vendor: "BSEED", model: "TS0003", description: "Zigbee switch" },
tuya.whitelabel("Tuya", "TS0003_1", "3 gang switch", ["_TZ3000_ouwfc1qj"]),
tuya.whitelabel("Zemismart", "TB26-3", "3 gang switch", ["_TZ3000_eqsair32"]),
],
meta: { disableDefaultResponse: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_4o16jdca", "_TZ3000_odzoiovu", "_TZ3000_hbic3ka3", "_TZ3000_lvhy15ix"]),
model: "TS0003_switch_module_2",
vendor: "Tuya",
description: "3 gang switch module",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
indicatorMode: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [tuya.whitelabel("AVATTO", "ZWSM16-3-Zigbee", "3 gang switch module", ["_TZ3000_hbic3ka3"])],
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_ju82pu2b"]),
model: "TW-03",
vendor: "Tuya",
description: "3-Gang switch",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_vsasbzkf", "_TZ3000_nnwehhst"]),
model: "TS0003_switch_module_1",
vendor: "Tuya",
description: "3 gang switch module",
whiteLabel: [{ vendor: "OXT", model: "SWTZ23" }],
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
backlightModeOffOn: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: [{ modelID: "TS0003", manufacturerName: "_TZ3000_mw1pqqqt" }],
model: "_TZ3000_mw1pqqqt",
description: "3 channel USB switch",
vendor: "Tuya",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: false,
indicatorMode: false,
onOffCountdown: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
},
{
fingerprint: tuya.fingerprint("TS0001", [
"_TZ3000_tqlv4ug4",
"_TZ3000_gjrubzje",
"_TZ3000_tygpxwqa",
"_TZ3000_4rbqgcuv",
"_TZ3000_veu2v775",
"_TZ3000_prits6g4",
]),
model: "TS0001_switch_module",
vendor: "Tuya",
description: "1 gang switch module",
whiteLabel: [
{ vendor: "OXT", model: "SWTZ21" },
{ vendor: "Moes", model: "ZM-104-M" },
tuya.whitelabel("AVATTO", "ZWSM16-1-Zigbee", "1 gang switch module", ["_TZ3000_4rbqgcuv"]),
],
extend: [tuya.modernExtend.tuyaOnOff({ switchType: true, onOffCountdown: true })],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0004", ["_TZ3000_ltt60asa", "_TZ3000_mmkbptmx"]),
model: "TS0004_switch_module",
vendor: "Tuya",
description: "4 gang switch module",
whiteLabel: [{ vendor: "OXT", model: "SWTZ27" }],
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
},
},
{
zigbeeModel: [
"owvfni3\u0000",
"owvfni3",
"u1rkty3",
"aabybja", // Curtain motors
"mcdj3aq",
"mcdj3aq\u0000", // Tubular motors
],
fingerprint: [
...tuya.fingerprint("TS0601", [
"_TZE200_5zbp6j0u",
"_TZE200_nkoabg8w",
"_TZE200_xuzcvlku",
"_TZE200_4vobcgd3",
"_TZE200_nogaemzt",
"_TZE200_r0jdjrvi",
"_TZE200_pk0sfzvr",
"_TZE200_fdtjuw7u",
"_TZE200_zpzndjez",
"_TZE200_wmcdj3aq",
"_TZE200_cowvfni3",
"_TZE200_rddyvrci",
"_TZE200_nueqqe6k",
"_TZE200_bqcqqjpb",
"_TZE200_xaabybja",
"_TZE200_rmymn92d",
"_TZE200_feolm6rk",
"_TZE200_3i3exuay",
"_TZE200_tvrvdj6o",
"_TZE200_b2u1drdv",
"_TZE200_ol5jlkkr",
"_TZE204_guvc7pdy",
"_TZE200_zxxfv8wi",
"_TZE200_1fuxihti",
"_TZE204_1fuxihti",
"_TZE204_57hjqelq",
"_TZE200_hojryzzd",
"_TZE204_m1wl5fvq",
"_TZE200_en3wvcbx",
"_TZE200_fctwhugx",
"_TZE200_hsgrhjpf",
"_TZE200_g5wdnuow",
"_TZE200_5sbebbzs",
"_TZE200_udank5zs",
"_TZE204_dpqsvdbi",
"_TZE200_zuz7f94z",
"_TZE200_nv6nxo0c",
"_TZE200_3ylew7b4",
"_TZE200_llm0epxg",
"_TZE200_n1aauwb4",
"_TZE200_xu4a5rhj",
"_TZE200_bjzrowv2",
"_TZE204_bjzrowv2",
"_TZE200_axgvo9jh",
"_TZE200_gaj531w3",
"_TZE200_yia0p3tr",
"_TZE200_rsj5pu8y",
"_TZE204_nladmfvf",
"_TZE200_2odrmqwq",
"_TZE204_lh3arisb",
"_TZE284_udank5zs",
"_TZE200_7shyddj3",
"_TZE204_a2jcoyuk",
"_TZE204_zuq5xxib",
]),
...tuya.fingerprint("zo2pocs\u0000", ["_TYST11_fzo2pocs"]),
...tuya.fingerprint("dank5zs\u0000", ["_TYST11_udank5zs"]),
],
model: "TS0601_cover_1",
vendor: "Tuya",
description: "Curtain motor/roller blind motor/window pusher/tubular motor",
whiteLabel: [
{ vendor: "Yushun", model: "YS-MT750" },
tuya.whitelabel("Yushun", "YS-MT750L", "Curtain motor", ["_TZE200_bqcqqjpb", "_TZE200_gaj531w3"]),
{ vendor: "Zemismart", model: "ZM79E-DT" },
{ vendor: "Binthen", model: "BCM100D" },
{ vendor: "Binthen", model: "CV01A" },
{ vendor: "Zemismart", model: "M515EGB" },
{ vendor: "Oz Smart Things", model: "ZM85EL-1Z" },
{ vendor: "Tuya", model: "M515EGZT" },
{ vendor: "Tuya", model: "DT82LEMA-1.2N" },
{ vendor: "Tuya", model: "ZD82TN", description: "Curtain motor" },
{ vendor: "Larkkey", model: "ZSTY-SM-1SRZG-EU" },
{ vendor: "Zemismart", model: "AM43", description: "Roller blind motor" },
{
vendor: "Zemismart",
model: "M2805EGBZTN",
description: "Tubular motor",
},
{
vendor: "Zemismart",
model: "BCM500DS-TYZ",
description: "Curtain motor",
},
{ vendor: "A-OK", model: "AM25", description: "Tubular motor" },
{ vendor: "Alutech", model: "AM/R-Sm", description: "Tubular motor" },
tuya.whitelabel("Shenzhen Golden Security Technology", "GM46", "Curtain motor", ["_TZE204_guvc7pdy"]),
tuya.whitelabel("Roximo", "CRTZ01", "Curtain motor", ["_TZE204_57hjqelq"]),
{ vendor: "Quoya", model: "AT8510-TY" },
tuya.whitelabel("Somgoms", "ZSTY-SM-1DMZG-US-W_1", "Curtain switch", ["_TZE200_axgvo9jh"]),
tuya.whitelabel("HUARUI", "CMD900LE", "Lithium battery intelligent curtain opening and closing motor", ["_TZE200_zxxfv8wi"]),
tuya.whitelabel("Novato", "WPK", "Smart curtain track", ["_TZE204_lh3arisb"]),
tuya.whitelabel("Zemismart", "ZMS1-TYZ", "Smart curtain track", ["_TZE204_zuq5xxib"]),
],
fromZigbee: [legacy.fromZigbee.tuya_cover, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.tuya_cover_control, legacy.toZigbee.tuya_cover_options],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e
.composite("options", "options", ea.STATE_SET)
.withFeature(e.numeric("motor_speed", ea.STATE_SET).withValueMin(0).withValueMax(255).withDescription("Motor speed"))
.withFeature(e.binary("reverse_direction", ea.STATE_SET, true, false).withDescription("Reverse the motor direction")),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_xu4a5rhj"]),
model: "M3TYW-2.0-13",
vendor: "Tuya",
description: "Longsam M3 curtain motor",
fromZigbee: [legacy.fromZigbee.tuya_cover, fz.ignore_basic_report],
toZigbee: [tzLocal.invert_cover_percent_fix, legacy.toZigbee.tuya_cover_options],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e
.composite("options", "options", ea.STATE_SET)
.withFeature(e.numeric("motor_speed", ea.STATE_SET).withValueMin(0).withValueMax(255).withDescription("Motor speed"))
.withFeature(e.binary("reverse_direction", ea.STATE_SET, true, false).withDescription("Reverse the motor direction")),
],
options: [exposes.options.cover_position_percent_fix()],
},
{
fingerprint: [...tuya.fingerprint("TS0601", ["_TZE200_eegnwoyw"]), ...tuya.fingerprint("TS0105", ["_TZE600_ogyg1y6b"])],
model: "TS0601_cover_2",
vendor: "Tuya",
description: "Curtain motor or roller blind motor with fixed speed",
whiteLabel: [
tuya.whitelabel("Zemismart", "BCM100DB", "Curtain Motor", ["_TZE200_eegnwoyw"]),
tuya.whitelabel("Nova Digital", "ZBCMR-01", "Roller Blind Motor", ["_TZE600_ogyg1y6b"]),
],
fromZigbee: [legacy.fromZigbee.tuya_cover, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.tuya_cover_control],
exposes: [e.cover_position().setAccess("position", ea.STATE_SET)],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_cpbo62rn", "_TZE200_libht6ua", "_TZE284_libht6ua"]),
model: "TS0601_cover_6",
vendor: "Tuya",
description: "Cover motor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.text("work_state", ea.STATE),
e.cover_position().setAccess("position", ea.STATE_SET),
e.battery(),
e.enum("opening_mode", ea.STATE_SET, ["tilt", "lift"]).withDescription("Opening mode"),
e.enum("motor_direction", ea.STATE_SET, ["left", "right"]).withDescription("Motor side"),
e.enum("set_upper_limit", ea.STATE_SET, ["start", "stop"]).withDescription("Learning"),
e.enum("factory_reset", ea.STATE_SET, ["SET"]).withDescription("Remove limits"),
],
whiteLabel: [tuya.whitelabel("Tuya", "LY-108", "Cover", ["_TZE200_cpbo62rn"])],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
CLOSE: tuya.enum(2),
STOP: tuya.enum(1),
OPEN: tuya.enum(0),
}),
],
[2, "position", tuya.valueConverter.coverPositionInverted],
[3, "position", tuya.valueConverter.coverPositionInverted],
[
4,
"opening_mode",
tuya.valueConverterBasic.lookup({
tilt: tuya.enum(0),
lift: tuya.enum(1),
}),
],
[
7,
"work_state",
tuya.valueConverterBasic.lookup({
standby: tuya.enum(0),
success: tuya.enum(1),
learning: tuya.enum(2),
}),
],
[13, "battery", tuya.valueConverter.raw],
[
101,
"motor_direction",
tuya.valueConverterBasic.lookup({
left: tuya.enum(0),
right: tuya.enum(1),
}),
],
[
102,
"set_upper_limit",
tuya.valueConverterBasic.lookup({
start: tuya.enum(1),
stop: tuya.enum(0),
}),
],
[107, "factory_reset", tuya.valueConverter.setLimit],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_zvo63cmo"]),
model: "TS0601_cover_7",
vendor: "Tuya",
description: "Cover motor",
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [e.cover_position().setAccess("position", ea.STATE_SET), e.battery()],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.raw],
// motor_direction doesn't work: https://github.com/Koenkk/zigbee2mqtt/issues/18103
// [5, 'motor_direction', tuya.valueConverterBasic.lookup({'normal': tuya.enum(0), 'reversed': tuya.enum(1)})],
[101, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_r0jdjrvi", "_TZE200_g5xqosu7", "_TZE204_g5xqosu7", "_TZE284_fzo2pocs", "_TZE200_9vpe3fl1"]),
model: "TS0601_cover_8",
vendor: "Tuya",
description: "Cover motor",
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
options: [exposes.options.invert_cover()],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("reverse_direction", ea.STATE_SET, ["forward", "back"]).withDescription("Reverse the motor direction"),
e.binary("motor_fault", ea.STATE, true, false).withDescription("Motor Fault"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPositionInverted],
[3, "position", tuya.valueConverter.coverPositionInverted],
[
5,
"reverse_direction",
tuya.valueConverterBasic.lookup({
forward: tuya.enum(0),
back: tuya.enum(1),
}),
],
[12, "motor_fault", tuya.valueConverter.trueFalse1],
],
},
whiteLabel: [
tuya.whitelabel("Lilistore", "TS0601_lilistore", "Cover motor", ["_TZE204_r0jdjrvi"]),
tuya.whitelabel("Zemismart", "ZM90E-DT250N/A400", "Window opener", ["_TZE204_r0jdjrvi"]),
tuya.whitelabel("Nova Digital", "CMR-1", "Roller Blind Motor", ["_TZE200_9vpe3fl1"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_a8z0g46u", "_TZE204_a8z0g46u"]),
model: "YY-LT500",
vendor: "Tuya",
description: "Window opener",
options: [exposes.options.invert_cover()],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [e.cover_position().setAccess("position", ea.STATE_SET)],
meta: {
tuyaDatapoints: [
[
2,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[7, "position", tuya.valueConverter.coverPosition],
[8, "position", tuya.valueConverter.coverPosition],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_p2qzzazi"]),
model: "TS0601_cover_9",
vendor: "Tuya",
description: "Cover motor",
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [e.cover_position().setAccess("position", ea.STATE_SET), e.battery()],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.raw],
[
5,
"motor_direction",
tuya.valueConverterBasic.lookup({
normal: tuya.enum(0),
reversed: tuya.enum(1),
}),
],
[101, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_clm4gdw4", "_TZE200_2vfxweng", "_TZE200_gnw1rril", "_TZE204_ycke4deo"]),
model: "TS0601_cover_10",
vendor: "Tuya",
description: "Cover motor",
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("motor_direction", ea.STATE_SET, ["normal", "reversed"]).withDescription("Set the motor direction"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(2),
STOP: tuya.enum(1),
CLOSE: tuya.enum(0),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.raw],
[5, "motor_direction", tuya.valueConverterBasic.lookup({ normal: false, reversed: true })],
],
},
whiteLabel: [tuya.whitelabel("Nova Digital", "ZC-GM42", "Roller blind motor", ["_TZE204_ycke4deo"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ax8a8ahx"]),
model: "ZM79E-DT",
vendor: "Tervix",
description: "Pro Line Zigbee curtain motor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.text("work_state", ea.STATE),
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("opening_mode", ea.STATE_SET, ["tilt", "lift"]).withDescription("Opening mode"),
e.enum("motor_direction", ea.STATE_SET, ["left", "right"]).withDescription("Motor side"),
e.enum("set_upper_limit", ea.STATE_SET, ["start", "stop"]).withDescription("Learning"),
e.enum("factory_reset", ea.STATE_SET, ["SET"]).withDescription("Remove limits"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
CLOSE: tuya.enum(2),
STOP: tuya.enum(1),
OPEN: tuya.enum(0),
}),
],
[2, "position", tuya.valueConverter.coverPositionInverted],
[3, "position", tuya.valueConverter.coverPositionInverted],
[
4,
"opening_mode",
tuya.valueConverterBasic.lookup({
tilt: tuya.enum(0),
lift: tuya.enum(1),
}),
],
[
7,
"work_state",
tuya.valueConverterBasic.lookup({
standby: tuya.enum(0),
success: tuya.enum(1),
learning: tuya.enum(2),
}),
],
[
101,
"motor_direction",
tuya.valueConverterBasic.lookup({
left: tuya.enum(0),
right: tuya.enum(1),
}),
],
[
102,
"set_upper_limit",
tuya.valueConverterBasic.lookup({
start: tuya.enum(1),
stop: tuya.enum(0),
}),
],
[107, "factory_reset", tuya.valueConverter.setLimit],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_2rvvqjoa"]),
model: "BX82-TYZ1",
vendor: "Manhot",
description: "Cover motor",
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("motor_direction", ea.STATE_SET, ["normal", "reversed"]).withDescription("Set the motor direction"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(2),
STOP: tuya.enum(1),
CLOSE: tuya.enum(0),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.raw],
[
5,
"motor_direction",
tuya.valueConverterBasic.lookup({
normal: tuya.enum(0),
reversed: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_2gi1hy8s"]),
model: "MB60L-ZG-ZT-TY",
vendor: "Manhot",
description: "Smart blinds motor",
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.battery(),
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("set_limits", ea.STATE_SET, ["up", "down", "reset"]),
e.enum("motor_direction", ea.STATE_SET, ["normal", "reversed"]).withDescription("Motor Steering"),
e.binary("tilt_mode", ea.STATE_SET, "ON", "OFF").withDescription("Step movement"),
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withDescription("Child Lock"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[9, "position", tuya.valueConverter.coverPositionInverted],
[
11,
"motor_direction",
tuya.valueConverterBasic.lookup({
normal: tuya.enum(0),
reversed: tuya.enum(1),
}),
],
[13, "battery", tuya.valueConverter.raw],
[
16,
"set_limits",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
reset: tuya.enum(2),
}),
],
[101, "child_lock", tuya.valueConverter.onOff],
[103, "tilt_mode", tuya.valueConverter.onOff],
],
},
},
{
zigbeeModel: ["kud7u2l"],
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_ckud7u2l",
"_TZE200_ywdxldoj",
"_TZE200_do5qy8zo",
"_TZE200_cwnjrr72",
"_TZE200_pvvbommb",
"_TZE200_9sfg7gm0",
"_TZE200_2atgpdho",
"_TZE200_cpmgn2cf",
"_TZE200_znlqjmih",
"_TZE200_8thwkzxl",
"_TZE200_4eeyebrt",
"_TZE200_8whxpsiw",
"_TZE200_xby0s3ta",
"_TZE200_7fqkphoq",
"_TZE200_rufdtfyv" /* model: '07732L', vendor: 'Immax' */,
"_TZE200_lpwgshtl",
"_TZE200_rk1wojce" /* model: 'P5630S', vendor: 'Emos' */,
"_TZE200_rndg81sf" /* model: 'HY368', vendor: 'THALEOS' */,
"_TZE200_qjp4ynvi",
]),
model: "TS0601_thermostat",
vendor: "Tuya",
description: "Radiator valve with thermostat",
whiteLabel: [
{ vendor: "Moes", model: "HY368" },
{ vendor: "Moes", model: "HY369RT" },
{ vendor: "SHOJZJ", model: "378RT" },
{ vendor: "Silvercrest", model: "TVR01" },
{ vendor: "Immax", model: "07732B" },
tuya.whitelabel("Immax", "07732L", "Radiator valve with thermostat", ["_TZE200_rufdtfyv"]),
{ vendor: "Evolveo", model: "Heat M30" },
tuya.whitelabel("Emos", "P5630S", "Radiator valve with thermostat", ["_TZE200_rk1wojce"]),
tuya.whitelabel("THALEOS", "HY368", "Radiator valve with thermostat", ["_TZE200_rndg81sf"]),
],
meta: {
tuyaThermostatPreset: legacy.thermostatPresets,
tuyaThermostatSystemMode: legacy.thermostatSystemModes3,
},
ota: true,
onEvent: tuya.onEventSetLocalTime,
fromZigbee: [legacy.fromZigbee.tuya_thermostat, fz.ignore_basic_report, fz.ignore_tuya_set_time],
toZigbee: [
legacy.toZigbee.tuya_thermostat_child_lock,
legacy.toZigbee.tuya_thermostat_window_detection,
legacy.toZigbee.tuya_thermostat_valve_detection,
legacy.toZigbee.tuya_thermostat_current_heating_setpoint,
legacy.toZigbee.tuya_thermostat_auto_lock,
legacy.toZigbee.tuya_thermostat_calibration,
legacy.toZigbee.tuya_thermostat_min_temp,
legacy.toZigbee.tuya_thermostat_max_temp,
legacy.toZigbee.tuya_thermostat_boost_time,
legacy.toZigbee.tuya_thermostat_comfort_temp,
legacy.toZigbee.tuya_thermostat_eco_temp,
legacy.toZigbee.tuya_thermostat_force_to_mode,
legacy.toZigbee.tuya_thermostat_force,
legacy.toZigbee.tuya_thermostat_preset,
legacy.toZigbee.tuya_thermostat_window_detect,
legacy.toZigbee.tuya_thermostat_schedule,
legacy.toZigbee.tuya_thermostat_week,
legacy.toZigbee.tuya_thermostat_schedule_programming_mode,
legacy.toZigbee.tuya_thermostat_away_mode,
legacy.toZigbee.tuya_thermostat_away_preset,
],
exposes: [
e.child_lock(),
e.window_detection(),
e.binary("window_open", ea.STATE, true, false).withDescription("Window open?"),
e.battery_low(),
e.valve_detection(),
e.position(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["heat", "auto", "off"], ea.STATE_SET, "Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate " +
"to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` " +
"instead setting the desired temperature.")
.withLocalTemperatureCalibration(-9, 9, 0.5, ea.STATE_SET)
.withPreset(["schedule", "manual", "boost", "complex", "comfort", "eco", "away"])
.withRunningState(["idle", "heat"], ea.STATE),
e.auto_lock(),
e.away_mode(),
e.away_preset_days(),
e.boost_time(),
e.comfort_temperature(),
e.eco_temperature(),
e.force(),
e.max_temperature().withValueMin(16).withValueMax(70),
e.min_temperature(),
e.away_preset_temperature(),
e.week(),
e
.text("workdays_schedule", ea.STATE_SET)
.withDescription('Workdays schedule, 6 entries max, example: "00:20/5°C 01:20/5°C 6:59/15°C 18:00/5°C 20:00/5°C 23:30/5°C"'),
e
.text("holidays_schedule", ea.STATE_SET)
.withDescription('Holidays schedule, 6 entries max, example: "00:20/5°C 01:20/5°C 6:59/15°C 18:00/5°C 20:00/5°C 23:30/5°C"'),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_g2ki0ejr"]),
model: "BAB-1413_Pro",
vendor: "Tuya",
description: "Thermostat radiator valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
ota: true,
exposes: [
e.battery(),
e.child_lock(),
e
.numeric("max_temperature_limit", ea.STATE_SET)
.withUnit("°C")
.withDescription("Max temperature limit")
.withValueMin(15)
.withValueMax(45)
.withValueStep(0.5),
e
.numeric("min_temperature_limit", ea.STATE_SET)
.withUnit("°C")
.withDescription("Min temperature limit")
.withValueMin(5)
.withValueMax(15)
.withValueStep(0.5),
e.window_detection(),
e.open_window_temperature().withValueMin(5).withValueMax(30).withValueStep(0.5),
e.comfort_temperature().withValueMin(5).withValueMax(35),
e.eco_temperature().withValueMin(5).withValueMax(35).withValueStep(0.5),
e.holiday_temperature().withValueMin(5).withValueMax(35).withValueStep(0.5),
e
.climate()
.withPreset(["auto", "manual", "holiday", "comfort"])
.withLocalTemperatureCalibration(-9, 9, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 45, 0.5, ea.STATE_SET)
.withSystemMode(["off", "heat"], ea.STATE_SET, "Only for Homeassistant")
.withRunningState(["idle", "heat"], ea.STATE_SET),
tuya.exposes.frostProtection("When Anti-Freezing function is activated, the temperature in the house is kept " +
'at 8 °C, the device display "AF".press the pair button to cancel.'),
e
.numeric("boost_time", ea.STATE_SET)
.withUnit("min")
.withDescription("Boost running time. Minimum 0 - maximum 24 hours")
.withValueMin(0)
.withValueMax(1440)
.withValueStep(15)
.withCategory("config"),
e.numeric("boost_timeset_countdown", ea.STATE).withUnit("min").withDescription("Boost time remaining"),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "06:00/21.5 17:20/26 20:00/21 24:00/18").map((text) => text.withCategory("config")),
e.binary("valve", ea.STATE, "CLOSED", "OPEN"),
// e.enum('factory_reset', ea.STATE_SET, ['factory reset']).withLabel('Factory reset').withDescription('Reset all settings to factory ones'),
e
.binary("factory_reset", ea.STATE_SET, "ON", "OFF")
.withDescription("Back to factory settings, USE WITH CAUTION"),
tuya.exposes.errorStatus(),
],
meta: {
tuyaDatapoints: [
[
49,
"running_state",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(1),
idle: tuya.enum(0),
}),
],
[
49,
"system_mode",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(1),
off: tuya.enum(0),
}),
],
[
2,
"preset",
tuya.valueConverterBasic.lookup({
comfort: tuya.enum(3),
auto: tuya.enum(0),
manual: tuya.enum(2),
holiday: tuya.enum(1),
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[7, "child_lock", tuya.valueConverter.lockUnlock],
[9, "max_temperature_limit", tuya.valueConverter.divideBy10],
[10, "min_temperature_limit", tuya.valueConverter.divideBy10],
[14, "window_detection", tuya.valueConverter.onOff],
[16, "open_window_temperature", tuya.valueConverter.divideBy10],
[17, "open_window_time", tuya.valueConverter.raw],
// [18, 'backlight', tuya.valueConverter.raw],
[19, "factory_reset", tuya.valueConverter.onOff],
[21, "holiday_temperature", tuya.valueConverter.raw],
[24, "comfort_temperature", tuya.valueConverter.divideBy10],
[25, "eco_temperature", tuya.valueConverter.divideBy10],
[17, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[18, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[19, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[20, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[21, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[22, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[23, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
// [35, 'error_status', tuya.valueConverter.raw],
[36, "frost_protection", tuya.valueConverter.onOff],
// [37, 'boost_time', tuya.valueConverter.raw],
// [38, 'boost_timeset_countdown', tuya.valueConverter.countdown],
// [39, 'Switch Scale', tuya.valueConverter.raw],
// Did not work properly from Smart life also
// [47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration1],
// [48, 'valve_testing', tuya.valueConverter.raw],
[49, "valve", tuya.valueConverter.trueFalseEnum0],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_tbgecldg", "_TZE284_tbgecldg", "_TZE200_tbgecldg"]),
model: "PO-THCO-EAU",
vendor: "Powernity",
description: "Thermostat radiator valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery().withUnit("%"),
e.child_lock(),
e.comfort_temperature().withValueMin(0.5).withValueMax(29.5),
e.eco_temperature().withValueMin(0.5).withValueMax(29.5),
e.holiday_temperature().withValueMin(0.5).withValueMax(29.5),
e
.numeric("auto_temperature", ea.STATE_SET)
.withDescription("Auto settings temperature")
.withUnit("°C")
.withValueMin(0.5)
.withValueStep(0.5)
.withValueMax(29.5),
e
.climate()
.withPreset(["auto", "manual", "holiday"])
.withLocalTemperatureCalibration(-5.5, 5.5, 0.1, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 0.5, 29.5, 0.5, ea.STATE_SET),
e.binary("boost_heating", ea.STATE_SET, "ON", "OFF").withDescription("Boost Heating: the device will enter the boost heating mode."),
e
.numeric("boost_time", ea.STATE_SET)
.withUnit("s")
.withDescription("Setting " +
"minimum 0 - maximum 900 seconds boost time. The boost function is activated. The remaining " +
"time for the function will be counted down in seconds ( 900 to 0 ).")
.withValueMin(0)
.withValueMax(900),
e.binary("window_open", ea.STATE, "OPEN", "CLOSE").withDescription("Window status CLOSE or OPEN "),
e.open_window_temperature().withValueMin(5).withValueMax(25),
e
.numeric("open_window_time", ea.STATE_SET)
.withDescription("In the setting time, when the range of indoor temperature changes reaches the set range, the window opening reminder will be displayed")
.withUnit("minutes")
.withValueMin(0)
.withValueMax(60)
.withValueStep(1),
tuya.exposes.errorStatus(),
],
meta: {
tuyaDatapoints: [
[
2,
"preset",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
manual: tuya.enum(1),
holiday: tuya.enum(2),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy2],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[30, "child_lock", tuya.valueConverter.lockUnlock],
[34, "battery", tuya.valueConverterBasic.scale(0, 100, 50, 150)],
[101, "comfort_temperature", tuya.valueConverter.divideBy2],
[102, "eco_temperature", tuya.valueConverter.divideBy2],
[103, "holiday_temperature", tuya.valueConverter.divideBy2],
[104, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[105, "auto_temperature", tuya.valueConverter.divideBy2],
[106, "boost_heating", tuya.valueConverter.onOff],
[107, "window_open", tuya.valueConverter.onOff],
[116, "open_window_temperature", tuya.valueConverter.divideBy2],
[117, "open_window_time", tuya.valueConverter.raw],
[118, "boost_time", tuya.valueConverter.countdown],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_68nvbio9",
"_TZE200_pw7mji0l",
"_TZE200_cf1sl3tj",
"_TZE200_nw1r9hp6",
"_TZE200_9p5xmj5r",
"_TZE200_eevqq1uv",
]),
model: "TS0601_cover_3",
vendor: "Tuya",
description: "Cover motor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
options: [exposes.options.invert_cover()],
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("reverse_direction", ea.STATE_SET, ["forward", "back"]).withDescription("Reverse the motor direction"),
e.enum("border", ea.STATE_SET, ["up", "down", "up_delete", "down_delete", "remove_top_bottom"]),
e.enum("click_control", ea.STATE_SET, ["up", "down"]).withDescription("Single motor steps"),
e.binary("motor_fault", ea.STATE, true, false),
],
whiteLabel: [
tuya.whitelabel("Zemismart", "ZM16EL-03/33", "Cover motor", ["_TZE200_68nvbio9"]),
tuya.whitelabel("Zemismart", "ZM25EL", "Cover motor", ["_TZE200_pw7mji0l"]),
tuya.whitelabel("Zemismart", "ZM85EL-2Z", "Roman Rod I type U curtains track", ["_TZE200_cf1sl3tj", "_TZE200_nw1r9hp6"]),
tuya.whitelabel("Hiladuo", "B09M3R35GC", "Motorized roller shade", ["_TZE200_9p5xmj5r"]),
],
meta: {
// All datapoints go in here
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.coverPosition],
[
5,
"reverse_direction",
tuya.valueConverterBasic.lookup({
forward: tuya.enum(0),
back: tuya.enum(1),
}),
],
[12, "motor_fault", tuya.valueConverter.trueFalse1],
[13, "battery", tuya.valueConverter.raw],
[
16,
"border",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
up_delete: tuya.enum(2),
down_delete: tuya.enum(3),
remove_top_bottom: tuya.enum(4),
}),
],
[
20,
"click_control",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_zah67ekd", "_TZE200_icka1clh"]),
model: "TS0601_cover_4",
vendor: "Tuya",
description: "Cover",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("motor_direction", ea.STATE_SET, ["normal", "reversed"]).withDescription("Set the motor direction"),
e.numeric("motor_speed", ea.STATE_SET).withValueMin(0).withValueMax(255).withDescription("Motor speed").withUnit("rpm"),
e.enum("opening_mode", ea.STATE_SET, ["tilt", "lift"]).withDescription("Opening mode"),
e.enum("set_upper_limit", ea.SET, ["SET"]).withDescription("Set the upper limit, to reset limits use factory_reset"),
e.enum("set_bottom_limit", ea.SET, ["SET"]).withDescription("Set the bottom limit, to reset limits use factory_reset"),
e.binary("factory_reset", ea.SET, true, false).withDescription("Factory reset the device"),
],
whiteLabel: [tuya.whitelabel("Moes", "AM43-0.45/40-ES-EB", "Roller blind/shades drive motor", ["_TZE200_zah67ekd", "_TZE200_icka1clh"])],
configure: (device, coordinatorEndpoint) => {
device.powerSource = "Mains (single phase)";
device.save();
},
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[3, "position", tuya.valueConverter.raw],
[5, "motor_direction", tuya.valueConverter.tubularMotorDirection],
[7, null, null], // work_state, not useful, ignore
[
101,
"opening_mode",
tuya.valueConverterBasic.lookup({
tilt: tuya.enum(0),
lift: tuya.enum(1),
}),
],
[102, "factory_reset", tuya.valueConverter.raw],
[103, "set_upper_limit", tuya.valueConverter.setLimit],
[104, "set_bottom_limit", tuya.valueConverter.setLimit],
[105, "motor_speed", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_sur6q7ko" /* model: '3012732', vendor: 'LSC Smart Connect' */,
"_TZE200_hue3yfsn" /* model: 'TV02-Zigbee', vendor: 'Tuya' */,
"_TZE200_e9ba97vf" /* model: 'TV01-ZB', vendor: 'Moes' */,
"_TZE200_husqqvux" /* model: 'TSL-TRV-TV01ZG', vendor: 'Tesla Smart' */,
"_TZE200_lnbfnyxd" /* model: 'TSL-TRV-TV01ZG', vendor: 'Tesla Smart' */,
"_TZE200_fsow0qsk" /* model: 'TSL-TRV-TV05ZG', vendor: 'Tesla Smart' */,
"_TZE200_lllliz3p" /* model: 'TV02-Zigbee', vendor: 'Tuya' */,
"_TZE200_mudxchsu" /* model: 'TV05-ZG curve', vendor: 'Tuya' */,
"_TZE200_7yoranx2" /* model: 'TV01-ZB', vendor: 'Moes' */,
"_TZE200_kds0pmmv",
"_TZE200_py4cm3he" /* model: 'TV06-Zigbee', vendor: 'Tuya' */,
"_TZE200_wsbfwodu" /* model: 'HA-08 THERMO', vendor: 'AlecoAir' */,
]),
model: "TV02-Zigbee",
vendor: "Tuya",
description: "Thermostat radiator valve",
whiteLabel: [
{ vendor: "Moes", model: "TV01-ZB" },
{ vendor: "AVATTO", model: "TRV06-1" },
{ vendor: "Tesla Smart", model: "TSL-TRV-TV01ZG" },
{ vendor: "Tesla Smart", model: "TSL-TRV-TV05ZG" },
{ vendor: "Unknown/id3.pl", model: "GTZ08" },
tuya.whitelabel("Moes", "ZTRV-ZX-TV01-MS", "Thermostat radiator valve", ["_TZE200_7yoranx2"]),
tuya.whitelabel("Moes", "TV01-ZB", "Thermostat radiator valve", ["_TZE200_e9ba97vf"]),
tuya.whitelabel("AlecoAir", "HA-08_THERMO", "Thermostat radiator valve", ["_TZE200_wsbfwodu"]),
],
ota: true,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery_low(),
e.child_lock(),
e.open_window(),
e.open_window_temperature().withValueMin(5).withValueMax(30),
e.comfort_temperature().withValueMin(5).withValueMax(30),
e.eco_temperature().withValueMin(5).withValueMax(30),
e
.climate()
.withPreset(["auto", "manual", "holiday"])
.withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 30, 0.5, ea.STATE_SET)
.withSystemMode(["off", "heat"], ea.STATE_SET, "Only for Homeassistant"),
e
.binary("heating_stop", ea.STATE_SET, "ON", "OFF")
.withDescription("Battery life can be prolonged" +
" by switching the heating off. To achieve this, the valve is closed fully. To activate the " +
'heating stop, the device display "HS", press the pair button to cancel.'),
tuya.exposes.frostProtection("When Anti-Freezing function is activated, the temperature in the house is kept " +
'at 8 °C, the device display "AF".press the pair button to cancel.'),
e
.numeric("boost_timeset_countdown", ea.STATE_SET)
.withUnit("s")
.withDescription("Setting " +
"minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining " +
"time for the function will be counted down in seconds ( 465 to 0 ).")
.withValueMin(0)
.withValueMax(465),
e.holiday_temperature().withValueMin(5).withValueMax(30),
e
.text("holiday_start_stop", ea.STATE_SET)
.withDescription("The holiday mode will automatically start " +
"at the set time starting point and run the holiday temperature. Can be defined in the following format: " +
"`startYear/startMonth/startDay startHours:startMinutes | endYear/endMonth/endDay endHours:endMinutes`. " +
'For example: `2022/10/01 16:30 | 2022/10/21 18:10`. After the end of holiday mode, it switches to "auto" ' +
"mode and uses schedule."),
e
.enum("working_day", ea.STATE_SET, ["mon_sun", "mon_fri+sat+sun", "separate"])
.withDescription("`mon_sun` " +
"- schedule for Monday used for each day (define it only for Monday). `mon_fri+sat+sun` - schedule for " +
"workdays used from Monday (define it only for Monday), Saturday and Sunday are defined separately. `separate` " +
"- schedule for each day is defined separately."),
e
.composite("schedule", "schedule", ea.SET)
.withFeature(e.enum("week_day", ea.SET, ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]))
.withFeature(e.text("schedule", ea.SET))
.withDescription('Schedule will work with "auto" preset. In this mode, the device executes ' +
"a preset week programming temperature time and temperature. Before using these properties, check `working_day` " +
"property. Each day can contain up to 10 segments. At least 1 segment should be defined. Different count of segments " +
"can be defined for each day, e.g., 3 segments for Monday, 5 segments for Thursday, etc. It should be defined in the " +
"following format: `hours:minutes/temperature`. Minutes can be only tens, i.e., 00, 10, 20, 30, 40, 50. Segments should " +
"be divided by space symbol. Each day should end with the last segment of 24:00. Examples: `04:00/20 08:30/22 10:10/18 " +
"18:40/24 22:50/19.5`; `06:00/21.5 17:20/26 24:00/18`. The temperature will be set from the beginning/start of one " +
"period and until the next period, e.g., `04:00/20 24:00/22` means that from 00:00 to 04:00 temperature will be 20 " +
"degrees and from 04:00 to 00:00 temperature will be 22 degrees."),
...tuya.exposes.scheduleAllDays(ea.STATE, "HH:MM/C"),
e.binary("online", ea.STATE_SET, "ON", "OFF").withDescription("The current data request from the device."),
tuya.exposes.errorStatus(),
],
meta: {
tuyaDatapoints: [
[2, "preset", tuya.valueConverter.tv02Preset()],
[8, "open_window", tuya.valueConverter.onOff],
[10, null, tuya.valueConverter.TV02FrostProtection],
[10, "frost_protection", tuya.valueConverter.TV02FrostProtection],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[27, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[
31,
"working_day",
tuya.valueConverterBasic.lookup({
mon_sun: tuya.enum(0),
"mon_fri+sat+sun": tuya.enum(1),
separate: tuya.enum(2),
}),
],
[32, "holiday_temperature", tuya.valueConverter.divideBy10],
[35, "battery_low", tuya.valueConverter.trueFalse0],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[45, "error_status", tuya.valueConverter.raw],
[46, "holiday_start_stop", tuya.valueConverter.thermostatHolidayStartStop],
[101, "boost_timeset_countdown", tuya.valueConverter.raw],
[102, "open_window_temperature", tuya.valueConverter.divideBy10],
[104, "comfort_temperature", tuya.valueConverter.divideBy10],
[105, "eco_temperature", tuya.valueConverter.divideBy10],
[106, "schedule", tuya.valueConverter.thermostatScheduleDaySingleDP],
[107, null, tuya.valueConverter.TV02SystemMode],
[107, "system_mode", tuya.valueConverter.TV02SystemMode],
[107, "heating_stop", tuya.valueConverter.TV02SystemMode],
[115, "online", tuya.valueConverter.onOffNotStrict],
[108, "schedule_monday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[112, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[109, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[113, "schedule_thursday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[110, "schedule_friday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[114, "schedule_saturday", tuya.valueConverter.thermostatScheduleDaySingleDP],
[111, "schedule_sunday", tuya.valueConverter.thermostatScheduleDaySingleDP],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_0hg58wyk" /* model: 'S366', vendor: 'Cloud Even' */]),
model: "TS0601_thermostat_2",
vendor: "Tuya",
description: "Thermostat radiator valve",
whiteLabel: [{ vendor: "S366", model: "Cloud Even" }],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[
2,
"preset",
tuya.valueConverterBasic.lookup({
manual: tuya.enum(0),
holiday: tuya.enum(1),
program: tuya.enum(2),
}),
],
[3, null, null], // TODO: Unknown DP
[8, "open_window", tuya.valueConverter.onOff],
[10, "frost_protection", tuya.valueConverter.onOff],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[27, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[35, "battery_low", tuya.valueConverter.trueFalse0],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[45, "error_status", tuya.valueConverter.raw],
[101, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[102, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[103, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[104, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[105, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[106, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[107, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP],
],
},
exposes: [
e.battery_low(),
e.child_lock(),
e.open_window(),
tuya.exposes.frostProtection(),
tuya.exposes.errorStatus(),
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "holiday", "program"])
.withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 30, 0.5, ea.STATE_SET),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
],
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_bvu2wnxz" /* model: 'ME167', vendor: 'AVATTO' */,
"_TZE200_6rdj8dzm" /* model: 'ME167', vendor: 'AVATTO' */,
"_TZE200_9xfjixap" /* model: 'ME167', vendor: 'AVATTO' */,
"_TZE200_jkfbph7l" /* model: 'ME167', vendor: 'AVATTO' */,
"_TZE200_p3dbf6qs" /* model: 'ME167', vendor: 'AVATTO' */,
"_TZE200_rxntag7i" /* model: 'ME168', vendor: 'AVATTO' */,
"_TZE200_yqgbrdyo",
"_TZE284_p3dbf6qs",
"_TZE200_rxq4iti9",
"_TZE204_ogx8u5z6",
"_TZE284_ogx8u5z6",
"_TZE200_hvaxb2tc" /* model: 'TRV06', vendor: 'AVATTO' */,
"_TZE284_o3x45p96" /* model: 'TRV06', vendor: 'AVATTO' */,
"_TZE284_c6wv4xyo" /* model: 'AVATTO_TRV06', vendor: 'AVATTO' */,
"_TZE204_o3x45p96" /* model: 'AVATTO_TRV06', vendor: 'AVATTO' */,
"_TZE200_ow09xlxm" /* model: 'TRV06-AT', vendor: 'THALEOS' */,
"_TZE284_rv6iuyxb" /* model: 'TRV06-AT', vendor: 'THALEOS' */,
"_TZE200_rv6iuyxb" /* model: 'TRV06-AT', vendor: 'THALEOS' */,
"_TZE200_suxywabt" /* model: 'TRV06-AT', vendor: 'THALEOS' */,
]),
model: "TS0601_thermostat_3",
vendor: "Tuya",
description: "Thermostatic radiator valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
whiteLabel: [
tuya.whitelabel("AVATTO", "ME167", "Thermostatic radiator valve", [
"_TZE200_p3dbf6qs",
"_TZE200_bvu2wnxz",
"_TZE200_6rdj8dzm",
"_TZE200_9xfjixap",
"_TZE200_jkfbph7l",
]),
tuya.whitelabel("AVATTO", "ME168_1", "Thermostatic radiator valve", ["_TZE200_rxntag7i"]),
tuya.whitelabel("AVATTO", "TRV06_1", "Thermostatic radiator valve", ["_TZE200_hvaxb2tc", "_TZE284_o3x45p96"]),
tuya.whitelabel("EARU", "TRV06", "Smart thermostat module", ["_TZE200_yqgbrdyo", "_TZE200_rxq4iti9"]),
tuya.whitelabel("AVATTO", "AVATTO_TRV06", "Thermostatic radiator valve", ["_TZE284_c6wv4xyo", "_TZE204_o3x45p96"]),
tuya.whitelabel("THALEOS", "TRV06-AT", "Thermostatic radiator valve", [
"_TZE200_ow09xlxm",
"_TZE284_rv6iuyxb",
"_TZE200_rv6iuyxb",
"_TZE200_suxywabt",
]),
],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.child_lock(),
e.battery_low(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 1, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["auto", "heat", "off"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withPiHeatingDemand()
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e
.binary("scale_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("If the heat sink is not fully opened within " +
"two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be " +
"able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every " +
'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
"again."),
e
.binary("frost_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
e.numeric("error", ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
],
meta: {
tuyaDatapoints: [
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
heat: tuya.enum(1),
off: tuya.enum(2),
}),
],
[
3,
"running_state",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(0),
idle: tuya.enum(1),
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[7, "child_lock", tuya.valueConverter.lockUnlock],
[28, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1, 6)],
[29, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2, 6)],
[30, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3, 6)],
[31, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4, 6)],
[32, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5, 6)],
[33, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6, 6)],
[34, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7, 6)],
[35, null, tuya.valueConverter.errorOrBatteryLow],
[36, "frost_protection", tuya.valueConverter.onOff],
[39, "scale_protection", tuya.valueConverter.onOff],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration2],
[101, "pi_heating_demand", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_pcdmj88b"]),
model: "TS0601_thermostat_4",
vendor: "Tuya",
description: "Thermostatic radiator valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.child_lock(),
e.battery(),
e.battery_low(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 45, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withPreset(["schedule", "holiday", "manual", "comfort", "eco"])
.withSystemMode(["off", "heat"], ea.STATE)
.withLocalTemperatureCalibration(-12, 12, 1, ea.STATE_SET),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e.holiday_temperature().withValueMin(5).withValueMax(45),
e.comfort_temperature().withValueMin(5).withValueMax(45),
e.eco_temperature().withValueMin(5).withValueMax(45),
e
.binary("scale_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("If the heat sink is not fully opened within " +
"two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be " +
"able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every " +
'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
"again."),
e
.binary("frost_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
e.numeric("error", ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
e.binary("boost_heating", ea.STATE_SET, "ON", "OFF").withDescription("Boost Heating: the device will enter the boost heating mode."),
],
meta: {
tuyaDatapoints: [
[
2,
"preset",
tuya.valueConverterBasic.lookup({
schedule: tuya.enum(0),
holiday: tuya.enum(1),
manual: tuya.enum(2),
comfort: tuya.enum(3),
eco: tuya.enum(4),
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[7, "child_lock", tuya.valueConverter.lockUnlock],
[21, "holiday_temperature", tuya.valueConverter.divideBy10],
[24, "comfort_temperature", tuya.valueConverter.divideBy10],
[25, "eco_temperature", tuya.valueConverter.divideBy10],
[28, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[29, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[30, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[31, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[32, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[33, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[34, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[35, "fault_alarm", tuya.valueConverter.errorOrBatteryLow],
[36, "frost_protection", tuya.valueConverter.onOff],
[37, "boost_heating", tuya.valueConverter.onOff],
[39, "scale_protection", tuya.valueConverter.onOff],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration2],
[
49,
"system_mode",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
heat: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: [...tuya.fingerprint("v90ladg\u0000", ["_TYST11_wv90ladg"]), ...tuya.fingerprint("TS0601", ["_TZE200_wv90ladg"])],
model: "HT-08",
vendor: "ETOP",
description: "Wall-mount thermostat",
fromZigbee: [
legacy.fromZigbee.tuya_thermostat_weekly_schedule_2,
legacy.fromZigbee.etop_thermostat,
fz.ignore_basic_report,
fz.ignore_tuya_set_time,
],
toZigbee: [
legacy.toZigbee.etop_thermostat_system_mode,
legacy.toZigbee.etop_thermostat_away_mode,
legacy.toZigbee.tuya_thermostat_child_lock,
legacy.toZigbee.tuya_thermostat_current_heating_setpoint,
legacy.toZigbee.tuya_thermostat_weekly_schedule,
],
onEvent: tuya.onEventSetTime,
meta: {
thermostat: {
weeklyScheduleMaxTransitions: 4,
weeklyScheduleSupportedModes: [1], // bits: 0-heat present, 1-cool present (dec: 1-heat,2-cool,3-heat+cool)
weeklyScheduleFirstDayDpId: 101,
},
},
exposes: [
e.child_lock(),
e.away_mode(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["off", "heat", "auto"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE),
],
},
{
fingerprint: [...tuya.fingerprint("dpplnsn\u0000", ["_TYST11_2dpplnsn"]), ...tuya.fingerprint("TS0601", ["_TZE200_2dpplnsn"])],
model: "HT-10",
vendor: "ETOP",
description: "Radiator valve",
fromZigbee: [
legacy.fromZigbee.tuya_thermostat_weekly_schedule_2,
legacy.fromZigbee.etop_thermostat,
fz.ignore_basic_report,
fz.ignore_tuya_set_time,
],
toZigbee: [
legacy.toZigbee.etop_thermostat_system_mode,
legacy.toZigbee.etop_thermostat_away_mode,
legacy.toZigbee.tuya_thermostat_child_lock,
legacy.toZigbee.tuya_thermostat_current_heating_setpoint,
legacy.toZigbee.tuya_thermostat_weekly_schedule,
],
onEvent: tuya.onEventSetTime,
meta: {
timeout: 20000, // TRV wakes up every 10sec
thermostat: {
weeklyScheduleMaxTransitions: 4,
weeklyScheduleSupportedModes: [1], // bits: 0-heat present, 1-cool present (dec: 1-heat,2-cool,3-heat+cool)
weeklyScheduleFirstDayDpId: 101,
},
},
exposes: [
e.battery_low(),
e.child_lock(),
e.away_mode(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["off", "heat", "auto"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_a4bpgplm", "_TZE200_dv8abrrz", "_TZE200_z1tyspqw", "_TZE200_bvrlmajk"]),
model: "TS0601_thermostat_1",
vendor: "Tuya",
description: "Thermostatic radiator valve",
whiteLabel: [
tuya.whitelabel("id3", "GTZ06", "Thermostatic radiator valve", ["_TZE200_z1tyspqw"]),
tuya.whitelabel("AVATTO", "TRV07", "Thermostatic radiator valve", ["_TZE200_bvrlmajk"]),
],
onEvent: tuya.onEventSetLocalTime,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.child_lock(),
e.max_temperature(),
e.min_temperature(),
e.position(),
e.window_detection(),
e.binary("window", ea.STATE, "CLOSE", "OPEN").withDescription("Window status closed or open "),
e.binary("alarm_switch", ea.STATE, "ON", "OFF").withDescription("Thermostat in error state"),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET)
.withPreset(["auto", "manual", "off", "on"], "MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. " +
'When the set temperature is lower than the "minimum temperature", the valve is closed (forced closed). ' +
"AUTO MODE ⏱ - In this mode, the device executes a preset week programming temperature time and temperature. " +
"ON - In this mode, the thermostat stays open " +
"OFF - In this mode, the thermostat stays closed")
.withSystemMode(["auto", "heat", "off"], ea.STATE)
.withRunningState(["idle", "heat"], ea.STATE),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e
.binary("boost_heating", ea.STATE_SET, "ON", "OFF")
.withDescription('Boost Heating: press and hold "+" for 3 seconds, ' +
"the device will enter the boost heating mode, and the ▷╵◁ will flash. The countdown will be displayed in the APP"),
e.numeric("boost_time", ea.STATE_SET).withUnit("min").withDescription("Countdown in minutes").withValueMin(0).withValueMax(1000),
],
meta: {
tuyaDatapoints: [
[1, null, tuya.valueConverter.thermostatSystemModeAndPreset(null)],
[1, "system_mode", tuya.valueConverter.thermostatSystemModeAndPreset("system_mode")],
[1, "preset", tuya.valueConverter.thermostatSystemModeAndPreset("preset")],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[4, "boost_heating", tuya.valueConverter.onOff],
[5, "boost_time", tuya.valueConverter.countdown],
[6, "running_state", tuya.valueConverterBasic.lookup({ heat: 1, idle: 0 })],
[7, "window", tuya.valueConverterBasic.lookup({ OPEN: 1, CLOSE: 0 })],
[8, "window_detection", tuya.valueConverter.onOff],
[12, "child_lock", tuya.valueConverter.lockUnlock],
[13, "battery", tuya.valueConverter.raw],
[14, "alarm_switch", tuya.valueConverter.onOff],
[15, "min_temperature", tuya.valueConverter.divideBy10],
[16, "max_temperature", tuya.valueConverter.divideBy10],
[17, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[18, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[19, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[20, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[21, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[22, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[23, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[101, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[102, "position", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_rtrmfadk", "_TZE204_cvcu2p6e"]),
model: "TRV601",
vendor: "Tuya",
whiteLabel: [tuya.whitelabel("Sber", "SBDV-00185", "Thermostatic radiator valve", ["_TZE204_cvcu2p6e"])],
description: "Thermostatic radiator valve.",
onEvent: tuya.onEventSetLocalTime,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.child_lock(),
e.max_temperature(),
e.min_temperature(),
e.position(),
e.window_detection(),
e.binary("window", ea.STATE, "OPEN", "CLOSE").withDescription("Window status closed or open "),
e.binary("alarm_switch", ea.STATE, "ON", "OFF").withDescription("Thermostat in error state"),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET)
.withPreset(["auto", "manual", "off", "on"], "MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. " +
'When the set temperature is lower than the "minimum temperature", the valve is closed (forced closed). ' +
"AUTO MODE ⏱ - In this mode, the device executes a preset week programming temperature time and temperature. " +
"ON - In this mode, the thermostat stays open " +
"OFF - In this mode, the thermostat stays closed")
.withSystemMode(["auto", "heat", "off"], ea.STATE)
.withRunningState(["idle", "heat"], ea.STATE),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e
.enum("mode", ea.STATE_SET, ["comfort", "eco"])
.withDescription("Hysteresis - comfort > switches off/on exactly at reached " +
"temperature with valve smooth from 0 to 100%, eco > 0.5 degrees above or below, valve either 0 or 100%"),
],
meta: {
tuyaDatapoints: [
[1, null, tuya.valueConverter.thermostatSystemModeAndPreset(null)],
[1, "system_mode", tuya.valueConverter.thermostatSystemModeAndPreset("system_mode")],
[1, "preset", tuya.valueConverter.thermostatSystemModeAndPreset("preset")],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[6, "running_state", tuya.valueConverterBasic.lookup({ heat: 1, idle: 0 })],
[7, "window", tuya.valueConverterBasic.lookup({ OPEN: 1, CLOSE: 0 })],
[8, "window_detection", tuya.valueConverter.onOff],
[12, "child_lock", tuya.valueConverter.lockUnlock],
[13, "battery", tuya.valueConverter.raw],
[14, "alarm_switch", tuya.valueConverter.onOff],
[15, "min_temperature", tuya.valueConverter.divideBy10],
[16, "max_temperature", tuya.valueConverter.divideBy10],
[17, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[18, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[19, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[20, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[21, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[22, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[23, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[101, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[108, "position", tuya.valueConverter.divideBy10],
[
114,
"mode",
tuya.valueConverterBasic.lookup({
comfort: tuya.enum(0),
eco: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_9mjy74mp", "_TZE200_rtrmfadk", "_TZE200_9mjy74mp"]),
model: "TRV602",
vendor: "Tuya",
description: "Thermostatic radiator valve.",
whiteLabel: [tuya.whitelabel("Moes", "TRV801", "Thermostatic radiator valve", ["_TZE204_9mjy74mp", "_TZE200_9mjy74mp"])],
onEvent: tuya.onEventSetLocalTime,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.child_lock(),
e.max_temperature(),
e.min_temperature(),
e.position(),
e.window_detection(),
e.binary("window", ea.STATE, "OPEN", "CLOSE").withDescription("Window status closed or open "),
e.binary("alarm_switch", ea.STATE, "ON", "OFF").withDescription("Thermostat in error state"),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET)
.withPreset(["auto", "manual", "off", "on"], "MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. " +
'When the set temperature is lower than the "minimum temperature", the valve is closed (forced closed). ' +
"AUTO MODE ⏱ - In this mode, the device executes a preset week programming temperature time and temperature. " +
"ON - In this mode, the thermostat stays open " +
"OFF - In this mode, the thermostat stays closed")
.withSystemMode(["auto", "heat", "off"], ea.STATE)
.withRunningState(["idle", "heat"], ea.STATE),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e.enum("display_brightness", ea.STATE_SET, ["high", "medium", "low"]).withDescription("Display brightness"),
e.enum("screen_orientation", ea.STATE_SET, ["up", "right", "down", "left"]).withDescription("Screen orientation"),
e
.enum("mode", ea.STATE_SET, ["comfort", "eco"])
.withDescription("Hysteresis - comfort > switches off/on exactly at reached " +
"temperature with valve smooth from 0 to 100%, eco > 0.5 degrees above or below, valve either 0 or 100%"),
],
meta: {
tuyaDatapoints: [
[1, null, tuya.valueConverter.thermostatSystemModeAndPreset(null)],
[1, "system_mode", tuya.valueConverter.thermostatSystemModeAndPreset("system_mode")],
[1, "preset", tuya.valueConverter.thermostatSystemModeAndPreset("preset")],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[6, "running_state", tuya.valueConverterBasic.lookup({ heat: 1, idle: 0 })],
[7, "window", tuya.valueConverterBasic.lookup({ OPEN: 1, CLOSE: 0 })],
[8, "window_detection", tuya.valueConverter.onOff],
[12, "child_lock", tuya.valueConverter.lockUnlock],
[13, "battery", tuya.valueConverter.raw],
[14, "alarm_switch", tuya.valueConverter.onOff],
[15, "min_temperature", tuya.valueConverter.divideBy10],
[16, "max_temperature", tuya.valueConverter.divideBy10],
[17, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[18, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[19, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[20, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[21, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[22, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[23, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[101, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[108, "position", tuya.valueConverter.divideBy10],
[
111,
"display_brightness",
tuya.valueConverterBasic.lookup({
high: tuya.enum(0),
medium: tuya.enum(1),
low: tuya.enum(2),
}),
],
[
113,
"screen_orientation",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
right: tuya.enum(1),
down: tuya.enum(2),
left: tuya.enum(3),
}),
],
[
114,
"mode",
tuya.valueConverterBasic.lookup({
comfort: tuya.enum(0),
eco: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_qyr2m29i", "_TZE204_ltwbm23f"]),
model: "TRV602Z",
vendor: "Tuya",
description: "Thermostatic radiator valve.",
whiteLabel: [tuya.whitelabel("Moes", "TRV801Z", "Thermostatic radiator valve", ["_TZE204_qyr2m29i"])],
extend: [tuyaBase({ dp: true })],
exposes: [
e.battery(),
e.child_lock(),
e.max_temperature(),
e.min_temperature(),
e.position(),
e.window_detection(),
e
.numeric("boost_timeset_countdown", ea.STATE_SET)
.withUnit("m")
.withDescription("Setting " +
"minimum 0 - maximum 120 minutes boost time. The boost function is activated. The remaining " +
"time for the function will be counted down in minutes ( 120 to 0 ).")
.withValueMin(0)
.withValueMax(120),
e.binary("frost_protection", ea.STATE_SET, "ON", "OFF").withDescription("Antifreeze function"),
e.binary("window", ea.STATE, "OPEN", "CLOSE").withDescription("Window status closed or open "),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperatureCalibration(-10, 10, 0.1, ea.STATE_SET)
.withPreset(["off", "antifrost", "eco", "comfort", "auto", "on"])
.withRunningState(["idle", "heat"], ea.STATE)
.withSystemMode(["auto", "heat", "off"], ea.STATE),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e.comfort_temperature().withValueMin(5).withValueMax(30).withDescription("Comfort mode temperature"),
e.eco_temperature().withValueMin(5).withValueMax(30).withDescription("Eco mode temperature"),
e.holiday_temperature().withValueMin(5).withValueMax(30).withDescription("Antifreeze mode temperature"),
e.enum("display_brightness", ea.STATE_SET, ["high", "medium", "low"]).withDescription("Display brightness"),
e.enum("screen_orientation", ea.STATE_SET, ["up", "down"]).withDescription("Screen orientation"),
e
.enum("hysteresis", ea.STATE_SET, ["comfort", "eco"])
.withDescription("Hysteresis - comfort > switches off/on exactly at reached " +
"temperature with valve smooth from 0 to 100%, eco > 0.5 degrees above or below, valve either 0 or 100%"),
e.enum("motor_thrust", ea.STATE_SET, ["strong", "middle", "weak"]),
],
meta: {
tuyaDatapoints: [
[
2,
"preset",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
antifrost: tuya.enum(1),
eco: tuya.enum(2),
comfort: tuya.enum(3),
auto: tuya.enum(4),
on: tuya.enum(5),
}),
],
[2, "system_mode", tuya.valueConverter.thermostatSystemModeAndPreset("system_mode")],
[3, "running_state", tuya.valueConverterBasic.lookup({ heat: 1, idle: 0 })],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[
7,
"child_lock",
tuya.valueConverterBasic.lookup({
LOCK: true,
UNLOCK: false,
}),
],
[9, "max_temperature", tuya.valueConverter.divideBy10],
[10, "min_temperature", tuya.valueConverter.divideBy10],
[
14,
"window_detection",
tuya.valueConverterBasic.lookup({
ON: true,
OFF: false,
}),
],
[
15,
"window",
tuya.valueConverterBasic.lookup({
CLOSE: tuya.enum(0),
OPEN: tuya.enum(1),
}),
],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[102, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(1)],
[103, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(2)],
[104, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(3)],
[105, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(4)],
[106, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(5)],
[107, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(6)],
[108, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(7)],
[
110,
"motor_thrust",
tuya.valueConverterBasic.lookup({
strong: tuya.enum(0),
middle: tuya.enum(1),
weak: tuya.enum(2),
}),
],
[
111,
"display_brightness",
tuya.valueConverterBasic.lookup({
high: tuya.enum(0),
medium: tuya.enum(1),
low: tuya.enum(2),
}),
],
[
113,
"screen_orientation",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
}),
],
[114, "position", tuya.valueConverter.divideBy10],
[118, "boost_timeset_countdown", tuya.valueConverter.raw],
[119, "comfort_temperature", tuya.valueConverter.divideBy10],
[120, "eco_temperature", tuya.valueConverter.divideBy10],
[121, "holiday_temperature", tuya.valueConverter.divideBy10],
[122, "frost_protection", tuya.valueConverter.onOff],
[
127,
"hysteresis",
tuya.valueConverterBasic.lookup({
comfort: tuya.enum(0),
eco: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_xalsoe3m"]),
model: "ZHT-002",
vendor: "Moes",
description: "ZHT series thermostat",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON/OFF"),
e.child_lock(),
e.binary("system_mode", ea.STATE_SET, "Auto", "Manual").withDescription("Manual = Manual or Schedule = Auto"),
e.eco_mode(),
e.temperature_sensor_select(["IN", "AL", "OU"]).withLabel("Sensor").withDescription("Choose which sensor to use. Default: AL"),
e.enum("valve_state", ea.STATE, ["close", "open"]).withDescription("State of the valve"),
e
.text("workdays_schedule", ea.STATE_SET)
.withDescription('Workdays schedule, 4 entries max, example: "06:00/20°C 11:20/22°C 16:59/15°C 22:00/25°C"'),
e.min_temperature().withValueMin(0).withValueMax(20),
e.max_temperature().withValueMin(20).withValueMax(50),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 0, 50, 1, ea.STATE_SET)
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
e
.numeric("max_temperature_limit", ea.STATE_SET)
.withDescription("Max temperature limit")
.withValueMin(25)
.withValueMax(70)
.withValueStep(1),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withValueMax(5)
.withValueMin(1)
.withValueStep(1)
.withPreset("default", 1, "Default value")
.withDescription("The difference between the local temperature that triggers heating and the set temperature"),
e.enum("working_day", ea.STATE_SET, ["disabled", "5-2", "6-1", "7"]).withDescription("Workday setting"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
manual: tuya.enum(1),
}),
],
[16, "local_temperature", tuya.valueConverter.divideBy10],
[18, "min_temperature", tuya.valueConverter.raw],
[19, "local_temperature_calibration", tuya.valueConverter.localTemperatureCalibration],
[
23,
"working_day",
tuya.valueConverterBasic.lookup((_, device) => {
if (device.manufacturerName === "_TZE204_xalsoe3m") {
return {
disabled: tuya.enum(0),
"5-2": tuya.enum(1),
"6-1": tuya.enum(2),
"7": tuya.enum(3),
};
}
return {
disabled: tuya.enum(0),
"5-2": tuya.enum(2),
"6-1": tuya.enum(1),
"7": tuya.enum(3),
};
}),
],
[
32,
"sensor",
tuya.valueConverterBasic.lookup({
IN: tuya.enum(0),
AL: tuya.enum(2),
OU: tuya.enum(1),
}),
],
[34, "max_temperature", tuya.valueConverter.raw],
[39, "child_lock", tuya.valueConverter.lockUnlock],
[40, "eco_mode", tuya.valueConverter.onOff],
[
47,
"valve_state",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
open: tuya.enum(1),
}),
],
[50, "current_heating_setpoint", tuya.valueConverter.raw],
[68, "programming_mode", tuya.valueConverter.raw],
[101, "max_temperature_limit", tuya.valueConverter.raw],
[102, "deadzone_temperature", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_ymldrmzx"]),
model: "TRV603-WZ",
vendor: "Tuya",
description: "Thermostatic radiator valve.",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.child_lock(),
e.window_detection(),
e.binary("window", ea.STATE, "OPEN", "CLOSE").withDescription("Window status closed or open "),
e.enum("mode", ea.STATE_SET, ["auto", "manual"]).withDescription("Mode"),
e.binary("holiday_mode", ea.STATE_SET, "ON", "OFF"),
e.binary("heating_stop", ea.STATE_SET, "ON", "OFF"),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET),
e.comfort_temperature().withValueMin(5).withValueMax(30).withDescription("Comfort mode temperature"),
e.eco_temperature().withValueMin(5).withValueMax(30).withDescription("Eco mode temperature"),
e.enum("screen_orientation", ea.STATE_SET, ["up", "right", "down", "left"]).withDescription("Screen orientation"),
tuya.exposes.frostProtection(),
e.binary("boost_heating", ea.STATE_SET, "ON", "OFF"),
e.numeric("boost_time", ea.STATE_SET).withUnit("min").withDescription("Countdown in minutes").withValueMin(0).withValueMax(1000),
e.numeric("fault_code", ea.STATE).withDescription("Raw fault code"),
],
meta: {
tuyaDatapoints: [
[
2,
"mode",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
manual: tuya.enum(2),
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[
7,
"child_lock",
tuya.valueConverterBasic.lookup({
LOCK: true,
UNLOCK: false,
}),
],
[14, "window_detection", tuya.valueConverter.onOff],
[
15,
"window",
tuya.valueConverterBasic.lookup({
CLOSE: tuya.enum(0),
OPEN: tuya.enum(1),
}),
],
[21, "holiday_temperature", tuya.valueConverter.divideBy10],
[36, "frost_protection", tuya.valueConverter.onOff],
[39, "switch_scale", tuya.valueConverter.raw],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[101, "boost_heating", tuya.valueConverter.onOff],
[102, "boost_time", tuya.valueConverter.countdown],
[103, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(1)],
[104, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(2)],
[105, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(3)],
[106, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(4)],
[107, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(5)],
[108, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(6)],
[109, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(7)],
[110, "holiday_mode", tuya.valueConverter.onOff],
[
111,
"screen_orientation",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
right: tuya.enum(1),
down: tuya.enum(2),
left: tuya.enum(3),
}),
],
[112, "antifrost_temperature", tuya.valueConverter.divideBy10],
[113, "heating_stop", tuya.valueConverter.onOff],
[114, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[115, "programming_mode", tuya.valueConverter.raw],
[116, "eco_temperature", tuya.valueConverter.divideBy10],
[117, "comfort_temperature", tuya.valueConverter.divideBy10],
[118, "fault_code", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["TS0121"],
model: "TS0121_plug",
description: "10A UK or 16A EU smart plug",
whiteLabel: [
{ vendor: "BlitzWolf", model: "BW-SHP13" },
{ vendor: "Connecte", model: "4500990" },
{ vendor: "Connecte", model: "4500991" },
{ vendor: "Connecte", model: "4500992" },
{ vendor: "Connecte", model: "4500993" },
],
vendor: "Tuya",
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, tuya.fz.power_outage_memory, tuya.fz.indicator_mode],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tuya.tz.backlight_indicator_mode_1],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acVoltageMultiplier: 1,
acVoltageDivisor: 1,
acCurrentMultiplier: 1,
acCurrentDivisor: 1000,
acPowerMultiplier: 1,
acPowerDivisor: 1,
});
try {
await reporting.currentSummDelivered(endpoint);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
}
catch {
/* fails for some https://github.com/Koenkk/zigbee2mqtt/issues/11179
and https://github.com/Koenkk/zigbee2mqtt/issues/16864 */
}
await endpoint.read("genOnOff", ["onOff", "moesStartUpOnOff", "tuyaBacklightMode"]);
},
options: [exposes.options.measurement_poll_interval()],
// This device doesn't support reporting correctly.
// https://github.com/Koenkk/zigbee-herdsman-converters/pull/1270
exposes: [
e.switch(),
e.power(),
e.current(),
e.voltage(),
e.energy(),
e.enum("power_outage_memory", ea.ALL, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
e.enum("indicator_mode", ea.ALL, ["off", "off/on", "on/off"]).withDescription("LED indicator mode"),
],
onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, true, false),
},
{
fingerprint: tuya.fingerprint("TS0111", ["_TYZB01_ymcdbl3u"]),
model: "TS0111_valve",
vendor: "Tuya",
whiteLabel: [{ vendor: "Tuya", model: "SM-AW713Z" }],
description: "Smart water/gas valve",
extend: [tuya.modernExtend.tuyaOnOff({ indicatorMode: true })],
},
{
// Note: below you will find the TS011F_plug_2 and TS011F_plug_3. These are identified via a fingerprint and
// thus preferred above the TS011F_plug_1 if the fingerprint matches
zigbeeModel: ["TS011F"],
model: "TS011F_plug_1",
description: "Smart plug (with power monitoring)",
vendor: "Tuya",
whiteLabel: [
{ vendor: "LELLKI", model: "TS011F_plug" },
{ vendor: "Neo", model: "NAS-WR01B" },
{ vendor: "BlitzWolf", model: "BW-SHP15" },
{ vendor: "BlitzWolf", model: "BW-SHP13" },
{ vendor: "MatSee Plus", model: "PJ-ZSW01" },
{ vendor: "MODEMIX", model: "MOD037" },
{ vendor: "MODEMIX", model: "MOD048" },
{ vendor: "Coswall", model: "CS-AJ-DE2U-ZG-11" },
{ vendor: "Aubess", model: "TS011F_plug_1" },
tuya.whitelabel("Nous", "A1Z", "Smart plug (with power monitoring)", ["_TZ3000_2putqrmw", "_TZ3000_ksw8qtmt"]),
tuya.whitelabel("Moes", "MOES_plug", "Smart plug (with power monitoring)", ["_TZ3000_yujkchbz"]),
tuya.whitelabel("Moes", "ZK-EU", "Smart wallsocket (with power monitoring)", ["_TZ3000_ss98ec5d"]),
tuya.whitelabel("Elivco", "LSPA9", "Smart plug (with power monitoring)", ["_TZ3000_okaz9tjs"]),
tuya.whitelabel("PSMART", "T440", "Smart wallsocket (with power monitoring)", ["_TZ3000_y4ona9me"]),
tuya.whitelabel("Nous", "A6Z", "Outdoor smart socket", ["_TZ3000_266azbg3"]),
tuya.whitelabel("Nedis", "ZBPO130FWT", "Outdoor smart plug (with power monitoring)", ["_TZ3000_3ias4w4o"]),
tuya.whitelabel("Nous", "A9Z", "Smart ZigBee Socket", ["_TZ3210_ddigca5n"]),
tuya.whitelabel("Girier", "JR-ZPM01", "Smart Plug", ["_TZ3000_ww6drja5"]),
],
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
electricalMeasurements: true,
electricalMeasurementsFzConverter: fzLocal.TS011F_electrical_measurement,
powerOutageMemory: true,
indicatorMode: true,
childLock: true,
onOffCountdown: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
if (!["_TZ3000_0zfrhq4i", "_TZ3000_okaz9tjs", "_TZ3000_typdpbpg"].includes(device.manufacturerName)) {
// Gives INVALID_DATA_TYPE error for _TZ3000_0zfrhq4i (as well as a few others in issue 20028)
// https://github.com/Koenkk/zigbee2mqtt/discussions/19680#discussioncomment-7667035
await reporting.activePower(endpoint, { change: 10 });
}
await reporting.currentSummDelivered(endpoint);
const acCurrentDivisor = device.manufacturerName === "_TZ3000_typdpbpg" ? 2000 : 1000;
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
utils.attachOutputCluster(device, "genOta");
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS011F", [
"_TZ3000_hyfvrar3",
"_TZ3000_v1pdxuqq",
"_TZ3000_8a833yls",
"_TZ3000_bfn1w0mm",
"_TZ3000_nzkqcvvs",
"_TZ3000_rtcrrvia",
]),
model: "TS011F_plug_2",
description: "Smart plug (without power monitoring)",
vendor: "Tuya",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOutageMemory: true,
indicatorMode: true,
childLock: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: [
{ modelID: "TS011F", applicationVersion: 160, priority: -1 },
{ modelID: "TS011F", applicationVersion: 100, priority: -1 },
{ modelID: "TS011F", applicationVersion: 69, priority: -1 },
{ modelID: "TS011F", applicationVersion: 68, priority: -1 },
{ modelID: "TS011F", applicationVersion: 65, priority: -1 },
{ modelID: "TS011F", applicationVersion: 64, priority: -1 },
{ modelID: "TS011F", softwareBuildID: "1.0.5\u0000", priority: -1 },
],
model: "TS011F_plug_3",
description: "Smart plug (with power monitoring by polling)",
vendor: "Tuya",
whiteLabel: [
{ vendor: "VIKEFON", model: "TS011F" },
{ vendor: "BlitzWolf", model: "BW-SHP15" },
{ vendor: "AVATTO", model: "MIUCOT10Z" },
{ vendor: "Neo", model: "NAS-WR01B" },
{ vendor: "Neo", model: "PLUG-001SPB2" },
],
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
electricalMeasurements: true,
powerOutageMemory: true,
indicatorMode: true,
childLock: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
utils.attachOutputCluster(device, "genOta");
device.save();
},
options: [exposes.options.measurement_poll_interval()],
onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, true, // polling for voltage, current and power
[100, 160].includes(device.applicationVersion) || ["1.0.5\u0000"].includes(device.softwareBuildID)),
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_in5s3wn1", "_TZ3000_wbloefbf"]),
model: "TS011F_switch_5_gang",
description: "2 gang 2 usb 1 wall ac outlet",
whiteLabel: [{ vendor: "Milfra", model: "M11Z" }],
vendor: "Tuya",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOutageMemory: true,
childLock: true,
endpoints: ["l1", "l2", "l3", "l4", "l5"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(5), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_dlug3kbc"]),
model: "TS011F_3_gang",
description: "3 gang wall ac outlet",
vendor: "Tuya",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOutageMemory: true,
childLock: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_0zaf1cr8", "_TZE204_ntcy3xu1", "_TZE284_0zaf1cr8"]),
model: "TS0601_smoke_1",
vendor: "Tuya",
description: "Smoke sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.smoke(), e.tamper(), e.battery_low()],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[4, "tamper", tuya.valueConverter.raw],
[14, "battery_low", tuya.valueConverter.trueFalse0],
],
},
whiteLabel: [tuya.whitelabel("Nous", "E8", "Smoke sensor", ["_TZE200_0zaf1cr8", "_TZE284_0zaf1cr8"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ntcy3xu1"]),
model: "TS0601_smoke_6",
vendor: "Tuya",
description: "Smoke sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.smoke(), e.tamper(), tuya.exposes.batteryState()],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[4, "tamper", tuya.valueConverter.raw],
[14, "battery_state", tuya.valueConverter.batteryState],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_m9skfctm", "_TZE200_rccxox8p", "_TZE284_rccxox8p"]),
model: "PA-44Z",
vendor: "Tuya",
description: "Photoelectric smoke detector",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.smoke(),
e.battery(),
tuya.exposes.silence(),
e.test(),
e.numeric("smoke_concentration", ea.STATE).withUnit("ppm").withDescription("Parts per million of smoke detected"),
e.binary("device_fault", ea.STATE, true, false).withDescription("Indicates a fault with the device"),
],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[2, "smoke_concentration", tuya.valueConverter.divideBy10],
[11, "device_fault", tuya.valueConverter.raw],
[15, "battery", tuya.valueConverter.raw],
[16, "silence", tuya.valueConverter.raw],
[101, "test", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ux5v4dbd"]),
vendor: "Tuya",
model: "TS0601_smoke_3",
description: "Photoelectric smoke detector",
whiteLabel: [{ vendor: "KnockautX", model: "SMOAL024" }],
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [e.smoke(), tuya.exposes.batteryState()],
meta: {
tuyaDatapoints: [
/**
* According to the Vendor "KnockautX / Brelag AG" DP 16 "muffling"
* is supported as well. But it was not possible to verify this using
* SMOLA024 devices - therefore it is not included in the device definition.
*
* Data Transfer Type: Send and Report
* Data Type: Bool
* muffling: 16,
*/
[1, "smoke", tuya.valueConverter.trueFalse0],
[14, "battery_state", tuya.valueConverter.batteryState],
],
},
},
{
zigbeeModel: ["5p1vj8r"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_t5p1vj8r", "_TZE200_uebojraa", "_TZE200_vzekyi4c", "_TZE200_yh7aoahi", "_TZE200_dq1mfjug"]),
model: "TS0601_smoke_4",
vendor: "Tuya",
description: "Smoke sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [e.smoke(), e.battery(), tuya.exposes.batteryState()],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[14, "battery_state", tuya.valueConverter.batteryState],
[15, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ytibqbra"]),
model: "TS0601_smoke_5",
vendor: "Tuya",
description: "Smoke sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.smoke(),
e.tamper(),
e.battery(),
tuya.exposes.faultAlarm(),
tuya.exposes.silence(),
e.binary("alarm", ea.STATE_SET, "ON", "OFF").withDescription("Enable the alarm"),
],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[4, "tamper", tuya.valueConverter.raw],
[11, "fault_alarm", tuya.valueConverter.trueFalse1],
[15, "battery", tuya.valueConverter.raw],
[16, "silence", tuya.valueConverter.raw],
[17, "alarm", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_e2bedvo9", "_TZE200_dnz6yvl2", "_TZE284_6ycgarab"]),
model: "ZSS-QY-SSD-A-EN",
vendor: "Tuya",
description: "Smart smoke alarm",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.smoke(),
tuya.exposes.faultAlarm(),
tuya.exposes.batteryState(),
e.battery(),
tuya.exposes.silence(),
tuya.exposes.selfTest(),
e.numeric("smoke_concentration", ea.STATE).withUnit("ppm").withDescription("Parts per million of smoke detected"),
],
meta: {
tuyaDatapoints: [
[1, "smoke", tuya.valueConverter.trueFalse0],
[2, "smoke_concentration", tuya.valueConverter.divideBy10],
[11, "fault_alarm", tuya.valueConverter.trueFalse1],
[14, "battery_state", tuya.valueConverter.batteryState],
[15, "battery", tuya.valueConverter.raw],
[16, "silence", tuya.valueConverter.raw],
[17, "self_test", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_5d3vhjro"]),
model: "SA12IZL",
vendor: "Tuya",
description: "Smart smoke alarm",
meta: { timeout: 30000, disableDefaultResponse: true },
fromZigbee: [legacy.fromZigbee.SA12IZL],
toZigbee: [legacy.toZigbee.SA12IZL_silence_siren, legacy.toZigbee.SA12IZL_alarm],
exposes: [
e.battery(),
e.binary("smoke", ea.STATE, true, false).withDescription("Smoke alarm status"),
e.enum("battery_level", ea.STATE, ["low", "middle", "high"]).withDescription("Battery level state"),
e.binary("alarm", ea.STATE_SET, true, false).withDescription("Enable the alarm"),
e.binary("silence_siren", ea.STATE_SET, true, false).withDescription("Silence the siren"),
],
onEvent: tuya.onEventSetTime,
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_cjbofhxw", "_TZE284_cjbofhxw"]),
model: "PJ-MGW1203",
vendor: "Tuya",
description: "Clamp meter",
fromZigbee: [tuya.fz.datapoints, tuya.fz.gateway_connection_status],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.current(), e.power(), e.voltage(), e.energy()],
meta: {
tuyaDatapoints: [
[18, "current", tuya.valueConverter.divideBy1000],
[19, "power", tuya.valueConverter.divideBy10],
[20, "voltage", tuya.valueConverter.divideBy10],
[101, "energy", tuya.valueConverter.divideBy1000],
],
},
whiteLabel: [tuya.whitelabel("Tuya", "PJ-1203-W", "Electricity energy monitor", ["_TZE284_cjbofhxw"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_bkkmqmyo", "_TZE200_eaac7dkw", "_TZE204_bkkmqmyo"]),
model: "TS0601_din_1",
vendor: "Tuya",
description: "Zigbee DIN energy meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.ac_frequency(),
e.energy(),
e.power(),
e.power_factor().withUnit("%"),
e.voltage(),
e.current(),
e.produced_energy(),
e.power_reactive(),
e.numeric("energy_reactive", ea.STATE).withUnit("kVArh").withDescription("Sum of reactive energy"),
e.numeric("total_energy", ea.STATE).withUnit("kWh").withDescription("Total consumed and produced energy"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant1], // voltage and current
[16, "state", tuya.valueConverter.onOff],
[101, "total_energy", tuya.valueConverter.divideBy100], // total energy produced + consumed
[102, "produced_energy", tuya.valueConverter.divideBy100],
[103, "power", tuya.valueConverter.raw],
[105, "ac_frequency", tuya.valueConverter.divideBy100],
[109, "energy_reactive", tuya.valueConverter.divideBy100], // reactive energy in VArh
[110, "power_reactive", tuya.valueConverter.raw], // reactive power
[111, "power_factor", tuya.valueConverter.divideBy10],
// Ignored for now; we don't know what the values mean
[9, null, null], // Fault - we don't know the possible values here
[17, null, null], // Alarm set1 - value seems garbage "AAAAAAAAAAAAAABkAAEOAACqAAAAAAAKAAAAAAAA"
[18, null, null], // 18 - Alarm set2 - value seems garbage "AAUAZAAFAB4APAAAAAAAAAA="
],
},
whiteLabel: [
{ vendor: "Tuya", model: "RC-MCB" },
tuya.whitelabel("Hiking", "DDS238-2", "Single phase DIN-rail energy meter with switch function", [
"_TZE200_bkkmqmyo",
"_TZE204_bkkmqmyo",
]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_m64smti7"]),
model: "RMDZB-1PNL63",
vendor: "TNCE",
description: "Zigbee DIN single phase energy meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.energy(),
e
.enum("fault", ea.STATE, [
"clear",
"short_circuit_alarm",
"surge_alarm",
"overload_alarm",
"leakagecurr_alarm",
"temp_dif_fault",
"fire_alarm",
"high_power_alarm",
"self_test_alarm",
"ov_cr",
"unbalance_alarm",
"ov_vol",
"undervoltage_alarm",
"miss_phase_alarm",
"outage_alarm",
"magnetism_alarm",
"credit_alarm",
"no_balance_alarm",
])
.withDescription("Fault status of the device (clear = nothing)"),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.currentWithPhase("a"),
e.temperature(),
e
.binary("over_current_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("over_current_threshold", ea.STATE_SET)
.withUnit("A")
.withDescription("Setup the value on the device")
.withValueMin(1)
.withValueMax(63),
e
.binary("over_voltage_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(250)
.withValueMax(300),
e
.binary("under_voltage_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(150)
.withValueMax(200),
e
.binary("high_temperature_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("high_temperature_threshold", ea.STATE_SET)
.withUnit("°C")
.withDescription("Setup value on the device")
.withValueMin(40)
.withValueMax(100),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")],
[
9,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
short_circuit_alarm: 1,
surge_alarm: 2,
overload_alarm: 4,
leakagecurr_alarm: 8,
temp_dif_fault: 16,
fire_alarm: 32,
high_power_alarm: 64,
self_test_alarm: 128,
ov_cr: 256,
unbalance_alarm: 512,
ov_vol: 1024,
undervoltage_alarm: 2048,
miss_phase_alarm: 4096,
outage_alarm: 8192,
magnetism_alarm: 16384,
credit_alarm: 32768,
no_balance_alarm: 65536,
}),
],
[16, "state", tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold_2],
[17, "high_temperature_threshold", tuya.valueConverter.threshold_2],
[17, "high_temperature_breaker", tuya.valueConverter.threshold_2],
[18, null, tuya.valueConverter.threshold_3],
[18, "over_current_threshold", tuya.valueConverter.threshold_3],
[18, "over_current_breaker", tuya.valueConverter.threshold_3],
[18, "over_voltage_threshold", tuya.valueConverter.threshold_3],
[18, "over_voltage_breaker", tuya.valueConverter.threshold_3],
[18, "under_voltage_threshold", tuya.valueConverter.threshold_3],
[18, "under_voltage_breaker", tuya.valueConverter.threshold_3],
[103, "temperature", tuya.valueConverter.raw],
// Ignored for now; we don't know what the values mean
[11, null, null], // Switch prepayment
[12, null, null], // Energy reset
[13, null, null], // Balance enertgy
[14, null, null], // Charge energy
[105, null, null], // Countdown
[106, null, null], // Cycle time
],
},
whiteLabel: [{ vendor: "TNCE", model: "RMDZB-1PNL63" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_wbhaespm", "_TZE200_wbhaespm"]),
model: "STB3L-125-ZJ",
vendor: "SUTON",
description: "Zigbee DIN RCBO energy meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.energy(),
e
.enum("fault", ea.STATE, [
"clear",
"short_circuit_alarm",
"surge_alarm",
"overload_alarm",
"leakagecurr_alarm",
"temp_dif_fault",
"fire_alarm",
"high_power_alarm",
"self_test_alarm",
"ov_cr",
"unbalance_alarm",
"ov_vol",
"undervoltage_alarm",
"miss_phase_alarm",
"outage_alarm",
"magnetism_alarm",
"credit_alarm",
"no_balance_alarm",
])
.withDescription("Fault status of the device (clear = nothing)"),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.temperature(),
e.binary("leakage_test", ea.STATE_SET, "ON", "OFF").withDescription("Turn ON to perform a leagage test"),
e
.binary("over_current_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("over_current_threshold", ea.STATE_SET)
.withUnit("A")
.withDescription("Setup the value on the device")
.withValueMin(1)
.withValueMax(63),
e
.binary("over_voltage_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(250)
.withValueMax(300),
e
.binary("under_voltage_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(150)
.withValueMax(200),
e
.binary("insufficient_balance_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("insufficient_balance_threshold", ea.STATE_SET)
.withUnit("kWh")
.withDescription("Setup value on the device")
.withValueMin(1)
.withValueMax(65535),
e
.binary("overload_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("overload_threshold", ea.STATE_SET)
.withUnit("kW")
.withDescription("Setup value on the device")
.withValueMin(1)
.withValueMax(25),
e
.binary("leakage_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("leakage_threshold", ea.STATE_SET)
.withUnit("mA")
.withDescription("Setup value on the device")
.withValueMin(10)
.withValueMax(90),
e
.binary("high_temperature_breaker", ea.STATE_SET, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will turn off when threshold reached"),
e
.numeric("high_temperature_threshold", ea.STATE_SET)
.withUnit("°C")
.withDescription("Setup value on the device")
.withValueMin(40)
.withValueMax(100),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")],
[7, null, tuya.valueConverter.phaseVariant2WithPhase("b")],
[8, null, tuya.valueConverter.phaseVariant2WithPhase("c")],
[
9,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
short_circuit_alarm: 1,
surge_alarm: 2,
overload_alarm: 4,
leakagecurr_alarm: 8,
temp_dif_fault: 16,
fire_alarm: 32,
high_power_alarm: 64,
self_test_alarm: 128,
ov_cr: 256,
unbalance_alarm: 512,
ov_vol: 1024,
undervoltage_alarm: 2048,
miss_phase_alarm: 4096,
outage_alarm: 8192,
magnetism_alarm: 16384,
credit_alarm: 32768,
no_balance_alarm: 65536,
}),
],
[16, "state", tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold_2],
[17, "overload_breaker", tuya.valueConverter.threshold_2],
[17, "overload_threshold", tuya.valueConverter.threshold_2],
[17, "leakage_threshold", tuya.valueConverter.threshold_2],
[17, "leakage_breaker", tuya.valueConverter.threshold_2],
[17, "high_temperature_threshold", tuya.valueConverter.threshold_2],
[17, "high_temperature_breaker", tuya.valueConverter.threshold_2],
[18, null, tuya.valueConverter.threshold_3],
[18, "over_current_threshold", tuya.valueConverter.threshold_3],
[18, "over_current_breaker", tuya.valueConverter.threshold_3],
[18, "over_voltage_threshold", tuya.valueConverter.threshold_3],
[18, "over_voltage_breaker", tuya.valueConverter.threshold_3],
[18, "under_voltage_threshold", tuya.valueConverter.threshold_3],
[18, "under_voltage_breaker", tuya.valueConverter.threshold_3],
[18, "insufficient_balance_threshold", tuya.valueConverter.threshold_3],
[18, "insufficient_balance_breaker", tuya.valueConverter.threshold_3],
[21, "leakage_test", tuya.valueConverter.onOff], // Leakage test
[102, "temperature", tuya.valueConverter.divideBy10],
// Ignored for now; we don't know what the values mean
[12, null, null], // Clear energy`
[13, null, null],
[14, null, null], // Leakage current
[15, null, null],
],
},
whiteLabel: [{ vendor: "SUTON", model: "STB3L-125/ZJ" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_lsanae15", "_TZE204_lsanae15"]),
model: "TS0601_din_2",
vendor: "Tuya",
description: "Zigbee DIN energy meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.energy(),
e.power(),
e.voltage(),
e.current(),
e
.enum("fault", ea.STATE, [
"clear",
"over_current_threshold",
"over_power_threshold",
"over_voltage threshold",
"wrong_frequency_threshold",
])
.withDescription("Fault status of the device (clear = nothing)"),
e.enum("threshold_1", ea.STATE, ["not_set", "over_current_threshold", "over_voltage_threshold"]).withDescription("State of threshold_1"),
e
.binary("threshold_1_protection", ea.STATE, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will be off when threshold reached"),
e
.numeric("threshold_1_value", ea.STATE)
.withDescription("Can be in Volt or Ampere depending on threshold setting. Setup the value on the device"),
e.enum("threshold_2", ea.STATE, ["not_set", "over_current_threshold", "over_voltage_threshold"]).withDescription("State of threshold_2"),
e
.binary("threshold_2_protection", ea.STATE, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will be off when threshold reached"),
e.numeric("threshold_2_value", ea.STATE).withDescription("Setup value on the device"),
e.binary("clear_fault", ea.STATE_SET, "ON", "OFF").withDescription("Turn ON to clear last the fault"),
e.text("meter_id", ea.STATE).withDescription("Meter ID (ID of device)"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[3, null, null], // Monthly, but sends data only after request
[4, null, null], // Dayly, but sends data only after request
[6, null, tuya.valueConverter.phaseVariant2], // voltage and current
[
10,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
over_current_threshold: 1,
over_power_threshold: 2,
over_voltage_threshold: 4,
wrong_frequency_threshold: 8,
}),
],
[11, null, null], // Frozen - strange function, in native app - nothing is clear
[16, "state", tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold], // It's settable, but can't write converter
[18, "meter_id", tuya.valueConverter.raw],
[20, "clear_fault", tuya.valueConverter.onOff], // Clear fault
[21, null, null], // Forward Energy T1 - don't know what this
[22, null, null], // Forward Energy T2 - don't know what this
[23, null, null], // Forward Energy T3 - don't know what this
[24, null, null], // Forward Energy T4 - don't know what this
],
},
whiteLabel: [tuya.whitelabel("MatSee Plus", "DAC2161C", "Smart Zigbee energy meter 80A din rail", ["_TZE200_lsanae15", "_TZE204_lsanae15"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_rhblgy0z", "_TZE204_rhblgy0z"]),
model: "TS0601_din_3",
vendor: "Tuya",
description: "Zigbee DIN energy meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [{ vendor: "XOCA", model: "DAC2161C" }],
exposes: [
tuya.exposes.switch(),
e.energy(),
e.produced_energy(),
e.power(),
e.voltage(),
e.current(),
e
.enum("fault", ea.STATE, [
"clear",
"over_current_threshold",
"over_power_threshold",
"over_voltage threshold",
"wrong_frequency_threshold",
])
.withDescription("Fault status of the device (clear = nothing)"),
e.enum("threshold_1", ea.STATE, ["not_set", "over_current_threshold", "over_voltage_threshold"]).withDescription("State of threshold_1"),
e
.binary("threshold_1_protection", ea.STATE, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will be off when threshold reached"),
e
.numeric("threshold_1_value", ea.STATE)
.withDescription("Can be in Volt or Ampere depending on threshold setting. Setup the value on the device"),
e.enum("threshold_2", ea.STATE, ["not_set", "over_current_threshold", "over_voltage_threshold"]).withDescription("State of threshold_2"),
e
.binary("threshold_2_protection", ea.STATE, "ON", "OFF")
.withDescription("OFF - alarm only, ON - relay will be off when threshold reached"),
e.numeric("threshold_2_value", ea.STATE).withDescription("Setup value on the device"),
e.binary("clear_fault", ea.STATE_SET, "ON", "OFF").withDescription("Turn ON to clear last the fault"),
e.text("meter_id", ea.STATE).withDescription("Meter ID (ID of device)"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[3, null, null], // Monthly, but sends data only after request
[4, null, null], // Dayly, but sends data only after request
[6, null, tuya.valueConverter.phaseVariant2], // voltage and current
[
10,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
over_current_threshold: 1,
over_power_threshold: 2,
over_voltage_threshold: 4,
wrong_frequency_threshold: 8,
}),
],
[11, null, null], // Frozen - strange function, in native app - nothing is clear
[16, "state", tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold], // It's settable, but can't write converter
[18, "meter_id", tuya.valueConverter.raw],
[20, "clear_fault", tuya.valueConverter.onOff], // Clear fault
[21, null, null], // Forward Energy T1 - don't know what this
[22, null, null], // Forward Energy T2 - don't know what this
[23, null, null], // Forward Energy T3 - don't know what this
[24, null, null], // Forward Energy T4 - don't know what this
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_byzdayie", "_TZE200_fsb6zw01", "_TZE200_ewxhg6o9"]),
model: "TS0601_din",
vendor: "Tuya",
description: "Zigbee smart energy meter DDS238-2 Zigbee",
fromZigbee: [legacy.fromZigbee.tuya_dinrail_switch],
toZigbee: [legacy.toZigbee.tuya_switch_state],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
},
exposes: [e.switch().setAccess("state", ea.STATE_SET), e.voltage(), e.power(), e.current(), e.energy()],
},
{
fingerprint: tuya.fingerprint("TS1101", ["_TZ3000_xfs39dbf"]),
model: "TS1101_dimmer_module_1ch",
vendor: "Tuya",
description: "Zigbee dimmer module 1 channel",
extend: [tuyaLight({ minBrightness: "attribute" })],
},
{
fingerprint: tuya.fingerprint("TS1101", ["_TZ3000_7ysdnebc"]),
model: "TS1101_dimmer_module_2ch",
vendor: "Tuya",
description: "Zigbee dimmer module 2 channel",
whiteLabel: [{ vendor: "OXT", model: "SWTZ25" }],
extend: [
m.deviceEndpoints({ endpoints: { l1: 1, l2: 2 } }),
tuyaLight({
minBrightness: "attribute",
endpointNames: ["l1", "l2"],
configureReporting: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
},
},
{
zigbeeModel: ["RH3001"],
fingerprint: [
{
type: "EndDevice",
manufacturerID: 4098,
applicationVersion: 66,
endpoints: [
{
ID: 1,
profileID: 260,
deviceID: 1026,
inputClusters: [0, 10, 1, 1280],
outputClusters: [25],
},
],
},
],
model: "SNTZ007",
vendor: "Tuya",
description: "Rechargeable Zigbee contact sensor",
fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ignore_time_read],
toZigbee: [],
exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery()],
whiteLabel: [{ vendor: "BlitzWolf", model: "BW-IS2" }],
},
{
zigbeeModel: ["RH3040"],
model: "RH3040",
vendor: "Tuya",
description: "PIR sensor",
fromZigbee: [fz.battery, fz.ignore_basic_report, fz.ias_occupancy_alarm_1],
toZigbee: [],
whiteLabel: [
{ vendor: "Samotech", model: "SM301Z" },
{ vendor: "Nedis", model: "ZBSM10WT" },
],
exposes: [e.battery(), e.occupancy(), e.battery_low(), e.tamper()],
},
{
zigbeeModel: ["TS0115"],
model: "TS0115",
vendor: "Tuya",
description: "Multiprise with 4 AC outlets and 2 USB super charging ports (10A or 16A)",
extend: [
tuya.modernExtend.tuyaOnOff({
endpoints: ["l1", "l2", "l3", "l4", "l5"],
}),
],
whiteLabel: [{ vendor: "UseeLink", model: "SM-SO306E/K/M" }],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 7 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(7), coordinatorEndpoint, ["genOnOff"]);
await device.getEndpoint(1).read("genOnOff", ["onOff", "moesStartUpOnOff"]);
await device.getEndpoint(2).read("genOnOff", ["onOff"]);
await device.getEndpoint(3).read("genOnOff", ["onOff"]);
await device.getEndpoint(4).read("genOnOff", ["onOff"]);
await device.getEndpoint(7).read("genOnOff", ["onOff"]);
},
},
{
zigbeeModel: ["RH3052"],
model: "TT001ZAV20",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [fz.humidity, fz.temperature, fz.battery],
toZigbee: [],
exposes: [e.humidity(), e.temperature(), e.battery()],
},
{
fingerprint: tuya.fingerprint("TS0011", ["_TZ3000_l8fsgo6p"]),
zigbeeModel: ["TS0011"],
model: "TS0011",
vendor: "Tuya",
description: "Smart light switch - 1 gang",
extend: [tuya.modernExtend.tuyaOnOff({ backlightModeOffNormalInverted: true })],
whiteLabel: [
{ vendor: "Vrey", model: "VR-X712U-0013" },
{ vendor: "TUYATEC", model: "GDKES-01TZXD" },
{
vendor: "Lonsonho",
model: "QS-Zigbee-S05-L",
description: "1 gang smart switch module without neutral wire",
},
{ vendor: "Mercator Ikuü", model: "SSW01" },
tuya.whitelabel("Nous", "LZ3", "Smart water/gas valve", ["_TZ3000_abjodzas"]),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
// Reports itself as battery which is not correct: https://github.com/Koenkk/zigbee2mqtt/issues/6190
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS0011", ["_TZ3000_qmi1cfuq", "_TZ3000_txpirhfq", "_TZ3000_ji4araar"]),
model: "TS0011_switch_module",
vendor: "Tuya",
description: "1 gang switch module - (without neutral)",
extend: [tuya.modernExtend.tuyaOnOff({ switchType: true })],
whiteLabel: [
{ vendor: "AVATTO", model: "1gang N-ZLWSM01" },
{ vendor: "SMATRUL", model: "TMZ02L-16A-W" },
{ vendor: "Aubess", model: "TMZ02L-16A-B" },
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
zigbeeModel: ["TS0012"],
model: "TS0012",
vendor: "Tuya",
description: "Smart light switch - 2 gang",
whiteLabel: [
{ vendor: "Vrey", model: "VR-X712U-0013" },
{ vendor: "TUYATEC", model: "GDKES-02TZXD" },
{ vendor: "Earda", model: "ESW-2ZAA-EU" },
{ vendor: "Moes", model: "ZS-US2-BK-MS" },
tuya.whitelabel("Moes", "ZS-EUB_2gang", "Smart light switch - 2 gang", ["_TZ3000_18ejxno0"]),
],
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeOffNormalInverted: true,
endpoints: ["left", "right"],
}),
],
endpoint: (device) => {
return { left: 1, right: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS0012", ["_TZ3000_jl7qyupf", "_TZ3000_nPGIPl5D", "_TZ3000_kpatq5pq", "_TZ3000_ljhbw1c9", "_TZ3000_4zf0crgo"]),
model: "TS0012_switch_module",
vendor: "Tuya",
description: "2 gang switch module - (without neutral)",
whiteLabel: [
{ vendor: "AVATTO", model: "2gang N-ZLWSM01" },
tuya.whitelabel("AVATTO", "LZWSM16-2", "2 gang switch module - (without neutral)", ["_TZ3000_kpatq5pq", "_TZ3000_ljhbw1c9"]),
],
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
onOffCountdown: true,
endpoints: ["left", "right"],
}),
m.forcePowerSource({ powerSource: "Mains (single phase)" }),
],
endpoint: (device) => {
return { left: 1, right: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
zigbeeModel: ["TS0013"],
model: "TS0013",
vendor: "Tuya",
description: "Smart light switch - 3 gang without neutral wire",
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeOffNormalInverted: true,
endpoints: ["left", "center", "right"],
}),
],
endpoint: (device) => {
return { left: 1, center: 2, right: 3 };
},
whiteLabel: [{ vendor: "TUYATEC", model: "GDKES-03TZXD" }],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
try {
for (const ID of [1, 2, 3]) {
const endpoint = device.getEndpoint(ID);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
}
}
catch {
// Fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/4872
}
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS0013", ["_TZ3000_ypgri8yz", "_TZ3000_sznawwyw"]),
model: "TS0013_switch_module",
vendor: "Tuya",
description: "3 gang switch module - (without neutral)",
whiteLabel: [
{ vendor: "AVATTO", model: "3gang N-ZLWSM01" },
tuya.whitelabel("AVATTO", "LZWSM16-3", "3 gang switch module - (without neutral)", ["_TZ3000_sznawwyw"]),
tuya.whitelabel("Girier", "ZB08", "3 Channel Switch Module-L - (No Neutral Wire)", ["_TZ3000_ypgri8yz"]),
],
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
onOffCountdown: true,
endpoints: ["left", "center", "right"],
}),
m.forcePowerSource({ powerSource: "Mains (single phase)" }),
],
endpoint: (device) => {
return { left: 1, center: 2, right: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
try {
for (const ID of [1, 2, 3]) {
const endpoint = device.getEndpoint(ID);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
}
}
catch {
// Fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/4872
}
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
zigbeeModel: ["TS0014"],
model: "TS0014",
vendor: "Tuya",
description: "Smart light switch - 4 gang without neutral wire",
extend: [
tuya.modernExtend.tuyaOnOff({
backlightModeLowMediumHigh: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
whiteLabel: [
{ vendor: "TUYATEC", model: "GDKES-04TZXD" },
{ vendor: "Vizo", model: "VZ-222S" },
{ vendor: "MakeGood", model: "MG-ZG04W/B/G" },
{ vendor: "Mercator Ikuü", model: "SSW04" },
],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
try {
for (const ID of [1, 2, 3, 4]) {
const endpoint = device.getEndpoint(ID);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
}
}
catch {
// Fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/4872
}
device.powerSource = "Mains (single phase)";
device.save();
},
},
{
zigbeeModel: ["gq8b1uv"],
model: "gq8b1uv",
vendor: "Tuya",
description: "Zigbee smart dimmer",
fromZigbee: [legacy.fromZigbee.tuya_dimmer, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.tuya_dimmer_state, legacy.toZigbee.tuya_dimmer_level],
exposes: [e.light_brightness().setAccess("state", ea.STATE_SET).setAccess("brightness", ea.STATE_SET)],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl"]);
},
},
{
zigbeeModel: ["HY0017", "005f0c3b"],
model: "U86KCJ-ZP",
vendor: "Tuya",
description: "Smart 6 key scene wall switch",
fromZigbee: [fzLocal.scenes_recall_scene_65029],
exposes: [e.action(["scene_1", "scene_2", "scene_3", "scene_4", "scene_5", "scene_6"])],
toZigbee: [],
},
{
zigbeeModel: ["TS0026"],
model: "TS0026",
vendor: "Tuya",
description: "6 button scene wall switch",
fromZigbee: [fzLocal.scenes_recall_scene_65029, fzLocal.scene_recall],
exposes: [e.action(["scene_1", "scene_2", "scene_3", "scene_4", "scene_5", "scene_6"])],
toZigbee: [],
},
{
zigbeeModel: ["q9mpfhw"],
model: "SNTZ009",
vendor: "Tuya",
description: "Water leak sensor",
fromZigbee: [legacy.fromZigbee.tuya_water_leak, fz.ignore_basic_report],
exposes: [e.water_leak()],
toZigbee: [],
},
{
zigbeeModel: ["TS0004"],
model: "TS0004",
vendor: "Tuya",
description: "Smart light switch - 4 gang with neutral wire",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
backlightModeOffOn: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
whiteLabel: [
tuya.whitelabel("Tuya", "DS-111", "Smart light switch - 4 gang with neutral wire", ["_TZ3000_mdj7kra9"]),
tuya.whitelabel("MHCOZY", "TYWB 4ch-RF", "4 channel relay", ["_TZ3000_u3oupgdy", "_TZ3000_imaccztn"]),
tuya.whitelabel("AVATTO", "TS0004_1", "Smart light switch - 4 gang with neutral wire", ["_TZ3000_nivavasg", "_TZ3000_gexniqbq"]),
],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_1s0vfmtv", "_TZ3002_zjuvw9zf", "_TZ3002_gdwja9a7"]),
model: "TS0726_2_gang",
vendor: "Tuya",
description: "2 gang switch with neutral wire",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode],
exposes: [
...[1, 2].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
e.action(["scene_1", "scene_2"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_9vcekkp1", "_TZ3000_m4ah6bcz"]),
model: "TS0726_multi_1_gang",
vendor: "Tuya",
description: "Multi 1 gang switch with backlight",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode, tuya.tz.backlight_indicator_mode_2],
exposes: [
e.switch(),
e.power_on_behavior(),
e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(["scene_1"]),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_m3pafcnk", "_TZ3002_m3pafcnk"]),
model: "TS0726_multi_3_gang",
vendor: "Tuya",
description: "multi 3 gang switch with backlight",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode, tuya.tz.backlight_indicator_mode_2],
exposes: [
...[1, 2, 3].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2, 3].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2, 3].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(["scene_1", "scene_2", "scene_3"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_aewsvjcu"]),
model: "TS0726_multi_4_gang",
vendor: "Tuya",
description: "Multi 4 gang switch with backlight",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode, tuya.tz.backlight_indicator_mode_2],
exposes: [
...[1, 2, 3, 4].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(["scene_1", "scene_2", "scene_3", "scene_4"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_qhyadm57"]),
model: "TS0726_4_gang_switch_and_2_scene",
vendor: "Tuya",
description: "Multi 4 gang switch and 2 scene with backlight",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode, tuya.tz.backlight_indicator_mode_2],
exposes: [
...[1, 2, 3, 4].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(["scene_1", "scene_2", "scene_3", "scene_4", "scene_5", "scene_6"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5, l6: 6 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4, 5, 6]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_jn2x20tg"]),
model: "TS0726_1_gang",
vendor: "Tuya",
description: "1 gang switch with neutral wire",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode],
exposes: [e.switch(), e.power_on_behavior(), e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]), e.action(["scene_1"])],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_iedhxgyi"]),
model: "TS0726_3_gang",
vendor: "Tuya",
description: "3 gang switch with neutral wire",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode],
exposes: [
...[1, 2, 3].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2, 3].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2, 3].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
e.action(["scene_1", "scene_2", "scene_3"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_wsspgtcd", "_TZ3000_s678wazd", "_TZ3002_pzao9ls1"]),
model: "TS0726_4_gang",
vendor: "Tuya",
description: "4 gang switch with neutral wire",
fromZigbee: [fz.on_off, tuya.fz.power_on_behavior_2, fz.ignore_basic_report, fzLocal.TS0726_action],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_2, tzLocal.TS0726_switch_mode],
exposes: [
...[1, 2, 3, 4].map((ep) => e.switch().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.power_on_behavior().withEndpoint(`l${ep}`)),
...[1, 2, 3, 4].map((ep) => e.enum("switch_mode", ea.STATE_SET, ["switch", "scene"]).withEndpoint(`l${ep}`)),
e.action(["scene_1", "scene_2", "scene_3", "scene_4"]),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3002_sal078g8"]),
model: "TS0726_switch_4g_2s",
vendor: "Tuya",
description: "COSWALL smart switch (4 gang + 2 scene)",
fromZigbee: [fzLocal.TS0726_action],
exposes: [e.action(["scene_1", "scene_2", "scene_3", "scene_4", "scene_5", "scene_6"])],
extend: [
tuya.modernExtend.tuyaOnOff({
switchMode: true,
powerOnBehavior2: true,
backlightModeOffOn: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5, l6: 6 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4, 5, 6]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
zigbeeModel: ["TS0006"],
model: "TS0006",
vendor: "Tuya",
description: "6 gang switch module with neutral wire",
extend: [tuya.modernExtend.tuyaOnOff()],
exposes: [
e.switch().withEndpoint("l1"),
e.switch().withEndpoint("l2"),
e.switch().withEndpoint("l3"),
e.switch().withEndpoint("l4"),
e.switch().withEndpoint("l5"),
e.switch().withEndpoint("l6"),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5, l6: 6 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(5), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(6), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [tuya.whitelabel("AVATTO", "TS0006_1", "4 gang switch module with neutral wire and socket", ["_TZ3000_cvis4qmw"])],
},
{
zigbeeModel: ["HY0080"],
model: "U86KWF-ZPSJ",
vendor: "Tuya",
description: "Environment controller",
fromZigbee: [fz.thermostat, fz.fan],
toZigbee: [
tz.thermostat_local_temperature,
tz.thermostat_local_temperature_calibration,
tz.thermostat_occupancy,
tz.thermostat_occupied_heating_setpoint,
tz.thermostat_unoccupied_heating_setpoint,
tz.thermostat_occupied_cooling_setpoint,
tz.thermostat_unoccupied_cooling_setpoint,
tz.thermostat_setpoint_raise_lower,
tz.thermostat_remote_sensing,
tz.thermostat_control_sequence_of_operation,
tz.thermostat_system_mode,
tz.thermostat_weekly_schedule,
tz.thermostat_clear_weekly_schedule,
tz.thermostat_relay_status_log,
tz.thermostat_temperature_setpoint_hold,
tz.thermostat_temperature_setpoint_hold_duration,
tz.fan_mode,
],
exposes: [
e
.climate()
.withSetpoint("occupied_heating_setpoint", 5, 30, 0.5)
.withLocalTemperature()
.withSystemMode(["off", "auto", "heat"], ea.ALL)
.withRunningState(["idle", "heat", "cool"], ea.STATE)
.withLocalTemperatureCalibration(-30, 30, 0.1, ea.ALL)
.withPiHeatingDemand(),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(9);
await reporting.bind(endpoint, coordinatorEndpoint, ["hvacThermostat", "hvacFanCtrl"]);
await reporting.thermostatTemperature(endpoint);
await reporting.thermostatSystemMode(endpoint);
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
await reporting.thermostatOccupiedCoolingSetpoint(endpoint);
await reporting.thermostatUnoccupiedCoolingSetpoint(endpoint);
await reporting.fanMode(endpoint);
},
},
{
zigbeeModel: ["6dfgetq"],
model: "D3-DPWK-TY",
vendor: "Tuya",
description: "HVAC controller",
exposes: [
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 30, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["off", "auto", "heat"], ea.STATE_SET)
.withRunningState(["idle", "heat", "cool"], ea.STATE),
],
fromZigbee: [legacy.fromZigbee.tuya_thermostat, fz.ignore_basic_report, legacy.fromZigbee.tuya_dimmer],
meta: {
tuyaThermostatSystemMode: legacy.thermostatSystemModes2,
tuyaThermostatPreset: legacy.thermostatPresets,
},
toZigbee: [
legacy.toZigbee.tuya_thermostat_current_heating_setpoint,
legacy.toZigbee.tuya_thermostat_system_mode,
legacy.toZigbee.tuya_thermostat_fan_mode,
legacy.toZigbee.tuya_dimmer_state,
],
},
{
zigbeeModel: ["E220-KR4N0Z0-HA", "JZ-ZB-004"],
model: "E220-KR4N0Z0-HA",
vendor: "Tuya",
description: "Multiprise with 4 AC outlets and 2 USB super charging ports (16A)",
extend: [tuya.modernExtend.tuyaOnOff()],
fromZigbee: [fz.on_off_skip_duplicate_transaction],
exposes: [e.switch().withEndpoint("l1"), e.switch().withEndpoint("l2"), e.switch().withEndpoint("l3"), e.switch().withEndpoint("l4")],
whiteLabel: [{ vendor: "LELLKI", model: "WP33-EU" }],
meta: { multiEndpoint: true },
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
},
},
{
zigbeeModel: ["TS0216"],
model: "TS0216",
vendor: "Tuya",
description: "Sound and flash siren",
fromZigbee: [fz.ts0216_siren, fz.battery],
exposes: [
e.battery(),
e.binary("alarm", ea.STATE_SET, true, false),
e.numeric("volume", ea.ALL).withValueMin(0).withValueMax(100).withDescription("Volume of siren"),
],
toZigbee: [tz.ts0216_alarm, tz.ts0216_duration, tz.ts0216_volume],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
// Device advertises itself as Router but is an EndDevice
device.type = "EndDevice";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_znzs7yaw"]),
model: "HY08WE",
vendor: "Tuya",
description: "Wall-mount thermostat",
fromZigbee: [legacy.fromZigbee.hy_thermostat, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.hy_thermostat],
onEvent: tuya.onEventSetTime,
exposes: [
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 30, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSystemMode(["off", "auto", "heat"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_g9a3awaj"]),
model: "ZWT07",
vendor: "Tuya",
description: "Wall-mount thermostat",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent({ timeStart: "1970" }),
configure: tuya.configureMagicPacket,
exposes: [
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 60, 0.5, ea.STATE_SET)
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withPreset(["manual", "program"])
.withLocalTemperature(),
e.binary("frost", ea.STATE_SET, "ON", "OFF").withDescription("Antifreeze function"),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[
2,
"preset",
tuya.valueConverterBasic.lookup({
manual: tuya.enum(1),
program: tuya.enum(0),
}),
],
[36, "running_state", tuya.valueConverterBasic.lookup({ heat: 1, idle: 0 })],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[10, "frost", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_2ekuz3dz"]),
model: "X5H-GB-B",
vendor: "Tuya",
description: "Wall-mount thermostat",
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, legacy.fromZigbee.x5h_thermostat],
toZigbee: [legacy.toZigbee.x5h_thermostat],
whiteLabel: [
{ vendor: "Beok", model: "TGR85-ZB" },
{ vendor: "AVATTO", model: "ZWT-100-16A" },
],
exposes: [
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 60, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9.9, 9.9, 0.1, ea.STATE_SET)
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withPreset(["manual", "program"]),
e.temperature_sensor_select(["internal", "external", "both"]),
e
.text("schedule", ea.STATE_SET)
.withDescription("There are 8 periods in the schedule in total. " +
"6 for workdays and 2 for holidays. It should be set in the following format for each of the periods: " +
"`hours:minutes/temperature`. All periods should be set at once and delimited by the space symbol. " +
"For example: `06:00/20.5 08:00/15 11:30/15 13:30/15 17:00/22 22:00/15 06:00/20 22:00/15`. " +
"The thermostat doesn't report the schedule by itself even if you change it manually from device"),
e.child_lock(),
e.week(),
e.enum("brightness_state", ea.STATE_SET, ["off", "low", "medium", "high"]).withDescription("Screen brightness"),
e.binary("sound", ea.STATE_SET, "ON", "OFF").withDescription("Switches beep sound when interacting with thermostat"),
e.binary("frost_protection", ea.STATE_SET, "ON", "OFF").withDescription("Antifreeze function"),
e.binary("factory_reset", ea.STATE_SET, "ON", "OFF").withDescription("Resets all settings to default. Doesn't unpair device."),
e
.numeric("heating_temp_limit", ea.STATE_SET)
.withUnit("°C")
.withValueMax(60)
.withValueMin(5)
.withValueStep(1)
.withPreset("default", 35, "Default value")
.withDescription("Heating temperature limit"),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withUnit("°C")
.withValueMax(9.5)
.withValueMin(0.5)
.withValueStep(0.5)
.withPreset("default", 1, "Default value")
.withDescription("The delta between local_temperature and current_heating_setpoint to trigger Heat"),
e
.numeric("upper_temp", ea.STATE_SET)
.withUnit("°C")
.withValueMax(95)
.withValueMin(35)
.withValueStep(1)
.withPreset("default", 60, "Default value"),
],
onEvent: tuya.onEventSetTime,
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_viy9ihs7", "_TZE204_lzriup1j", "_TZE204_xnbkhhdr", "_TZE284_xnbkhhdr", "_TZE204_oh8y8pv8"]),
model: "ZWT198/ZWT100-BH",
vendor: "Tuya",
description: "Wall thermostat",
onEvent: tuya.onEvent({
timeStart: "1970",
respondToMcuVersionResponse: false,
}),
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.binary("factory_reset", ea.STATE_SET, "ON", "OFF").withDescription("Full factory reset, use with caution!"),
e.child_lock(),
e.temperature_sensor_select(["internal", "external", "both"]),
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "auto", "temporary_manual"])
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9.9, 9.9, 0.1, ea.STATE_SET),
e.binary("frost_protection", ea.STATE_SET, "ON", "OFF").withDescription("Antifreeze function"),
e
.max_temperature_limit()
.withUnit("°C")
.withValueMin(15)
.withValueMax(90)
.withValueStep(0.5)
.withPreset("default", 60, "Default value")
.withDescription("Maximum upper temperature"),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withUnit("°C")
.withValueMax(10)
.withValueMin(0.1)
.withValueStep(0.1)
.withPreset("default", 1, "Default value")
.withDescription("The delta between local_temperature (5<t<35)and current_heating_setpoint to trigger Heat"),
e.enum("backlight_mode", ea.STATE_SET, ["off", "low", "medium", "high"]).withDescription("Intensity of the backlight"),
e.enum("working_day", ea.STATE_SET, ["disabled", "6-1", "5-2", "7"]).withDescription("Workday setting"),
e.text("schedule_weekday", ea.STATE_SET).withDescription("Workdays (6 times `hh:mm/cc.c°C`)"),
e
.text("schedule_holiday", ea.STATE_SET)
.withDescription("Holidays (2 times `hh:mm/cc.c°C)`"),
// ============== exposes for found, but not functional datapoints:
/*
e.min_temperature_limit() // dp 16
.withValueMin(5)
.withValueMax(15)
.withValueStep(0.5)
.withPreset('default', 10, 'Default value')
.withDescription('dp16 is listed in Tuya, but no communication from device'),
e.binary('dp105', ea.STATE_SET, 'ON', 'OFF')
.withDescription('dp105 is not listed in Tuya, but device sends datapoint, binary: true/false'),
e.binary('dp111', ea.STATE_SET, 'ON', 'OFF')
.withDescription('dp111 is not listed in Tuya, but device sends datapoint, binary: true/false'),
*/
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[
4,
"preset",
tuya.valueConverterBasic.lookup((_, device) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/21353#issuecomment-1938328429
if (device.manufacturerName === "_TZE204_lzriup1j") {
return {
auto: tuya.enum(1),
manual: tuya.enum(0),
temporary_manual: tuya.enum(2),
};
}
return {
auto: tuya.enum(0),
manual: tuya.enum(1),
temporary_manual: tuya.enum(2),
};
}),
],
[9, "child_lock", tuya.valueConverter.lockUnlock],
[11, "faultalarm", tuya.valueConverter.raw],
[15, "max_temperature_limit", tuya.valueConverter.divideBy10],
[19, "local_temperature_calibration", tuya.valueConverter.localTempCalibration3],
[
101,
"running_state",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(1),
idle: tuya.enum(0),
}),
],
[102, "frost_protection", tuya.valueConverter.onOff],
[103, "factory_reset", tuya.valueConverter.onOff],
[
104,
"working_day",
tuya.valueConverterBasic.lookup((_, device) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/23979
if (device.manufacturerName === "_TZE200_viy9ihs7") {
return {
disabled: tuya.enum(0),
"6-1": tuya.enum(1),
"5-2": tuya.enum(2),
"7": tuya.enum(3),
};
}
return {
disabled: tuya.enum(0),
"6-1": tuya.enum(2),
"5-2": tuya.enum(1),
"7": tuya.enum(3),
};
}),
],
[
106,
"sensor",
tuya.valueConverterBasic.lookup({
internal: tuya.enum(0),
external: tuya.enum(1),
both: tuya.enum(2),
}),
],
[107, "deadzone_temperature", tuya.valueConverter.divideBy10],
[109, null, tuya.valueConverter.ZWT198_schedule],
[109, "schedule_weekday", tuya.valueConverter.ZWT198_schedule],
[109, "schedule_holiday", tuya.valueConverter.ZWT198_schedule],
[110, "backlight_mode", tuya.valueConverter.backlightModeOffLowMediumHigh],
// ============== found but not functional datapoints:
// [16, 'min_temperature_limit', tuya.valueConverter.divideBy10], // datapoint listed in Tuya, but no communication from device
// [105, 'dp105', tuya.valueConverter.onOff], // not listed in Tuya, but device sends datapoint
// [111, 'dp111', tuya.valueConverter.onOff], // not listed in Tuya, but device sends datapoint
// These are the schedule values in bytes, 8 periods in total (4 bytes per period).
// For each period:
// 1st byte: hour
// 2nd byte: minute
// 3rd, 4th bytes: temperature multiplied by 10
// On the device last 2 periods are ignored if schedule_mode is 7day. When schedule_mode is disabled,
// scheduling can't be configured at all on the device.
// For example, if schedule_mode is weekday/sat+sun and this byte array is received:
// [6,10,1,144,8,10,0,170,11,40,0,170,12,40,0,170,17,10,0,230,22,10,0,170,8,5,0,200,23,0,0,160]
// Then the schedule is:
// Mon-Fri: 6:10 --> 40C, 8:10 --> 17C, 11:40 --> 17C, 12:40 --> 17C, 17:10 --> 23C, 22:10 --> 17C
// Sat-Sun: 8:05 --> 20C, 23:00 --> 16C
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_mwomyz5n", "_TZE204_cvub6xbb"]),
model: "TGM50-ZB",
vendor: "Tuya",
description: "Beok wall thermostat",
onEvent: tuya.onEvent({ timeStart: "1970" }),
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.child_lock(),
e.temperature_sensor_select(["internal", "external", "both"]),
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "auto"])
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9.9, 9.9, 0.1, ea.STATE_SET),
e.enum("backlight_mode", ea.STATE_SET, ["off", "always_low", "always_mid", "always_high"]).withDescription("Intensity of the backlight"),
e.binary("frost_protection", ea.STATE_SET, "ON", "OFF").withDescription("Antifreeze function"),
e
.max_temperature_limit()
.withUnit("°C")
.withValueMin(15)
.withValueMax(90)
.withValueStep(0.5)
.withPreset("default", 60, "Default value")
.withDescription("Maximum upper temperature"),
e
.numeric("temperature_delta", ea.STATE_SET)
.withUnit("°C")
.withValueMax(10)
.withValueMin(0.5)
.withValueStep(0.5)
.withPreset("default", 1, "Default value")
.withDescription("The delta between local_temperature and current_heating_setpoint to trigger Heat"),
e.binary("factory_reset", ea.STATE_SET, "ON", "OFF").withDescription("Full factory reset, use with caution!"),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[
4,
"preset",
tuya.valueConverterBasic.lookup({
manual: tuya.enum(0),
auto: tuya.enum(1),
}),
],
[9, "child_lock", tuya.valueConverter.lockUnlock],
[15, "max_temperature_limit", tuya.valueConverter.divideBy10],
[19, "local_temperature_calibration", tuya.valueConverter.localTempCalibration3],
[
101,
"running_state",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(1),
idle: tuya.enum(0),
}),
],
[102, "frost_protection", tuya.valueConverter.onOff],
[103, "factory_reset", tuya.valueConverter.onOff],
[
106,
"sensor",
tuya.valueConverterBasic.lookup({
internal: tuya.enum(0),
external: tuya.enum(1),
both: tuya.enum(2),
}),
],
[107, "temperature_delta", tuya.valueConverter.divideBy10],
[
110,
"backlight_mode",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
always_low: tuya.enum(1),
always_mid: tuya.enum(2),
always_high: tuya.enum(3),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0222", ["_TZ3000_kky16aay", "_TZE204_myd45weu"]),
model: "TS0222_temperature_humidity",
vendor: "Tuya",
description: "Temperature & humidity sensor",
fromZigbee: [fzLocal.TS0222_humidity, fz.battery, fz.temperature],
toZigbee: [],
configure: tuya.configureMagicPacket,
exposes: [e.battery(), e.temperature(), e.humidity()],
whiteLabel: [tuya.whitelabel("Tuya", "QT-07S", "Soil sensor", ["_TZE204_myd45weu"])],
extend: [m.illuminance()],
},
{
fingerprint: tuya.fingerprint("TS0222", ["_TZ3000_8uxxzz4b", "_TZ3000_hy6ncvmw", "_TZ3000_9kbbfeho", "_TZ3000_l6rsaipj"]),
model: "TS0222_light",
vendor: "Tuya",
description: "Light sensor",
fromZigbee: [fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
whiteLabel: [tuya.whitelabel("Moes", "ZSS-QT-LS-C", "Light sensor", ["_TZ3000_9kbbfeho"])],
exposes: [e.battery()],
extend: [m.illuminance()],
},
{
fingerprint: tuya.fingerprint("TS0222", ["_TZ3000_t9qqxn70"]),
model: "THE01860A",
vendor: "Tuya",
description: "Temp & humidity flower sensor with illuminance",
fromZigbee: [fz.humidity, fz.battery, fz.temperature],
toZigbee: [],
configure: tuya.configureMagicPacket,
exposes: [e.battery(), e.temperature(), e.humidity()],
extend: [m.illuminance()],
},
{
fingerprint: tuya.fingerprint("TS0222", ["_TYZB01_4mdqxxnn", "_TYZB01_m6ec2pgj", "_TZ3000_do6txrcw"]),
model: "TS0222",
vendor: "Tuya",
description: "Light intensity sensor",
fromZigbee: [fz.battery, legacy.fromZigbee.TS0222],
toZigbee: [],
exposes: [e.battery()],
configure: tuya.configureMagicPacket,
extend: [m.illuminance()],
},
{
zigbeeModel: ["TS0210"],
model: "TS0210",
vendor: "Tuya",
description: "Vibration sensor",
whiteLabel: [
tuya.whitelabel("Niceboy", "ORBIS Vibration Sensor", "Vibration sensor", ["_TYZB01_821siati"]),
tuya.whitelabel("iHseno", "_TZ3000_lzdjjfss", "Vibration sensor", ["_TZ3000_lzdjjfss"]),
],
fromZigbee: [fz.battery, fz.ias_vibration_alarm_1_with_timeout],
toZigbee: [tz.TS0210_sensitivity],
exposes: [
e.battery(),
e.battery_voltage(),
e.vibration(),
e
.numeric("sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(50)
.withDescription("Sensitivity of the sensor (0 = highest sensitivity, 50 = lowest sensitivity). " +
"Press button on the device right before changing this"),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_8ply8mjj"]),
model: "COZIGVS",
vendor: "Conecto",
description: "Vibration sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.vibration(),
e
.numeric("sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(2)
.withDescription("Sensitivity of the sensor (single press the button when muted to switch between" +
" low (one beep), medium (two beeps) and max (three beeps))"),
e.text("buzzer_mute", ea.STATE).withDescription("ON when buzzer is muted (double press the button on device to toggle)"),
],
meta: {
tuyaDatapoints: [
[1, "vibration", tuya.valueConverter.trueFalse1],
[101, "sensitivity", tuya.valueConverter.raw],
[103, "buzzer_mute", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_8bxrzyxz", "_TZ3000_ky0fq4ho"]),
model: "TS011F_din_smart_relay",
description: "Din smart relay (with power monitoring)",
vendor: "Tuya",
fromZigbee: [
fz.on_off,
fz.electrical_measurement,
fz.metering,
fz.ignore_basic_report,
tuya.fz.power_outage_memory,
fz.tuya_relay_din_led_indicator,
],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tz.tuya_relay_din_led_indicator],
whiteLabel: [{ vendor: "MatSee Plus", model: "ATMS1602Z" }],
ota: true,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
await reporting.currentSummDelivered(endpoint);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
exposes: [
e.switch(),
e.power(),
e.current(),
e.voltage(),
e.energy(),
e.enum("power_outage_memory", ea.ALL, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
e.enum("indicator_mode", ea.STATE_SET, ["off", "on_off", "off_on"]).withDescription("Relay LED indicator mode"),
],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_qeuvnohg", "_TZ3000_6l1pjfqe", "_TZ3000_2iiimqs9"]),
model: "TS011F_din_smart_relay_polling",
description: "Din smart relay (with power monitoring via polling)",
vendor: "Tuya",
fromZigbee: [
fz.on_off,
fz.electrical_measurement,
fz.metering,
fz.ignore_basic_report,
tuya.fz.power_outage_memory,
fz.tuya_relay_din_led_indicator,
],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tz.tuya_relay_din_led_indicator],
whiteLabel: [
tuya.whitelabel("Tongou", "TO-Q-SY1-JZT", "Din smart relay (with power monitoring via polling)", ["_TZ3000_qeuvnohg"]),
tuya.whitelabel("TOMZN", "TOB9Z-63M", "Din smart relay (with power monitoring via polling)", ["_TZ3000_6l1pjfqe"]),
tuya.whitelabel("Nous", "DZ", "DIN Switch (with power monitoring via polling)", ["_TZ3000_2iiimqs9"]),
],
ota: true,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
await reporting.currentSummDelivered(endpoint);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
exposes: [
e.switch(),
e.power(),
e.current(),
e.voltage(),
e.energy(),
e.enum("power_outage_memory", ea.ALL, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
e.enum("indicator_mode", ea.STATE_SET, ["off", "on_off", "off_on"]).withDescription("Relay LED indicator mode"),
],
options: [exposes.options.measurement_poll_interval()],
onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, true, false),
},
{
fingerprint: [...tuya.fingerprint("TS011F", ["_TZ3000_7issjl2q"]), ...tuya.fingerprint("TS0011", ["_TZ3000_gzvniqjb"])],
model: "ATMS1601Z",
description: "Din smart relay (without power monitoring)",
vendor: "Tuya",
fromZigbee: [fz.on_off, fz.ignore_basic_report, tuya.fz.power_outage_memory, fz.tuya_relay_din_led_indicator],
toZigbee: [tz.on_off, tuya.tz.power_on_behavior_1, tz.tuya_relay_din_led_indicator],
whiteLabel: [tuya.whitelabel("Tongou", "TO-Q-SY1-ZT", "Din smart relay (without power monitoring)", ["_TZ3000_gzvniqjb"])],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
device.save();
},
exposes: [
e.switch(),
e.enum("power_outage_memory", ea.ALL, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
e.enum("indicator_mode", ea.STATE_SET, ["off", "on_off", "off_on"]).withDescription("Relay LED indicator mode"),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_nklqjk62", "_TZE200_nklqjk62"]),
model: "PJ-ZGD01",
vendor: "Tuya",
description: "Garage door opener",
whiteLabel: [{ vendor: "MatSee Plus", model: "PJ-ZGD01" }],
extend: [
tuyaMagicPacket(),
dpBinary({
name: "trigger",
dp: 1,
type: tuya.dataTypes.bool,
valueOn: [true, true],
valueOff: [false, false],
description: "Request door to close (= false) or open (= true), will not pulse output if contact shows door is already in requested state",
}),
dpNumeric({
name: "countdown",
dp: 2,
type: tuya.dataTypes.number,
description: "Countdown to trigger door movement after a certain time, will pulse output in all cases",
unit: "s",
valueMin: 0,
valueMax: 43200,
}),
dpBinary({
name: "garage_door_contact",
dp: 3,
type: tuya.dataTypes.bool,
valueOn: [true, false],
valueOff: [false, true],
description: "Indicates if the garage door contact is closed (= true) or open (= false)",
readOnly: true,
}),
dpNumeric({
name: "run_time",
dp: 4,
type: tuya.dataTypes.number,
description: "Configure the time to wait for the door contact status to change before triggering a run time alarm",
unit: "s",
valueMin: 0,
valueMax: 120,
}),
dpNumeric({
name: "open_alarm_time",
dp: 5,
type: tuya.dataTypes.number,
description: "Configure the amount of time the door may be open before an open time alarm is triggered",
unit: "s",
valueMin: 0,
valueMax: 86400,
}),
dpEnumLookup({
name: "status",
dp: 12,
type: tuya.dataTypes.enum,
description: "Indicates run time alarm, door open alarm or normal status, will not return to normal until door is triggered again",
lookup: { "Open Time Alarm": 0, "Run Time Alarm": 1, Normal: 2 },
readOnly: true,
}),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wfxuhoea"]),
model: "GDC311ZBQ1",
vendor: "Tuya",
description: "LoraTap garage door opener with wireless sensor",
fromZigbee: [legacy.fromZigbee.matsee_garage_door_opener, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.matsee_garage_door_opener, legacy.toZigbee.tuya_data_point_test],
whiteLabel: [{ vendor: "LoraTap", model: "GDC311ZBQ1" }],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]);
},
exposes: [
e.binary("trigger", ea.STATE_SET, true, false).withDescription("Trigger the door movement"),
e
.binary("garage_door_contact", ea.STATE, false, true)
.withDescription("Indicates if the garage door contact is closed (= true) or open (= false)"),
],
},
{
fingerprint: tuya.fingerprint("TS0603", ["_TZE608_c75zqghm", "_TZE608_fmemczv1", "_TZE608_xkr8gep3"]),
model: "TS0603",
vendor: "Tuya",
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.raw],
[3, "garage_door_contact", tuya.valueConverter.trueFalseInvert],
[12, null, null],
],
},
description: "Garage door opener",
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]);
},
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.binary("state", ea.STATE_SET, true, false).withDescription("Trigger the door movement"),
e
.binary("garage_door_contact", ea.STATE, true, false)
.withDescription("Indicates if the garage door contact is closed (= true) or open (= false)"),
],
},
{
fingerprint: tuya.fingerprint("TS0201", ["_TZ3000_qaaysllp"]),
model: "LCZ030",
vendor: "Tuya",
description: "Temperature & humidity & illuminance sensor with display",
fromZigbee: [fz.battery, fz.temperature, fz.humidity, fz.ts0201_temperature_humidity_alarm],
toZigbee: [tz.ts0201_temperature_humidity_alarm],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
// Enables reporting of measurement state changes
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(endpoint, coordinatorEndpoint, [
"genBasic",
"genPowerCfg",
"msTemperatureMeasurement",
"msRelativeHumidity",
"manuSpecificTuya_2",
]);
},
exposes: [
e.temperature(),
e.humidity(),
e.battery(),
e
.numeric("alarm_temperature_max", ea.STATE_SET)
.withUnit("°C")
.withDescription("Alarm temperature max")
.withValueMin(-20)
.withValueMax(80),
e
.numeric("alarm_temperature_min", ea.STATE_SET)
.withUnit("°C")
.withDescription("Alarm temperature min")
.withValueMin(-20)
.withValueMax(80),
e.numeric("alarm_humidity_max", ea.STATE_SET).withUnit("%").withDescription("Alarm humidity max").withValueMin(0).withValueMax(100),
e.numeric("alarm_humidity_min", ea.STATE_SET).withUnit("%").withDescription("Alarm humidity min").withValueMin(0).withValueMax(100),
e.enum("alarm_humidity", ea.STATE, ["below_min_humdity", "over_humidity", "off"]).withDescription("Alarm humidity status"),
e.enum("alarm_temperature", ea.STATE, ["below_min_temperature", "over_temperature", "off"]).withDescription("Alarm temperature status"),
],
extend: [m.illuminance()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_auin8mzr"]),
model: "TS0601_motion_sensor",
vendor: "Tuya",
description: "Human presence sensor AIR",
fromZigbee: [legacy.fromZigbee.tuya_motion_sensor],
toZigbee: [legacy.toZigbee.tuya_motion_sensor],
exposes: [
e.occupancy(),
e.enum("o_sensitivity", ea.STATE_SET, Object.values(legacy.msLookups.OSensitivity)).withDescription("O-Sensitivity mode"),
e.enum("v_sensitivity", ea.STATE_SET, Object.values(legacy.msLookups.VSensitivity)).withDescription("V-Sensitivity mode"),
e.enum("led_status", ea.STATE_SET, ["ON", "OFF"]).withDescription("Led status switch"),
e.numeric("vacancy_delay", ea.STATE_SET).withUnit("sec").withDescription("Vacancy delay").withValueMin(0).withValueMax(1000),
e.numeric("light_on_luminance_prefer", ea.STATE_SET).withDescription("Light-On luminance prefer").withValueMin(0).withValueMax(10000),
e.numeric("light_off_luminance_prefer", ea.STATE_SET).withDescription("Light-Off luminance prefer").withValueMin(0).withValueMax(10000),
e.enum("mode", ea.STATE_SET, Object.values(legacy.msLookups.Mode)).withDescription("Working mode"),
e.numeric("luminance_level", ea.STATE).withDescription("Luminance level"),
e.numeric("reference_luminance", ea.STATE).withDescription("Reference luminance"),
e.numeric("vacant_confirm_time", ea.STATE).withDescription("Vacant confirm time"),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_lu01t0zl", "_TZE200_vrfecyku", "_TZE200_ypprdwsl", "_TZE200_jkbljri7"]),
model: "MIR-HE200-TY",
vendor: "Tuya",
description: "Human presence sensor with fall function",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await tuya.sendDataPointEnum(endpoint, legacy.dataPoints.trsfTumbleSwitch, 0);
await tuya.configureMagicPacket(device, coordinatorEndpoint);
},
exposes: [
e.illuminance(),
e.presence(),
e.occupancy(),
e.numeric("motion_speed", ea.STATE).withDescription("Speed of movement"),
e
.enum("motion_direction", ea.STATE, ["standing_still", "moving_forward", "moving_backward"])
.withDescription("direction of movement from the point of view of the radar"),
e
.numeric("radar_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("Sensitivity of the radar"),
e
.enum("radar_scene", ea.STATE_SET, ["default", "area", "toilet", "bedroom", "parlour", "office", "hotel"])
.withDescription("Presets for sensitivity for presence and movement"),
e.enum("tumble_switch", ea.STATE_SET, ["ON", "OFF"]).withDescription("Tumble status switch"),
e
.numeric("fall_sensitivity", ea.STATE_SET)
.withValueMin(1)
.withValueMax(10)
.withValueStep(1)
.withDescription("Fall sensitivity of the radar"),
e
.numeric("tumble_alarm_time", ea.STATE_SET)
.withValueMin(1)
.withValueMax(5)
.withValueStep(1)
.withUnit("min")
.withDescription("Tumble alarm time"),
e.enum("fall_down_status", ea.STATE, ["none", "maybe_fall", "fall"]).withDescription("Fall down status"),
e.text("static_dwell_alarm", ea.STATE).withDescription("Static dwell alarm"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[2, "radar_sensitivity", tuya.valueConverter.raw],
[102, "occupancy", tuya.valueConverter.trueFalse1],
[103, "illuminance", tuya.valueConverter.raw],
[105, "tumble_switch", tuya.valueConverter.plus1],
[106, "tumble_alarm_time", tuya.valueConverter.raw],
[
112,
"radar_scene",
tuya.valueConverterBasic.lookup({
default: 0,
area: 1,
toilet: 2,
bedroom: 3,
parlour: 4,
office: 5,
hotel: 6,
}),
],
[
114,
"motion_direction",
tuya.valueConverterBasic.lookup({
standing_still: 0,
moving_forward: 1,
moving_backward: 2,
}),
],
[115, "motion_speed", tuya.valueConverter.raw],
[116, "fall_down_status", tuya.valueConverterBasic.lookup({ none: 0, maybe_fall: 1, fall: 2 })],
[117, "static_dwell_alarm", tuya.valueConverter.raw],
[118, "fall_sensitivity", tuya.valueConverter.raw],
// Below are ignored
[101, null, null], // reset_flag_code
[104, null, null], // detection_flag_code
[107, null, null], // radar_check_end_code
[108, null, null], // radar_check_start_code
[109, null, null], // hw_version_code
[110, null, null], // sw_version_code
[111, null, null], // radar_id_code
],
},
},
{
zigbeeModel: ["TS0046"],
model: "TS0046",
vendor: "Tuya",
description: "Wireless switch with 6 buttons",
whiteLabel: [{ vendor: "LoraTap", model: "SS9600ZB" }],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
exposes: [
e.battery(),
e.action([
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
"5_single",
"5_double",
"5_hold",
"6_single",
"6_double",
"6_hold",
]),
],
toZigbee: [],
configure: tuya.configureMagicPacket,
},
{
fingerprint: tuya.fingerprint("TS004F", ["_TZ3000_g9g2xnch", "_TZ3000_pcqjmcud"]),
model: "YSR-MINI-Z",
vendor: "Tuya",
description: "2 in 1 dimming remote control and scene control",
exposes: [
e.battery(),
e.action([
"on",
"off",
"brightness_move_up",
"brightness_step_up",
"brightness_step_down",
"brightness_move_down",
"brightness_stop",
"color_temperature_step_down",
"color_temperature_step_up",
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
]),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
.withDescription('Operation mode: "command" - for group control, "event" - for clicks'),
],
fromZigbee: [
fz.battery,
fz.command_on,
fz.command_off,
fz.command_step,
fz.command_move,
fz.command_stop,
fz.command_step_color_temperature,
tuya.fz.on_off_action,
fz.tuya_operation_mode,
],
toZigbee: [tz.tuya_operation_mode],
onEvent: tuya.onEventSetLocalTime,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("genBasic", [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe]);
await endpoint.write("genOnOff", { tuyaOperationMode: 1 });
await endpoint.read("genOnOff", ["tuyaOperationMode"]);
try {
await endpoint.read(0xe001, [0xd011]);
}
catch {
/* do nothing */
}
await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_hkdl5fmv"]),
model: "TS0601_rcbo",
vendor: "Tuya",
whiteLabel: [
{ vendor: "HOCH", model: "ZJSBL7-100Z" },
{ vendor: "WDYK", model: "ZJSBL7-100Z" },
],
description: "DIN mount RCBO with smart energy metering",
fromZigbee: [legacy.fromZigbee.hoch_din],
toZigbee: [legacy.toZigbee.hoch_din],
exposes: [
e.text("meter_number", ea.STATE).withDescription("Meter number"),
e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("State"),
e.text("alarm", ea.STATE).withDescription("Alarm text"),
e.binary("trip", ea.STATE_SET, "trip", "clear").withDescription("Trip"),
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withDescription("Child lock"),
e.enum("power_on_behavior", ea.STATE_SET, ["off", "on", "previous"]).withDescription("Power on behavior"),
e.numeric("countdown_timer", ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit("s").withDescription("Countdown timer"),
e.numeric("voltage_rms", ea.STATE).withUnit("V").withDescription("Voltage RMS"),
e.numeric("current", ea.STATE).withUnit("A").withDescription("Current"),
e.numeric("current_average", ea.STATE).withUnit("A").withDescription("Current average"),
e.power(),
e.voltage(),
e.energy(),
e.temperature(),
e.numeric("power_l1", ea.STATE).withUnit("W").withDescription("Instantaneous measured power on phase 1"),
e.numeric("power_l2", ea.STATE).withUnit("W").withDescription("Instantaneous measured power on phase 2"),
e.numeric("power_l3", ea.STATE).withUnit("W").withDescription("Instantaneous measured power on phase 3"),
e.numeric("energy_consumed", ea.STATE).withUnit("kWh").withDescription("Consumed energy"),
e.enum("clear_device_data", ea.SET, [""]).withDescription("Clear device data"),
],
},
{
fingerprint: tuya.fingerprint("TS004F", [
"_TZ3000_4fjiwweb",
"_TZ3000_uri7ongn",
"_TZ3000_ixla93vd",
"_TZ3000_qja6nq5z",
"_TZ3000_402vrq2i",
"_TZ3000_abrsvsou",
]),
model: "ERS-10TZBVK-AA",
vendor: "Tuya",
description: "Smart knob",
fromZigbee: [
fz.command_step,
fz.command_toggle,
fz.command_move_hue,
fz.command_step_color_temperature,
fz.command_stop_move_raw,
fz.tuya_multi_action,
fz.tuya_operation_mode,
fz.battery,
],
whiteLabel: [tuya.whitelabel("Tuya", "ZG-101Z_D", "Smart knob", ["_TZ3000_402vrq2i"])],
toZigbee: [tz.tuya_operation_mode],
exposes: [
e.action([
"toggle",
"brightness_step_up",
"brightness_step_down",
"color_temperature_step_up",
"color_temperature_step_down",
"saturation_move",
"hue_move",
"hue_stop",
"single",
"double",
"hold",
"rotate_left",
"rotate_right",
]),
e.numeric("action_step_size", ea.STATE).withValueMin(0).withValueMax(255),
e.numeric("action_transition_time", ea.STATE).withUnit("s"),
e.numeric("action_rate", ea.STATE).withValueMin(0).withValueMax(255),
e.battery(),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
.withDescription('Operation mode: "command" - for group control, "event" - for clicks'),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("genBasic", [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe]);
await endpoint.write("genOnOff", { tuyaOperationMode: 1 });
await endpoint.read("genOnOff", ["tuyaOperationMode"]);
try {
await endpoint.read(0xe001, [0xd011]);
}
catch {
/* do nothing */
}
await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]);
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
// Only the ones with applicationVersion 145 should be detected as this, e.g. applicationVersion 66 should be detected as ERS-10TZBVK-AA.
// https://github.com/Koenkk/zigbee2mqtt/issues/25053
zigbeeModel: ["ZG-101ZD"],
fingerprint: [
{
modelID: "TS004F",
manufacturerName: "_TZ3000_abrsvsou",
applicationVersion: 145,
priority: 1,
},
],
model: "ZG-101Z/D",
vendor: "Tuya",
description: "Smart knob",
fromZigbee: [fz.tuya_multi_action, fz.battery, fz.tuya_operation_mode],
exposes: [
e.action(["rotate_left", "rotate_right"]),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
.withDescription('Operation mode: "command" - for group control, "event" - for clicks'),
],
extend: [m.battery(), tuya.modernExtend.tuyaMagicPacket()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_kzm5w4iz"]),
model: "TS0601_vibration_sensor",
vendor: "Tuya",
description: "Smart vibration sensor",
fromZigbee: [legacy.fromZigbee.tuya_smart_vibration_sensor],
toZigbee: [],
exposes: [e.contact(), e.battery(), e.vibration()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_yi4jtqq1", "_TZE200_khx7nnka", "_TZE204_khx7nnka"]),
model: "XFY-CGQ-ZIGB",
vendor: "Tuya",
description: "Illuminance sensor",
fromZigbee: [legacy.fromZigbee.tuya_illuminance_sensor],
toZigbee: [],
exposes: [e.illuminance(), e.brightness_state()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_kltffuzl", "_TZE200_fwoorn8y"]),
model: "TM001-ZA/TM081",
vendor: "Tuya",
description: "Door and window sensor",
fromZigbee: [legacy.fromZigbee.tm081],
toZigbee: [],
exposes: [e.contact(), e.battery()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_2m38mh6k"]),
model: "SS9600ZB",
vendor: "Tuya",
description: "6 gang remote",
exposes: [
e.battery(),
e.action([
"1_single",
"1_double",
"1_hold",
"2_single",
"2_double",
"2_hold",
"3_single",
"3_double",
"3_hold",
"4_single",
"4_double",
"4_hold",
"5_single",
"5_double",
"5_hold",
"6_single",
"6_double",
"6_hold",
]),
],
fromZigbee: [legacy.fromZigbee.tuya_remote],
toZigbee: [],
},
{
zigbeeModel: ["TS0052"],
model: "TS0052",
vendor: "Tuya",
description: "Zigbee dimmer module 1 channel",
extend: [
tuyaLight({
powerOnBehavior: true,
configureReporting: true,
switchType: true,
minBrightness: "attribute",
}),
],
whiteLabel: [tuya.whitelabel("Tuya", "FS-05R", "Mini dimmable switch 1 channel", ["_TZ3000_mgusv51k"])],
},
{
fingerprint: tuya.fingerprint("TS0052", ["_TZ3000_zjtxnoft", "_TZ3000_kvwrdf47"]),
model: "TS0052_2",
vendor: "Tuya",
description: "Zigbee dimmer module 2 channel",
extend: [
m.deviceEndpoints({ endpoints: { l1: 1, l2: 2 } }),
tuyaLight({
powerOnBehavior: true,
configureReporting: true,
switchType: true,
minBrightness: "attribute",
endpointNames: ["l1", "l2"],
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_ikvncluo",
"_TZE200_lyetpprm",
"_TZE200_jva8ink8",
"_TZE204_xpq2rzhq",
"_TZE200_holel4dk",
"_TZE200_xpq2rzhq",
"_TZE200_wukb7rhc",
"_TZE204_xsm7l9xa",
"_TZE204_ztc6ggyl",
"_TZE200_ztc6ggyl",
"_TZE200_sgpeacqp",
"_TZE204_fwondbzy",
]),
model: "TS0601_smart_human_presence_sensor_1",
vendor: "Tuya",
description: "Smart Human presence sensor",
fromZigbee: [legacy.fz.tuya_smart_human_presense_sensor],
toZigbee: [legacy.tz.tuya_smart_human_presense_sensor],
whiteLabel: [
tuya.whitelabel("Tuya", "ZY-M100-L", "Ceiling human breathe sensor", ["_TZE204_ztc6ggyl"]),
tuya.whitelabel("Moes", "ZSS-QY-HP", "Human presence sensor", ["_TZE204_fwondbzy"]),
],
exposes: [
e.illuminance(),
e.presence(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e.numeric("radar_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(9).withValueStep(1).withDescription("sensitivity of the radar"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Minimum range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Maximum range")
.withUnit("m"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Detection delay")
.withUnit("s"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(0).withValueMax(1500).withValueStep(1).withDescription("Fading time").withUnit("s"),
// e.text('cli', ea.STATE).withDescription('not recognize'),
e
.enum("self_test", ea.STATE, Object.values(legacy.tuyaHPSCheckingResult))
.withDescription("Self_test, possible results: checking, check_success, check_failure, others, comm_fault, radar_fault."),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_atuj3i0w"]),
model: "M8Pro",
vendor: "Tuya",
description: "4 gang switch with LCD",
extend: [tuyaBase({ dp: true }), m.deviceEndpoints({ endpoints: { l1: 1, l2: 1, l3: 1, l4: 1 } })],
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
e.text("name", ea.STATE_SET).withEndpoint("l1").withDescription("Name for Switch 1"),
e.text("name", ea.STATE_SET).withEndpoint("l2").withDescription("Name for Switch 2"),
e.text("name", ea.STATE_SET).withEndpoint("l3").withDescription("Name for Switch 3"),
e.text("name", ea.STATE_SET).withEndpoint("l4").withDescription("Name for Switch 4"),
e.text("scene_name", ea.STATE_SET).withEndpoint("l1").withDescription("Name for Scene 1"),
e.text("scene_name", ea.STATE_SET).withEndpoint("l2").withDescription("Name for Scene 2"),
e.text("scene_name", ea.STATE_SET).withEndpoint("l3").withDescription("Name for Scene 3"),
e.text("scene_name", ea.STATE_SET).withEndpoint("l4").withDescription("Name for Scene 4"),
exposes.enum("mode", ea.STATE_SET, ["switch_1", "scene_1", "smart_light_1"]).withEndpoint("l1").withDescription("Switch1 mode"),
exposes.enum("mode", ea.STATE_SET, ["switch_1", "scene_1", "smart_light_1"]).withEndpoint("l2").withDescription("Switch2 mode"),
exposes.enum("mode", ea.STATE_SET, ["switch_1", "scene_1", "smart_light_1"]).withEndpoint("l3").withDescription("Switch3 mode"),
exposes.enum("mode", ea.STATE_SET, ["switch_1", "scene_1", "smart_light_1"]).withEndpoint("l4").withDescription("Switch4 mode"),
e.action(["scene_1", "scene_2", "scene_3", "scene_4"]),
],
meta: {
tuyaDatapoints: [
[24, "state_l1", tuya.valueConverter.onOff],
[25, "state_l2", tuya.valueConverter.onOff],
[26, "state_l3", tuya.valueConverter.onOff],
[27, "state_l4", tuya.valueConverter.onOff],
[103, "name_l1", convLocal.name],
[104, "name_l2", convLocal.name],
[105, "name_l3", convLocal.name],
[106, "name_l4", convLocal.name],
[107, "scene_name_l1", convLocal.name],
[108, "scene_name_l2", convLocal.name],
[109, "scene_name_l3", convLocal.name],
[110, "scene_name_l4", convLocal.name],
[18, "mode_l1", tuya.valueConverterBasic.lookup({ switch_1: tuya.enum(0), scene_1: tuya.enum(1), smart_light_1: tuya.enum(2) })],
[19, "mode_l2", tuya.valueConverterBasic.lookup({ switch_1: tuya.enum(0), scene_1: tuya.enum(1), smart_light_1: tuya.enum(2) })],
[20, "mode_l3", tuya.valueConverterBasic.lookup({ switch_1: tuya.enum(0), scene_1: tuya.enum(1), smart_light_1: tuya.enum(2) })],
[21, "mode_l4", tuya.valueConverterBasic.lookup({ switch_1: tuya.enum(0), scene_1: tuya.enum(1), smart_light_1: tuya.enum(2) })],
[1, "action", tuya.valueConverter.static("scene_1")],
[2, "action", tuya.valueConverter.static("scene_2")],
[3, "action", tuya.valueConverter.static("scene_3")],
[4, "action", tuya.valueConverter.static("scene_4")],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_bmdsp6bs"]),
model: "Y1_IN",
vendor: "Tuya",
description: "Smart human presence sensor 24G",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.presence(),
e.illuminance(),
e.numeric("keep_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Keep sensitivity"),
e.numeric("trigger_sensitivity", ea.STATE_SET).withValueMin(1).withValueMax(20).withValueStep(1).withDescription("Trigger sensitivity"),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMin(1)
.withValueMax(60)
.withValueStep(1)
.withDescription("Presence timeout")
.withUnit("s"),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[102, "fading_time", tuya.valueConverter.raw],
[103, "illuminance", tuya.valueConverter.raw],
[110, "keep_sensitivity", tuya.valueConverter.raw],
[114, "trigger_sensitivity", tuya.valueConverter.raw],
[182, "target_distance", tuya.valueConverter.divideBy10],
[183, null, null],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_sxm7l9xa", "_TZE204_e5m9c5hl"]),
model: "ZY-M100-S_1",
vendor: "Tuya",
description: "Mini human breathe sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
whiteLabel: [tuya.whitelabel("Wenzhi", "WZ-M100-W", "Human presence sensor", ["_TZE204_e5m9c5hl"])],
exposes: [
e.illuminance(),
e.presence(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e.numeric("radar_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(9).withValueStep(1).withDescription("sensitivity of the radar"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Minimum range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Maximum range")
.withUnit("m"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Detection delay")
.withUnit("s"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(0.5).withValueMax(1500).withValueStep(1).withDescription("Fading time").withUnit("s"),
],
meta: {
tuyaDatapoints: [
[104, "illuminance", tuya.valueConverter.raw],
[105, "presence", tuya.valueConverter.trueFalse1],
[106, "radar_sensitivity", tuya.valueConverter.raw],
[107, "maximum_range", tuya.valueConverter.divideBy100],
[108, "minimum_range", tuya.valueConverter.divideBy100],
[109, "target_distance", tuya.valueConverter.divideBy100],
[110, "fading_time", tuya.valueConverter.divideBy10],
[111, "detection_delay", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_qasjif9e", "_TZE204_ztqnh5cg", "_TZE204_iadro9bf", "_TZE284_iadro9bf"]),
model: "ZY-M100-S_2",
vendor: "Tuya",
description: "Mini human breathe sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.illuminance(),
e.presence(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e.numeric("radar_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(9).withValueStep(1).withDescription("sensitivity of the radar"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Minimum range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9.5)
.withValueStep(0.15)
.withDescription("Maximum range")
.withUnit("m"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Detection delay")
.withUnit("s"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(0.5).withValueMax(1500).withValueStep(1).withDescription("Fading time").withUnit("s"),
],
meta: {
tuyaDatapoints: [
[
1,
"presence",
{
from: (v, meta, options) => {
if (meta.device.manufacturerName === "_TZE284_iadro9bf") {
return tuya.valueConverter.trueFalse0.from(v);
}
return tuya.valueConverter.trueFalse1.from(v);
},
},
],
[9, "target_distance", tuya.valueConverter.divideBy100],
[12, "illuminance", tuya.valueConverter.raw], // _TZE284_iadro9bf
[104, "illuminance", tuya.valueConverter.raw],
[2, "radar_sensitivity", tuya.valueConverter.raw],
[4, "maximum_range", tuya.valueConverter.divideBy100],
[3, "minimum_range", tuya.valueConverter.divideBy100],
[102, "fading_time", tuya.valueConverter.divideBy10],
[101, "detection_delay", tuya.valueConverter.divideBy10],
],
},
whiteLabel: [tuya.whitelabel("iHseno", "TY_24G_Sensor_V2", "Human presence sensor 24G", ["_TZE204_ztqnh5cg"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_laokfqwu"]),
model: "WZ-M100",
vendor: "Wenzhi",
description: "Human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.illuminance(),
e.presence(),
e
.numeric("target_distance", ea.STATE)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withDescription("Distance to target")
.withUnit("m"),
e.numeric("sensitivity", ea.STATE_SET).withValueMin(1).withValueMax(9).withValueStep(1).withDescription("sensitivity of the radar"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10.0)
.withValueStep(0.1)
.withDescription("minimum detection range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10.0)
.withValueStep(0.1)
.withDescription("maximum detection range")
.withUnit("m"),
e
.numeric("interval_time", ea.STATE_SET)
.withValueMin(1)
.withValueMax(3600)
.withValueStep(1)
.withDescription("interval_time")
.withUnit("s"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10.0)
.withValueStep(0.1)
.withDescription("detection delay")
.withUnit("s"),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMax(1500)
.withValueMin(5)
.withValueStep(5)
.withDescription("presence timeout")
.withUnit("s"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[2, "sensitivity", tuya.valueConverter.raw],
[3, "minimum_range", tuya.valueConverter.divideBy100],
[4, "maximum_range", tuya.valueConverter.divideBy100],
[9, "target_distance", tuya.valueConverter.divideBy100],
[103, "illuminance", tuya.valueConverter.raw],
[104, "interval_time", tuya.valueConverter.raw],
[105, "detection_delay", tuya.valueConverter.divideBy10],
[106, "fading_time", tuya.valueConverter.divideBy10],
],
},
},
{
zigbeeModel: ["ZG-205ZL"],
fingerprint: [
{ modelID: "TS0225", manufacturerName: "_TZE200_hl0ss9oa" },
{ modelID: "CK-BL702-MWS-01(7016)", manufacturerName: "ZGAF-205L" },
],
model: "ZG-205ZL",
vendor: "Tuya",
description: "24Ghz/5.8GHz human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.enum("motion_state", ea.STATE, ["none", "large", "small", "static"]).withDescription("Motion state"),
e.illuminance(),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(3600)
.withValueStep(1)
.withUnit("s")
.withDescription("Presence keep time"),
e
.numeric("large_motion_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Large motion detection distance"),
e
.numeric("large_motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Large motion detection sensitivity"),
e
.numeric("small_motion_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Small motion detection distance"),
e
.numeric("small_motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Small motion detection sensitivity"),
e
.numeric("static_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Static detection distance"),
e
.numeric("static_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Static detection sensitivity"),
e.enum("mode", ea.STATE_SET, ["off", "arm", "alarm", "doorbell"]).withDescription("Working mode"),
e.enum("alarm_volume", ea.STATE_SET, ["mute", "low", "medium", "high"]).withDescription("Alarm volume"),
e.numeric("alarm_time", ea.STATE_SET).withValueMin(1).withValueMax(60).withValueStep(1).withUnit("m").withDescription("Alarm time"),
e.binary("light_mode", ea.STATE_SET, "ON", "OFF").withDescription("LED indicator mode"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[20, "illuminance", tuya.valueConverter.raw],
[
11,
"motion_state",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
large: tuya.enum(1),
small: tuya.enum(2),
static: tuya.enum(3),
}),
],
[12, "fading_time", tuya.valueConverter.raw],
[13, "large_motion_detection_distance", tuya.valueConverter.divideBy100],
[15, "large_motion_detection_sensitivity", tuya.valueConverter.raw],
[14, "small_motion_detection_distance", tuya.valueConverter.divideBy100],
[16, "small_motion_detection_sensitivity", tuya.valueConverter.raw],
[103, "static_detection_distance", tuya.valueConverter.divideBy100],
[104, "static_detection_sensitivity", tuya.valueConverter.raw],
[
105,
"mode",
tuya.valueConverterBasic.lookup({
arm: tuya.enum(0),
off: tuya.enum(1),
alarm: tuya.enum(2),
doorbell: tuya.enum(3),
}),
],
[
102,
"alarm_volume",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
mute: tuya.enum(3),
}),
],
[101, "alarm_time", tuya.valueConverter.raw],
[24, "light_mode", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_whkgqxse"]),
model: "JM-TRH-ZGB-V1",
vendor: "Tuya",
description: "Temperature & humidity sensor with clock",
fromZigbee: [legacy.fromZigbee.nous_lcd_temperature_humidity_sensor, fz.ignore_tuya_set_time],
toZigbee: [legacy.toZigbee.nous_lcd_temperature_humidity_sensor],
onEvent: tuya.onEventSetLocalTime,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]);
},
exposes: [
e.temperature(),
e.humidity(),
e.battery(),
e
.numeric("temperature_report_interval", ea.STATE_SET)
.withUnit("min")
.withValueMin(5)
.withValueMax(60)
.withValueStep(5)
.withDescription("Temperature Report interval"),
e.enum("temperature_unit_convert", ea.STATE_SET, ["celsius", "fahrenheit"]).withDescription("Current display unit"),
e.enum("temperature_alarm", ea.STATE, ["canceled", "lower_alarm", "upper_alarm"]).withDescription("Temperature alarm status"),
e.numeric("max_temperature", ea.STATE_SET).withUnit("°C").withValueMin(-20).withValueMax(60).withDescription("Alarm temperature max"),
e.numeric("min_temperature", ea.STATE_SET).withUnit("°C").withValueMin(-20).withValueMax(60).withDescription("Alarm temperature min"),
e.enum("humidity_alarm", ea.STATE, ["canceled", "lower_alarm", "upper_alarm"]).withDescription("Humidity alarm status"),
e.numeric("max_humidity", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Alarm humidity max"),
e.numeric("min_humidity", ea.STATE_SET).withUnit("%").withValueMin(0).withValueMax(100).withDescription("Alarm humidity min"),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_zyrdrmno"]),
model: "ZB-Sm",
vendor: "Tuya",
description: "Tubular motor",
fromZigbee: [legacy.fromZigbee.zb_sm_cover, fz.ignore_basic_report],
toZigbee: [legacy.toZigbee.zb_sm_cover],
onEvent: tuya.onEventSetTime,
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("goto_positon", ea.SET, ["25", "50", "75", "FAVORITE"]),
e.enum("motor_state", ea.STATE, ["OPENING", "CLOSING", "STOPPED"]),
e.numeric("active_power", ea.STATE).withDescription("Active power").withUnit("mWt"),
e.numeric("cycle_count", ea.STATE).withDescription("Cycle count"),
e.numeric("cycle_time", ea.STATE).withDescription("Cycle time").withUnit("ms"),
e.enum("top_limit", ea.STATE_SET, ["SET", "CLEAR"]).withDescription("Setup or clear top limit"),
e.enum("bottom_limit", ea.STATE_SET, ["SET", "CLEAR"]).withDescription("Setup or clear bottom limit"),
e.numeric("favorite_position", ea.STATE_SET).withValueMin(0).withValueMax(100).withDescription("Favorite position of this cover"),
e.binary("reverse_direction", ea.STATE_SET, true, false).withDescription("Inverts the cover direction"),
e.text("motor_type", ea.STATE),
e.enum("report", ea.SET, [""]),
],
},
{
fingerprint: tuya.fingerprint("TS1201", [
"_TZ3290_7v1k4vufotpowp9z",
"_TZ3290_rlkmy85q4pzoxobl",
"_TZ3290_jxvzqatwgsaqzx1u",
"_TZ3290_lypnqvlem5eq1ree",
"_TZ3290_uc8lwbi2",
]),
model: "ZS06",
vendor: "Tuya",
description: "Universal smart IR remote control",
fromZigbee: [
fzZosung.zosung_send_ir_code_00,
fzZosung.zosung_send_ir_code_01,
fzZosung.zosung_send_ir_code_02,
fzZosung.zosung_send_ir_code_03,
fzZosung.zosung_send_ir_code_04,
fzZosung.zosung_send_ir_code_05,
],
toZigbee: [tzZosung.zosung_ir_code_to_send, tzZosung.zosung_learn_ir_code],
exposes: [ez.learn_ir_code(), ez.learned_ir_code(), ez.ir_code_to_send()],
whiteLabel: [
tuya.whitelabel("Tuya", "UFO-R4Z", "Universal smart IR remote control", ["_TZ3290_rlkmy85q4pzoxobl"]),
tuya.whitelabel("QA", "QAIRZPRO", "Infrared hub pro", ["_TZ3290_jxvzqatwgsaqzx1u", "_TZ3290_lypnqvlem5eq1ree"]),
tuya.whitelabel("Zemismart", "ZM-18-USB", "Universal smart IR remote control", ["_TZ3290_uc8lwbi2"]),
],
},
{
fingerprint: tuya.fingerprint("TS0201", ["_TZ3000_itnrsufe"]),
model: "KCTW1Z",
vendor: "Tuya",
description: "Temperature & humidity sensor with LCD",
fromZigbee: [fz.temperature, fzLocal.humidity10, fzLocal.temperature_unit, fz.battery, fz.ignore_tuya_set_time],
toZigbee: [tzLocal.temperature_unit],
onEvent: tuya.onEventSetLocalTime,
exposes: [
e.temperature(),
e.humidity(),
e.battery(),
e.battery_voltage(),
e.enum("temperature_unit", ea.STATE_SET, ["celsius", "fahrenheit"]).withDescription("Current display unit"),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "msTemperatureMeasurement", "msRelativeHumidity"]);
await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]);
await reporting.batteryPercentageRemaining(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_0u3bj3rc", "_TZE200_v6ossqfy", "_TZE200_mx6u6l4y"]),
model: "TS0601_human_presence_sensor",
vendor: "Tuya",
description: "Human presence sensor Zigbee",
fromZigbee: [legacy.fromZigbee.hpsz],
toZigbee: [legacy.toZigbee.hpsz],
onEvent: tuya.onEventSetLocalTime,
exposes: [
e.presence(),
e.numeric("duration_of_attendance", ea.STATE).withUnit("min").withDescription("Shows the presence duration in minutes"),
e.numeric("duration_of_absence", ea.STATE).withUnit("min").withDescription("Shows the duration of the absence in minutes"),
e.binary("led_state", ea.STATE_SET, true, false).withDescription("Turns the onboard LED on or off"),
],
},
{
zigbeeModel: ["ZG-227Z", "ZG-227ZL"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_qoy0ekbd", "_TZE200_znbl8dj5", "_TZE200_a8sdabtg", "_TZE200_dikkika5", "_TZE200_vs0skpuc"]),
model: "ZG-227ZL",
vendor: "Tuya",
description: "Temperature & humidity LCD sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.temperature(),
e.humidity(),
tuya.exposes.temperatureUnit(),
tuya.exposes.temperatureCalibration(),
tuya.exposes.humidityCalibration(),
e.battery(),
],
whiteLabel: [
tuya.whitelabel("HOBEIAN", "ZG-227Z", "Temperature and humidity sensor", ["_TZE200_a8sdabtg", "_TZE200_vs0skpuc"]),
tuya.whitelabel("KOJIMA", "KOJIMA-THS-ZG-LCD", "Temperature and humidity sensor", ["_TZE200_dikkika5"]),
],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[2, "humidity", tuya.valueConverter.raw],
[4, "battery", tuya.valueConverter.raw],
[9, "temperature_unit", tuya.valueConverter.temperatureUnit],
[23, "temperature_calibration", tuya.valueConverter.divideBy10],
[24, "humidity_calibration", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_j7sgd8po"]),
model: "S8",
vendor: "SODA",
description: "S8 premium window handle",
extend: [],
toZigbee: [tuya.tz.datapoints],
fromZigbee: [tuya.fz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.battery_low(),
e.binary("vacation", ea.STATE_SET, "ON", "OFF").withDescription("Vacation mode"),
e.enum("alarm", ea.STATE, ["ALARM", "IDLE"]).withDescription("Alarm"),
e.binary("alarm_switch", ea.STATE_SET, "ON", "OFF").withDescription("Alarm enable"),
e.binary("handlesound", ea.STATE_SET, "ON", "OFF").withDescription("Handle closed sound"),
e.enum("opening_mode", ea.STATE, ["closed", "tilted"]).withDescription("Window tilt"),
e.temperature(),
e.humidity(),
e.binary("keysound", ea.STATE_SET, "ON", "OFF").withDescription("Key beep sound"),
e.enum("sensitivity", ea.STATE_SET, ["off", "low", "medium", "high", "max"]).withDescription("Sensitivity of the alarm sensor"),
e.enum("position", ea.STATE, ["up", "right", "down", "left"]),
e.enum("button_left", ea.STATE, ["released", "pressed"]),
e.enum("button_right", ea.STATE, ["released", "pressed"]),
e
.numeric("duration", ea.STATE_SET)
.withValueMin(0)
.withValueMax(300)
.withValueStep(1)
.withUnit("sec")
.withDescription("Duration of the alarm")
.withPreset("default", 180, "Default value"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("min")
.withDescription("Update frequency")
.withValueMin(0)
.withValueMax(700)
.withPreset("default", 20, "Default value"),
e.enum("calibrate", ea.STATE_SET, ["clear", "execute"]),
],
meta: {
tuyaDatapoints: [
[3, "battery", tuya.valueConverter.raw],
[8, "temperature", tuya.valueConverter.divideBy10],
[101, "humidity", tuya.valueConverter.raw],
[
102,
"alarm",
tuya.valueConverterBasic.lookup({
IDLE: tuya.enum(0),
ALARM: tuya.enum(1),
}),
],
[
103,
"opening_mode",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
tilted: tuya.enum(1),
}),
],
[
104,
"position",
tuya.valueConverterBasic.lookup({
left: tuya.enum(4),
up: tuya.enum(1),
down: tuya.enum(2),
right: tuya.enum(3),
}),
],
[
105,
"button_left",
tuya.valueConverterBasic.lookup({
released: tuya.enum(0),
pressed: tuya.enum(1),
}),
],
[
106,
"button_right",
tuya.valueConverterBasic.lookup({
released: tuya.enum(0),
pressed: tuya.enum(1),
}),
],
[
107,
"vacation",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[
108,
"sensitivity",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
low: tuya.enum(1),
medium: tuya.enum(2),
high: tuya.enum(3),
max: tuya.enum(4),
}),
],
[
109,
"alarm_switch",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[110, "update_frequency", tuya.valueConverter.raw],
[
111,
"keysound",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[
112,
"battery_low",
tuya.valueConverterBasic.lookup({
ON: tuya.enum(0),
OFF: tuya.enum(1),
}),
],
[113, "duration", tuya.valueConverter.raw],
[
114,
"handlesound",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[
120,
"calibrate",
tuya.valueConverterBasic.lookup({
clear: tuya.enum(0),
execute: tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ysm4dsb1"]),
model: "RSH-HS06",
vendor: "Tuya",
description: "Temperature and humidity sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent({ queryOnDeviceAnnounce: true }),
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
exposes: [
e.temperature(),
e.humidity(),
tuya.exposes.temperatureUnit(),
tuya.exposes.temperatureCalibration(),
tuya.exposes.humidityCalibration(),
e.battery(),
],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[2, "humidity", tuya.valueConverter.raw],
[4, "battery", tuya.valueConverter.raw],
[9, "temperature_unit", tuya.valueConverter.temperatureUnit],
[23, "temperature_calibration", tuya.valueConverter.divideBy10],
[24, "humidity_calibration", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_n8dljorx"]),
model: "ZG-102Z",
vendor: "Tuya",
description: "Door sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.contact(), e.battery()],
meta: {
tuyaDatapoints: [
[1, "contact", tuya.valueConverter.inverse],
[2, "battery", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-102ZL"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_pay2byax", "_TZE200_ijey4q29"]),
model: "ZG-102ZL",
vendor: "Tuya",
description: "Luminance door sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.contact(),
e.illuminance().withUnit("lx"),
e.battery(),
e
.numeric("illuminance_interval", ea.STATE_SET)
.withValueMin(1)
.withValueMax(720)
.withValueStep(1)
.withUnit("minutes")
.withDescription("Brightness acquisition interval (refresh and update only while active)"),
],
meta: {
tuyaDatapoints: [
[1, "contact", tuya.valueConverter.inverse],
[101, "illuminance", tuya.valueConverter.raw],
[2, "battery", tuya.valueConverter.raw],
[102, "illuminance_interval", tuya.valueConverter.raw],
],
},
},
{
fingerprint: [...tuya.fingerprint("TS0601", ["_TZE200_f1pvdgoh", "_TZE200_me6wtiqs"]), ...tuya.fingerprint("\u0000B", ["_TZE200_f1pvdgoh"])],
model: "TS0601_pir",
vendor: "Tuya",
description: "Haozee PIR sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
exposes: [e.occupancy(), e.illuminance(), e.battery()],
whiteLabel: [tuya.whitelabel("Immax", "07527L", "NEO Smart PIR sensor 2v1 Zigbee 3.0", ["_TZE200_me6wtiqs"])],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse0],
[4, "battery", tuya.valueConverter.raw],
[101, "illuminance", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-225Z"],
fingerprint: [...tuya.fingerprint("TS0601", ["_TZE200_8isdky6j"]), ...tuya.fingerprint("TS0225", ["_TZE200_p6fuhvez"])],
model: "ZG-225Z",
vendor: "Tuya",
description: "Gas sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.gas(),
tuya.exposes.gasValue().withUnit("ppm"),
e.enum("sensitivity", ea.STATE_SET, ["low", "medium", "high"]).withDescription("Gas sensor sensitivity"),
e.enum("ring", ea.STATE_SET, ["ring1", "ring2"]).withDescription("Ring"),
],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalse0],
[2, "gas_value", tuya.valueConverter.raw],
[
101,
"sensitivity",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
}),
],
[
6,
"ring",
tuya.valueConverterBasic.lookup({
ring1: tuya.enum(0),
ring2: tuya.enum(1),
}),
],
],
},
},
{
zigbeeModel: ["ZG-204ZL"],
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_3towulqd",
"_TZE200_1ibpyhdc",
"_TZE200_bh3n6gk8",
"_TZE200_ttcovulf",
"_TZE200_gjldowol",
"_TZE200_s6hzw8g2",
]),
model: "ZG-204ZL",
vendor: "Tuya",
description: "Luminance motion sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.occupancy(),
e.illuminance().withUnit("lx"),
e.battery(),
e
.enum("sensitivity", ea.STATE_SET, ["low", "medium", "high"])
.withDescription("PIR sensor sensitivity (refresh and update only while active)"),
e
.enum("keep_time", ea.STATE_SET, ["10", "30", "60", "120"])
.withDescription("PIR keep time in seconds (refresh and update only while active)"),
e
.numeric("illuminance_interval", ea.STATE_SET)
.withValueMin(1)
.withValueMax(720)
.withValueStep(1)
.withUnit("minutes")
.withDescription("Brightness acquisition interval (refresh and update only while active)"),
],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse0],
[4, "battery", tuya.valueConverter.raw],
[
9,
"sensitivity",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
}),
],
[
10,
"keep_time",
tuya.valueConverterBasic.lookup({
"10": tuya.enum(0),
"30": tuya.enum(1),
"60": tuya.enum(2),
"120": tuya.enum(3),
}),
],
[12, "illuminance", tuya.valueConverter.raw],
[101, "illuminance", tuya.valueConverter.raw], // For _TZE200_s6hzw8g2
[102, "illuminance_interval", tuya.valueConverter.raw],
],
},
whiteLabel: [tuya.whitelabel("Nedis", "ZBSM20WT", "Nedis motion sensor", ["_TZE200_s6hzw8g2"])],
},
{
zigbeeModel: ["CK-BL702-MWS-01(7016)"],
fingerprint: tuya.fingerprint("TS0225", ["_TZE200_2aaelwxk"]),
model: "ZG-205Z/A",
vendor: "Tuya",
description: "5.8Ghz/24Ghz Human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.enum("motion_state", ea.STATE, ["none", "small", "medium", "large", "far", "near"]).withDescription("State of the motion"),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e.illuminance().withUnit("lx"),
e
.numeric("large_motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Motion detection sensitivity"),
e
.numeric("large_motion_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Motion detection distance"),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(28800)
.withValueStep(1)
.withUnit("s")
.withDescription("For how much time presence should stay true after detecting it"),
e
.numeric("medium_motion_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Medium motion detection distance"),
e
.numeric("medium_motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Medium motion detection sensitivity"),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED Indicator"),
e
.numeric("small_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Small detection distance"),
e
.numeric("small_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Small detection sensitivity"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Minimum range"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[2, "large_motion_detection_sensitivity", tuya.valueConverter.raw],
[4, "large_motion_detection_distance", tuya.valueConverter.divideBy100],
[
101,
"motion_state",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
large: tuya.enum(1),
medium: tuya.enum(2),
small: tuya.enum(3),
far: tuya.enum(4),
near: tuya.enum(5),
}),
],
[102, "fading_time", tuya.valueConverter.raw],
[104, "medium_motion_detection_distance", tuya.valueConverter.divideBy100],
[105, "medium_motion_detection_sensitivity", tuya.valueConverter.raw],
[106, "illuminance", tuya.valueConverter.raw],
[107, "indicator", tuya.valueConverter.onOff],
[108, "small_detection_distance", tuya.valueConverter.divideBy100],
[109, "small_detection_sensitivity", tuya.valueConverter.raw],
[122, "target_distance", tuya.valueConverter.divideBy100],
[123, "minimum_range", tuya.valueConverter.divideBy100],
// Not exposed DPs/untested
// [103, 'motion_false_detection', tuya.valueConverter.raw],
// [113, 'breathe_false_detection', tuya.valueConverter.raw],
// [3, 'mov_minimum_distance', tuya.valueConverter.raw],
// [110, 'micro_minimum_distance', tuya.valueConverter.raw],
// [111, 'motionless_minimum_distance', tuya.valueConverter.raw],
// [112, 'reset_setting', tuya.valueConverter.raw],
// [114, 'time', tuya.valueConverter.raw],
// [115, 'alarm_time', tuya.valueConverter.raw],
// [116, 'alarm_volume', tuya.valueConverterBasic.lookup(
// {'low': tuya.enum(0), 'medium': tuya.enum(1), 'high': tuya.enum(2), 'mute': tuya.enum(3)})],
// [117, 'working_mode', tuya.valueConverterBasic.lookup(
// {'arm': tuya.enum(0), 'off': tuya.enum(1), 'alarm': tuya.enum(2), 'doorbell': tuya.enum(3)})],
// [118, 'auto1', tuya.valueConverter.raw],
// [119, 'auto2', tuya.valueConverter.raw],
// [120, 'auto3', tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-204ZM"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_2aaelwxk", "_TZE200_kb5noeto", "_TZE200_tyffvoij"]),
model: "ZG-204ZM",
vendor: "Tuya",
description: "PIR 24Ghz human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.enum("motion_state", ea.STATE, ["none", "large", "small", "static"]).withDescription("Motion state"),
e.illuminance(),
e.battery(),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(28800)
.withValueStep(1)
.withUnit("s")
.withDescription("Presence keep time"),
e
.numeric("static_detection_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Static detection distance"),
e
.numeric("static_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Static detection sensitivity"),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED indicator mode"),
e
.enum("motion_detection_mode", ea.STATE_SET, ["only_pir", "pir_and_radar", "only_radar"])
.withDescription("Motion detection mode (Firmware version>=0122052017)"),
e
.numeric("motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("x")
.withDescription("Motion detection sensitivity (Firmware version>=0122052017)"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[106, "illuminance", tuya.valueConverter.raw],
[
101,
"motion_state",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
large: tuya.enum(1),
small: tuya.enum(2),
static: tuya.enum(3),
}),
],
[102, "fading_time", tuya.valueConverter.raw],
[4, "static_detection_distance", tuya.valueConverter.divideBy100],
[2, "static_detection_sensitivity", tuya.valueConverter.raw],
[107, "indicator", tuya.valueConverter.onOff],
[121, "battery", tuya.valueConverter.raw],
[
122,
"motion_detection_mode",
tuya.valueConverterBasic.lookup({
only_pir: tuya.enum(0),
pir_and_radar: tuya.enum(1),
only_radar: tuya.enum(2),
}),
],
[123, "motion_detection_sensitivity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_zxbtub8r"]),
model: "TS110E_1gang_1",
vendor: "Tuya",
description: "1 channel dimmer",
extend: [m.light({ powerOnBehavior: false, configureReporting: true })],
fromZigbee: [tuya.fz.power_on_behavior_1, fz.TS110E_switch_type, fz.TS110E, fz.on_off],
toZigbee: [tz.TS110E_light_onoff_brightness, tuya.tz.power_on_behavior_1, tz.TS110E_options],
exposes: [e.power_on_behavior(), tuya.exposes.switchType(), e.min_brightness(), e.max_brightness()],
configure: tuya.configureMagicPacket,
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_ngqk6jia", "_TZ3210_weaqkhab", "_TZ3210_k1msuvg6"]),
model: "TS110E_1gang_2",
vendor: "Tuya",
description: "1 channel dimmer",
whiteLabel: [
tuya.whitelabel("Lonsonho", "QS-Zigbee-D02-TRIAC-L_1", "1 channel dimmer", ["_TZ3210_weaqkhab"]),
tuya.whitelabel("Lonsonho", "QS-Zigbee-D02-TRIAC-LN_1", "1 channel dimmer", ["_TZ3210_ngqk6jia"]),
],
ota: true,
fromZigbee: [fz.TS110E, fz.TS110E_light_type, tuya.fz.power_on_behavior_1, fz.on_off],
toZigbee: [tz.TS110E_onoff_brightness, tz.TS110E_options, tuya.tz.power_on_behavior_1, tz.light_brightness_move, tzLocal.ts110eCountdown],
exposes: (device, options) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/26791#issuecomment-2765734859
const countdownValueStep = device?.manufacturerName === "_TZ3210_ngqk6jia" ? 30 : 1;
return [
e.light_brightness().withMinBrightness().withMaxBrightness(),
tuya.exposes.lightType().withAccess(ea.ALL),
e.power_on_behavior().withAccess(ea.ALL),
tuya.exposes.switchType(),
tuya.exposes.countdown().withValueStep(countdownValueStep),
];
},
extend: [
m.deviceAddCustomCluster("genOnOff", {
ID: zigbee_herdsman_1.Zcl.Clusters.genOnOff.ID,
attributes: {},
commands: {
tuyaCountdown: {
ID: 0xf0,
parameters: [{ name: "data", type: 1008 /* BUFFER */ }],
},
},
commandsResponse: {},
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_ysfo0wla"]),
model: "EKAC-T3095Z",
vendor: "Ekaza",
description: "1 channel dimmer",
fromZigbee: [fz.TS110E, tuya.fz.power_on_behavior_1, fz.on_off],
toZigbee: [tz.TS110E_onoff_brightness, tz.TS110E_options, tuya.tz.power_on_behavior_1, tz.light_brightness_move],
exposes: [e.light_brightness().withMinBrightness().withMaxBrightness(), e.power_on_behavior().withAccess(ea.ALL)],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_wdexaypg"]),
model: "TS110E_2gang_1",
vendor: "Tuya",
description: "2 channel dimmer",
extend: [
m.deviceEndpoints({ endpoints: { l1: 1, l2: 2 } }),
m.light({
powerOnBehavior: false,
endpointNames: ["l1", "l2"],
configureReporting: true,
}),
],
fromZigbee: [tuya.fz.power_on_behavior_1, fz.TS110E_switch_type, fz.TS110E],
toZigbee: [tz.TS110E_light_onoff_brightness, tuya.tz.power_on_behavior_1, tz.TS110E_options],
configure: tuya.configureMagicPacket,
exposes: [
e.min_brightness().withEndpoint("l1"),
e.max_brightness().withEndpoint("l1"),
e.min_brightness().withEndpoint("l2"),
e.max_brightness().withEndpoint("l2"),
e.power_on_behavior(),
tuya.exposes.switchType().withEndpoint("l1"),
tuya.exposes.switchType().withEndpoint("l2"),
],
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_pagajpog", "_TZ3210_4ubylghk", "_TZ3210_vfwhhldz", "_TZ3210_3mpwqzuu", "_TZ3210_mt5xjoy6"]),
model: "TS110E_2gang_2",
vendor: "Tuya",
description: "2 channel dimmer",
whiteLabel: [tuya.whitelabel("Nedis", "ZBWD20RD", "SmartLife Triac Dimmer", ["_TZ3210_mt5xjoy6"])],
fromZigbee: [fz.TS110E, fz.TS110E_light_type, tuya.fz.power_on_behavior_1, fz.on_off],
toZigbee: [tz.TS110E_onoff_brightness, tz.TS110E_options, tuya.tz.power_on_behavior_1, tz.light_brightness_move],
meta: { multiEndpoint: true },
exposes: [
e.light_brightness().withMinBrightness().withMaxBrightness().withEndpoint("l1"),
e.light_brightness().withMinBrightness().withMaxBrightness().withEndpoint("l2"),
e.power_on_behavior().withEndpoint("l1"),
e.power_on_behavior().withEndpoint("l2"),
tuya.exposes.lightType().withAccess(ea.ALL),
tuya.exposes.switchType().withEndpoint("l1"),
tuya.exposes.switchType().withEndpoint("l2"),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl"]);
await reporting.onOff(endpoint);
},
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nslr42tt"]),
model: "TS0601_3_phase_clamp_meter",
vendor: "Tuya",
description: "3-phase clamp power meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [
{ vendor: "MatSee Plus", model: "PC321-Z-TY" },
{ vendor: "OWON", model: "PC321-Z-TY" },
],
exposes: [
e.ac_frequency(),
e.temperature(),
e.current(),
e.power(),
e.energy(),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyWithPhase("c"),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.powerFactorWithPhase("c"),
],
meta: {
multiEndpointSkip: ["power_factor", "power_factor_phase_b", "power_factor_phase_c", "energy"],
tuyaDatapoints: [
[132, "ac_frequency", tuya.valueConverter.raw],
[133, "temperature", tuya.valueConverter.divideBy10],
[1, "energy", tuya.valueConverter.divideBy100],
[101, "energy_a", tuya.valueConverter.divideBy1000],
[111, "energy_b", tuya.valueConverter.divideBy1000],
[121, "energy_c", tuya.valueConverter.divideBy1000],
[131, "current", tuya.valueConverter.divideBy1000],
[9, "power", tuya.valueConverter.power],
[102, "power_factor_a", tuya.valueConverter.raw],
[112, "power_factor_b", tuya.valueConverter.raw],
[122, "power_factor_c", tuya.valueConverter.raw],
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")],
[7, null, tuya.valueConverter.phaseVariant2WithPhase("b")],
[8, null, tuya.valueConverter.phaseVariant2WithPhase("c")],
[134, "device_status", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_x8fp01wi", "_TZE204_x8fp01wi"]),
model: "TS0601_3_phase_clamp_meter_relay",
vendor: "Tuya",
description: "3-phase clamp power meter with relay",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [{ vendor: "Wenzhou Taiye Electric", model: "TAC7361C BI" }],
exposes: [
e.switch().setAccess("state", ea.STATE_SET),
e.power(),
e.energy(),
e.produced_energy(),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
],
meta: {
tuyaDatapoints: [
[16, "state", tuya.valueConverter.onOff],
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[9, "power", tuya.valueConverter.power],
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")],
[7, null, tuya.valueConverter.phaseVariant2WithPhase("b")],
[8, null, tuya.valueConverter.phaseVariant2WithPhase("c")],
],
},
},
{
zigbeeModel: ["TS0049"],
model: "TS0049",
vendor: "Tuya",
description: "Water valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.errorStatus(),
tuya.exposes.switch(),
tuya.exposes.batteryState(),
tuya.exposes.countdown().withValueMin(0).withValueMax(255).withUnit("minutes").withDescription("Max on time in minutes"),
],
meta: {
tuyaSendCommand: "sendData",
tuyaDatapoints: [
[26, "error_status", tuya.valueConverter.raw],
[101, "state", tuya.valueConverter.onOff],
[111, "countdown", tuya.valueConverter.raw],
[115, "battery_state", tuya.valueConverter.batteryState],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_eaet5qt5", "_TZE284_fhvpaltk"]),
model: "TS0601_water_switch",
vendor: "Tuya",
description: "Dual water valve",
fromZigbee: [tuya.fz.datapoints, fz.battery],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.enum("valve_status", ea.STATE, ["manual", "auto", "idle"]).withDescription("Valve 1 status (manual, auto, idle)").withEndpoint("l1"),
e.enum("valve_status", ea.STATE, ["manual", "auto", "idle"]).withDescription("Valve 2 status (manual, auto, idle)").withEndpoint("l2"),
e.switch().withEndpoint("l1").withDescription("Valve 1 on/off").withLabel("Valve 1"),
e.switch().withEndpoint("l2").withDescription("Valve 2 on/off").withLabel("Valve 2"),
e
.numeric("countdown", ea.STATE_SET)
.withUnit("min")
.withDescription("Valve 1 countdown in minutes")
.withValueMin(0)
.withValueMax(1440)
.withEndpoint("l1"),
e
.numeric("countdown", ea.STATE_SET)
.withUnit("min")
.withDescription("Valve 2 countdown in minutes")
.withValueMin(0)
.withValueMax(1440)
.withEndpoint("l2"),
e.numeric("valve_duration", ea.STATE).withUnit("s").withDescription("Valve 1 irrigation last duration in seconds").withEndpoint("l1"),
e.numeric("valve_duration", ea.STATE).withUnit("s").withDescription("Valve 2 irrigation last duration in seconds").withEndpoint("l2"),
e.battery(),
e.battery_voltage(),
],
meta: {
tuyaSendCommand: "sendData",
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff], // Valve 1 on/off
[2, "state_l2", tuya.valueConverter.onOff], // Valve 2 on/off
[13, "countdown_l1", tuya.valueConverter.raw], // Valve 1 countdown
[14, "countdown_l2", tuya.valueConverter.raw], // Valve 2 countdown
[25, "valve_duration_l1", tuya.valueConverter.raw], // Valve 1 duration
[26, "valve_duration_l2", tuya.valueConverter.raw], // Valve 2 duration
[104, "valve_status_l1", tuya.valueConverterBasic.lookup({ manual: 0, auto: 1, idle: 2 })], // Valve 1 status
[105, "valve_status_l2", tuya.valueConverterBasic.lookup({ manual: 0, auto: 1, idle: 2 })], // Valve 2 status
],
multiEndpoint: true, // Enable multi-endpoint support
},
endpoint: (device) => {
return {
l1: 1, // Valve 1 uses endpoint 1
l2: 1, // Valve 2 also uses endpoint 1
};
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_r32ctezx", "_TZE204_r32ctezx"]),
model: "TS0601_fan_switch",
vendor: "Tuya",
description: "Fan switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.power_on_behavior(["off", "on"]).withAccess(ea.STATE_SET),
tuya.exposes.countdown().withValueMin(0).withValueMax(43200).withUnit("s").withDescription("Max ON time in seconds"),
e.numeric("fan_speed", ea.STATE_SET).withValueMin(1).withValueMax(5).withValueStep(1).withDescription("Speed off the fan"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[2, "countdown", tuya.valueConverter.countdown],
[
3,
"fan_speed",
tuya.valueConverterBasic.lookup({
"1": tuya.enum(0),
"2": tuya.enum(1),
"3": tuya.enum(2),
"4": tuya.enum(3),
"5": tuya.enum(4),
}),
],
[
11,
"power_on_behavior",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
on: tuya.enum(1),
}),
],
],
},
whiteLabel: [{ vendor: "Lerlink", model: "T2-Z67/T2-W67" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_hmqzfqml", "_TZE200_qanl25yu"]),
model: "TS0601_fan_and_light_switch",
vendor: "Tuya",
description: "Fan & light switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.binary("status_indication", ea.STATE_SET, "ON", "OFF").withDescription("Light switch"),
tuya.exposes.switch(),
e.power_on_behavior(["OFF", "ON"]).withAccess(ea.STATE_SET),
e.enum("fan_speed", ea.STATE_SET, ["minimum", "medium", "maximum"]).withDescription("Speed of the fan"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
101,
"fan_speed",
tuya.valueConverterBasic.lookup({
minimum: tuya.enum(0),
medium: tuya.enum(1),
maximum: tuya.enum(2),
}),
],
[
11,
"power_on_behavior",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[5, "status_indication", tuya.valueConverter.onOff],
],
},
whiteLabel: [{ vendor: "Liwokit", model: "Fan+Light-01" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_lawxy9e2", "_TZE204_lawxy9e2"]),
model: "TS0601_fan_5_levels_and_light_switch",
vendor: "Tuya",
description: "Fan with 5 levels & light switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.binary("status_indication", ea.STATE_SET, "ON", "OFF").withDescription("Light switch"),
tuya.exposes.switch(),
e.power_on_behavior(["OFF", "ON"]).withAccess(ea.STATE_SET).withDescription("Fan On Off"),
e.numeric("fan_speed", ea.STATE_SET).withValueMin(1).withValueMax(5).withValueStep(1).withDescription("Speed off the fan"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
3,
"fan_speed",
tuya.valueConverterBasic.lookup({
"1": tuya.enum(0),
"2": tuya.enum(1),
"3": tuya.enum(2),
"4": tuya.enum(3),
"5": tuya.enum(4),
}, "5"),
],
[
11,
"power_on_behavior",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[5, "status_indication", tuya.valueConverter.onOff],
],
},
whiteLabel: [{ vendor: "Liwokit", model: "Fan+Light-01" }],
},
{
zigbeeModel: ["TS0224"],
model: "TS0224",
vendor: "Tuya",
description: "Smart light & sound siren",
fromZigbee: [],
toZigbee: [tz.warning, tzLocal.TS0224],
exposes: [
e.warning(),
e.binary("light", ea.STATE_SET, "ON", "OFF").withDescription("Turn the light of the alarm ON/OFF"),
e
.numeric("duration", ea.STATE_SET)
.withValueMin(60)
.withValueMax(3600)
.withValueStep(1)
.withUnit("s")
.withDescription("Duration of the alarm"),
e.enum("volume", ea.STATE_SET, ["mute", "low", "medium", "high"]).withDescription("Volume of the alarm"),
],
},
{
fingerprint: tuya.fingerprint("TS0041", ["_TZ3000_fa9mlvja"]),
model: "IH-K663",
vendor: "Tuya",
description: "Smart button",
exposes: [e.battery(), e.battery_voltage(), e.action(["single", "double"])],
fromZigbee: [tuya.fz.on_off_action, fz.battery],
toZigbee: [],
configure: tuya.configureMagicPacket,
},
{
fingerprint: tuya.fingerprint("TS011F", [
"_TZ3000_cayepv1a",
"_TZ3000_lepzuhto",
"_TZ3000_qystbcjg",
"_TZ3000_zrm3oxsh",
"_TZ3000_303avxxt",
"_TZ3000_zjchz7pd",
]),
model: "TS011F_with_threshold",
description: "Din rail switch with power monitoring and threshold settings",
vendor: "Tuya",
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
electricalMeasurements: true,
electricalMeasurementsFzConverter: fzLocal.TS011F_electrical_measurement,
powerOutageMemory: true,
indicatorMode: true,
onOffCountdown: true,
}),
],
fromZigbee: [fz.temperature, fzLocal.TS011F_threshold],
toZigbee: [tzLocal.TS011F_threshold],
exposes: (device, options) => {
const exposes = [];
if (!["_TZ3000_303avxxt", "_TZ3000_zjchz7pd"].includes(device?.manufacturerName)) {
exposes.push(e.temperature(), e
.numeric("temperature_threshold", ea.STATE_SET)
.withValueMin(40)
.withValueMax(100)
.withValueStep(1)
.withUnit("°C")
.withDescription("High temperature threshold"), e.binary("temperature_breaker", ea.STATE_SET, "ON", "OFF").withDescription("High temperature breaker"));
}
exposes.push(e
.numeric("power_threshold", ea.STATE_SET)
.withValueMin(1)
.withValueMax(26)
.withValueStep(1)
.withUnit("kW")
.withDescription("High power threshold"), e.binary("power_breaker", ea.STATE_SET, "ON", "OFF").withDescription("High power breaker"), e
.numeric("over_current_threshold", ea.STATE_SET)
.withValueMin(1)
.withValueMax(64)
.withValueStep(1)
.withUnit("A")
.withDescription("Over-current threshold"), e.binary("over_current_breaker", ea.STATE_SET, "ON", "OFF").withDescription("Over-current breaker"), e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withValueMin(220)
.withValueMax(265)
.withValueStep(1)
.withUnit("V")
.withDescription("Over-voltage threshold"), e.binary("over_voltage_breaker", ea.STATE_SET, "ON", "OFF").withDescription("Over-voltage breaker"), e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withValueMin(76)
.withValueMax(240)
.withValueStep(1)
.withUnit("V")
.withDescription("Under-voltage threshold"), e.binary("under_voltage_breaker", ea.STATE_SET, "ON", "OFF").withDescription("Under-voltage breaker"));
return exposes;
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await endpoint.command("genBasic", "tuyaSetup", {});
await reporting.bind(endpoint, coordinatorEndpoint, ["msTemperatureMeasurement"]);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement", "seMetering"]);
await reporting.rmsVoltage(endpoint, { change: 5 });
await reporting.rmsCurrent(endpoint, { change: 50 });
await reporting.activePower(endpoint, { change: 10 });
await reporting.currentSummDelivered(endpoint);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
whiteLabel: [
tuya.whitelabel("Tongou", "TO-Q-SY2-163JZT", "Smart circuit breaker", ["_TZ3000_cayepv1a"]),
tuya.whitelabel("EARU", "EAKCB-T-M-Z", "Smart circuit breaker", ["_TZ3000_lepzuhto"]),
tuya.whitelabel("EARU", "EAYCB-Z-2P", "Smart circuit breaker with leakage protection", ["_TZ3000_zrm3oxsh"]),
tuya.whitelabel("UNSH", "SMKG-1KNL-EU-Z", "Smart circuit Breaker", ["_TZ3000_qystbcjg"]),
tuya.whitelabel("Tomzn", "TOB9Z-VAP", "Smart circuit breaker", ["_TZ3000_303avxxt"]),
tuya.whitelabel("Immax", "07573L", "Smart circuit breaker", ["_TZ3000_zjchz7pd"]),
],
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3000_hdc8bbha"]),
model: "QS-Zigbee-SEC01-U",
vendor: "Tuya",
description: "Zigbee 3.0 smart light switch module 1 gang",
extend: [tuya.modernExtend.tuyaOnOff({ switchType: true })],
configure: async (device, coordinatorEndpoint) => {
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
// Device advertises itself as Router but is an EndDevice
device.type = "EndDevice";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3218_hdc8bbha"]),
model: "QS-Zigbee-SEC01-DC",
vendor: "Tuya",
description: "Mini 1 Gang Zigbee Switch Module",
extend: [tuya.modernExtend.tuyaOnOff({ switchType: true })],
configure: async (device, coordinatorEndpoint) => {
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
device.powerSource = "Mains (single phase)";
// Device advertises itself as Router but is an EndDevice
device.type = "EndDevice";
device.save();
},
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3000_m8f3z8ju"]),
model: "QS-Zigbee-SEC02-U",
vendor: "Tuya",
description: "Zigbee 3.0 smart light switch module 2 gang",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
},
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZ3000_bmqxalil", "_TZ3000_w1tcofu8"]),
model: "TS0001_switch_1_gang",
vendor: "Tuya",
description: "1-Gang switch with backlight",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
backlightModeOffOn: true,
}),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("Homeetec", "Homeetec_37022454", "1 Gang switch with backlight", ["_TZ3000_bmqxalil"]),
tuya.whitelabel("RoomsAI", "RoomsAI_37022454", "1 Gang switch with backlight", ["_TZ3000_w1tcofu8"]),
],
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_pv4puuxi", "_TZ3000_avky2mvc", "_TZ3000_785olaiq", "_TZ3000_qxcnwv26"]),
model: "TS0003_switch_3_gang",
vendor: "Tuya",
description: "3-Gang switch with backlight",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
backlightModeOffOn: true,
endpoints: ["left", "center", "right"],
}),
],
endpoint: (device) => {
return { left: 1, center: 2, right: 3 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [
tuya.whitelabel("Homeetec", "37022474_1", "3 Gang switch with backlight", ["_TZ3000_pv4puuxi"]),
tuya.whitelabel("RoomsAI", "37022474_2", "3 Gang switch with backlight", ["_TZ3000_avky2mvc"]),
tuya.whitelabel("Nova Digital", "WS-US-ZB", "3 Gang switch with backlight", ["_TZ3000_785olaiq"]),
tuya.whitelabel("Nova Digital", "FZB-3", "3 Gang physical switch with backlight", ["_TZ3000_qxcnwv26"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_hewlydpz"]),
model: "TS0601_switch_4_gang_2",
vendor: "Tuya",
description: "4 gang switch with backlight",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.backlightModeOffOn(),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[7, "backlight_mode", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Homeetec", "37022714", "4 Gang switch with backlight", ["_TZE200_hewlydpz"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_p6vz3wzt"]),
model: "TS0601_cover_5",
vendor: "Tuya",
description: "Curtain/blind switch",
options: [exposes.options.invert_cover()],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("calibration", ea.STATE_SET, ["START", "END"]).withDescription("Calibration"),
e.binary("backlight_mode", ea.STATE_SET, "ON", "OFF").withDescription("Backlight"),
e.enum("motor_steering", ea.STATE_SET, ["FORWARD", "BACKWARD"]).withDescription("Motor Steering"),
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withDescription("Child Lock"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[
3,
"calibration",
tuya.valueConverterBasic.lookup({
START: tuya.enum(0),
END: tuya.enum(1),
}),
],
[7, "backlight_mode", tuya.valueConverter.onOff],
[
8,
"motor_steering",
tuya.valueConverterBasic.lookup({
FORWARD: tuya.enum(0),
BACKWARD: tuya.enum(1),
}),
],
[103, "child_lock", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Homeetec", "37022483", "Curtain/blind switch", ["_TZE200_p6vz3wzt"])],
},
{
zigbeeModel: ["TS030F"],
model: "TS030F",
vendor: "Tuya",
description: "Smart blind controller",
fromZigbee: [fz.cover_position_tilt, fz.tuya_cover_options_2],
toZigbee: [tz.cover_position_tilt, tz.cover_state, tzLocal.TS030F_border, tz.moes_cover_calibration, tz.tuya_cover_reversal],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "closuresWindowCovering"]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.currentPositionLiftPercentage(endpoint);
},
whiteLabel: [tuya.whitelabel("Lidl", "HG09648", "Livarno roller blinds", ["_TZB000_42ha4rsc"])],
exposes: [
e.cover_position(),
e.enum("border", ea.SET, ["up", "down", "up_delete", "down_delete"]),
e.numeric("calibration_time", ea.ALL).withValueMin(0).withValueMax(100),
e
.binary("motor_reversal", ea.ALL, "ON", "OFF")
.withDescription("Reverse the motor, resets all endpoints! Also the upper border after hardware initialisation. Be careful!" +
"After this you have to turn off and turn on the roller so that it can drive into the uppest position."),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_jhkttplm"]),
model: "TS0601_cover_with_1_switch",
vendor: "Tuya",
description: "Curtain/blind switch with 1 Gang switch",
options: [exposes.options.invert_cover()],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
tuya.exposes.switch().withEndpoint("l1"),
e.enum("calibration", ea.STATE_SET, ["START", "END"]).withDescription("Calibration"),
e.binary("backlight_mode", ea.STATE_SET, "ON", "OFF").withDescription("Backlight"),
e.enum("motor_steering", ea.STATE_SET, ["FORWARD", "BACKWARD"]).withDescription("Motor Steering"),
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withDescription("Child Lock"),
],
endpoint: (device) => {
return { l1: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[
3,
"calibration",
tuya.valueConverterBasic.lookup({
START: tuya.enum(0),
END: tuya.enum(1),
}),
],
[7, "backlight_mode", tuya.valueConverter.onOff],
[
8,
"motor_steering",
tuya.valueConverterBasic.lookup({
FORWARD: tuya.enum(0),
BACKWARD: tuya.enum(1),
}),
],
[101, "state_l1", tuya.valueConverter.onOff],
[103, "child_lock", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Homeetec", "37022493", "Curtain/blind switch with 1 Gang switch", ["_TZE200_jhkttplm"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_5nldle7w"]),
model: "TS0601_cover_with_2_switch",
vendor: "Tuya",
description: "Curtain/blind switch with 2 Gang switch",
options: [exposes.options.invert_cover()],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
e.enum("calibration", ea.STATE_SET, ["START", "END"]).withDescription("Calibration"),
e.binary("backlight_mode", ea.STATE_SET, "ON", "OFF").withDescription("Backlight"),
e.enum("motor_steering", ea.STATE_SET, ["FORWARD", "BACKWARD"]).withDescription("Motor Steering"),
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withDescription("Child Lock"),
],
endpoint: (device) => {
return { l1: 1, l2: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPosition],
[
3,
"calibration",
tuya.valueConverterBasic.lookup({
START: tuya.enum(0),
END: tuya.enum(1),
}),
],
[7, "backlight_mode", tuya.valueConverter.onOff],
[
8,
"motor_steering",
tuya.valueConverterBasic.lookup({
FORWARD: tuya.enum(0),
BACKWARD: tuya.enum(1),
}),
],
[101, "state_l2", tuya.valueConverter.onOff],
[102, "state_l1", tuya.valueConverter.onOff],
[103, "child_lock", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Homeetec", "37022173", "Curtain/blind switch with 2 Gang switch", ["_TZE200_5nldle7w"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_bcusnqt8"]),
model: "SPM01",
vendor: "Tuya",
description: "Smart energy monitor for 1P+N system",
ota: true,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.voltage(),
e.power(),
e.current(),
// Change the description according to the specifications of the device
e
.energy()
.withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[
6,
null,
{
from: (v) => {
return {
voltage: v.readUint16BE(0) / 10,
current: ((v.readUint8(2) << 16) + (v.readUint8(3) << 8) + v.readUint8(4)) / 1000,
power: (v.readUint8(5) << 16) + (v.readUint8(6) << 8) + v.readUint8(7),
};
},
},
],
[6, "voltage", tuya.valueConverter.raw],
[6, "current", tuya.valueConverter.raw],
[6, "power", tuya.valueConverter.raw],
// [9,'',tuya.valueConverter.raw] // Unknown / datatype=5 (bitmap)
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ves1ycwx", "_TZE284_ves1ycwx", "_TZE200_ves1ycwx"]),
model: "SPM02",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("X"),
tuya.exposes.voltageWithPhase("Y"),
tuya.exposes.voltageWithPhase("Z"),
tuya.exposes.powerWithPhase("X"),
tuya.exposes.powerWithPhase("Y"),
tuya.exposes.powerWithPhase("Z"),
tuya.exposes.currentWithPhase("X"),
tuya.exposes.currentWithPhase("Y"),
tuya.exposes.currentWithPhase("Z"),
// Change the description according to the specifications of the device
e
.energy()
.withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant2WithPhase("X")],
[7, null, tuya.valueConverter.phaseVariant2WithPhase("Y")],
[8, null, tuya.valueConverter.phaseVariant2WithPhase("Z")],
// [9,'',tuya.valueConverter.raw] // Unknown / datatype=5 (bitmap)
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_qhlxve78", "_TZE284_qhlxve78", "_TZE204_qhlxve78"]),
model: "SPM01V2",
vendor: "Tuya",
description: "Smart energy monitor for 1P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.voltage(),
e.power(),
e.current(),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%"),
e.ac_frequency(),
e
.numeric("data_report_duration", ea.SET)
.withValueMin(5)
.withValueMax(3600)
.withDescription("WARNING: You must update device firmware to V3.1.3 before changing this setting! Use Tuya gateway/app to update firmware. Data report duration set (Threshold value range 5~3600 seconds)"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
// [6, null, tuya.valueConverter.phaseVariant3],
[15, "power_factor", tuya.valueConverter.raw],
// [16, 'clear_energy', tuya.valueConverter.onOff],
[
18,
"data_report_duration",
{
to: (v) => {
const value = Math.max(5, Math.min(3600, Math.round(v)));
const byte1 = (value >> 8) & 0xff;
const byte2 = value & 0xff;
return [
// Unknown what these bytes mean, possibly configures other settings of the device
0x01,
0x01,
0x00,
0x3c,
0x03,
0x01,
0x00,
0xfd,
0x04,
0x00,
0x00,
0xb4,
0x07,
0x01,
0x00,
0x00,
0x08,
0x01,
// Report duration
byte1,
byte2,
// Unknown what these bytes mean, possibly configures other settings of the device
0x09,
0x00,
0x00,
0x00,
];
},
},
],
[101, "ac_frequency", tuya.valueConverter.divideBy100],
[102, "voltage", tuya.valueConverter.divideBy10],
[103, "current", tuya.valueConverter.divideBy1000],
[104, "power", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_v9hkz2yn", "_TZE284_v9hkz2yn", "_TZE200_v9hkz2yn"]),
model: "SPM02V2",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%"),
e.power(),
e.ac_frequency(),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
// [6, null, tuya.valueConverter.phaseVariant2WithPhase('X')],
// [7, null, tuya.valueConverter.phaseVariant2WithPhase('Y')],
// [8, null, tuya.valueConverter.phaseVariant2WithPhase('Z')],
[15, "power_factor", tuya.valueConverter.raw],
[101, "ac_frequency", tuya.valueConverter.divideBy100],
[102, "voltage_a", tuya.valueConverter.divideBy10],
[103, "current_a", tuya.valueConverter.divideBy1000],
[104, "power_a", tuya.valueConverter.raw],
[105, "voltage_b", tuya.valueConverter.divideBy10],
[106, "current_b", tuya.valueConverter.divideBy1000],
[107, "power_b", tuya.valueConverter.raw],
[108, "voltage_c", tuya.valueConverter.divideBy10],
[109, "current_c", tuya.valueConverter.divideBy1000],
[110, "power_c", tuya.valueConverter.raw],
[111, "power", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_dhotiauw"]),
model: "2CT",
vendor: "Tuya",
description: "Bidirectional energy meter with 80A current clamp",
extend: [tuyaBase({ dp: true })],
exposes: [
e.ac_frequency(),
e.voltage(),
e.power(),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("s")
.withDescription("Update frequency")
.withValueMin(3)
.withValueMax(60)
.withPreset("default", 10, "Default value"),
e.numeric("timestamp_a", ea.STATE).withDescription("Timestamp at power measure (phase a)"),
e.numeric("timestamp_b", ea.STATE).withDescription("Timestamp at power measure (phase b)"),
e
.numeric("calibration_ac_frequency", ea.STATE_SET)
.withDescription("Calibration AC frequency")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
e
.numeric("calibration_voltage", ea.STATE_SET)
.withDescription("Calibration voltage")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
e
.numeric("calibration_power_a", ea.STATE_SET)
.withDescription("Calibration power A")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
e
.numeric("calibration_current_a", ea.STATE_SET)
.withDescription("Calibration current A")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
e
.numeric("calibration_power_b", ea.STATE_SET)
.withDescription("Calibration power B")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
e
.numeric("calibration_current_b", ea.STATE_SET)
.withDescription("Calibration current B")
.withValueMin(0.5)
.withValueMax(1.5)
.withValueStep(0.01)
.withPreset("default", 1.0, "Default value"),
],
meta: {
multiEndpointSkip: ["power_factor", "power_factor_phase_a", "power_factor_phase_b", "energy"],
tuyaDatapoints: [
[105, "ac_frequency", tuya.valueConverter.divideBy100],
[103, "power_a", tuya.valueConverter.divideBy10],
[104, "power_b", tuya.valueConverter.divideBy10],
[19, "power", tuya.valueConverter.divideBy10],
[20, "voltage", tuya.valueConverter.divideBy10],
[101, "current_a", tuya.valueConverter.divideBy1000],
[102, "current_b", tuya.valueConverter.divideBy1000],
[120, "power_factor_a", tuya.valueConverter.raw],
[121, "power_factor_b", tuya.valueConverter.raw],
[115, "energy_a", tuya.valueConverter.divideBy100],
[117, "energy_b", tuya.valueConverter.divideBy100],
[122, "update_frequency", tuya.valueConverter.raw],
[123, "calibration_voltage", tuya.valueConverter.divideBy1000],
[125, "calibration_current_a", tuya.valueConverter.divideBy1000],
[126, "calibration_power_a", tuya.valueConverter.divideBy1000],
[130, "calibration_current_b", tuya.valueConverter.divideBy1000],
[131, "calibration_power_b", tuya.valueConverter.divideBy1000],
[124, "calibration_ac_frequency", tuya.valueConverter.divideBy1000],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_iwn0gpzz", "_TZE204_iwn0gpzz", "_TZE284_iwn0gpzz"]),
model: "SPM01V2.5",
vendor: "Tuya",
description: "Smart energy monitor for 1P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.voltage(),
e.power(),
e.current(),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%"),
e.ac_frequency(),
e
.numeric("data_report_duration", ea.SET)
.withValueMin(5)
.withValueMax(3600)
.withDescription("WARNING: You must update device firmware to V3.2.2 before changing this setting! Use Tuya gateway/app to update firmware. Data report duration set (Threshold value range 5~3600 seconds)"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[
18,
"data_report_duration",
{
to: (v) => {
const value = Math.max(5, Math.min(3600, Math.round(v)));
const byte1 = (value >> 8) & 0xff;
const byte2 = value & 0xff;
return [
// Other settings of the device
0x01,
0x01,
0x00,
0x3c,
0x03,
0x01,
0x00,
0xfd,
0x04,
0x00,
0x00,
0xb4,
0x07,
0x01,
0x00,
0x00,
0x08,
0x01,
// Report duration
byte1,
byte2,
// Only modify the report duration
0x09,
0x00,
0x00,
0x00,
];
},
},
],
[23, "produced_energy", tuya.valueConverter.divideBy100],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[102, "voltage", tuya.valueConverter.divideBy10],
[103, "current", tuya.valueConverter.divideBy1000],
[104, "power", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ny94onlb", "_TZE200_ny94onlb", "_TZE284_ny94onlb"]),
model: "SPM02V2.5",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%").withDescription("Total power factor"),
e.power(),
e.ac_frequency(),
e.numeric("data_report_duration", ea.SET).withValueMin(5).withValueMax(3600),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[
18,
"data_report_duration",
{
to: (v) => {
const value = Math.max(5, Math.min(3600, Math.round(v)));
const byte1 = (value >> 8) & 0xff;
const byte2 = value & 0xff;
return [
// Other settings of the device
0x01,
0x01,
0x00,
0x3c,
0x02,
0x00,
0x00,
0x0a,
0x03,
0x01,
0x00,
0xfd,
0x04,
0x00,
0x00,
0xb4,
0x05,
0x01,
0x00,
0x00,
0x07,
0x01,
0x00,
0x00,
0x08,
0x01,
// Report duration
byte1,
byte2,
// Only modify the report duration
0x09,
0x00,
0x00,
0x00,
];
},
},
],
[23, "produced_energy", tuya.valueConverter.divideBy100],
[29, "power", tuya.valueConverter.raw],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[102, "voltage_a", tuya.valueConverter.divideBy10],
[103, "current_a", tuya.valueConverter.divideBy1000],
[104, "power_a", tuya.valueConverter.raw],
[105, "voltage_b", tuya.valueConverter.divideBy10],
[106, "current_b", tuya.valueConverter.divideBy1000],
[107, "power_b", tuya.valueConverter.raw],
[108, "voltage_c", tuya.valueConverter.divideBy10],
[109, "current_c", tuya.valueConverter.divideBy1000],
[110, "power_c", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_dikb3dp6", "_TZE204_dikb3dp6", "_TZE284_dikb3dp6"]),
model: "SPM02V3",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%").withDescription("Total power factor"),
e.power().withDescription("Total active power"),
e.ac_frequency(),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyWithPhase("c"),
tuya.exposes.energyProducedWithPhase("a"),
tuya.exposes.energyProducedWithPhase("b"),
tuya.exposes.energyProducedWithPhase("c"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.powerFactorWithPhase("c"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("s")
.withDescription("Update frequency")
.withValueMin(5)
.withValueMax(3600)
.withPreset("default", 10, "Default value"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[23, "produced_energy", tuya.valueConverter.divideBy100],
[29, "power", tuya.valueConverter.raw],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[102, "update_frequency", tuya.valueConverterBasic.divideBy(1)],
[103, "voltage_a", tuya.valueConverter.divideBy10],
[104, "current_a", tuya.valueConverter.divideBy1000],
[105, "power_a", tuya.valueConverter.raw],
[108, "power_factor_a", tuya.valueConverter.raw],
[109, "energy_a", tuya.valueConverter.divideBy100],
[110, "energy_produced_a", tuya.valueConverter.divideBy100],
[112, "voltage_b", tuya.valueConverter.divideBy10],
[113, "current_b", tuya.valueConverter.divideBy1000],
[114, "power_b", tuya.valueConverter.raw],
[117, "power_factor_b", tuya.valueConverter.raw],
[118, "energy_b", tuya.valueConverter.divideBy100],
[119, "energy_produced_b", tuya.valueConverter.divideBy100],
[121, "voltage_c", tuya.valueConverter.divideBy10],
[122, "current_c", tuya.valueConverter.divideBy1000],
[123, "power_c", tuya.valueConverter.raw],
[126, "power_factor_c", tuya.valueConverter.raw],
[127, "energy_c", tuya.valueConverter.divideBy100],
[128, "energy_produced_c", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ugekduaj", "_TZE200_ugekduaj", "_TZE204_loejka0i"]),
model: "SDM01",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [tuya.whitelabel("Nous", "D4Z", "Smart energy monitor for 3P+N system", ["_TZE204_loejka0i"])],
exposes: [
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%").withDescription("Total power factor"),
e.power().withDescription("Total active power"),
e.ac_frequency(),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyWithPhase("c"),
tuya.exposes.energyProducedWithPhase("a"),
tuya.exposes.energyProducedWithPhase("b"),
tuya.exposes.energyProducedWithPhase("c"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.powerFactorWithPhase("c"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[15, "power_factor", tuya.valueConverter.raw],
[101, "ac_frequency", tuya.valueConverter.divideBy100],
[102, "voltage_a", tuya.valueConverter.divideBy10],
[103, "current_a", tuya.valueConverter.divideBy1000],
[104, "power_a", tuya.valueConverter.raw],
[105, "voltage_b", tuya.valueConverter.divideBy10],
[106, "current_b", tuya.valueConverter.divideBy1000],
[107, "power_b", tuya.valueConverter.raw],
[108, "voltage_c", tuya.valueConverter.divideBy10],
[109, "current_c", tuya.valueConverter.divideBy1000],
[110, "power_c", tuya.valueConverter.raw],
[111, "power", tuya.valueConverter.raw],
[112, "energy_a", tuya.valueConverter.divideBy100],
[114, "energy_b", tuya.valueConverter.divideBy100],
[116, "energy_c", tuya.valueConverter.divideBy100],
[113, "energy_produced_a", tuya.valueConverter.divideBy100],
[115, "energy_produced_b", tuya.valueConverter.divideBy100],
[117, "energy_produced_c", tuya.valueConverter.divideBy100],
[118, "power_factor_a", tuya.valueConverter.raw],
[119, "power_factor_b", tuya.valueConverter.raw],
[120, "power_factor_c", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_gomuk3dc", "_TZE284_gomuk3dc", "_TZE200_gomuk3dc"]),
model: "SDM01V1.5",
vendor: "Tuya",
description: "Smart energy monitor for 3P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%").withDescription("Total power factor"),
e.power().withDescription("Total active power"),
e.ac_frequency(),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyWithPhase("c"),
tuya.exposes.energyProducedWithPhase("a"),
tuya.exposes.energyProducedWithPhase("b"),
tuya.exposes.energyProducedWithPhase("c"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.powerFactorWithPhase("c"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("s")
.withDescription("Update frequency")
.withValueMin(5)
.withValueMax(3600)
.withPreset("default", 10, "Default value"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[23, "produced_energy", tuya.valueConverter.divideBy100],
[29, "power", tuya.valueConverter.raw],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[102, "update_frequency", tuya.valueConverterBasic.divideBy(1)],
[103, "voltage_a", tuya.valueConverter.divideBy10],
[104, "current_a", tuya.valueConverter.divideBy1000],
[105, "power_a", tuya.valueConverter.raw],
[108, "power_factor_a", tuya.valueConverter.raw],
[109, "energy_a", tuya.valueConverter.divideBy100],
[110, "energy_produced_a", tuya.valueConverter.divideBy100],
[112, "voltage_b", tuya.valueConverter.divideBy10],
[113, "current_b", tuya.valueConverter.divideBy1000],
[114, "power_b", tuya.valueConverter.raw],
[117, "power_factor_b", tuya.valueConverter.raw],
[118, "energy_b", tuya.valueConverter.divideBy100],
[119, "energy_produced_b", tuya.valueConverter.divideBy100],
[121, "voltage_c", tuya.valueConverter.divideBy10],
[122, "current_c", tuya.valueConverter.divideBy1000],
[123, "power_c", tuya.valueConverter.raw],
[126, "power_factor_c", tuya.valueConverter.raw],
[127, "energy_c", tuya.valueConverter.divideBy100],
[128, "energy_produced_c", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_78ioiaml", "_TZE284_78ioiaml", "_TZE200_78ioiaml"]),
model: "SDM02V1",
vendor: "Tuya",
description: "Smart energy monitor for 2P+N system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.voltageWithPhase("l1"),
tuya.exposes.voltageWithPhase("l2"),
tuya.exposes.powerWithPhase("l1"),
tuya.exposes.powerWithPhase("l2"),
tuya.exposes.currentWithPhase("l1"),
tuya.exposes.currentWithPhase("l2"),
e.energy().withDescription("Total forward active energy"),
e.produced_energy().withDescription("Total reverse active energy"),
e.power_factor().withUnit("%").withDescription("Total power factor"),
e.power().withDescription("Total active power"),
e.ac_frequency(),
tuya.exposes.energyWithPhase("l1"),
tuya.exposes.energyWithPhase("l2"),
tuya.exposes.energyProducedWithPhase("l1"),
tuya.exposes.energyProducedWithPhase("l2"),
tuya.exposes.powerFactorWithPhase("l1"),
tuya.exposes.powerFactorWithPhase("l2"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("s")
.withDescription("Update frequency")
.withValueMin(5)
.withValueMax(3600)
.withPreset("default", 10, "Default value"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[23, "produced_energy", tuya.valueConverter.divideBy100],
[29, "power", tuya.valueConverter.raw],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[102, "update_frequency", tuya.valueConverterBasic.divideBy(1)],
[103, "voltage_l1", tuya.valueConverter.divideBy10],
[104, "current_l1", tuya.valueConverter.divideBy1000],
[105, "power_l1", tuya.valueConverter.raw],
[108, "power_factor_l1", tuya.valueConverter.raw],
[109, "energy_l1", tuya.valueConverter.divideBy100],
[110, "energy_produced_l1", tuya.valueConverter.divideBy100],
[112, "voltage_l2", tuya.valueConverter.divideBy10],
[113, "current_l2", tuya.valueConverter.divideBy1000],
[114, "power_l2", tuya.valueConverter.raw],
[117, "power_factor_l2", tuya.valueConverter.raw],
[118, "energy_l2", tuya.valueConverter.divideBy100],
[119, "energy_produced_l2", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ac0fhfiq", "_TZE284_ac0fhfiq"]),
model: "TS0601_bidirectional_energy meter",
vendor: "Tuya",
description: "Bidirectional energy meter with 150A Current Clamp",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.energy(),
e.produced_energy(),
e.power(),
e.voltage(),
e.current(),
e.enum("energy_flow", ea.STATE, ["consuming", "producing"]).withDescription("Direction of energy"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[2, "produced_energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant3],
[102, "energy_flow", tuya.valueConverterBasic.lookup({ consuming: 0, producing: 1 })],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_vmcgja59",
"_TZE204_dvosyycn",
"_TZE200_wktrysab",
"_TZE204_wktrysab",
"_TZE204_nvxorhcj",
"_TZE204_tdhnhhiy",
]),
model: "TS0601_switch_8",
vendor: "Tuya",
description: "ZYXH 8 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
tuya.exposes.switch().withEndpoint("l7"),
tuya.exposes.switch().withEndpoint("l8"),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, l5: 1, l6: 1, l7: 1, l8: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[0x65, "state_l7", tuya.valueConverter.onOff],
[0x66, "state_l8", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Nova Digital", "ZTS-8W-B", "8 Gang Switch", ["_TZE204_nvxorhcj"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_adlblwab"]),
model: "TS0601_switch_8_2",
vendor: "Tuya",
description: "8 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
tuya.exposes.switch().withEndpoint("l7"),
tuya.exposes.switch().withEndpoint("l8"),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l3"),
tuya.exposes.countdown().withEndpoint("l4"),
tuya.exposes.countdown().withEndpoint("l5"),
tuya.exposes.countdown().withEndpoint("l6"),
tuya.exposes.countdown().withEndpoint("l7"),
tuya.exposes.countdown().withEndpoint("l8"),
e.power_on_behavior().withAccess(ea.STATE_SET),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, l5: 1, l6: 1, l7: 1, l8: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[7, "state_l7", tuya.valueConverter.onOff],
[8, "state_l8", tuya.valueConverter.onOff],
[9, "countdown_l1", tuya.valueConverter.countdown],
[10, "countdown_l2", tuya.valueConverter.countdown],
[11, "countdown_l3", tuya.valueConverter.countdown],
[12, "countdown_l4", tuya.valueConverter.countdown],
[13, "countdown_l5", tuya.valueConverter.countdown],
[14, "countdown_l6", tuya.valueConverter.countdown],
[15, "countdown_l7", tuya.valueConverter.countdown],
[16, "countdown_l8", tuya.valueConverter.countdown],
[27, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_7sjncirf"]),
model: "TS0601_switch_10",
vendor: "Tuya",
description: "10 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [...Array.from({ length: 10 }, (_, i) => tuya.exposes.switch().withEndpoint(`l${i + 1}`))],
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
l7: 1,
l8: 1,
l9: 1,
l10: 1,
l11: 1,
l12: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[0x65, "state_l7", tuya.valueConverter.onOff],
[0x66, "state_l8", tuya.valueConverter.onOff],
[0x67, "state_l9", tuya.valueConverter.onOff],
[0x68, "state_l10", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_dqolcpcp", "_TZE284_dqolcpcp"]),
model: "TS0601_switch_12",
vendor: "Tuya",
description: "ZXYH 12 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [...Array.from({ length: 12 }, (_, i) => tuya.exposes.switch().withEndpoint(`l${i + 1}`))],
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
l7: 1,
l8: 1,
l9: 1,
l10: 1,
l11: 1,
l12: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[0x65, "state_l7", tuya.valueConverter.onOff],
[0x66, "state_l8", tuya.valueConverter.onOff],
[0x67, "state_l9", tuya.valueConverter.onOff],
[0x68, "state_l10", tuya.valueConverter.onOff],
[0x69, "state_l11", tuya.valueConverter.onOff],
[0x6a, "state_l12", tuya.valueConverter.onOff],
],
},
},
// TS011F
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_8fdayfch", "_TZ3000_1hwjutgo", "_TZ3000_lnggrqqi", "_TZ3000_tvuarksa"]),
model: "TS011F_1",
vendor: "Tuya",
description: "Switch",
extend: [tuya.modernExtend.tuyaOnOff()],
whiteLabel: [
{ vendor: "Mumubiz", model: "ZJSB9-80Z" },
tuya.whitelabel("KTNNKG", "ZB1248-10A", "Relay switch", ["_TZ3000_8fdayfch"]),
tuya.whitelabel("UseeLink", "SM-AZ713", "Smart water/gas valve", ["_TZ3000_tvuarksa"]),
],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_rqbjepe8", "_TZ3000_uwkja6z1"]),
model: "TS011F_4",
description: "2 gang plug",
vendor: "Tuya",
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
electricalMeasurements: true,
powerOutageMemory: true,
indicatorMode: true,
childLock: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: {
multiEndpoint: true,
multiEndpointSkip: ["energy", "current", "voltage", "power"],
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", {
acCurrentDivisor: 1000,
acCurrentMultiplier: 1,
});
endpoint.saveClusterAttributeKeyValue("seMetering", {
divisor: 100,
multiplier: 1,
});
device.save();
},
options: [exposes.options.measurement_poll_interval()],
onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, true, false),
whiteLabel: [tuya.whitelabel("Nous", "A4Z", "2 gang outdoor plug", ["_TZ3000_rqbjepe8", "_TZ3000_uwkja6z1"])],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_cfnprab5", "_TZ3000_o005nuxx", "_TZ3000_gdyjfvgm"]),
model: "TS011F_5",
description: "5 gang switch",
vendor: "Tuya",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOutageMemory: true,
childLock: true,
endpoints: ["l1", "l2", "l3", "l4", "l5"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4, l5: 5 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ID of [1, 2, 3, 4, 5]) {
await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ["genOnOff"]);
}
},
whiteLabel: [
tuya.whitelabel("UseeLink", "SM-0306E-2W", "4 gang switch, with USB", ["_TZ3000_cfnprab5"]),
tuya.whitelabel("UseeLink", "SM-O301-AZ", "AU 4 plug 10A power board + USB", ["_TZ3000_o005nuxx"]),
],
},
{
zigbeeModel: ["SM0202"],
model: "SM0202",
vendor: "Tuya",
description: "Motion sensor",
fromZigbee: [fz.ias_occupancy_alarm_1_with_timeout, fz.battery],
toZigbee: [],
exposes: [e.occupancy(), e.battery_low(), e.battery(), e.battery_voltage()],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]);
await reporting.batteryPercentageRemaining(endpoint);
},
whiteLabel: [
tuya.whitelabel("Cleverio", "SS200", "Motion sensor", ["_TYZB01_z2umiwvq"]),
tuya.whitelabel("Marmitek", "SM0202_1", "Motion sensor", ["_TYZB01_yr95mpib"]),
],
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZ3210_dse8ogfy", "_TZ3210_j4pdtz9v"]),
model: "TS0001_fingerbot",
vendor: "Tuya",
description: "Zigbee fingerbot plus",
whiteLabel: [tuya.whitelabel("Adaprox", "TS0001_fingerbot_1", "Zigbee fingerbot plus", ["_TZ3210_dse8ogfy"])],
fromZigbee: [fz.on_off, tuya.fz.datapoints],
toZigbee: [tz.on_off, tuya.tz.datapoints],
exposes: [
e.switch(),
e.battery(),
e.enum("mode", ea.STATE_SET, ["click", "switch", "program"]).withDescription("Working mode"),
e.numeric("lower", ea.STATE_SET).withValueMin(50).withValueMax(100).withValueStep(1).withUnit("%").withDescription("Down movement limit"),
e.numeric("upper", ea.STATE_SET).withValueMin(0).withValueMax(50).withValueStep(1).withUnit("%").withDescription("Up movement limit"),
e.numeric("delay", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withUnit("s").withDescription("Sustain time"),
e.binary("reverse", ea.STATE_SET, "ON", "OFF").withDescription("Reverse"),
e.binary("touch", ea.STATE_SET, "ON", "OFF").withDescription("Touch control"),
],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
},
meta: {
tuyaSendCommand: "sendData",
tuyaDatapoints: [
[
0x65,
"mode",
tuya.valueConverterBasic.lookup({
click: tuya.enum(0),
switch: tuya.enum(1),
program: tuya.enum(2),
}),
],
[0x66, "lower", tuya.valueConverter.raw],
[0x67, "delay", tuya.valueConverter.raw],
[
0x68,
"reverse",
tuya.valueConverterBasic.lookup({
ON: tuya.enum(1),
OFF: tuya.enum(0),
}),
],
[0x69, "battery", tuya.valueConverter.raw],
[0x6a, "upper", tuya.valueConverter.raw],
[0x6b, "touch", tuya.valueConverterBasic.lookup({ ON: true, OFF: false })],
// ? [0x6c, '', tuya.valueConverter.onOff],
[0x6d, "program", tuya.valueConverter.raw],
// ? [0x70, '', tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_8eazvzo6"]),
model: "SWS6TZ-WHITE",
vendor: "Tuya",
description: "6 gang wall switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.switch().withEndpoint("l1"),
e.switch().withEndpoint("l2"),
e.switch().withEndpoint("l3"),
e.switch().withEndpoint("l4"),
e.switch().withEndpoint("l5"),
e.switch().withEndpoint("l6"),
e.current(),
e.power(),
e.voltage(),
],
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, l5: 1, l6: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[21, "current", tuya.valueConverter.divideBy1000],
[22, "power", tuya.valueConverter.divideBy10],
[23, "voltage", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_0j5jma9b", "_TZE200_h2rctifa"]),
model: "ZS-TYG3-SM-61Z",
vendor: "Tuya",
description: "Smart switch (4 gang + 2 scene) with backlight and neutral wire",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withDescription("All Switches"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l3"),
tuya.exposes.countdown().withEndpoint("l4"),
tuya.exposes.countdown().withEndpoint("l5"),
tuya.exposes.countdown().withEndpoint("l6"),
e.power_on_behavior().withAccess(ea.STATE_SET),
],
onEvent: tuya.onEventSetTime,
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
state: 1,
backlight: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[7, "countdown_l1", tuya.valueConverter.countdown],
[8, "countdown_l2", tuya.valueConverter.countdown],
[9, "countdown_l3", tuya.valueConverter.countdown],
[10, "countdown_l4", tuya.valueConverter.countdown],
[11, "countdown_l5", tuya.valueConverter.countdown],
[12, "countdown_l6", tuya.valueConverter.countdown],
[13, "state", tuya.valueConverter.onOff],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[16, "backlight_mode", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wunufsil"]),
model: "ZS-TYG3-SM-21Z",
vendor: "Tuya",
description: "2 gang smart switch with backlight and neutral wire",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withDescription("All Switches"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
e.power_on_behavior().withAccess(ea.STATE_SET),
],
onEvent: tuya.onEventSetTime,
endpoint: (device) => {
return { l1: 1, l2: 1, state: 1, backlight: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[7, "countdown_l1", tuya.valueConverter.countdown],
[8, "countdown_l2", tuya.valueConverter.countdown],
[13, "state", tuya.valueConverter.onOff],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[16, "backlight_mode", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_vhy3iakz"]),
model: "ZS-TYG3-SM-31Z",
vendor: "Tuya",
description: "3 gang smart switch with backlight and neutral wire",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withDescription("All Switches"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l3"),
e.power_on_behavior(["off", "on", "previous"]).withAccess(ea.STATE_SET),
],
onEvent: tuya.onEventSetTime,
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, state: 1, backlight: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[7, "countdown_l1", tuya.valueConverter.countdown],
[8, "countdown_l2", tuya.valueConverter.countdown],
[9, "countdown_l3", tuya.valueConverter.countdown],
[13, "state", tuya.valueConverter.onOff],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[16, "backlight_mode", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_k6jhsr0q", "_TZE204_unsxl4ir"]),
model: "ZS-TYG3-SM-41Z",
vendor: "Tuya",
description: "4 gang smart switch with backlight and neutral wire",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch().withDescription("All Switches"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
tuya.exposes.countdown().withEndpoint("l1"),
tuya.exposes.countdown().withEndpoint("l2"),
tuya.exposes.countdown().withEndpoint("l3"),
tuya.exposes.countdown().withEndpoint("l4"),
e.power_on_behavior(["off", "on", "previous"]).withAccess(ea.STATE_SET),
],
onEvent: tuya.onEventSetTime,
endpoint: (device) => {
return { l1: 1, l2: 1, l3: 1, l4: 1, state: 1, backlight: 1 };
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[7, "countdown_l1", tuya.valueConverter.countdown],
[8, "countdown_l2", tuya.valueConverter.countdown],
[9, "countdown_l3", tuya.valueConverter.countdown],
[10, "countdown_l4", tuya.valueConverter.countdown],
[13, "state", tuya.valueConverter.onOff],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[16, "backlight_mode", tuya.valueConverter.onOff],
],
},
whiteLabel: [tuya.whitelabel("Nova Digital", "FZB-4", "Interruptor de 4 canais com backlight e neutro", ["TZE204_unsxl4ir"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nvodulvi"]),
model: "M9-zigbee-SL",
vendor: "Tuya",
description: "Smart Switch (4 gang + 4 scene) with neutral wire and motion sensing",
fromZigbee: [tuya.fz.datapoints, fz.ias_occupancy_only_alarm_2, tuya.fz.indicator_mode],
toZigbee: [tuya.tz.datapoints, tuya.tz.power_on_behavior_1, tuya.tz.backlight_indicator_mode_1],
configure: tuya.configureMagicPacket,
exposes: [
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.switch().withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => e.power_on_behavior().withAccess(ea.STATE_SET).withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.switchMode().withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.lightMode().withEndpoint(`l${i}`)),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(["scene_1", "scene_2", "scene_3", "scene_4", "scene_5", "scene_6", "scene_7", "scene_8"]),
e.presence(),
new exposes.Numeric("delay", ea.STATE_SET).withUnit("sec").withDescription("light off delay").withValueMin(0).withValueMax(1000),
],
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
state: 1,
backlight: 1,
l7: 1,
l8: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[16, "backlight_mode", tuya.valueConverter.onOff],
[29, "power_on_behavior_l1", tuya.valueConverter.powerOnBehaviorEnum],
[30, "power_on_behavior_l2", tuya.valueConverter.powerOnBehaviorEnum],
[31, "power_on_behavior_l3", tuya.valueConverter.powerOnBehaviorEnum],
[32, "power_on_behavior_l4", tuya.valueConverter.powerOnBehaviorEnum],
[33, "power_on_behavior_l5", tuya.valueConverter.powerOnBehaviorEnum],
[34, "power_on_behavior_l6", tuya.valueConverter.powerOnBehaviorEnum],
[101, "action", tuya.valueConverter.static("scene_1")],
[102, "action", tuya.valueConverter.static("scene_2")],
[103, "action", tuya.valueConverter.static("scene_3")],
[104, "action", tuya.valueConverter.static("scene_4")],
[105, "presence", tuya.valueConverter.raw],
[106, "delay", tuya.valueConverter.raw],
[108, "action", tuya.valueConverter.static("scene_5")],
[109, "action", tuya.valueConverter.static("scene_6")],
[110, "action", tuya.valueConverter.static("scene_7")],
[111, "action", tuya.valueConverter.static("scene_8")],
[112, "state_l7", tuya.valueConverter.onOff],
[113, "state_l8", tuya.valueConverter.onOff],
[114, "switch_mode_l1", tuya.valueConverter.switchMode],
[115, "switch_mode_l2", tuya.valueConverter.switchMode],
[116, "switch_mode_l3", tuya.valueConverter.switchMode],
[117, "switch_mode_l4", tuya.valueConverter.switchMode],
[118, "switch_mode_l5", tuya.valueConverter.switchMode],
[119, "switch_mode_l6", tuya.valueConverter.switchMode],
[120, "switch_mode_l7", tuya.valueConverter.switchMode],
[121, "switch_mode_l8", tuya.valueConverter.switchMode],
[122, "light_mode_l1", tuya.valueConverter.lightMode],
[123, "light_mode_l2", tuya.valueConverter.lightMode],
[124, "light_mode_l3", tuya.valueConverter.lightMode],
[125, "light_mode_l4", tuya.valueConverter.lightMode],
[126, "light_mode_l5", tuya.valueConverter.lightMode],
[127, "light_mode_l6", tuya.valueConverter.lightMode],
[128, "light_mode_l7", tuya.valueConverter.lightMode],
[129, "light_mode_l8", tuya.valueConverter.lightMode],
[130, "power_on_behavior_l7", tuya.valueConverter.powerOnBehaviorEnum],
[131, "power_on_behavior_l8", tuya.valueConverter.powerOnBehaviorEnum],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_sooucan5", "_TZE204_oqtpvx51"]),
model: "YXZBRB58",
vendor: "Tuya",
description: "Smart human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.illuminance(),
e.presence(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e.numeric("radar_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(9).withValueStep(1).withDescription("Sensitivity of the radar"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Minimum range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Maximum range")
.withUnit("m"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Detection delay")
.withUnit("s"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(0).withValueMax(1500).withValueStep(1).withDescription("Fading time").withUnit("s"),
e
.enum("radar_scene", ea.STATE_SET, ["default", "bathroom", "bedroom", "sleeping", "unknown"])
.withDescription("Presets for sensitivity for presence and movement"),
],
meta: {
tuyaDatapoints: [
[0x01, "presence", tuya.valueConverter.trueFalse1],
[0x02, "radar_sensitivity", tuya.valueConverter.raw],
[0x03, "minimum_range", tuya.valueConverter.divideBy100],
[0x04, "maximum_range", tuya.valueConverter.divideBy100],
[0x65, "illuminance", tuya.valueConverter.raw],
[0x66, "detection_delay", tuya.valueConverter.divideBy10],
[0x67, "fading_time", tuya.valueConverter.divideBy10],
[
0x68,
"radar_scene",
tuya.valueConverterBasic.lookup({
default: tuya.enum(0),
bathroom: tuya.enum(1),
bedroom: tuya.enum(2),
sleeping: tuya.enum(3),
unknown: tuya.enum(4),
}),
],
[0x69, "target_distance", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_86nbew0j", "_TZE200_io0zdqh1", "_TZE200_drs6j6m5", "_TZE200_ywe90lt0", "_TZE200_qyss8gjy"]),
model: "TS0601_light",
vendor: "Tuya",
description: "Light",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [tuya.exposes.lightBrightness(), e.power_on_behavior().withAccess(ea.STATE_SET)],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff, { skip: tuya.skip.stateOnAndBrightnessPresent }],
[2, "power_on_behavior", tuya.valueConverter.powerOnBehavior],
[3, "brightness", tuya.valueConverter.scale0_254to0_1000],
],
},
whiteLabel: [
tuya.whitelabel("Ltech", "TY-12-100-400-W1Z", "12W 100-400mA Zigbee CC Dimmable LED driver", ["_TZE200_86nbew0j"]),
tuya.whitelabel("Ltech", "TY-75-24-G2Z2", "150W 24V Zigbee CV tunable white LED driver", ["_TZE200_io0zdqh1"]),
tuya.whitelabel("Lifud", "LF-AAZ012-0400-42", "Zigbee dimmable LED driver 4-40W 220-240Vac", ["_TZE200_drs6j6m5"]),
tuya.whitelabel("Lifud", "LF-GAZ150A6250-24", "Lifud Zigbee LED Driver CCT 150W 24V", ["_TZE200_ywe90lt0"]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_k7mfgaen", "_TZE204_fncxk3ob"]),
model: "YXZBSL",
vendor: "Tuya",
description: "Smart siren",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.binary("alarm", ea.STATE_SET, "ON", "OFF").withDescription("Turn the light of the alarm ON/OFF"),
e.enum("type", ea.STATE_SET, ["sound", "light", "sound+light", "normal"]).withDescription("Alarm type"),
e.enum("volume", ea.STATE_SET, ["mute", "low", "middle", "high"]).withDescription("Volume of the alarm"),
e
.enum("ringtone", ea.STATE_SET, [
"melody1",
"melody2",
"melody3",
"melody4",
"melody5",
"melody6",
"melody7",
"melody8",
"door",
"water",
"temperature",
"entered",
"left",
])
.withDescription("Ringtone of the alarm"),
e.enum("power_type", ea.STATE, ["battery", "cable"]).withDescription("Power type"),
e
.numeric("duration", ea.STATE_SET)
.withValueMin(1)
.withValueMax(60)
.withValueStep(1)
.withUnit("min")
.withDescription("Duration of the alarm"),
e.enum("battery_level", ea.STATE, ["low", "middle", "high"]).withDescription("Battery level state"),
e.battery(),
],
meta: {
tuyaDatapoints: [
[
1,
"type",
tuya.valueConverterBasic.lookup({
sound: tuya.enum(0),
light: tuya.enum(1),
"sound+light": tuya.enum(2),
normal: tuya.enum(3),
}),
],
[
5,
"volume",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
middle: tuya.enum(1),
high: tuya.enum(2),
mute: tuya.enum(3),
}),
],
[6, "power_type", tuya.valueConverterBasic.lookup({ cable: false, battery: true })],
[7, "duration", tuya.valueConverter.raw],
[13, "alarm", tuya.valueConverter.onOff],
[
14,
"battery_level",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
middle: tuya.enum(1),
high: tuya.enum(2),
}),
],
[15, "battery", tuya.valueConverter.raw],
[
21,
"ringtone",
tuya.valueConverterBasic.lookup({
melody1: tuya.enum(0),
melody2: tuya.enum(1),
melody3: tuya.enum(2),
melody4: tuya.enum(3),
melody5: tuya.enum(4),
melody6: tuya.enum(5),
melody7: tuya.enum(6),
melody8: tuya.enum(7),
door: tuya.enum(8),
water: tuya.enum(9),
temperature: tuya.enum(10),
entered: tuya.enum(11),
left: tuya.enum(12),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_vmcgja59"]),
model: "ZYXH",
vendor: "Tuya",
description: "24 gang switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [...Array.from(Array(24).keys()).map((ep) => tuya.exposes.switch().withEndpoint(`l${ep + 1}`))],
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
l7: 1,
l8: 1,
l9: 1,
l10: 1,
l11: 1,
l12: 1,
l13: 1,
l14: 1,
l15: 1,
l16: 1,
l17: 1,
l18: 1,
l19: 1,
l20: 1,
l21: 1,
l22: 1,
l23: 1,
l24: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[0x65, "state_l7", tuya.valueConverter.onOff],
[0x66, "state_l8", tuya.valueConverter.onOff],
[0x67, "state_l9", tuya.valueConverter.onOff],
[0x68, "state_l10", tuya.valueConverter.onOff],
[0x69, "state_l11", tuya.valueConverter.onOff],
[0x6a, "state_l12", tuya.valueConverter.onOff],
[0x6b, "state_l13", tuya.valueConverter.onOff],
[0x6c, "state_l14", tuya.valueConverter.onOff],
[0x6d, "state_l15", tuya.valueConverter.onOff],
[0x6e, "state_l16", tuya.valueConverter.onOff],
[0x6f, "state_l17", tuya.valueConverter.onOff],
[0x70, "state_l18", tuya.valueConverter.onOff],
[0x71, "state_l19", tuya.valueConverter.onOff],
[0x72, "state_l20", tuya.valueConverter.onOff],
[0x73, "state_l21", tuya.valueConverter.onOff],
[0x74, "state_l22", tuya.valueConverter.onOff],
[0x75, "state_l23", tuya.valueConverter.onOff],
[0x76, "state_l24", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ijxvkhd0"]),
model: "ZY-M100-24G",
vendor: "Tuya",
description: "24G MmWave radar human presence motion sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.enum("state", ea.STATE, ["none", "presence", "move"]).withDescription("Presence state"),
e.presence(),
e.numeric("distance", ea.STATE).withUnit("m").withDescription("Target distance"),
e.illuminance(),
e
.numeric("motion_sensitivity", ea.STATE_SET)
.withValueMin(1)
.withValueMax(10)
.withValueStep(1)
.withCategory("config")
.withDescription("Motion sensitivity"),
e
.numeric("presence_sensitivity", ea.STATE_SET)
.withValueMin(1)
.withValueMax(10)
.withValueStep(1)
.withCategory("config")
.withDescription("Presence sensitivity"),
e
.numeric("max_range", ea.STATE_SET)
.withValueMin(1.5)
.withValueMax(5.5)
.withValueStep(1)
.withUnit("m")
.withCategory("config")
.withDescription("Maximum range"),
e
.numeric("presence_timeout", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1500)
.withValueStep(1)
.withUnit("s")
.withDescription("Presence timeout"),
],
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[112, "presence", tuya.valueConverter.trueFalse1],
[106, "motion_sensitivity", tuya.valueConverter.divideBy10FromOnly],
[111, "presence_sensitivity", tuya.valueConverter.divideBy10FromOnly],
[107, "max_range", tuya.valueConverter.divideBy100],
[109, "distance", tuya.valueConverter.divideBy100],
[110, "presence_timeout", tuya.valueConverter.raw],
[104, "illuminance", tuya.valueConverter.raw],
[102, "illuminance_treshold_max", tuya.valueConverter.raw],
[103, "illuminance_treshold_min", tuya.valueConverter.raw],
[105, "state", tuya.valueConverterBasic.lookup({ none: 0, presence: 1, move: 2 })],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_7gclukjs"]),
model: "ZY-M100-24GV2",
vendor: "Tuya",
description: "24G MmWave radar human presence motion sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.enum("state", ea.STATE, ["none", "presence", "move"]).withDescription("Presence state sensor"),
e.presence().withDescription("Occupancy"),
e.numeric("distance", ea.STATE).withUnit("m").withDescription("Target distance"),
e.illuminance().withDescription("Illuminance sensor"),
e.numeric("move_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Motion Sensitivity"),
e.numeric("presence_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Presence Sensitivity"),
e
.numeric("detection_distance_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8.25)
.withValueStep(0.75)
.withUnit("m")
.withDescription("Minimum range"),
e
.numeric("detection_distance_max", ea.STATE_SET)
.withValueMin(0.75)
.withValueMax(9.0)
.withValueStep(0.75)
.withUnit("m")
.withDescription("Maximum range"),
e
.numeric("presence_timeout", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1500)
.withValueStep(1)
.withUnit("s")
.withDescription("Fade time"),
],
meta: {
tuyaDatapoints: [
[104, "presence", tuya.valueConverter.trueFalse1],
[2, "move_sensitivity", tuya.valueConverter.raw],
[102, "presence_sensitivity", tuya.valueConverter.raw],
[3, "detection_distance_min", tuya.valueConverter.divideBy100],
[4, "detection_distance_max", tuya.valueConverter.divideBy100],
[9, "distance", tuya.valueConverter.divideBy10],
[105, "presence_timeout", tuya.valueConverter.raw],
[103, "illuminance", tuya.valueConverter.raw],
[1, "state", tuya.valueConverterBasic.lookup({ none: 0, presence: 1, move: 2 })],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ya4ft0w4", "_TZE200_ya4ft0w4", "_TZE204_gkfbdvyx", "_TZE200_gkfbdvyx"]),
model: "ZY-M100-24GV3",
vendor: "Tuya",
description: "24G MmWave radar human presence motion sensor (added distance switch)",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: (device, options) => {
const exps = [
e.enum("state", ea.STATE, ["none", "presence", "move"]).withDescription("Presence state sensor"),
e.presence().withDescription("Occupancy"),
e.numeric("distance", ea.STATE).withDescription("Target distance"),
e.binary("find_switch", ea.STATE_SET, "ON", "OFF").withDescription("distance switch"),
e.illuminance().withDescription("Illuminance sensor"),
e.numeric("move_sensitivity", ea.STATE_SET).withValueMin(1).withValueMax(10).withValueStep(1).withDescription("Motion Sensitivity"),
e
.numeric("presence_sensitivity", ea.STATE_SET)
.withValueMin(1)
.withValueMax(10)
.withValueStep(1)
.withDescription("Presence Sensitivity"),
e
.numeric("presence_timeout", ea.STATE_SET)
.withValueMin(1)
.withValueMax(15000)
.withValueStep(1)
.withUnit("s")
.withDescription("Fade time"),
];
if (!device || device.manufacturerName === "_TZE204_gkfbdvyx" || device.manufacturerName === "_TZE200_gkfbdvyx") {
exps.push(e
.numeric("detection_distance_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.5)
.withUnit("m")
.withDescription("Minimum range"));
exps.push(e
.numeric("detection_distance_max", ea.STATE_SET)
.withValueMin(0.5)
.withValueMax(9.0)
.withValueStep(0.5)
.withUnit("m")
.withDescription("Maximum range"));
}
else {
exps.push(e
.numeric("detection_distance_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8.25)
.withValueStep(0.75)
.withUnit("m")
.withDescription("Minimum range"));
exps.push(e
.numeric("detection_distance_max", ea.STATE_SET)
.withValueMin(0.75)
.withValueMax(9.0)
.withValueStep(0.75)
.withUnit("m")
.withDescription("Maximum range"));
}
return exps;
},
meta: {
tuyaDatapoints: [
[
1,
null,
{
from: (v, meta) => {
if (v === 0) {
return {
state: "none",
presence: false,
};
}
if (v === 1) {
return {
state: "presence",
presence: true,
};
}
if (v === 2) {
return {
state: "move",
presence: true,
};
}
return {
state: "none",
presence: false,
};
},
},
],
[2, "move_sensitivity", tuya.valueConverter.raw],
[3, "detection_distance_min", tuya.valueConverter.divideBy100],
[4, "detection_distance_max", tuya.valueConverter.divideBy100],
[9, "distance", tuya.valueConverter.divideBy10],
[101, "find_switch", tuya.valueConverter.onOff],
[102, "presence_sensitivity", tuya.valueConverter.raw],
[103, "illuminance", tuya.valueConverter.raw],
[105, "presence_timeout", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_e9ajs4ft"]),
model: "CTL-R1-TY-Zigbee",
vendor: "Tuya",
description: "24G radar human presence motion sensor.",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.illuminance().withUnit("lx"),
e.presence(),
e
.numeric("presence_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(100)
.withValueStep(1)
.withUnit("%")
.withDescription("Presence sensitivity"),
e
.numeric("detection_range", ea.STATE_SET)
.withValueMin(1.5)
.withValueMax(4.5)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Detection range"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(1)
.withValueMax(600)
.withValueStep(1)
.withUnit("s")
.withDescription("Presence detection delay"),
e
.numeric("illuminance_treshold_max", ea.STATE_SET)
.withValueMin(0)
.withValueMax(2000)
.withValueStep(1)
.withUnit("lx")
.withDescription("The max illumiance threshold to turn on the light"),
e
.numeric("illuminance_treshold_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(2000)
.withValueStep(1)
.withUnit("lx")
.withDescription("The min illumiance threshold to turn on the light"),
e
.binary("presence_illuminance_switch", ea.STATE_SET, true, false)
.withDescription(`Whether to enable 'light_switch' illumination is between min/max threshold`),
e
.binary("light_switch", ea.STATE, "ON", "OFF")
.withDescription("This state will determine the light on/off based on the lighting threshold and presence sensing"),
e.binary("light_linkage", ea.STATE_SET, true, false).withDescription("Light linkage"),
e
.enum("detection_method", ea.STATE_SET, ["only_move", "exist_move"])
.withDescription(`When 'only_move' is used, presence will only be triggered when there is movement`),
e.enum("indicator_light", ea.STATE_SET, ["presence", "off", "on"]).withDescription("Controls when the indicator light is turned on"),
e
.binary("identify", ea.STATE_SET, true, false)
.withDescription("After turning on, the indicator light quickly flashes, used to locate devices"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[2, "presence_sensitivity", tuya.valueConverter.raw],
[4, "detection_range", tuya.valueConverter.divideBy10],
[101, "illuminance", tuya.valueConverter.raw],
[102, "illuminance_treshold_max", tuya.valueConverter.raw],
[103, "illuminance_treshold_min", tuya.valueConverter.raw],
[104, "detection_delay", tuya.valueConverter.raw],
[109, "presence_illuminance_switch", tuya.valueConverter.trueFalseEnum1],
[105, "light_switch", tuya.valueConverter.onOff],
[106, "light_linkage", tuya.valueConverter.trueFalseEnum1],
[
107,
"indicator_light",
tuya.valueConverterBasic.lookup({
presence: tuya.enum(0),
off: tuya.enum(1),
on: tuya.enum(2),
}),
],
[
108,
"detection_method",
tuya.valueConverterBasic.lookup({
only_move: tuya.enum(0),
exist_move: tuya.enum(1),
}),
],
[113, "find_switch", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", [
"_TZE204_sbyx0lm6",
"_TZE204_clrdrnya",
"_TZE204_dtzziy1e",
"_TZE204_iaeejhvf",
"_TZE204_mtoaryre",
"_TZE200_mp902om5",
"_TZE204_pfayrzcw",
"_TZE284_4qznlkbu",
"_TZE200_clrdrnya",
"_TZE200_sbyx0lm6",
]),
model: "MTG075-ZB-RL",
vendor: "Tuya",
description: "2.4G/5.8G human presence sensor with relay",
whiteLabel: [
tuya.whitelabel("Tuya", "MTG275-ZB-RL", "2.4G/5.8G MmWave radar human presence motion sensor", ["_TZE204_dtzziy1e"]),
tuya.whitelabel("Tuya", "MTG035-ZB-RL", "Human presence sensor with relay", ["_TZE204_pfayrzcw"]),
tuya.whitelabel("Tuya", "MTG235-ZB-RL", "24G Human presence sensor with relay", ["_TZE204_clrdrnya", "_TZE200_clrdrnya"]),
tuya.whitelabel("QA", "QASZ24R", "mmWave 24 Ghz sensor with relay", ["_TZE284_4qznlkbu"]),
],
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.illuminance(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e
.numeric("radar_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9)
.withValueStep(1)
.withDescription("Detection threshold for the strength of object energy"),
e
.numeric("detection_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Maximum distance detected by the sensor"),
e
.numeric("shield_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Nearest distance detected by the sensor"),
e
.numeric("entry_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9)
.withValueStep(1)
.withDescription("Sensitivity threshold triggered for the first time when the target enters the detection range"),
e
.numeric("entry_distance_indentation", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Indent the distance inward based on the detection distance"),
e
.numeric("entry_filter_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withUnit("s")
.withDescription("Sensitivity threshold triggered for the first time when the target enters the detection range "),
e
.numeric("departure_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(600)
.withValueStep(1)
.withUnit("s")
.withDescription("Confirmation time after the target disappears"),
e
.numeric("block_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withUnit("s")
.withDescription("Time for the target to be detected again after switching from manned(occupy) to unmanned(unoccupy) mode"),
e.binary("breaker_status", ea.STATE_SET, "ON", "OFF").withDescription("Remotely control the breaker in standard mode"),
e
.enum("breaker_mode", ea.STATE_SET, ["standard", "local"])
.withDescription("Breaker mode: standard is remotely controlled, local is automatic"),
e
.numeric("illuminance_threshold", ea.STATE_SET)
.withValueMin(0)
.withValueMax(420)
.withValueStep(0.1)
.withUnit("lx")
.withDescription("Illumination threshold for local (automatic) switching mode operation"),
e.enum("status_indication", ea.STATE_SET, ["OFF", "ON"]).withDescription("Indicator light will flash when human presence is detected"),
e
.enum("sensor", ea.STATE_SET, ["on", "off", "occupied", "unoccupied"])
.withDescription("The radar sensor can be set in four states: on, off, occupied and unoccupied. For example, if set to occupied, " +
"it will continue to maintain presence regardless of whether someone is present or not. If set to unoccupied, the unoccupied " +
"state will be maintained permanently."),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[2, "radar_sensitivity", tuya.valueConverter.raw],
[3, "shield_range", tuya.valueConverter.divideBy100],
[4, "detection_range", tuya.valueConverter.divideBy100],
[6, "equipment_status", tuya.valueConverter.raw],
[9, "target_distance", tuya.valueConverter.divideBy100],
[101, "entry_filter_time", tuya.valueConverter.divideBy10],
[102, "departure_delay", tuya.valueConverter.raw],
[103, "cline", tuya.valueConverter.raw],
[104, "illuminance", tuya.valueConverter.divideBy10],
[105, "entry_sensitivity", tuya.valueConverter.raw],
[106, "entry_distance_indentation", tuya.valueConverter.divideBy100],
[
107,
"breaker_mode",
tuya.valueConverterBasic.lookup({
standard: tuya.enum(0),
local: tuya.enum(1),
}),
],
[
108,
"breaker_status",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[
109,
"status_indication",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[110, "illuminance_threshold", tuya.valueConverter.divideBy10],
[
111,
"breaker_polarity",
tuya.valueConverterBasic.lookup({
NC: tuya.enum(0),
NO: tuya.enum(1),
}),
],
[112, "block_time", tuya.valueConverter.divideBy10],
[113, "parameter_setting_result", tuya.valueConverter.raw],
[114, "factory_parameters", tuya.valueConverter.raw],
[
115,
"sensor",
tuya.valueConverterBasic.lookup({
on: tuya.enum(0),
off: tuya.enum(1),
occupied: tuya.enum(2),
unoccupied: tuya.enum(3),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_81yrt3lo", "_TZE284_81yrt3lo"]),
model: "PJ-1203A",
vendor: "Tuya",
description: "Bidirectional energy meter with 80A current clamp",
fromZigbee: [fzLocal.PJ1203A_strict_fz_datapoints, fzLocal.PJ1203A_sync_time_increase_seq],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
options: [
e
.binary("late_energy_flow_a", ea.SET, true, false)
.withDescription("Delay channel A publication until the next energy flow update (default false)."),
e
.binary("late_energy_flow_b", ea.SET, true, false)
.withDescription("Delay channel B publication until the next energy flow update (default false)."),
e
.binary("signed_power_a", ea.SET, true, false)
.withDescription("Report energy flow direction for channel A using signed power (default false)."),
e
.binary("signed_power_b", ea.SET, true, false)
.withDescription("Report energy flow direction for channel B using signed power (default false)."),
],
exposes: [
e.ac_frequency(),
e.voltage(),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("ab"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.energyFlowWithPhase("a", ["sign"]),
tuya.exposes.energyFlowWithPhase("b", ["sign"]),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyProducedWithPhase("a"),
tuya.exposes.energyProducedWithPhase("b"),
e
.numeric("update_frequency", ea.STATE_SET)
.withUnit("s")
.withDescription("Update frequency")
.withValueMin(3)
.withValueMax(60)
.withPreset("default", 10, "Default value"),
// Timestamp a and b are basically equivalent to last_seen
// but they indicate when the unsigned value of power_a and power_b
// were received. They can be several seconds in the past if
// the publication was delayed because of the late_energy_flow options.
e
.numeric("timestamp_a", ea.STATE)
.withDescription("Timestamp at power measure (phase a)"),
e.numeric("timestamp_b", ea.STATE).withDescription("Timestamp at power measure (phase b)"),
],
meta: {
multiEndpointSkip: ["power_factor", "power_factor_phase_b", "power_factor_phase_c", "energy"],
tuyaDatapoints: [
[111, "ac_frequency", tuya.valueConverter.divideBy100],
[112, "voltage", tuya.valueConverter.divideBy10],
[101, null, convLocal.powerPJ1203A("a")], // power_a
[105, null, convLocal.powerPJ1203A("b")], // power_b
[113, null, convLocal.currentPJ1203A("a")], // current_a
[114, null, convLocal.currentPJ1203A("b")], // current_b
[110, null, convLocal.powerFactorPJ1203A("a")], // power_factor_a
[121, null, convLocal.powerFactorPJ1203A("b")], // power_factor_b
[102, null, convLocal.energyFlowPJ1203A("a")], // energy_flow_a or the sign of power_a
[104, null, convLocal.energyFlowPJ1203A("b")], // energy_flow_b or the sign of power_b
[115, null, convLocal.powerAbPJ1203A()],
[106, "energy_a", tuya.valueConverter.divideBy100],
[108, "energy_b", tuya.valueConverter.divideBy100],
[107, "energy_produced_a", tuya.valueConverter.divideBy100],
[109, "energy_produced_b", tuya.valueConverter.divideBy100],
[129, "update_frequency", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_rks0sgb7"]),
model: "PC311-Z-TY",
vendor: "Tuya",
description: "Bidirectional energy meter with 80A current clamp",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.ac_frequency(),
e.voltage(),
e.power(),
e.current(),
e.energy(),
e.energy_produced(),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.powerFactorWithPhase("a"),
tuya.exposes.powerFactorWithPhase("b"),
tuya.exposes.energyWithPhase("a"),
tuya.exposes.energyWithPhase("b"),
tuya.exposes.energyProducedWithPhase("a"),
tuya.exposes.energyProducedWithPhase("b"),
],
meta: {
multiEndpointSkip: ["power_factor", "power_factor_phase_b", "power_factor_phase_c", "energy"],
tuyaDatapoints: [
[113, "ac_frequency", tuya.valueConverter.raw],
[108, "power_a", tuya.valueConverter.raw],
[111, "power_b", tuya.valueConverter.raw],
[9, "power", tuya.valueConverter.raw],
[106, "voltage", tuya.valueConverter.divideBy10],
[107, "current_a", tuya.valueConverter.divideBy1000],
[110, "current_b", tuya.valueConverter.divideBy1000],
[105, "current", tuya.valueConverter.divideBy1000],
[109, "power_factor_a", tuya.valueConverter.raw],
[112, "power_factor_b", tuya.valueConverter.raw],
[1, "energy", tuya.valueConverter.divideBy100],
[101, "energy_a", tuya.valueConverter.divideBy100],
[103, "energy_b", tuya.valueConverter.divideBy100],
[102, "energy_produced_a", tuya.valueConverter.divideBy100],
[104, "energy_produced_b", tuya.valueConverter.divideBy100],
[2, "energy_produced", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_mpbki2zm"]),
model: "TYBAC-006",
vendor: "Tuya",
description: "Wall-mount thermostat for 2-pipe fan-coil unit",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
options: [
e
.enum("control_sequence_of_operation", ea.SET, ["cooling_only", "cooling_and_heating_4-pipes"])
.withDescription("Operating environment of the thermostat"),
e.binary("expose_device_state", ea.SET, true, false).withDescription("Expose device power state as a separate property when enabled."),
],
exposes: (device, options) => {
const system_modes = ["off", "cool", "heat", "fan_only"];
// Device can operate either in 2-pipe or 4-pipe configuration
// For 2-pipe configurations remove 'heat' mode
switch (options?.control_sequence_of_operation) {
case "cooling_only":
system_modes.splice(2, 1);
break;
}
const exposes = [
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 1, ea.STATE_SET)
.withSystemMode(["off", "cool", "heat", "fan_only"], ea.STATE_SET)
.withFanMode(["low", "medium", "high", "auto"], ea.STATE_SET)
.withLocalTemperatureCalibration(-5, 5, 0.5, ea.STATE_SET),
e.child_lock(),
e.min_temperature().withValueMin(5).withValueMax(15),
e.max_temperature().withValueMin(15).withValueMax(45),
e.binary("eco_mode", ea.STATE_SET, "ON", "OFF").withDescription("ECO mode ON/OFF"),
e.max_temperature_limit().withDescription("ECO Heating energy-saving temperature (default: 20 ºC)").withValueMin(15).withValueMax(30),
e.min_temperature_limit().withDescription("ECO Cooling energy-saving temperature (default: 26 ºC)").withValueMin(15).withValueMax(30),
e.deadzone_temperature().withValueMin(0).withValueMax(5).withValueStep(1),
e.binary("valve", ea.STATE, "OPEN", "CLOSE").withDescription("3-Way Valve State"),
e.binary("manual_mode", ea.STATE_SET, "ON", "OFF").withDescription("Manual = ON or Schedule = OFF"),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
];
if (options?.expose_device_state === true) {
exposes.unshift(e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON or OFF"));
}
return exposes;
},
meta: {
publishDuplicateTransaction: true,
tuyaDatapoints: [
[
1,
"state",
{
to: async (v, meta) => {
if (meta.options?.expose_device_state === true) {
await tuya.sendDataPointBool(meta.device.endpoints[0], 1, utils.getFromLookup(v, { on: true, off: false }), "dataRequest", 1);
}
},
from: (v, meta, options) => {
meta.state.system_mode = v === true ? (meta.state.system_mode_device ?? "cool") : "off";
if (options?.expose_device_state === true) {
return v === true ? "ON" : "OFF";
}
// biome-ignore lint/performance/noDelete: ignored using `--suppress`
delete meta.state.state;
},
},
],
[
2,
"system_mode",
{
// Extend system_mode to support 'off' in addition to 'cool', 'heat' and 'fan_only'
to: async (v, meta) => {
const entity = meta.device.endpoints[0];
// Power State
await tuya.sendDataPointBool(entity, 1, v !== "off", "dataRequest", 1);
switch (v) {
case "cool":
await tuya.sendDataPointEnum(entity, 2, 0, "dataRequest", 1);
break;
case "heat":
await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1);
break;
case "fan_only":
await tuya.sendDataPointEnum(entity, 2, 2, "dataRequest", 1);
break;
}
},
from: (v, meta) => {
const modes = ["cool", "heat", "fan_only"];
meta.state.system_mode_device = modes[v];
return modes[v];
},
},
],
[4, "eco_mode", tuya.valueConverter.onOff],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[19, "max_temperature", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[26, "min_temperature", tuya.valueConverter.divideBy10],
[27, "local_temperature_calibration", tuya.valueConverter.localTemperatureCalibration],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
auto: tuya.enum(3),
}),
],
[36, "valve", tuya.valueConverterBasic.lookup({ OPEN: 0, CLOSE: 1 })],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[103, "deadzone_temperature", tuya.valueConverter.raw],
[104, "min_temperature_limit", tuya.valueConverter.divideBy10],
[105, "max_temperature_limit", tuya.valueConverter.divideBy10],
[106, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[107, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[108, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[109, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[110, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[111, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[112, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[101, "manual_mode", tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_mhxn2jso"]),
model: "rtsc11r",
vendor: "Tuya",
description: "5.8G human presence sensor with relay",
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
exposes: [
e.presence(),
e.illuminance().withUnit("lx"),
e
.numeric("detection_delay", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withDescription("Detection delay")
.withUnit("s"),
e
.numeric("detection_distance", ea.STATE)
.withValueMin(0)
.withValueMax(1000)
.withValueStep(1)
.withDescription("Distance of detected person")
.withUnit("cm"),
e.numeric("sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Detection sensitivity"),
e
.numeric("keep_time", ea.STATE_SET)
.withValueMin(5)
.withValueMax(3600)
.withValueStep(1)
.withDescription("Detection keep time")
.withUnit("s"),
e
.numeric("minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(1000)
.withValueStep(50)
.withDescription("Minimum detection range")
.withUnit("m"),
e
.numeric("maximum_range", ea.STATE_SET)
.withValueMin(50)
.withValueMax(1000)
.withValueStep(50)
.withDescription("Maximum detection range")
.withUnit("m"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[12, "detection_delay", tuya.valueConverter.divideBy10],
[19, "detection_distance", tuya.valueConverter.raw],
[20, "illuminance", tuya.valueConverter.raw],
[101, "sensitivity", tuya.valueConverter.divideBy10],
[102, "keep_time", tuya.valueConverter.raw],
[111, "minimum_range", tuya.valueConverter.divideBy100],
[112, "maximum_range", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_kyhbrfyl"]),
model: "NAS-PS09B2",
vendor: "Neo",
description: "Human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.occupancy(),
e.enum("human_motion_state", ea.STATE, ["none", "small", "large"]).withDescription("Human Motion State"),
e
.numeric("departure_delay", ea.STATE_SET)
.withUnit("s")
.withValueMin(3)
.withValueMax(600)
.withValueStep(1)
.withDescription("Presence Time"),
e
.numeric("radar_range", ea.STATE_SET)
.withUnit("cm")
.withValueMin(150)
.withValueMax(600)
.withValueStep(75)
.withDescription("Motion Range Detection"),
e
.numeric("radar_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(7)
.withValueStep(1)
.withDescription("Motion Detection Sensitivity"),
e
.numeric("presence_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(7)
.withValueStep(1)
.withDescription("Motionless Detection Sensitivity"),
e
.numeric("dis_current", ea.STATE)
.withUnit("cm")
.withValueMin(0)
.withValueMax(1000)
.withValueStep(1)
.withLabel("Current distance")
.withDescription("Current Distance of Detected Motion"),
],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse1],
[11, "human_motion_state", tuya.valueConverterBasic.lookup({ none: 0, small: 1, large: 2 })],
[12, "departure_delay", tuya.valueConverter.raw],
[13, "radar_range", tuya.valueConverter.raw],
[15, "radar_sensitivity", tuya.valueConverter.raw],
[16, "presence_sensitivity", tuya.valueConverter.raw],
[19, "dis_current", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_v1jqz5cy", "_TZE200_d9mzkhoq"]),
model: "BLE-YL01",
vendor: "Tuya",
description: "Smart WiFi Zigbee chlorine meter",
whiteLabel: [tuya.whitelabel("Tuya", "YK-S03", "Smart pH and Chlorine Tester for Swimming Pool", ["_TZE200_d9mzkhoq"])],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
// Don't query too often. Values are not always updated. https://github.com/Koenkk/zigbee2mqtt/issues/18704
onEvent: tuya.onEvent({
queryOnDeviceAnnounce: true,
// https://github.com/Koenkk/zigbee2mqtt/issues/23946#issuecomment-2941182834
queryIntervalSeconds: 20 * 60,
}),
configure: tuya.configureMagicPacket,
exposes: [
e.numeric("tds", ea.STATE).withUnit("ppm").withDescription("Total Dissolved Solids"),
e.temperature(),
e.battery(),
e
.numeric("ph", ea.STATE)
.withUnit("pH")
.withDescription("pH value, if the pH value is lower than 6.5, it means that the water quality " +
"is too acidic and has impurities, and it is necessary to add disinfectant water for disinfection"),
e.numeric("ec", ea.STATE).withUnit("µS/cm").withDescription("Electrical conductivity"),
e
.numeric("orp", ea.STATE)
.withUnit("mV")
.withDescription("Oxidation Reduction Potential value. If the ORP value is above 850mv, it " +
"means that the disinfectant has been added too much, and it is necessary to add water or change the water for neutralization. " +
"If the ORP value is below 487mv, it means that too little disinfectant has been added and the pool needs to be disinfected again"),
e
.numeric("free_chlorine", ea.STATE)
.withUnit("mg/L")
.withDescription("Free chlorine value. The water in the swimming pool should " +
"be between 6.5-8ph and ORP should be between 487-840mv, and the chlorine value will be displayed normally. Chlorine will not " +
"be displayed if either value is out of range"),
e.numeric("ph_max", ea.STATE_SET).withUnit("pH").withDescription("pH maximal value").withValueMin(0).withValueMax(20),
e.numeric("ph_min", ea.STATE_SET).withUnit("pH").withDescription("pH minimal value").withValueMin(0).withValueMax(20),
e
.numeric("ec_max", ea.STATE_SET)
.withUnit("µS/cm")
.withDescription("Electrical Conductivity maximal value")
.withValueMin(0)
.withValueMax(20000),
e
.numeric("ec_min", ea.STATE_SET)
.withUnit("µS/cm")
.withDescription("Electrical Conductivity minimal value")
.withValueMin(0)
.withValueMax(100),
e
.numeric("orp_max", ea.STATE_SET)
.withUnit("mV")
.withDescription("Oxidation Reduction Potential maximal value")
.withValueMin(0)
.withValueMax(1000),
e
.numeric("orp_min", ea.STATE_SET)
.withUnit("mV")
.withDescription("Oxidation Reduction Potential minimal value")
.withValueMin(0)
.withValueMax(1000),
e
.numeric("free_chlorine_max", ea.STATE_SET)
.withUnit("mg/L")
.withDescription("Free Chlorine maximal value")
.withValueMin(0)
.withValueMax(15),
e
.numeric("free_chlorine_min", ea.STATE_SET)
.withUnit("mg/L")
.withDescription("Free Chlorine minimal value")
.withValueMin(0)
.withValueMax(15),
e
.numeric("salinity", ea.STATE)
.withUnit("ppm")
.withDescription("Salt value"),
// e.numeric('backlightvalue', ea.STATE).withUnit('gg').withDescription('Backlight Value'),
],
meta: {
// All datapoints go in here
tuyaDatapoints: [
[1, "tds", tuya.valueConverter.raw],
[2, "temperature", tuya.valueConverter.divideBy10],
[7, "battery", tuya.valueConverter.raw],
[10, "ph", tuya.valueConverter.divideBy100],
[11, "ec", tuya.valueConverter.raw],
[101, "orp", tuya.valueConverter.raw],
[102, "free_chlorine", tuya.valueConverter.divideBy10],
// [105, 'backlightvalue', tuya.valueConverter.raw],
[106, "ph_max", tuya.valueConverter.divideBy10],
[107, "ph_min", tuya.valueConverter.divideBy10],
[108, "ec_max", tuya.valueConverter.raw],
[109, "ec_min", tuya.valueConverter.raw],
[110, "orp_max", tuya.valueConverter.raw],
[111, "orp_min", tuya.valueConverter.raw],
[112, "free_chlorine_max", tuya.valueConverter.divideBy10],
[113, "free_chlorine_min", tuya.valueConverter.divideBy10],
[117, "salinity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_mgxy2d9f"]),
model: "SP02-ZB001",
vendor: "iAlarm",
description: "Infrared motion sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [e.tamper(), e.battery(), e.occupancy()],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse0],
[4, "battery", tuya.valueConverter.raw],
[5, "tamper", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0201", ["_TZE200_iq4ygaai", "_TZE200_01fvxamo"]),
model: "THS317-ET-TY",
vendor: "Tuya",
description: "Temperature sensor with probe",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.temperature(), e.battery()],
whiteLabel: [tuya.whitelabel("OWON", "THS317-ET-EY", "Temperature sensor with probe", ["_TZE200_01fvxamo"])],
meta: {
tuyaDatapoints: [
[1, "temperature", tuya.valueConverter.divideBy10],
[4, "battery", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_iuk8kupi", "_TZE204_iuk8kupi"]),
model: "DCR-RQJ",
vendor: "Tuya",
description: "Carbon monoxide sensor gas leak detector",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [e.gas(), tuya.exposes.gasValue().withUnit("LEL %"), e.carbon_monoxide(), e.co()],
meta: {
tuyaDatapoints: [
[1, "gas", tuya.valueConverter.trueFalseEnum0],
[2, "gas_value", tuya.valueConverter.divideBy1000],
[18, "carbon_monoxide", tuya.valueConverter.trueFalseEnum0],
[19, "co", tuya.valueConverter.divideBy100],
],
},
},
{
zigbeeModel: ["ZG-101Z"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_nojsjtj2"]),
model: "ZG-101Z",
vendor: "Loginovo",
description: "SOS button",
extend: [
tuya.modernExtend.combineActions([
tuya.modernExtend.dpAction({ dp: 26, lookup: { sos: 0 } }),
tuya.modernExtend.dpAction({ dp: 29, lookup: { emergency: 0 } }),
]),
m.iasZoneAlarm({ zoneType: "generic", zoneAttributes: ["battery_low"] }),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_muvkrjr5"]),
model: "SZR07U",
vendor: "Tuya",
description: "24GHz millimeter wave radar",
configure: tuya.configureMagicPacket,
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
exposes: [
e.presence(),
e
.numeric("detection_range", ea.STATE_SET)
.withValueMin(1.5)
.withValueMax(6)
.withValueStep(0.75)
.withUnit("m")
.withDescription("Maximum range"),
e
.numeric("radar_sensitivity", ea.STATE_SET)
.withValueMin(68)
.withValueMax(90)
.withValueStep(1)
.withDescription("Sensitivity of the radar"),
e
.numeric("target_distance", ea.STATE)
.withValueMin(0)
.withValueMax(1000)
.withValueStep(1)
.withDescription("Distance of detected target")
.withUnit("cm"),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED indicator"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(3).withValueMax(1799).withValueStep(1).withDescription("Fading time").withUnit("s"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[13, "detection_range", tuya.valueConverter.divideBy100],
[16, "radar_sensitivity", tuya.valueConverter.raw],
[19, "target_distance", tuya.valueConverter.raw],
[101, "indicator", tuya.valueConverter.onOff],
[102, null, null], // toggle to enable presence notifications in app is ignored
[103, "fading_time", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0004", ["_TZ3000_5ajpkyq6"]),
model: "TS0004_switch_module_2",
vendor: "Tuya",
description: "4 gang switch module",
extend: [
tuya.modernExtend.tuyaOnOff({
switchType: true,
indicatorMode: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ["genOnOff"]);
},
whiteLabel: [tuya.whitelabel("AVATTO", "ZWSM16-4-Zigbee", "4 gang switch module", ["_TZ3000_5ajpkyq6"])],
},
{
fingerprint: tuya.fingerprint("TS1002", ["_TZ3000_etufnltx"]),
model: "F00XN00-04-1",
vendor: "FORIA",
description: "Dimmer 4 scenes",
extend: [
tuya.modernExtend.tuyaMagicPacket(),
m.battery({ voltage: true }),
tuya.modernExtend.combineActions([
m.actionEnumLookup({
actionLookup: { scene_1: 1, scene_2: 2, scene_3: 3, scene_4: 4 },
cluster: "genOnOff",
commands: ["commandTuyaAction"],
attribute: "data",
parse: (msg, attr) => msg.data[attr][1],
}),
m.commandsOnOff(),
m.commandsLevelCtrl({
commands: ["brightness_move_up", "brightness_move_down", "brightness_stop"],
}),
]),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_kobbcyum", "_TZE284_kobbcyum", "_TZE284_hecsejsb"]),
model: "TOWSMR1",
vendor: "Tongou",
description: "Single-phase multifunction RCBO (DIN Module)",
fromZigbee: [tuya.fz.datapoints, tuya.fz.gateway_connection_status],
toZigbee: [tuya.tz.datapoints],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
exposes: [
tuya.exposes.switch(),
e.temperature(),
e.current(),
e.power(),
e.voltage(),
e.energy(),
e.numeric("leakage_current", ea.STATE).withUnit("mA").withDescription("Current leakage"),
e
.enum("event", ea.STATE, [
"normal",
"over_current_trip",
"over_power_trip",
"high_temp_trip",
"over_voltage_trip",
"under_voltage_trip",
"over_current_alarm",
"over_power_alarm",
"high_temp_alarm",
"over_voltage_alarm",
"under_voltage_alarm",
"remote_on",
"remote_off",
"manual_on",
"manual_off",
"leakage_trip",
"leakage_alarm",
"restore_default",
"automatic_closing",
"electricity_shortage",
"electricity_shortage_alarm",
"timing_switch_On",
"timing_switch_off",
])
.withDescription("Last event of the device"),
e.enum("over_current_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over current setting"),
e
.numeric("over_current_threshold", ea.STATE_SET)
.withUnit("A")
.withDescription("Setup the value on the device")
.withValueMin(1)
.withValueMax(40),
e.enum("over_voltage_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over voltage setting"),
e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(240)
.withValueMax(295),
e.enum("under_voltage_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Under voltage setting"),
e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(145)
.withValueMax(220),
e.enum("leakage_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Leakage setting"),
e
.numeric("leakage_threshold", ea.STATE_SET)
.withUnit("mA")
.withDescription("Setup value on the device")
.withValueMin(30)
.withValueMax(100),
e.enum("temperature_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Temperature setting"),
e
.numeric("temperature_threshold", ea.STATE_SET)
.withUnit("°C")
.withDescription("Setup value on the device")
.withValueMin(-25)
.withValueMax(100),
e.enum("over_power_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over power setting"),
e
.numeric("over_power_threshold", ea.STATE_SET)
.withUnit("W")
.withDescription("Setup value on the device")
.withValueMin(1)
.withValueMax(25000),
e
.binary("auto_reclosing", ea.STATE_SET, "ON", "OFF")
.withLabel("Auto reclosing")
.withDescription("When the circuit breaker trips due to voltage protection, it will automatically close when the circuit voltage returns to normal"),
e.binary("restore_default", ea.STATE_SET, "ON", "OFF").withDescription("Turn ON to restore default settings"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant2], // voltage and current
[15, "leakage_current", tuya.valueConverter.raw],
[16, "state", tuya.valueConverter.onOff],
[
110,
"event",
tuya.valueConverterBasic.lookup({
normal: 0,
over_current_trip: 1,
over_power_trip: 2,
high_temp_trip: 3,
over_voltage_trip: 4,
under_voltage_trip: 5,
over_current_alarm: 6,
over_power_alarm: 7,
high_temp_alarm: 8,
over_voltage_alarm: 9,
under_voltage_alarm: 10,
remote_on: 11,
remote_off: 12,
manual_on: 13,
manual_off: 14,
leakage_trip: 15,
leakage_alarm: 16,
restore_default: 17,
automatic_closing: 18,
electricity_shortage: 19,
electricity_shortage_alarm: 20,
timing_switch_on: 21,
timing_switch_off: 22,
}),
],
[
102,
"over_voltage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
103,
"under_voltage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
104,
"over_current_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
105,
"over_power_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
107,
"temperature_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
108,
"leakage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[112, "auto_reclosing", tuya.valueConverter.onOff],
[113, "restore_default", tuya.valueConverter.onOff],
[114, "over_current_threshold", tuya.valueConverter.raw],
[115, "over_voltage_threshold", tuya.valueConverter.raw],
[116, "under_voltage_threshold", tuya.valueConverter.raw],
[117, "leakage_threshold", tuya.valueConverter.raw],
[118, "temperature_threshold", tuya.valueConverter.divideBy10],
[119, "over_power_threshold", tuya.valueConverter.raw],
[131, "temperature", tuya.valueConverter.divideBy10],
],
},
onEvent: tuya.onEvent({
respondToMcuVersionResponse: false,
queryIntervalSeconds: 10,
}),
},
{
fingerprint: [{ modelID: "TS0601", manufacturerName: "_TZE284_6ocnqlhn" }],
model: "TO-Q-SYS-JZT",
vendor: "Tongou",
description: "Din rail smart meter",
fromZigbee: [tuya.fz.datapoints, tuya.fz.gateway_connection_status],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent({
respondToMcuVersionResponse: false,
queryIntervalSeconds: 10,
}),
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
exposes: [
tuya.exposes.switch(),
e.power(),
e.current(),
e.voltage(),
e.energy(),
e.ac_frequency(),
e.power_factor().withUnit("%"),
e.numeric("temperature", ea.STATE).withUnit("°C").withDescription("Current temperature"),
e
.enum("event", ea.STATE, [
"normal",
"over_current_trip",
"over_power_trip",
"high_temp_trip",
"over_voltage_trip",
"under_voltage_trip",
"over_current_alarm",
"over_power_alarm",
"high_temp_alarm",
"over_voltage_alarm",
"under_voltage_alarm",
"remote_on",
"remote_off",
"manual_on",
"manual_off",
"leakage_trip",
"leakage_alarm",
"restore_default",
"automatic_closing",
"electricity_shortage",
"electricity_shortage_alarm",
"timing_switch_On",
"timing_switch_off",
])
.withDescription("Last event of the device"),
e.enum("over_current_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over current setting"),
e
.numeric("over_current_threshold", ea.STATE_SET)
.withUnit("A")
.withDescription("Setup the value on the device")
.withValueMin(1)
.withValueMax(50),
e.enum("over_voltage_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over voltage setting"),
e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(240)
.withValueMax(295),
e.enum("under_voltage_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Under voltage setting"),
e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withUnit("V")
.withDescription("Setup value on the device")
.withValueMin(90)
.withValueMax(220),
e.enum("temperature_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Temperature setting"),
e
.numeric("temperature_threshold", ea.STATE_SET)
.withUnit("°C")
.withDescription("Setup value on the device")
.withValueMin(-25)
.withValueMax(80),
e.enum("over_power_setting", ea.STATE_SET, ["Ignore", "Alarm", "Trip"]).withDescription("Over power setting"),
e
.numeric("over_power_threshold", ea.STATE_SET)
.withUnit("W")
.withDescription("Setup value on the device")
.withValueMin(1000)
.withValueMax(26000),
e.numeric("test1", ea.STATE), // ?
e.numeric("test5", ea.STATE), // ?
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[6, null, tuya.valueConverter.phaseVariant2],
[13, "test1", tuya.valueConverter.raw], // ?
[15, "leakage_current", tuya.valueConverter.raw],
[16, "state", tuya.valueConverter.onOff],
[32, "ac_frequency", tuya.valueConverter.divideBy100],
[50, "power_factor", tuya.valueConverter.raw],
[
102,
"over_voltage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
103,
"under_voltage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
104,
"over_current_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
105,
"over_power_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
107,
"temperature_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
108,
"leakage_setting",
tuya.valueConverterBasic.lookup({
Ignore: tuya.enum(0),
Alarm: tuya.enum(1),
Trip: tuya.enum(2),
}),
],
[
110,
"event",
tuya.valueConverterBasic.lookup({
normal: 0,
over_current_trip: 1,
over_power_trip: 2,
high_temp_trip: 3,
over_voltage_trip: 4,
under_voltage_trip: 5,
over_current_alarm: 6,
over_power_alarm: 7,
high_temp_alarm: 8,
over_voltage_alarm: 9,
under_voltage_alarm: 10,
remote_on: 11,
remote_off: 12,
manual_on: 13,
manual_off: 14,
leakage_trip: 15,
leakage_alarm: 16,
restore_default: 17,
automatic_closing: 18,
electricity_shortage: 19,
electricity_shortage_alarm: 20,
timing_switch_on: 21,
timing_switch_off: 22,
}),
],
[114, "over_current_threshold", tuya.valueConverter.raw],
[115, "over_voltage_threshold", tuya.valueConverter.raw],
[116, "under_voltage_threshold", tuya.valueConverter.raw],
[118, "temperature_threshold", tuya.valueConverter.divideBy10],
[119, "over_power_threshold", tuya.valueConverter.raw],
[125, "test5", tuya.valueConverter.raw], // ?
[131, "temperature", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_l6llgoxq"]),
model: "EA4161C-BI",
vendor: "Tuya",
description: "Single-phase multifunction energy meter (DIN Module)",
fromZigbee: [tuya.fz.datapoints, tuya.fz.gateway_connection_status],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [e.current(), e.power(), e.voltage(), e.energy(), e.text("meter_id", ea.STATE).withDescription("Meter ID (ID of device)")],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[3, null, null], // Monthly, but sends data only after request
[4, null, null], // Dayly, but sends data only after request
[6, null, tuya.valueConverter.phaseVariant2], // voltage and current
[
10,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
over_current_threshold: 1,
over_power_threshold: 2,
over_voltage_threshold: 4,
wrong_frequency_threshold: 8,
}),
],
[11, null, null], // Frozen - strange function, in native app - nothing is clear
[16, "state", tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold], // It's settable, but can't write converter
[18, "meter_id", tuya.valueConverter.raw],
[20, "clear_fault", tuya.valueConverter.onOff], // Clear fault
[21, null, null], // Forward Energy T1 - don't know what this
[22, null, null], // Forward Energy T2 - don't know what this
[23, null, null], // Forward Energy T3 - don't know what this
[24, null, null], // Forward Energy T4 - don't know what this
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZ3000_kkerjand"]),
model: "SZT06 V2.0",
vendor: "Tuya",
description: "Smart mini temperature and humidity sensor",
extend: [m.temperature(), m.humidity(), m.identify({ isSleepy: true }), m.battery({ voltage: true })],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_pl31aqf5"]),
model: "ZR360CDB",
vendor: "Zorro Alert",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
description: "Multifunctional CO2 detector",
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.humidity(),
e.temperature(),
e.co2(),
e.enum("alarm_ringtone", ea.STATE_SET, ["melody_1", "melody_2", "OFF"]).withDescription("Ringtone of the alarm"),
e.numeric("backlight_mode", ea.STATE_SET).withValueMin(1).withValueMax(3).withValueStep(1).withDescription("Backlight"),
tuya.exposes.batteryState(),
e.enum("air_quality", ea.STATE_GET, ["excellent", "moderate", "poor"]),
],
meta: {
tuyaDatapoints: [
[
1,
"air_quality",
tuya.valueConverterBasic.lookup({
excellent: tuya.enum(0),
moderate: tuya.enum(1),
poor: tuya.enum(2),
}),
],
[2, "co2", tuya.valueConverter.raw],
[
5,
"alarm_ringtone",
tuya.valueConverterBasic.lookup({
melody_1: tuya.enum(0),
melody_2: tuya.enum(1),
OFF: tuya.enum(2),
}),
],
[14, "battery_state", tuya.valueConverter.batteryState],
[17, "backlight_mode", tuya.valueConverter.raw],
[18, "temperature", tuya.valueConverter.raw],
[19, "humidity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_guijtl8k", "_TZ3210_hquixjeg"]),
model: "QS-Zigbee-D04",
vendor: "LEDRON",
description: "0-10v dimmer",
fromZigbee: [fz.TS110E, fz.on_off],
toZigbee: [tz.TS110E_onoff_brightness, tz.TS110E_options, tz.light_brightness_move],
whiteLabel: [tuya.whitelabel("Ledron", "QS-Zigbee-D06-DC", "Dimmer 12-36v", ["_TZ3210_hquixjeg"])],
exposes: [e.light_brightness().withMinBrightness().withMaxBrightness()],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl"]);
await reporting.onOff(endpoint);
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_edl8pz1k", "_TZE204_edl8pz1k"]),
model: "TS0601_floor_thermostat",
vendor: "Tuya",
description: "Zigbee thermostat for electric floors",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime, // Add this if you are getting no converter for 'commandMcuSyncTime'
configure: tuya.configureMagicPacket,
exposes: [
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "auto"])
.withRunningState(["idle", "heat"], ea.STATE)
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withDescription("Floor temperature")
.withLocalTemperatureCalibration(-9, 9, 0.1, ea.STATE_SET)
.withDescription("Calibration floor temperature sensor"),
e.deadzone_temperature().withValueMin(0).withValueMax(5).withValueStep(1).withDescription("Floor temperature"),
e.child_lock(),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[2, "preset", tuya.valueConverter.tv02Preset()],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[24, "device_temperature", tuya.valueConverter.divideBy10],
[27, "local_temperature_calibration", tuya.valueConverter.localTempCalibration2],
[
36,
"running_state",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(0),
idle: tuya.enum(1),
}),
],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[102, "local_temperature", tuya.valueConverter.divideBy10],
[103, "deadzone_temperature", tuya.valueConverter.raw],
[110, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[109, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[108, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[107, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[106, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[105, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP],
[101, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP],
],
},
whiteLabel: [{ vendor: "ELECTSMART", model: "EST-120Z" }],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_khah2lkr"]),
model: "TE-1Z",
vendor: "Tuya",
description: "Floor heating thermostat",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
// e.binary('system_mode', ea.STATE_SET, 'ON', 'OFF')
// .withDescription('Turn system on or standby mode'),
e
.binary("state", ea.STATE_SET, "ON", "OFF")
.withDescription("Turn system on or standby mode"),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
// you can change preset, but can't make auto back remotely so I would set this readonly
.withPreset(["auto", "manual", "mixed"])
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
.withLocalTemperature(ea.STATE),
e.child_lock(),
// you can change it to IN remotely but can not set it back, so I set it read only
e
.enum("sensor_mode", ea.STATE, ["IN", "OU", "AL"])
.withDescription("IN - internal sensor, no heat protection. OU - external sensor, no heat protection. AL - internal sensor for room temperature, external for heat protection"),
e
.binary("high_temperature_protection_state", ea.STATE_SET, "ON", "OFF")
.withDescription("If temperature hit the HIGH temperature limit, it " +
"will turn off heating until it drops for amount of deadzone/hysteresis " +
"degrees"),
e.binary("low_temperature_protection_state", ea.STATE_SET, "ON", "OFF"),
e
.numeric("high_temperature_protection_setting", ea.STATE_SET)
.withUnit("°C")
.withValueMin(20)
.withValueMax(70)
.withDescription("Alarm temperature max")
.withPreset("default", 45, "Default value"),
e
.numeric("low_temperature_protection_setting", ea.STATE_SET)
.withUnit("°C")
.withValueMin(1)
.withValueMax(10)
.withDescription("Alarm temperature min")
.withPreset("default", 5, "Default value"),
e.numeric("temperature_sensor", ea.STATE).withUnit("°C").withDescription("Floor temperature from external sensor"),
e
.deadzone_temperature()
.withValueMin(1)
.withValueMax(9)
.withValueStep(1)
.withUnit("°C")
.withDescription("Hysteresis")
.withPreset("default", 1, "Default value"),
e.max_temperature().withValueMin(20).withValueMax(70).withPreset("default", 35, "Default value"),
// @todo not tested
tuya.exposes.errorStatus(),
],
meta: {
tuyaDatapoints: [
// internal sensor temperature
[16, "local_temperature", tuya.valueConverter.divideBy10],
[50, "current_heating_setpoint", tuya.valueConverter.divideBy10],
// data type 1
[102, "running_state", tuya.valueConverterBasic.lookup({ idle: false, heat: true })],
[103, "temperature_sensor", tuya.valueConverter.divideBy10],
// can be changed by setting 112 below 20, data type 1
[106, "high_temperature_protection_state", tuya.valueConverter.onOff],
// can be changed by setting 113 over 10, data type 1
[107, "low_temperature_protection_state", tuya.valueConverter.onOff],
// range -9 to +9, data type 2, affects shown room temperature (even tho sensors detect its 19, you can make it show 21 by setting this to 2)
[109, "local_temperature_calibration", tuya.valueConverter.localTempCalibration3],
// according to manual settable between 0.5 and 2.5 degree.
// staring with 5 as 0.5 degree, and 25 as 2.5 degree (data type 2)
[110, "temperature_return_difference", tuya.valueConverter.raw],
// range 1-9. How far should temperature drop to turn back heating, if high temp protection kicked in
[111, "deadzone_temperature", tuya.valueConverter.raw],
// High temperature protection
// range 20-70, trying to turn below 20 keeps this datapoint at 20 but turns 106 to 0
[112, "high_temperature_protection_setting", tuya.valueConverter.raw],
// range 1-10, trying to turn over 10 keeps this datapoint at 10, but turns 107 to 0
[113, "low_temperature_protection_setting", tuya.valueConverter.raw],
[114, "max_temperature", tuya.valueConverter.raw],
// choose_sensor
// 0: device sensor. Switches "higsyht_temperature_protection_state" off
// 1: external sensor / high temperature protection off
// 2: internal for room + external for high temperature protection. Switches "hight_temperature_protection_state" on
[116, "sensor_mode", tuya.valueConverterBasic.lookup({ IN: 0, OU: 1, AL: 2 })],
// once every 24h it provides an array of numbers, maybe device fingerprint or something
// [119, 'unknown_119', tuya.valueConverter.raw],
// [120, 'unknown_120', tuya.valueConverter.raw],
// [121, 'unknown_121', tuya.valueConverter.raw],
// [122, 'unknown_122', tuya.valueConverter.raw],
// device state
// 0: standby mode - displays temperature but will not turn heating. Manual configuration is accessible only in this state
// 1: fully functional, can turn on heating
[125, "system_mode", tuya.valueConverter.onOff],
[125, "state", tuya.valueConverter.onOff],
// manual_mode
// 1: automatically turns heating when protection levels hit
// 2: you can turn off heating if it heats. You can set up target temperature
// 3: you can set up target temperature and it will automatically try to maintain it
[128, "preset", tuya.valueConverterBasic.lookup({ auto: 1, manual: 0, mixed: 3 })],
[129, "child_lock", tuya.valueConverter.lockUnlock],
// data type 5. Was [0] but went [16] when high temperature protection went into alert mode
[130, "error_status", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_tagezcph"]),
model: "PRO-900Z",
vendor: "ElectSmart",
description: "Thermostat for electric floor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.binary("child_lock", ea.STATE_SET, "ON", "OFF").withLabel("Child lock"),
e.binary("eco_mode", ea.STATE_SET, "OFF", "ON").withLabel("ECO mode").withDescription("Default: Off"),
e
.numeric("eco_temperature", ea.STATE_SET)
.withValueMin(5)
.withValueMax(30)
.withValueStep(1)
.withUnit("°C")
.withDescription("Max temperature in ECO mode. Default: 20"),
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "auto"])
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
.withDescription("Default: -3")
.withRunningState(["idle", "heat"], ea.STATE),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withValueMin(1)
.withValueMax(5)
.withValueStep(1)
.withUnit("°C")
.withDescription("Hysteresis. Default: 1"),
e.numeric("min_temperature", ea.STATE_SET).withValueMin(5).withValueMax(15).withValueStep(1).withUnit("°C").withDescription("Default: 5"),
e
.numeric("max_temperature", ea.STATE_SET)
.withValueMin(15)
.withValueMax(45)
.withValueStep(1)
.withUnit("°C")
.withDescription("Default: 35"),
e
.numeric("min_temperature_limit", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withUnit("°C")
.withLabel("Low temperature protection")
.withDescription("Default: 0"),
e
.numeric("max_temperature_limit", ea.STATE_SET)
.withValueMin(25)
.withValueMax(70)
.withValueStep(1)
.withUnit("°C")
.withLabel("High temperature protection")
.withDescription("Default: 45"),
e.temperature_sensor_select(["IN", "OU", "AL"]).withLabel("Sensor").withDescription("Choose which sensor to use. Default: AL"),
e
.numeric("external_temperature_input", ea.STATE)
.withLabel("Floor temperature")
.withUnit("°C")
.withDescription("Temperature from floor sensor"),
e
.numeric("brightness", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(1)
.withLabel("Screen brightness 06:00 - 22:00")
.withDescription("0 - on for 10 seconds. Default: 6"),
e
.numeric("display_brightness", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(1)
.withLabel("Screen brightness 22:00 - 06:00")
.withDescription("0 - on for 10 seconds. Default: 3"),
e
.text("schedule_monday", ea.STATE_SET)
.withLabel("Schedule for monday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_tuesday", ea.STATE_SET)
.withLabel("Schedule for tuesday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_wednesday", ea.STATE_SET)
.withLabel("Schedule for wednesday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_thursday", ea.STATE_SET)
.withLabel("Schedule for thursday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_friday", ea.STATE_SET)
.withLabel("Schedule for friday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_saturday", ea.STATE_SET)
.withLabel("Schedule for saturday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e
.text("schedule_sunday", ea.STATE_SET)
.withLabel("Schedule for sunday")
.withDescription("Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0"),
e.enum("factory_reset", ea.STATE_SET, ["factory reset"]).withLabel("Factory reset").withDescription("Reset all settings to factory ones"),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ off: false, heat: true })],
[
2,
"preset",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
manual: tuya.enum(1),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[19, "max_temperature", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[26, "min_temperature", tuya.valueConverter.divideBy10],
[27, "local_temperature_calibration", tuya.valueConverter.raw],
[28, "factory_reset", tuya.valueConverterBasic.lookup({ factory_reset: true })],
[
36,
"running_state",
tuya.valueConverterBasic.lookup({
idle: tuya.enum(1),
heat: tuya.enum(0),
}),
],
[39, "child_lock", tuya.valueConverterBasic.lookup({ ON: true, OFF: false })],
[40, "eco_mode", tuya.valueConverterBasic.lookup({ ON: true, OFF: false })],
[
43,
"sensor",
tuya.valueConverterBasic.lookup({
IN: tuya.enum(0),
OU: tuya.enum(2),
AL: tuya.enum(1),
}),
],
[102, "external_temperature_input", tuya.valueConverter.divideBy10],
[103, "deadzone_temperature", tuya.valueConverter.raw],
[104, "max_temperature_limit", tuya.valueConverter.divideBy10],
[101, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[105, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[106, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[107, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[108, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[109, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[110, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[111, "min_temperature_limit", tuya.valueConverter.divideBy10],
[112, "eco_temperature", tuya.valueConverter.divideBy10],
[113, "brightness", tuya.valueConverter.raw],
[114, "display_brightness", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_dsagrkvg"]),
model: "ZPV-01",
vendor: "Novato",
description: "Battery powered smart valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.switch().setAccess("state", ea.STATE_SET),
e.enum("valve_state", ea.STATE, ["close", "unknown", "open"]).withDescription("State of the valve"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
8,
"valve_state",
tuya.valueConverterBasic.lookup({
unknown: tuya.enum(0),
open: tuya.enum(1),
closed: tuya.enum(2),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3218_7fiyo3kv"]),
model: "TYZGTH1CH-D1RF",
vendor: "Mumubiz",
description: "Smart switch with temperature/humidity sensor",
meta: {
tuyaSendCommand: "sendData",
},
extend: [
tuya.modernExtend.tuyaMagicPacket(),
tuya.modernExtend.tuyaOnOff({
powerOutageMemory: true,
switchType: false,
}),
tuya.modernExtend.dpChildLock({ dp: 0x6f }),
tuya.modernExtend.dpTemperature({ dp: 0x66 }),
tuya.modernExtend.dpHumidity({ dp: 0x67 }),
tuya.modernExtend.dpNumeric({
dp: 0x6c,
name: "temperature_calibration",
type: tuya.dataTypes.number,
valueMin: -10,
valueMax: 10,
valueStep: 0.1,
unit: "°C",
scale: 10,
description: "Temperature calibration",
}),
tuya.modernExtend.dpNumeric({
dp: 0x6d,
name: "humidity_calibration",
type: tuya.dataTypes.number,
valueMin: -10,
valueMax: 10,
unit: "%",
description: "Humidity calibration",
}),
tuya.modernExtend.dpNumeric({
dp: 0x71,
name: "temperature_sensitivity",
type: tuya.dataTypes.number,
valueMin: 0.1,
valueMax: 1,
valueStep: 0.1,
unit: "°C",
scale: 10,
description: "Temperature sensitivity",
}),
tuya.modernExtend.dpNumeric({
dp: 0x70,
name: "humidity_sensitivity",
type: tuya.dataTypes.number,
valueMin: 1,
valueMax: 10,
unit: "%",
description: "Humidity sensitivity",
}),
tuya.modernExtend.dpBinary({
name: "manual_mode",
dp: 0x65,
type: tuya.dataTypes.enum,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Manual mode, ON = auto settings disabled, OFF = auto settings enabled",
}),
tuya.modernExtend.dpTHZBSettings(),
],
},
{
fingerprint: tuya.fingerprint("TS000F", ["_TZ3218_ya5d6wth"]),
model: "TYZGTH4CH-D1RF",
vendor: "Mumubiz",
description: "4 channel changeover contact with temperature and humidity sensing",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
onOffCountdown: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
tuya.modernExtend.dpTemperature({ dp: 102, scale: 10 }),
tuya.modernExtend.dpHumidity({ dp: 103 }),
],
endpoint: (device) => {
return { l1: 1, l2: 2, l3: 3, l4: 4 };
},
exposes: [],
meta: { multiEndpoint: true },
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_uxllnywp"]),
model: "RT_ZCZ03Z",
vendor: "Tuya",
description: "Human presence sensor 24G",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.illuminance(),
e.presence(),
e
.numeric("detection_distance_max", ea.STATE_SET)
.withValueMin(0)
.withValueMax(840)
.withValueStep(1)
.withDescription("Max detection distance")
.withUnit("cm"),
e
.numeric("detection_distance_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(840)
.withValueStep(1)
.withDescription("Min detection distance")
.withUnit("cm"),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("cm"),
e.numeric("fading_time", ea.STATE_SET).withValueMin(1).withValueMax(59).withValueStep(1).withDescription("Delay time").withUnit("s"),
e.numeric("presence_sensitivity", ea.STATE_SET).withValueMin(1).withValueMax(10).withValueStep(1).withDescription("Presence sensitivity"),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED Indicator"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverterBasic.trueFalse(4)],
[101, "target_distance", tuya.valueConverter.raw],
[102, "illuminance", tuya.valueConverter.raw],
[103, "fading_time", tuya.valueConverter.raw],
[104, "indicator", tuya.valueConverter.onOff],
[107, "detection_distance_max", tuya.valueConverter.raw],
[108, "detection_distance_min", tuya.valueConverter.raw],
[111, "presence_sensitivity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_q22avxbv", "_TZE204_mrffaamu", "_TZE204_tzreobvu", "_TZE284_mrffaamu"]),
model: "TOQCB2-80",
vendor: "Tongou",
description: "Smart circuit breaker",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
// Important: respondToMcuVersionResponse should be false otherwise there is an avalanche of commandMcuVersionResponse messages every second.
// queryIntervalSeconds: is doing a pooling to update the device's parameters, now defined to update data every 3 minutes.
onEvent: tuya.onEvent({
respondToMcuVersionResponse: false,
queryIntervalSeconds: 3 * 60,
}),
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
e.energy(),
e.power(),
e.voltage(),
e.current(),
e.temperature(),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e
.enum("last_event", ea.STATE, [
"normal",
"trip_over_current",
"trip_over_power",
"trip_over_temperature",
"trip_voltage_1",
"trip_voltage_2",
"alarm_over_current",
"alarm_over_power",
"alarm_over_temperature",
"alarm_voltage_1",
"alarm_voltage_2",
"remote_on",
"remote_off",
"manual_on",
"manual_off",
"value_15",
"value_16",
"factory_reset",
])
.withDescription("Last event"),
e.enum("over_current_setting", ea.STATE_SET, ["closed", "alarm", "trip"]).withDescription("Action if threshold value is reached"),
e
.numeric("current_threshold", ea.STATE_SET)
.withValueMin(1)
.withValueMax(63)
.withValueStep(1)
.withUnit("A")
.withDescription("Current threshold setting"),
e.enum("under_voltage_setting", ea.STATE_SET, ["closed", "alarm", "trip"]).withDescription("Action if threshold value is reached"),
e
.numeric("under_voltage_threshold", ea.STATE_SET)
.withValueMin(145)
.withValueMax(220)
.withValueStep(1)
.withUnit("V")
.withDescription("Under voltage threshold setting"),
e.enum("over_voltage_setting", ea.STATE_SET, ["closed", "alarm", "trip"]).withDescription("Action if threshold value is reached"),
e
.numeric("over_voltage_threshold", ea.STATE_SET)
.withValueMin(245)
.withValueMax(295)
.withValueStep(1)
.withUnit("V")
.withDescription("Over-voltage threshold setting"),
e.enum("over_power_setting", ea.STATE_SET, ["closed", "alarm", "trip"]).withDescription("Action if threshold value is reached"),
e
.numeric("over_power_threshold", ea.STATE_SET)
.withValueMin(200)
.withValueMax(20000)
.withValueStep(100)
.withUnit("W")
.withDescription("Over-power threshold setting"),
e.enum("temperature_setting", ea.STATE_SET, ["closed", "alarm", "trip"]).withDescription("Action if threshold value is reached"),
e
.numeric("temperature_threshold", ea.STATE_SET)
.withValueMin(-40)
.withValueMax(100)
.withValueStep(1)
.withUnit("°C")
.withDescription("Temperature threshold setting"),
e.binary("clear_fault", ea.STATE_SET, "ON", "OFF").withDescription("Recover from an incident"),
e.binary("factory_reset", ea.STATE_SET, "ON", "OFF").withDescription("Back to factory settings, USE WITH CAUTION"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
//[6, null, tuya.valueConverter.phaseVariant2],
[3, null, null], // Monthly, but sends data only after request
[4, null, null], // Dayly, but sends data only after request
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")],
[7, null, tuya.valueConverter.phaseVariant2WithPhase("b")],
[8, null, tuya.valueConverter.phaseVariant2WithPhase("c")],
[16, "state", tuya.valueConverter.onOff],
[
102,
"over_voltage_setting",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
alarm: tuya.enum(1),
trip: tuya.enum(2),
}),
],
[
103,
"under_voltage_setting",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
alarm: tuya.enum(1),
trip: tuya.enum(2),
}),
],
[
104,
"over_current_setting",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
alarm: tuya.enum(1),
trip: tuya.enum(2),
}),
],
[
105,
"over_power_setting",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
alarm: tuya.enum(1),
trip: tuya.enum(2),
}),
],
[
107,
"temperature_setting",
tuya.valueConverterBasic.lookup({
closed: tuya.enum(0),
alarm: tuya.enum(1),
trip: tuya.enum(2),
}),
],
//109, 'online_state, unknown, I have not seen any message from this DP],
[
110,
"last_event",
tuya.valueConverterBasic.lookup({
normal: tuya.enum(0),
trip_over_current: tuya.enum(1),
trip_over_power: tuya.enum(2),
trip_over_temperature: tuya.enum(3),
trip_voltage_1: tuya.enum(4),
trip_voltage_2: tuya.enum(5),
alarm_over_current: tuya.enum(6),
alarm_over_power: tuya.enum(7),
alarm_over_temperature: tuya.enum(8),
alarm_voltage_1: tuya.enum(9),
alarm_voltage_2: tuya.enum(10),
remote_on: tuya.enum(11),
remote_off: tuya.enum(12),
manual_on: tuya.enum(13),
manual_off: tuya.enum(14),
value_15: tuya.enum(15),
value_16: tuya.enum(16),
factory_reset: tuya.enum(17),
}),
],
[112, "clear_fault", tuya.valueConverter.onOff],
[113, "factory_reset", tuya.valueConverter.onOff],
[114, "current_threshold", tuya.valueConverter.raw],
[115, "over_voltage_threshold", tuya.valueConverter.raw],
[116, "under_voltage_threshold", tuya.valueConverter.raw],
[118, "temperature_threshold", tuya.valueConverter.divideBy10],
[119, "over_power_threshold", tuya.valueConverter.raw],
//[125, 'forward_electricity', tuya.valueConverter.divideBy100],
[131, "temperature", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_nbkshs6k"]),
model: "ZY-M100-S_3",
vendor: "Tuya",
description: "Human presence detector",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.presence(),
e.illuminance(),
e
.enum("sensitivity", ea.STATE_SET, ["low", "medium", "high"])
.withDescription("PIR sensor sensitivity (refresh and update only while active)"),
e.enum("keep_time", ea.STATE_SET, ["30", "60", "120"]).withDescription("PIR keep time in seconds (refresh and update only while active)"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverterBasic.lookup({ True: 0, False: 1 })],
[
9,
"sensitivity",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
}),
],
[
10,
"keep_time",
tuya.valueConverterBasic.lookup({
"30": tuya.enum(0),
"60": tuya.enum(1),
"120": tuya.enum(2),
}),
],
[12, "illuminance", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_dapwryy7"]),
model: "ZG-205Z",
vendor: "Tuya",
description: "5.8 GHz human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
exposes: [
e.presence(),
e
.enum("presence_state", ea.STATE, ["none", "presence", "peaceful", "small_movement", "large_movement"])
.withDescription("The presence state"),
e
.numeric("target_distance", ea.STATE)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Target distance"),
e.illuminance(),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED Indicator"),
e
.numeric("none_delay_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(28800)
.withValueStep(1)
.withUnit("Sec")
.withDescription("Hold delay time"),
e
.numeric("move_detection_max", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Move detection max distance"),
e
.numeric("move_detection_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Move detection min distance"),
e
.numeric("small_move_detection_max", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Small move detection max distance"),
e
.numeric("small_move_detection_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Small move detection min distance"),
e
.numeric("breath_detection_max", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Breath detection max distance"),
e
.numeric("breath_detection_min", ea.STATE_SET)
.withValueMin(0)
.withValueMax(6)
.withValueStep(0.01)
.withUnit("m")
.withDescription("Breath detection min distance"),
e.numeric("move_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Move sensitivity"),
e.numeric("breath_sensitivity", ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1).withDescription("Breath sensitivity"),
e
.numeric("small_move_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("Small Move sensitivity"),
],
meta: {
tuyaDatapoints: [
[
1,
null,
{
from: (v) => {
const lookup = {
none: tuya.enum(0),
presence: tuya.enum(1),
peaceful: tuya.enum(2),
small_movement: tuya.enum(3),
large_movement: tuya.enum(4),
};
const presenceState = Object.entries(lookup).find((i) => i[1].valueOf() === v)[0];
return {
presence: presenceState !== "none",
presence_state: presenceState,
};
},
},
],
[101, "target_distance", tuya.valueConverter.divideBy100],
[102, "illuminance", tuya.valueConverter.raw],
[103, "none_delay_time", tuya.valueConverter.raw],
[104, "indicator", tuya.valueConverter.onOff],
[107, "move_detection_max", tuya.valueConverter.divideBy100],
[108, "move_detection_min", tuya.valueConverter.divideBy100],
[109, "breath_detection_max", tuya.valueConverter.divideBy100],
[110, "breath_detection_min", tuya.valueConverter.divideBy100],
[114, "small_move_detection_max", tuya.valueConverter.divideBy100],
[115, "small_move_detection_min", tuya.valueConverter.divideBy100],
[116, "move_sensitivity", tuya.valueConverter.raw],
[117, "small_move_sensitivity", tuya.valueConverter.raw],
[118, "breath_sensitivity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ncti2pro", "_TZE204_l8xiyymq"]),
model: "PN6",
vendor: "ZSVIOT",
description: "6-way controller",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
tuya.exposes.switch(),
tuya.exposes.switchMode2().withEndpoint("l1_l2").withLabel("1-2 channels"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switchMode2().withEndpoint("l3_l4").withLabel("3-4 channels"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switchMode2().withEndpoint("l5_l6").withLabel("5-6 channels"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
tuya.exposes.switchType(),
e.power_on_behavior(["off", "on"]).withAccess(ea.STATE_SET),
],
endpoint: (device) => {
return {
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
state: 1,
l1_l2: 1,
l3_l4: 1,
l5_l6: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
[4, "state_l4", tuya.valueConverter.onOff],
[5, "state_l5", tuya.valueConverter.onOff],
[6, "state_l6", tuya.valueConverter.onOff],
[13, "state", tuya.valueConverter.onOff],
[14, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[107, "switch_type", tuya.valueConverter.switchType],
[113, "switch_mode_l1_l2", tuya.valueConverter.switchMode2],
[114, "switch_mode_l3_l4", tuya.valueConverter.switchMode2],
[115, "switch_mode_l5_l6", tuya.valueConverter.switchMode2],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_zqq3cipq"]),
model: "PN16",
vendor: "ZSVIOT",
description: "16-way controller",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.power_on_behavior(["off", "on", "previous"]).withAccess(ea.STATE_SET),
tuya.exposes.switch().withEndpoint("all"),
tuya.exposes.switchType().withEndpoint("l1_l8").withLabel("Switch type 1-8 channels"),
tuya.exposes.switch().withEndpoint("l1"),
tuya.exposes.switch().withEndpoint("l2"),
tuya.exposes.switch().withEndpoint("l3"),
tuya.exposes.switch().withEndpoint("l4"),
tuya.exposes.switch().withEndpoint("l5"),
tuya.exposes.switch().withEndpoint("l6"),
tuya.exposes.switch().withEndpoint("l7"),
tuya.exposes.switch().withEndpoint("l8"),
tuya.exposes.switchType().withEndpoint("l9_l16").withLabel("Switch type 9-16 channels"),
tuya.exposes.switch().withEndpoint("l9"),
tuya.exposes.switch().withEndpoint("l10"),
tuya.exposes.switchMode2().withEndpoint("l11_l12").withLabel("Mode 11-12 channels"),
tuya.exposes.switch().withEndpoint("l11"),
tuya.exposes.switch().withEndpoint("l12"),
tuya.exposes.switchMode2().withEndpoint("l13_l14").withLabel("Mode 13-14 channels"),
tuya.exposes.switch().withEndpoint("l13"),
tuya.exposes.switch().withEndpoint("l14"),
tuya.exposes.switchMode2().withEndpoint("l15_l16").withLabel("Mode 15-16 channels"),
tuya.exposes.switch().withEndpoint("l15"),
tuya.exposes.switch().withEndpoint("l16"),
],
endpoint: (device) => {
return {
all: 1,
l1: 1,
l2: 1,
l3: 1,
l4: 1,
l5: 1,
l6: 1,
l7: 1,
l8: 1,
l9: 1,
l10: 1,
l11: 1,
l12: 1,
l13: 1,
l14: 1,
l15: 1,
l16: 1,
l1_l8: 1,
l9_l16: 1,
l11_l12: 1,
l13_l14: 1,
l15_l16: 1,
};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, "state_all", tuya.valueConverter.onOff],
[101, "state_l1", tuya.valueConverter.onOff],
[102, "state_l2", tuya.valueConverter.onOff],
[103, "state_l3", tuya.valueConverter.onOff],
[104, "state_l4", tuya.valueConverter.onOff],
[105, "state_l5", tuya.valueConverter.onOff],
[106, "state_l6", tuya.valueConverter.onOff],
[107, "state_l7", tuya.valueConverter.onOff],
[108, "state_l8", tuya.valueConverter.onOff],
[109, "state_l9", tuya.valueConverter.onOff],
[110, "state_l10", tuya.valueConverter.onOff],
[111, "state_l11", tuya.valueConverter.onOff],
[112, "state_l12", tuya.valueConverter.onOff],
[113, "state_l13", tuya.valueConverter.onOff],
[114, "state_l14", tuya.valueConverter.onOff],
[115, "state_l15", tuya.valueConverter.onOff],
[116, "state_l16", tuya.valueConverter.onOff],
[117, "power_on_behavior", tuya.valueConverter.powerOnBehaviorEnum],
[118, "switch_type_l1_l8", tuya.valueConverter.switchType],
[119, "switch_type_l9_l16", tuya.valueConverter.switchType],
[120, "switch_mode_l11_l12", tuya.valueConverter.switchMode2],
[121, "switch_mode_l13_l14", tuya.valueConverter.switchMode2],
[122, "switch_mode_l15_l16", tuya.valueConverter.switchMode2],
],
},
},
{
zigbeeModel: ["TS0105"],
model: "TS0105",
vendor: "Tuya",
description: "3 gang switch",
extend: [tuyaBase({ dp: true }), m.deviceEndpoints({ endpoints: { l1: 1, l2: 1, l3: 1 } })],
exposes: [
e.switch().withEndpoint("l1").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l2").setAccess("state", ea.STATE_SET),
e.switch().withEndpoint("l3").setAccess("state", ea.STATE_SET),
],
meta: {
tuyaDatapoints: [
[1, "state_l1", tuya.valueConverter.onOff],
[2, "state_l2", tuya.valueConverter.onOff],
[3, "state_l3", tuya.valueConverter.onOff],
],
},
},
{
zigbeeModel: ["ZG-103Z"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_iba1ckek", "_TZE200_hggxgsjj", "_TZE200_yjryxpot"]),
model: "ZG-103Z",
vendor: "Tuya",
description: "Vibration sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.vibration(),
e.tilt(),
e.numeric("x", ea.STATE).withValueMin(0).withValueMax(256).withValueStep(1).withDescription("X coordinate"),
e.numeric("y", ea.STATE).withValueMin(0).withValueMax(256).withValueStep(1).withDescription("Y coordinate"),
e.numeric("z", ea.STATE).withValueMin(0).withValueMax(256).withValueStep(1).withDescription("Z coordinate"),
e.battery(),
e.enum("sensitivity", ea.STATE_SET, ["low", "middle", "high"]).withDescription("Vibration detection sensitivity"),
],
meta: {
tuyaDatapoints: [
[1, "vibration", tuya.valueConverter.trueFalseEnum1],
[7, "tilt", tuya.valueConverter.trueFalseEnum1],
[101, "x", tuya.valueConverter.raw],
[102, "y", tuya.valueConverter.raw],
[103, "z", tuya.valueConverter.raw],
[
104,
"sensitivity",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
middle: tuya.enum(1),
high: tuya.enum(2),
}),
],
[105, "battery", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-302ZM"],
fingerprint: tuya.fingerprint("TS0601", [
"_TZE200_kccdzaeo",
"_TZE200_s7rsrtbg",
"_TZE200_tmszbtzq",
"_TZE200_bfmfhxra",
"_TZE200_ahpcyzth",
"_TZE200_kijxnb8q",
]),
model: "ZG-302ZM",
vendor: "HOBEIAN",
description: "Motion sensing switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.binary("switch1", ea.STATE_SET, "ON", "OFF").withDescription("Switch1"),
e.binary("switch2", ea.STATE_SET, "ON", "OFF").withDescription("Switch2"),
e.binary("switch3", ea.STATE_SET, "ON", "OFF").withDescription("Switch3"),
e
.numeric("sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(19)
.withValueStep(1)
.withUnit("x")
.withDescription("detection sensitivity"),
e.binary("backlight", ea.STATE_SET, "ON", "OFF").withDescription("backlight"),
e
.numeric("trigger_hold", ea.STATE_SET)
.withValueMin(5)
.withValueMax(28800)
.withValueStep(1)
.withUnit("s")
.withDescription("Trigger hold(second)"),
tuya.exposes.powerOutageMemory(),
e
.enum("auto_on", ea.STATE_SET, ["off", "all", "ch1", "ch2", "ch3", "ch1_2", "ch2_3", "ch1_3"])
.withDescription("Someone turn on the light"),
e
.enum("auto_off", ea.STATE_SET, ["off", "all", "ch1", "ch2", "ch3", "ch1_2", "ch2_3", "ch1_3"])
.withDescription("No one turns off the lights"),
e.enum("trigger_switch", ea.STATE_SET, ["ch1", "ch2", "ch3"]).withDescription("Switch state reversal"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[101, "switch1", tuya.valueConverter.onOff],
[102, "switch2", tuya.valueConverter.onOff],
[103, "switch3", tuya.valueConverter.onOff],
[110, "sensitivity", tuya.valueConverter.raw],
[111, "backlight", tuya.valueConverter.onOff],
[114, "trigger_hold", tuya.valueConverter.raw],
[
112,
"power_outage_memory",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
on: tuya.enum(1),
restore: tuya.enum(2),
}),
],
[
113,
"auto_on",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
all: tuya.enum(1),
ch1: tuya.enum(1),
ch2: tuya.enum(2),
ch3: tuya.enum(3),
ch1_2: tuya.enum(4),
ch2_3: tuya.enum(5),
ch1_3: tuya.enum(6),
}),
],
[
115,
"auto_off",
tuya.valueConverterBasic.lookup({
off: tuya.enum(0),
all: tuya.enum(1),
ch1: tuya.enum(1),
ch2: tuya.enum(2),
ch3: tuya.enum(3),
ch1_2: tuya.enum(4),
ch2_3: tuya.enum(5),
ch1_3: tuya.enum(6),
}),
],
[
108,
"trigger_switch",
tuya.valueConverterBasic.lookup({
ch1: tuya.enum(0),
ch2: tuya.enum(1),
ch3: tuya.enum(2),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wqashyqo"]),
model: "ZG-303Z",
vendor: "HOBEIAN",
description: "Soil moisture sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.enum("water_warning", ea.STATE, ["none", "alarm"]).withDescription("Water shortage warning"),
e.temperature(),
e.humidity(),
e.soil_moisture(),
tuya.exposes.temperatureUnit(),
tuya.exposes.temperatureCalibration(),
tuya.exposes.humidityCalibration(),
tuya.exposes.soilCalibration(),
tuya.exposes.temperatureSampling(),
tuya.exposes.soilSampling(),
tuya.exposes.soilWarning(),
e.battery(),
],
meta: {
tuyaDatapoints: [
[
1,
"water_warning",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
alarm: tuya.enum(1),
}),
],
[103, "temperature", tuya.valueConverter.divideBy10],
[109, "humidity", tuya.valueConverter.raw],
[107, "soil_moisture", tuya.valueConverter.raw],
[108, "battery", tuya.valueConverter.raw],
[106, "temperature_unit", tuya.valueConverter.temperatureUnit],
[104, "temperature_calibration", tuya.valueConverter.divideBy10],
[105, "humidity_calibration", tuya.valueConverter.raw],
[102, "soil_calibration", tuya.valueConverter.raw],
[111, "temperature_sampling", tuya.valueConverter.raw],
[112, "soil_sampling", tuya.valueConverter.raw],
[110, "soil_warning", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_fhvdgeuh", "_TZE200_abatw3kj"]),
model: "TS0601_din_4",
vendor: "Tuya",
description: "Din rail switch with power monitoring and threshold settings",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
// Required to get the device to start reporting
await device.getEndpoint(1).command("manuSpecificTuya", "dataQuery", {});
},
whiteLabel: [tuya.whitelabel("RTX", "TS0601_RTX_DIN", "Din rail switch", ["_TZE200_abatw3kj"])],
exposes: [
e.switch().setAccess("state", ea.STATE_SET),
e.power(),
e.current(),
e.voltage(),
e.energy(),
e.numeric("temperature", ea.STATE).withUnit("°C").withDescription("Current temperature"),
e.numeric("leakage", ea.STATE).withUnit("mA").withDescription("Current leakage"),
],
meta: {
tuyaDatapoints: [
[16, "state", tuya.valueConverter.onOff],
[1, "energy", tuya.valueConverter.divideBy100], // Total forward energy
[6, null, tuya.valueConverter.phaseVariant2], // Phase A voltage and current
// [9, 'fault', tuya.valueConverter.raw], // no expose
// [11, 'switch_prepayment', tuya.valueConverter.raw], // no expose
// [12, 'clear_energy', tuya.valueConverter.raw], // no expose
// [14, 'charge_energy', tuya.valueConverter.raw], // no expose
[15, "leakage", tuya.valueConverter.raw],
// [102, 'reclosing_allowed_times', tuya.valueConverter.raw], // no expose
[103, "temperature", tuya.valueConverter.raw],
// [104, 'reclosing_enable', tuya.valueConverter.raw], // no expose
// [105, 'timer', tuya.valueConverter.raw], // no expose
// [106, 'cycle_schedule', tuya.valueConverter.raw], // no expose
// [107, 'reclose_recover_seconds', tuya.valueConverter.raw], // no expose
// [108, 'random_timing', tuya.valueConverter.raw], // no expose
// [109, 'switch_inching', tuya.valueConverter.raw], // no expose
// [119, 'power_on_delay_power_on_time', tuya.valueConverter.raw], // no expose
// [124, 'overcurrent_event_threshold_time', tuya.valueConverter.raw], // no expose
// [125, 'time_threshold_of_lost_flow_event', tuya.valueConverter.raw], // no expose
// [127, 'status', tuya.valueConverter.raw], // no expose
// [134, 'relay_status_for_power_on', tuya.valueConverter.raw], // no expose
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_hcxvyxa5"]),
model: "ZA03",
vendor: "Tuya",
description: "Siren alarm",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.binary("alarm", ea.STATE_SET, "ON", "OFF").withDescription("Sound the alarm"),
e.enum("volume", ea.STATE_SET, ["low", "medium", "high", "mute"]),
e.enum("ringtone", ea.STATE_SET, [
"ringtone 1",
"ringtone 2",
"ringtone 3",
"ringtone 4",
"ringtone 5",
"ringtone 6",
"ringtone 7",
"ringtone 8",
"ringtone 9",
"ringtone 10",
"ringtone 11",
"ringtone 12",
"ringtone 13",
"ringtone 14",
"ringtone 15",
"ringtone 16",
"ringtone 17",
"ringtone 18",
"ringtone 19",
"ringtone 20",
"ringtone 21",
"ringtone 22",
"ringtone 23",
"ringtone 24",
"ringtone 25",
"ringtone 26",
"ringtone 27",
"ringtone 28",
"ringtone 29",
"ringtone 30",
"ringtone 31",
"ringtone 32",
]),
e
.numeric("duration", ea.STATE_SET)
.withValueMin(1)
.withValueMax(380)
.withValueStep(1)
.withUnit("s")
.withDescription("How long the alarm sounds for when triggered"),
],
meta: {
tuyaDatapoints: [
[
5,
"volume",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
mute: tuya.enum(3),
}),
],
[7, "duration", tuya.valueConverter.raw],
[13, "alarm", tuya.valueConverter.onOff],
[
21,
"ringtone",
tuya.valueConverterBasic.lookup({
"ringtone 1": tuya.enum(0),
"ringtone 2": tuya.enum(1),
"ringtone 3": tuya.enum(2),
"ringtone 4": tuya.enum(3),
"ringtone 5": tuya.enum(4),
"ringtone 6": tuya.enum(5),
"ringtone 7": tuya.enum(6),
"ringtone 8": tuya.enum(7),
"ringtone 9": tuya.enum(8),
"ringtone 10": tuya.enum(9),
"ringtone 11": tuya.enum(10),
"ringtone 12": tuya.enum(11),
"ringtone 13": tuya.enum(12),
"ringtone 14": tuya.enum(13),
"ringtone 15": tuya.enum(14),
"ringtone 16": tuya.enum(15),
"ringtone 17": tuya.enum(16),
"ringtone 18": tuya.enum(17),
"ringtone 19": tuya.enum(18),
"ringtone 20": tuya.enum(19),
"ringtone 21": tuya.enum(20),
"ringtone 22": tuya.enum(21),
"ringtone 23": tuya.enum(22),
"ringtone 24": tuya.enum(23),
"ringtone 25": tuya.enum(24),
"ringtone 26": tuya.enum(25),
"ringtone 27": tuya.enum(26),
"ringtone 28": tuya.enum(27),
"ringtone 29": tuya.enum(28),
"ringtone 30": tuya.enum(29),
"ringtone 31": tuya.enum(30),
"ringtone 32": tuya.enum(31),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_ex3rcdha"]),
model: "ZY_HPS01",
vendor: "Tuya",
description: "mmWave radar 5.8GHz",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
extend: [],
exposes: [
e.illuminance().withUnit("lx"),
e.occupancy(),
e
.numeric("presence_timeout", ea.STATE_SET)
.withValueMin(0)
.withValueMax(180)
.withValueStep(1)
.withDescription("Presence timeout")
.withUnit("s"),
e
.numeric("move_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("sensitivity of the radar")
.withUnit("X"),
e
.numeric("move_minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(600)
.withValueStep(10)
.withDescription("Movement minimum range")
.withUnit("cm"),
e
.numeric("move_maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(600)
.withValueStep(10)
.withDescription("Movement maximum range")
.withUnit("cm"),
e
.numeric("breath_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("Breath sensitivity of the radar")
.withUnit("X"),
e
.numeric("breath_minimum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(600)
.withValueStep(10)
.withDescription("Breath minimum range")
.withUnit("cm"),
e
.numeric("breath_maximum_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(600)
.withValueStep(10)
.withDescription("Breath maximum range")
.withUnit("cm"),
],
meta: {
tuyaDatapoints: [
[12, "illuminance", tuya.valueConverter.raw],
[101, "occupancy", tuya.valueConverter.trueFalse0],
[104, "presence_timeout", tuya.valueConverter.raw],
[105, "move_sensitivity", tuya.valueConverter.raw],
[107, "breath_sensitivity", tuya.valueConverter.raw],
[109, "move_maximum_range", tuya.valueConverter.raw],
[110, "move_minimum_range", tuya.valueConverter.raw],
[111, "breath_maximum_range", tuya.valueConverter.raw],
[112, "breath_minimum_range", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ppuj1vem"]),
model: "ZPIR-10",
vendor: "Tuya",
description: "Treatlife human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [e.occupancy(), e.battery(), e.illuminance()],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse0],
[4, "battery", tuya.valueConverter.raw],
[101, "illuminance", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ha0vwoew"]),
model: "TS0601_thermostat_thermosphere",
vendor: "Tuya",
description: "ThermoSphere thermostat",
extend: [tuyaBase({ dp: true })],
exposes: [
e
.climate()
.withSystemMode(["off", "auto"], ea.STATE_SET, "Whether the thermostat is turned on or off")
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE),
e
.enum("sensor_mode", ea.STATE_SET, ["room_temperature", "floor_temperature", "room_with_floor_limit"])
.withDescription("What type of sensor are you using to measure the temperature of the floor?"),
e
.binary("adaptive_start", ea.STATE_SET, "ON", "OFF")
.withDescription("Preheat the room to the desired temperature before the scheduled start time."),
e.max_temperature_limit().withDescription("Maximum temperature (default: 35 ºC)").withValueMin(5).withValueMax(35).withValueStep(0.5),
e
.min_temperature_limit()
.withDescription("Minimum temperature limit for frost protection. Turns the thermostat on regardless of setpoint if the temperature drops below this.")
.withValueMin(1)
.withValueMax(5),
e
.enum("boost", ea.STATE_SET, ["ON", "OFF"])
.withDescription("Override the schedule and boost at the current temperature until turned off"),
e
.numeric("display_brightness", ea.STATE_SET)
.withDescription("Brightness of the display when in use")
.withValueMin(0)
.withValueMax(100)
.withValueStep(1),
e
.numeric("holiday_start_stop", ea.STATE_SET)
.withDescription("Set the number of days of holiday, this will start immediately.")
.withValueMax(99)
.withValueMin(0),
e.holiday_temperature().withValueMin(5).withValueMax(35),
e.binary("frost_protection", ea.STATE_SET, "ON", "OFF").withDescription("Turning on will keep heating at the minimum temperature limit"),
e
.numeric("switch_delay", ea.STATE_SET)
.withDescription("How long to wait between making a change and it taking effect")
.withValueMin(10)
.withValueMax(90)
.withValueStep(10)
.withUnit("s"),
e
.numeric("power_rating", ea.STATE_SET)
.withDescription("How much power is the underfloor heating rated to. Entering a value will allow the Thermostat to record a value of power usage that can be checked under settings on the physical Thermostat")
.withUnit("W")
.withValueMin(0)
.withValueMax(4500)
.withValueStep(100),
e
.binary("open_window_active", ea.STATE_SET, "ON", "OFF")
.withDescription("When active the heating will cut off if an Open Window is detected"),
e
.numeric("open_window_sensing_time", ea.STATE_SET)
.withDescription("The duration that the drop in temperature needs to occur over")
.withUnit("minutes")
.withValueMin(1)
.withValueMax(30)
.withValueStep(1),
e
.numeric("open_window_drop_limit", ea.STATE_SET)
.withDescription("The drop in ambient room temperature that will trigger an open window warning")
.withUnit("C")
.withValueMin(2)
.withValueMax(4)
.withValueStep(1),
e
.numeric("open_window_off_time", ea.STATE_SET)
.withDescription("The length of time the drop in temperature must be consistent for to turn the heating off")
.withUnit("minutes")
.withValueMin(10)
.withValueMax(60)
.withValueStep(5),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ off: false, auto: true })],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[
4,
"boost",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(1),
ON: tuya.enum(2),
}),
],
[18, "open_window_active", tuya.valueConverterBasic.lookup({ OFF: false, ON: true })],
[40, "open_window_sensing_time", tuya.valueConverterBasic.divideBy(1)],
[45, "open_window_drop_limit", tuya.valueConverter.divideBy10],
[47, "open_window_off_time", tuya.valueConverterBasic.divideBy(1)],
[37, "adaptive_start", tuya.valueConverterBasic.lookup({ OFF: false, ON: true })],
[38, "local_temperature", tuya.valueConverter.divideBy10],
[39, "max_temperature_limit", tuya.valueConverter.divideBy10],
[41, "holiday_start_stop", tuya.valueConverterBasic.divideBy(1)], //divideBy1 required to force the format. Raw does not work
[42, "holiday_temperature", tuya.valueConverter.divideBy10],
[
43,
"sensor_mode",
tuya.valueConverterBasic.lookup({
room_temperature: tuya.enum(0),
floor_temperature: tuya.enum(1),
room_with_floor_limit: tuya.enum(2),
}),
],
//[48, 'temp_tolerance', tuya.valueConverter.raw],
[50, "power_rating", tuya.valueConverterBasic.divideBy(1)],
[52, "frost_protection", tuya.valueConverterBasic.lookup({ OFF: false, ON: true })],
[53, "min_temperature_limit", tuya.valueConverter.divideBy10],
[54, "switch_delay", tuya.valueConverterBasic.divideBy(1)],
[55, "display_brightness", tuya.valueConverterBasic.divideBy(1)], //divideBy1 required to force the format. Raw does not work
//[16, 'schedule', tuya.valueConverter.Raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_pbo8cj0z"]),
model: "TS0601_GTZ10",
vendor: "Tuya",
description: "Thermostat radiator valve",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
ota: true,
exposes: [
e.battery(),
e.child_lock(),
e.window_detection(),
e.window_open(),
e.open_window_temperature().withValueMin(5).withValueMax(30),
e.max_temperature().withValueMin(15).withValueMax(45),
e.min_temperature().withValueMin(5).withValueMax(15),
e
.climate()
.withPreset(["manual", "auto", "holiday", "comfort", "eco", "off"])
.withSetpoint("current_heating_setpoint", 5, 40, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9, 9, 0.5, ea.STATE_SET)
.withSystemMode(["off", "heat", "auto"], ea.STATE_SET, "Only for Homeassistant")
.withRunningState(["idle", "heat"], ea.STATE),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
tuya.exposes
.errorStatus()
.withDescription("Error status. Possible codes: E1 - builtin sensor error, E2 - external sensor error, E3 - valve not installed, E4 - motor error."),
e
.binary("frost_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
e.binary("boost_heating", ea.STATE_SET, "ON", "OFF").withDescription("Boost Heating: the device will enter the boost heating mode."),
e
.numeric("boost_timeset_countdown", ea.STATE_SET)
.withUnit("m")
.withDescription("Setting " +
"minimum 0 - maximum 90 minutes boost time. The boost function is activated. The remaining " +
"time for the function will be counted down in minutes ( 90 to 0 ).")
.withValueMin(0)
.withValueMax(90),
e.binary("switch_type", ea.STATE_SET, "ON", "OFF").withDescription("Enables/disables valve switch"),
e
.numeric("position", ea.STATE)
.withUnit("%")
.withValueMin(0)
.withValueMax(100)
.withDescription("Position"), // set actually not working
e.enum("screen_orientation", ea.STATE_SET, ["up", "right", "down", "left"]).withDescription("Screen orientation"),
],
meta: {
tuyaDatapoints: [
[
2,
null,
tuya.valueConverter.thermostatSystemModeAndPresetMap({
fromMap: {
0: {
deviceMode: "manual",
systemMode: "heat",
preset: "manual",
},
1: { deviceMode: "auto", systemMode: "auto", preset: "auto" },
2: {
deviceMode: "holiday",
systemMode: "heat",
preset: "holiday",
},
3: {
deviceMode: "comfort",
systemMode: "heat",
preset: "comfort",
},
4: { deviceMode: "eco", systemMode: "heat", preset: "eco" },
5: { deviceMode: "off", systemMode: "off", preset: "off" },
},
}),
],
[
2,
"preset",
tuya.valueConverter.thermostatSystemModeAndPresetMap({
toMap: {
manual: new tuya.Enum(0),
auto: new tuya.Enum(1),
holiday: new tuya.Enum(2),
comfort: new tuya.Enum(3),
eco: new tuya.Enum(4),
off: new tuya.Enum(5),
},
}),
],
[
2,
"system_mode",
tuya.valueConverter.thermostatSystemModeAndPresetMap({
toMap: {
heat: new tuya.Enum(0),
auto: new tuya.Enum(1),
off: new tuya.Enum(5),
},
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[7, "child_lock", tuya.valueConverter.lockUnlock],
[9, "max_temperature", tuya.valueConverter.divideBy10],
[10, "min_temperature", tuya.valueConverter.divideBy10],
[14, "window_detection", tuya.valueConverter.onOff],
[15, "window_open", tuya.valueConverter.onOff],
[16, "open_window_temperature", tuya.valueConverter.divideBy10],
[28, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[29, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[30, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[31, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[32, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[33, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[34, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[35, "error_status", tuya.valueConverter.raw],
[36, "frost_protection", tuya.valueConverter.onOff],
[37, "boost_heating", tuya.valueConverter.onOff],
[38, "boost_timeset_countdown", tuya.valueConverter.raw],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[
49, //valve_state
"running_state",
tuya.valueConverterBasic.lookup({
idle: tuya.enum(0),
heat: tuya.enum(1),
closing: tuya.enum(2),
opening: tuya.enum(3),
}),
],
[113, "switch_type", tuya.valueConverter.onOff], // valve_switch
[115, "position", tuya.valueConverter.raw], // valve_opening
[
119,
"screen_orientation",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
left: tuya.enum(2),
right: tuya.enum(3),
}),
],
// Exposed but not used DPs
[1, "preheat", tuya.valueConverter.raw],
[3, "working_status", tuya.valueConverter.raw],
[8, "temperature_scale", tuya.valueConverter.raw],
[11, "max_temperature_f", tuya.valueConverter.divideBy10],
[12, "min_temperature_f", tuya.valueConverter.divideBy10],
[17, "open_window_time", tuya.valueConverter.raw],
[18, "backlight", tuya.valueConverter.raw],
[39, "switch_scale", tuya.valueConverter.raw],
[40, "local_temperature_f", tuya.valueConverter.divideBy10],
[41, "current_heating_setpoint_f", tuya.valueConverter.divideBy10],
[46, "open_window_temperature_f", tuya.valueConverter.divideBy10],
[48, "valve_testing", tuya.valueConverter.raw],
[112, "local_temperature_calibration_f", tuya.valueConverter.localTempCalibration1],
[114, "valve_control_type", tuya.valueConverterBasic.lookup({ PID: 0, ONOFF: 1 })],
[116, "frost_temperature", tuya.valueConverter.raw],
[117, "frost_temperature_f", tuya.valueConverter.raw],
[118, "auto_time", tuya.valueConverter.raw],
[120, "multi_control_link", tuya.valueConverter.raw],
[121, "holiday_time", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_kyyu8rbj"]),
model: "ME201WZ",
vendor: "Tuya",
description: "Water level sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.numeric("liquid_level_percent", ea.STATE).withUnit("%").withDescription("Liquid level ratio"),
e.numeric("liquid_depth", ea.STATE).withUnit("m").withDescription("Liquid Depth"),
e.enum("liquid_state", ea.STATE, ["low", "normal", "high"]).withDescription("Liquid level status"),
e
.numeric("max_set", ea.STATE_SET)
.withUnit("%")
.withDescription("Liquid max percentage")
.withValueMin(0)
.withValueMax(100)
.withValueStep(1),
e
.numeric("mini_set", ea.STATE_SET)
.withUnit("%")
.withDescription("Liquid minimal percentage")
.withValueMin(0)
.withValueMax(100)
.withValueStep(1),
e
.numeric("installation_height", ea.STATE_SET)
.withUnit("m")
.withDescription("Height from sensor to tank bottom")
.withValueMin(0.1)
.withValueMax(4)
.withValueStep(0.01),
e
.numeric("liquid_depth_max", ea.STATE_SET)
.withUnit("m")
.withDescription("Height from sensor to liquid level")
.withValueMin(0.1)
.withValueMax(4)
.withValueStep(0.01),
],
meta: {
tuyaDatapoints: [
[
1,
"liquid_state",
tuya.valueConverterBasic.lookup({
low: tuya.enum(1),
normal: tuya.enum(0),
high: tuya.enum(2),
}),
],
[2, "liquid_depth", tuya.valueConverter.divideBy100],
[22, "liquid_level_percent", tuya.valueConverter.raw],
[7, "max_set", tuya.valueConverter.raw],
[8, "mini_set", tuya.valueConverter.raw],
[19, "installation_height", tuya.valueConverter.divideBy100],
[21, "liquid_depth_max", tuya.valueConverter.divideBy100],
],
},
},
{
fingerprint: [{ modelID: "TS0601", manufacturerName: "_TZE200_lvkk0hdg" }],
model: "TLC2206",
vendor: "Tuya",
description: "Water level sensor",
extend: [m.forcePowerSource({ powerSource: "Mains (single phase)" })],
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.numeric("liquid_level_percent", ea.STATE).withUnit("%").withDescription("Liquid level ratio"),
e.numeric("liquid_depth", ea.STATE).withUnit("cm").withDescription("Liquid depth"),
e.enum("liquid_state", ea.STATE, ["low", "normal", "high"]).withDescription("Liquid level status"),
e
.numeric("max_set", ea.STATE_SET)
.withUnit("%")
.withDescription("Liquid max percentage")
.withValueMin(0)
.withValueMax(100)
.withValueStep(1),
e
.numeric("min_set", ea.STATE_SET)
.withUnit("%")
.withDescription("Liquid minimal percentage")
.withValueMin(0)
.withValueMax(100)
.withValueStep(1),
e
.numeric("installation_height", ea.STATE_SET)
.withUnit("mm")
.withDescription("Height from sensor to tank bottom")
.withValueMin(10)
.withValueMax(4000)
.withValueStep(5),
e
.numeric("liquid_depth_max", ea.STATE_SET)
.withUnit("mm")
.withDescription("Height from sensor to liquid level")
.withValueMin(10)
.withValueMax(4000)
.withValueStep(5),
],
meta: {
tuyaDatapoints: [
[
1,
"liquid_state",
tuya.valueConverterBasic.lookup({
low: tuya.enum(1),
normal: tuya.enum(0),
high: tuya.enum(2),
}),
],
[2, "liquid_depth", tuya.valueConverter.raw], // mm
[22, "liquid_level_percent", tuya.valueConverter.raw],
[7, "max_set", tuya.valueConverter.raw],
[8, "min_set", tuya.valueConverter.raw],
[19, "installation_height", tuya.valueConverter.raw],
[21, "liquid_depth_max", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_q12rv9gj"]),
model: "HHST001",
vendor: "HeatHUB",
description: "Fan coil thermostat",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON/OFF"),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSystemMode(["cool", "heat", "fan_only"], ea.STATE_SET)
.withSetpoint("current_heating_setpoint", 5, 45, 0.5, ea.STATE_SET)
.withFanMode(["auto", "high", "medium", "low", "off"], ea.STATE_SET)
.withLocalTemperatureCalibration(-9, 9, 0.1, ea.STATE_SET),
e
.numeric("deadzone_temperature", ea.STATE_SET)
.withValueMax(5)
.withValueMin(1)
.withValueStep(1)
.withPreset("default", 1, "Default value")
.withDescription("The difference between the local temperature that triggers heating and the set temperature"),
e.min_temperature().withValueMin(5).withValueMax(15),
e.max_temperature().withValueMin(35).withValueMax(45),
e.child_lock(),
e.humidity(),
e.binary("manual_mode", ea.STATE_SET, "Auto", "Manual").withDescription("Manual = Manual or Schedule = Auto"),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
cool: tuya.enum(0),
heat: tuya.enum(1),
fan_only: tuya.enum(2),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[19, "max_temperature", tuya.valueConverter.divideBy10],
[18, "max_temperature_f", tuya.valueConverter.raw],
[20, "min_temperature_f", tuya.valueConverter.raw],
[21, "local_temperature_f", tuya.valueConverter.raw],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[26, "min_temperature", tuya.valueConverter.divideBy10],
[102, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[103, "local_temperature_calibration_f", tuya.valueConverter.raw],
[104, "deadzone_temperature", tuya.valueConverter.raw],
[105, "deadzone_temperature_f", tuya.valueConverter.raw],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
high: tuya.enum(1),
medium: tuya.enum(2),
low: tuya.enum(3),
off: tuya.enum(4),
}),
],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[44, "current_heating_setpoint_f", tuya.valueConverter.raw],
[46, "temperature_scale", tuya.valueConverter.raw],
[
101,
"manual_mode",
tuya.valueConverterBasic.lookup({
Auto: tuya.enum(0),
Manual: tuya.enum(1),
Tempoary: tuya.enum(2),
}),
],
[113, "humidity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_8zizsafo", "_TZE284_iilebqoo"]),
model: "GX03",
vendor: "GIEX",
description: "GIEX 2 zone watering timer",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.binary("valve_1", ea.STATE_SET, "ON", "OFF").withDescription("Switch state"),
e
.numeric("countdown_1", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1440)
.withValueStep(1)
.withUnit("min")
.withDescription("Countdown timer for valve operation"),
e.binary("valve_2", ea.STATE_SET, "ON", "OFF").withDescription("Switch state"),
e
.numeric("countdown_2", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1440)
.withValueStep(1)
.withUnit("min")
.withDescription("Countdown timer for valve operation"),
e.battery(),
],
meta: {
tuyaDatapoints: [
[1, "valve_1", tuya.valueConverter.onOff],
[59, "battery", tuya.valueConverter.raw],
[
104,
"valve_1",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(2),
ON: tuya.enum(0),
}),
],
[2, "valve_2", tuya.valueConverter.onOff],
[
105,
"valve_2",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(2),
ON: tuya.enum(0),
}),
],
[13, "countdown_1", tuya.valueConverter.raw],
[14, "countdown_2", tuya.valueConverter.raw],
],
},
whiteLabel: [tuya.whitelabel("Nova Digital", "ZVL-DUAL", "Water Valve with 2 zones", ["_TZE284_iilebqoo"])],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_eaulras5"]),
model: "PJ3201A",
vendor: "Dongguan Pinjia Technology Co.,LTD.",
description: "Human Presence Sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.presence().withDescription("Indicates whether the device detected presence. Will be true also when movement (occupancy) is detected."),
e
.occupancy()
.withDescription("Indicates whether the device detected movement. Will be true when movement. Can remain true even if the target left the detection range. In this case presence will be reset to false reliably."),
e.numeric("closest_target_distance", ea.STATE).withDescription("the target distance away from the sensor").withUnit("m"),
e
.numeric("movement_timeout", ea.STATE_SET)
.withValueMin(0)
.withValueMax(43200)
.withValueStep(1)
.withDescription("Timeout until the movement (occupancy) is reset when no further movement is detected. (Occupancy -> None)")
.withUnit("s"),
e
.numeric("idle_timeout", ea.STATE_SET)
.withValueMin(0)
.withValueMax(43200)
.withValueStep(1)
.withDescription("Timeout until the presence is reset when no further presence is detected (Presence -> None)")
.withUnit("s"),
e.illuminance(),
e
.numeric("far_movement_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("the moving detecting sensitivity 1 meter away"),
e
.numeric("near_movement_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("the moving detecting sensitivity within 1 meter"),
e
.numeric("near_presence_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("the presence detecting sensitivity within 1 meter"),
e
.numeric("far_presence_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(1)
.withDescription("the presence detecting sensitivity 1 meter away"),
e
.numeric("closest_detection_distance", ea.STATE_SET)
.withValueMin(0.1)
.withValueMax(7)
.withValueStep(0.1)
.withDescription("The closest distance that can be detected")
.withUnit("m"),
e
.numeric("largest_movement_detection_distance", ea.STATE_SET)
.withValueMin(0.1)
.withValueMax(7)
.withValueStep(0.1)
.withDescription("The farthest distance that can be detected (moving)")
.withUnit("m"),
e
.numeric("largest_presence_detection_distance", ea.STATE_SET)
.withValueMin(0.1)
.withValueMax(7)
.withValueStep(0.1)
.withDescription("The farthest distance that can be detected (present)")
.withUnit("m"),
e.binary("restore_factory", ea.STATE_SET, "ON", "OFF").withDescription("restore_factory"),
e.binary("led_indicator", ea.STATE_SET, "ON", "OFF").withDescription("turn on or off the led "),
],
meta: {
tuyaDatapoints: [
[104, "presence", tuya.valueConverter.trueFalse1],
[112, "occupancy", tuya.valueConverter.trueFalseInvert],
[9, "closest_target_distance", tuya.valueConverter.divideBy100],
[101, "movement_timeout", tuya.valueConverter.raw],
[102, "idle_timeout", tuya.valueConverter.raw],
[103, "illuminance", tuya.valueConverter.divideBy10],
[105, "far_movement_sensitivity", tuya.valueConverter.raw],
[110, "near_movement_sensitivity", tuya.valueConverter.raw],
[109, "near_presence_sensitivity", tuya.valueConverter.raw],
[111, "far_presence_sensitivity", tuya.valueConverter.raw],
[3, "closest_detection_distance", tuya.valueConverter.divideBy100],
[4, "largest_movement_detection_distance", tuya.valueConverter.divideBy100],
[108, "largest_presence_detection_distance", tuya.valueConverter.divideBy100],
[106, "restore_factory", tuya.valueConverterBasic.lookup({ ON: false, OFF: true })],
[107, "led_indicator", tuya.valueConverterBasic.lookup({ ON: false, OFF: true })],
],
},
},
{
fingerprint: tuya.fingerprint("TS0225", ["_TZ321C_fkzihax8", "_TZ321C_4slreunp"]),
model: "MTD085-ZB",
vendor: "LeapMMW",
description: "Human presence sensor",
extend: [tuyaBase({ dp: true })],
fromZigbee: [fz.ias_occupancy_alarm_1, fz.ias_occupancy_alarm_1_report],
exposes: [
e.occupancy(),
e.illuminance(),
e.numeric("target_distance", ea.STATE).withDescription("Distance to target").withUnit("m"),
e
.numeric("radar_sensitivity", ea.STATE_SET)
.withValueMin(10)
.withValueMax(100)
.withValueStep(10)
.withUnit("%")
.withDescription("Detection threshold for the strength of object energy"),
e
.numeric("detection_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Maximum distance detected by the sensor"),
e
.numeric("shield_range", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Nearest distance detected by the sensor"),
e
.numeric("entry_sensitivity", ea.STATE_SET)
.withValueMin(10)
.withValueMax(100)
.withValueStep(10)
.withUnit("%")
.withDescription("Sensitivity threshold triggered for the first time when the target enters the detection range"),
e
.numeric("entry_distance", ea.STATE_SET)
.withValueMin(0)
.withValueMax(8)
.withValueStep(0.1)
.withUnit("m")
.withDescription("Detection distance when unoccupied"),
e
.numeric("entry_filter_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(0.5)
.withValueStep(0.05)
.withUnit("s")
.withDescription("Sensitivity threshold triggered for the first time when the target enters the detection range "),
e
.numeric("departure_delay", ea.STATE_SET)
.withValueMin(5)
.withValueMax(7200)
.withValueStep(1)
.withUnit("s")
.withDescription("Confirmation time after the target disappears"),
e
.numeric("block_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(10)
.withValueStep(0.1)
.withUnit("s")
.withDescription("Time for the target to be detected again after switching from manned(occupy) to unmanned(unoccupy) mode"),
e.enum("status_indication", ea.STATE_SET, ["OFF", "ON"]).withDescription("Indicator light will turn on when human presence is detected"),
e
.enum("sensor", ea.STATE_SET, ["on", "occupied", "unoccupied"])
.withDescription("The radar sensor can be set in three states: on, occupied and unoccupied. For example, if set to occupied, " +
"it will continue to maintain presence regardless of whether someone is present or not. If set to unoccupied, the unoccupied " +
"state will be maintained permanently."),
e
.enum("scene_preset", ea.STATE_SET, [
"Custom",
"Toilet",
"Kitchen",
"Hallway",
"Bedroom",
"Livingroom",
"Meetingroom",
"Factory default",
])
.withDescription("Presets"),
e
.enum("distance_report_mode", ea.STATE_SET, ["Normal", "Occupancy detection"])
.withDescription("Indicator light will turn on when human presence is detected"),
e
.enum("debug_mode", ea.STATE_SET, ["OFF", "ON"])
.withDescription("In debug mode, radar will report more information, can be used to identify interference"),
e.numeric("debug_distance", ea.STATE).withDescription("Real time distance to target").withUnit("m"),
e.numeric("debug_countdown", ea.STATE).withDescription("Time before the target disappears").withUnit("s"),
],
meta: {
tuyaSendCommand: "sendData",
tuyaDatapoints: [
// [1, 'presence', tuya.valueConverter.trueFalse1],
[101, "entry_sensitivity", tuya.valueConverter.raw],
[102, "entry_distance", tuya.valueConverter.divideBy100],
[103, "departure_delay", tuya.valueConverter.raw],
[104, "entry_filter_time", tuya.valueConverter.divideBy100],
[105, "block_time", tuya.valueConverter.divideBy10],
[107, "illuminance", tuya.valueConverter.divideBy10],
[
108,
"debug_mode",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[109, "debug_distance", tuya.valueConverter.divideBy100],
[110, "debug_countdown", tuya.valueConverter.raw],
[
111,
"scene_preset",
tuya.valueConverterBasic.lookup({
Custom: tuya.enum(0),
Toilet: tuya.enum(1),
Kitchen: tuya.enum(2),
Hallway: tuya.enum(3),
Bedroom: tuya.enum(4),
Livingroom: tuya.enum(5),
Meetingroom: tuya.enum(6),
Default: tuya.enum(7),
}),
],
[
112,
"sensor",
tuya.valueConverterBasic.lookup({
on: tuya.enum(0),
occupied: tuya.enum(1),
unoccupied: tuya.enum(2),
}),
],
[113, "cline", tuya.valueConverter.raw],
[
114,
"status_indication",
tuya.valueConverterBasic.lookup({
OFF: tuya.enum(0),
ON: tuya.enum(1),
}),
],
[115, "radar_sensitivity", tuya.valueConverter.raw],
[116, "shield_range", tuya.valueConverter.divideBy100],
[117, "detection_range", tuya.valueConverter.divideBy100],
[118, "equipment_status", tuya.valueConverter.raw],
[119, "target_distance", tuya.valueConverter.divideBy100],
[
120,
"distance_report_mode",
tuya.valueConverterBasic.lookup({
Normal: tuya.enum(0),
"Occupancy detection": tuya.enum(1),
}),
],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_d6i25bwg"]),
model: "PO-BOCO-ELEC",
vendor: "Powernity",
description: "Pilot wire heating module",
extend: [tuyaBase({ dp: true })],
exposes: [
e
.climate()
.withPreset(["manual", "auto", "holiday"])
.withLocalTemperature(ea.STATE)
.withSetpoint("occupied_heating_setpoint", 0, 20, 1, ea.STATE_SET)
.withLocalTemperatureCalibration(-5.5, 5.5, 0.5, ea.STATE_SET)
.withSystemMode(["off", "heat", "auto"], ea.STATE_SET, "Only for Homeassistant"),
e.enum("auto_mode", ea.STATE_SET, ["off", "antifrost", "eco", "comfort_-2", "comfort_-1", "comfort"]).withDescription("Auto Mode"),
e.enum("manual_mode", ea.STATE_SET, ["off", "antifrost", "eco", "comfort_-2", "comfort_-1", "comfort"]).withDescription("Manual Mode"),
tuya.exposes.frostProtection(),
// e.text("antifrost_mode", ea.STATE),
e.humidity(),
e.child_lock(),
e.window_detection(),
e
.enum("window_opening_mode", ea.STATE_SET, ["off", "antifrost", "eco", "comfort_-2", "comfort_-1", "comfort"])
.withDescription("Window Opening Mode"),
e
.numeric("window_opening_mode_duration", ea.STATE_SET)
.withUnit("min")
.withDescription("Duration of the window opening mode")
.withValueMin(1)
.withValueMax(90),
tuya.exposes.temperatureUnit(),
e
.binary("boost_heating", ea.STATE_SET, "ON", "OFF")
.withDescription("Boost Heating: the device will enter the boost heating mode.")
.withCategory("config"),
e
.numeric("boost_timeset_countdown", ea.STATE)
.withUnit("s")
.withDescription("The remaining " + "time for the function will be counted down in seconds ( 900 to 0 ) when the boost heating is activated.")
.withValueMin(0)
.withValueMax(900),
e
.numeric("power_rating", ea.STATE_SET)
.withDescription("How much power is the heater rated to. Entering a value will allow the Thermostat to record a value of power usage that can be checked under settings on the physical Thermostat")
.withUnit("kWh")
.withValueMin(10)
.withValueMax(10000)
.withValueStep(10)
.withCategory("config"),
e.numeric("energy_consumed", ea.STATE).withUnit("kWh").withDescription("Consumed energy"),
e
.enum("mode_switching", ea.STATE_SET, ["four_modes", "six_modes"])
.withDescription("Choose the number of mode your heater supports.")
.withCategory("config"),
e
.text("schedule_monday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_tuesday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_wednesday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_thursday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_friday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_saturday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("schedule_sunday", ea.STATE_SET)
.withDescription("Schedule for the auto mode. Can be defined in the following format: " +
"`mode / hours:minutes / mode`. " +
"For example: `comfort / 06:00 / eco / 12:00 / off`. " +
"Note: Minutes can only be set by multiple of 5. Your limited to 9 modes max."),
e
.text("holiday_start_stop", ea.STATE_SET)
.withDescription("The holiday mode will automatically start " +
"at the set time starting point and run the holiday mode. Can be defined in the following format: " +
"`startYear/startMonth/startDay startHours:startMinutes | endYear/endMonth/endDay endHours:endMinutes | mode`. " +
"For example: `2024/12/12 09:00 | 2024/12/14 10:00 | comfort`" +
"Note: You cannot set an interval superior at 255 hours. The end date minutes will be ignore."),
e.binary("reset_consumption", ea.STATE_SET, "ON", "OFF").withDescription("Reset energy consumption to zero").withCategory("config"),
],
meta: {
tuyaDatapoints: [
[
null,
"occupied_heating_setpoint",
{
to: async (v, meta) => {
const entity = meta.device.endpoints[0];
const mode = meta.state.mode_switching;
let temp = v;
if (meta.state.temperature_unit === "fahrenheit")
temp = ((temp - 32) * 5) / 9;
await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1); // manual
if (temp === 0) {
await tuya.sendDataPointEnum(entity, 127, 5, "dataRequest", 3); //off
}
else if (temp < 16) {
await tuya.sendDataPointEnum(entity, 127, 4, "dataRequest", 3); //antifrost
}
else if (temp >= 19) {
await tuya.sendDataPointEnum(entity, 127, 0, "dataRequest", 1); //comfort
}
else if (mode === 1) {
if (temp === 17) {
await tuya.sendDataPointEnum(entity, 127, 2, "dataRequest", 1); // comfort-2
}
else if (temp === 18) {
await tuya.sendDataPointEnum(entity, 127, 1, "dataRequest", 1); // comfort-1
}
}
else {
await tuya.sendDataPointEnum(entity, 127, 3, "dataRequest", 1); // eco
}
return v;
},
},
],
[
2,
"preset",
tuya.valueConverterBasic.lookup({
auto: tuya.enum(0),
manual: tuya.enum(1),
holiday: tuya.enum(2),
}),
],
[
null,
"system_mode",
{
// Extend system_mode to support 'off' in addition to 'heat' and 'auto'
to: async (v, meta) => {
const entity = meta.device.endpoints[0];
let temp = meta.state.occupied_heating_setpoint;
if (meta.state.temperature_unit === "fahrenheit")
temp = ((temp - 32) * 5) / 9;
const mode = meta.state.mode_switching;
switch (v) {
case "off":
await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1); // manual
await tuya.sendDataPointEnum(entity, 127, 5, "dataRequest", 1); // off
break;
case "heat":
await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1); // manual
if (temp === 0) {
await tuya.sendDataPointEnum(entity, 127, 5, "dataRequest", 3); //off
}
else if (temp < 16) {
await tuya.sendDataPointEnum(entity, 127, 4, "dataRequest", 3); //antifrost
}
else if (temp >= 19) {
await tuya.sendDataPointEnum(entity, 127, 0, "dataRequest", 1); //comfort
}
else if (mode === 1) {
if (temp === 17) {
await tuya.sendDataPointEnum(entity, 127, 2, "dataRequest", 1); // comfort-2
}
else if (temp === 18) {
await tuya.sendDataPointEnum(entity, 127, 1, "dataRequest", 1); // comfort-1
}
}
else {
await tuya.sendDataPointEnum(entity, 127, 3, "dataRequest", 1); // eco
}
break;
case "auto":
await tuya.sendDataPointEnum(entity, 2, 0, "dataRequest", 1); // auto
break;
}
},
},
],
[8, "humidity", tuya.valueConverter.raw],
[11, "energy_consumed", tuya.valueConverter.raw],
[16, "local_temperature", tuya.valueConverter.divideBy10],
[39, "child_lock", tuya.valueConverter.lockUnlock],
[46, "temperature_unit", tuya.valueConverter.temperatureUnitEnum],
[101, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
[108, "boost_heating", tuya.valueConverter.onOff],
[114, "schedule_monday", tuya.valueConverter.PO_BOCO_ELEC_schedule(1)],
[115, "schedule_tuesday", tuya.valueConverter.PO_BOCO_ELEC_schedule(2)],
[116, "schedule_wednesday", tuya.valueConverter.PO_BOCO_ELEC_schedule(3)],
[117, "schedule_thursday", tuya.valueConverter.PO_BOCO_ELEC_schedule(4)],
[118, "schedule_friday", tuya.valueConverter.PO_BOCO_ELEC_schedule(5)],
[119, "schedule_saturday", tuya.valueConverter.PO_BOCO_ELEC_schedule(6)],
[120, "schedule_sunday", tuya.valueConverter.PO_BOCO_ELEC_schedule(7)],
[123, "boost_timeset_countdown", tuya.valueConverter.raw],
// [125, "temperature_antifreeze", tuya.valueConverterBasic.raw],
[
126,
"auto_mode",
tuya.valueConverterBasic.lookup({
off: tuya.enum(5),
antifrost: tuya.enum(4),
eco: tuya.enum(3),
"comfort_-2": tuya.enum(2),
"comfort_-1": tuya.enum(1),
comfort: tuya.enum(0),
}),
],
[
127,
"manual_mode",
tuya.valueConverterBasic.lookup({
off: tuya.enum(5),
antifrost: tuya.enum(4),
eco: tuya.enum(3),
"comfort_-2": tuya.enum(2),
"comfort_-1": tuya.enum(1),
comfort: tuya.enum(0),
}),
],
[136, "frost_protection", tuya.valueConverter.onOff],
// [137, "antifrost", tuya.valueConverterBasic.raw],
[138, "window_detection", tuya.valueConverter.onOff],
[
139,
"window_opening_mode",
tuya.valueConverterBasic.lookup({
off: tuya.enum(5),
antifrost: tuya.enum(4),
eco: tuya.enum(3),
"comfort_-2": tuya.enum(2),
"comfort_-1": tuya.enum(1),
comfort: tuya.enum(0),
}),
],
[140, "window_opening_mode_duration", tuya.valueConverter.raw],
[141, "reset_consumption", tuya.valueConverter.onOff],
[142, "power_rating", tuya.valueConverter.raw],
[143, "holiday_start_stop", tuya.valueConverter.PO_BOCO_ELEC_holiday],
[
144,
"mode_switching",
tuya.valueConverterBasic.lookup({
four_modes: tuya.enum(0),
six_modes: tuya.enum(1),
}),
],
// [145, "weekly temperature replication function", ],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_eekpf0ft", "_TZE284_eekpf0ft"]),
model: "TR-M3Z",
vendor: "Tuya",
description: "Thermostatic radiator valve actuator",
extend: [tuyaBase({ dp: true })],
exposes: [
e.child_lock(),
e.battery(),
e.battery_low(),
e
.climate()
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withPreset(["manual", "schedule", "eco", "comfort", "frost_protection", "holiday", "off"])
.withSystemMode(["off", "heat"], ea.STATE)
.withRunningState(["idle", "heat"], ea.STATE)
.withLocalTemperatureCalibration(-9.5, 9.5, 0.5, ea.STATE_SET),
...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
e.eco_temperature().withValueMin(5).withValueMax(35).withValueStep(0.5),
e.comfort_temperature().withValueMin(5).withValueMax(35).withValueStep(0.5),
e.holiday_temperature().withValueMin(5).withValueMax(35).withValueStep(0.5),
e
.binary("window_detection", ea.STATE_SET, "ON", "OFF")
.withDescription("Startup: when room temperature decreases by 3°C within 5 minutes, stop heating. " +
"Close: when room temperature rises by 3 degrees / 48 minutes later / manual (three ways). " +
"After the window opening mode is turned on, one of these three conditions can trigger to exit the window opening mode."),
e.binary("window_open", ea.STATE, "OPEN", "CLOSE").withDescription("Window status CLOSE or OPEN "),
e
.binary("scale_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("If the heat sink is not fully opened within " +
"two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be " +
"able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every " +
'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
"again."),
e
.binary("frost_protection", ea.STATE_SET, "ON", "OFF")
.withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
e
.numeric("frost_protection_temperature", ea.STATE_SET)
.withUnit("°C")
.withValueMin(5)
.withValueMax(35)
.withValueStep(0.5)
.withDescription(""),
e
.numeric("temperature_accuracy", ea.STATE_SET)
.withUnit("°C")
.withValueMin(0.5)
.withValueMax(5)
.withValueStep(0.5)
.withDescription("The difference required between local temperature and set point to trigger the valve."),
e.numeric("error", ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
],
meta: {
tuyaDatapoints: [
[
2,
"preset",
tuya.valueConverterBasic.lookup({
manual: tuya.enum(0),
schedule: tuya.enum(1),
eco: tuya.enum(2),
comfort: tuya.enum(3),
frost_protection: tuya.enum(4),
holiday: tuya.enum(5),
off: tuya.enum(6),
}),
],
[
3,
"running_state",
tuya.valueConverterBasic.lookup({
idle: tuya.enum(0),
heat: tuya.enum(1),
}),
],
[4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[5, "local_temperature", tuya.valueConverter.divideBy10],
[6, "battery", tuya.valueConverter.raw],
[7, "child_lock", tuya.valueConverter.lockUnlock],
[14, "window_detection", tuya.valueConverter.onOff],
[
15,
"window_open",
tuya.valueConverterBasic.lookup({
CLOSE: tuya.enum(0),
OPEN: tuya.enum(1),
}),
],
[21, "holiday_temperature", tuya.valueConverter.divideBy10],
[28, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1, 6)],
[29, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2, 6)],
[30, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3, 6)],
[31, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4, 6)],
[32, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5, 6)],
[33, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6, 6)],
[34, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7, 6)],
[35, "fault_alarm", tuya.valueConverter.errorOrBatteryLow],
[36, "frost_protection", tuya.valueConverter.onOff],
[39, "scale_protection", tuya.valueConverter.onOff],
[47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration3],
[101, "system_mode", tuya.valueConverterBasic.lookup({ off: false, heat: true })],
[102, "temperature_accuracy", tuya.valueConverter.divideBy10],
[103, "eco_temperature", tuya.valueConverter.divideBy10],
[104, "comfort_temperature", tuya.valueConverter.divideBy10],
[105, "frost_protection_temperature", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wem3gxyx"]),
model: "AE-940K",
vendor: "ACMELEC",
description: "Compatible with Daikin vrv system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON/OFF"),
e
.climate()
.withSystemMode(["cool", "heat", "fan_only", "dry"], ea.STATE_SET)
.withSetpoint("current_heating_setpoint", 16, 32, 1, ea.STATE_SET)
.withFanMode(["low", "medium", "high", "auto"], ea.STATE_SET)
.withLocalTemperature(ea.STATE),
e.child_lock(),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
cool: tuya.enum(0),
heat: tuya.enum(1),
fan_only: tuya.enum(2),
dry: tuya.enum(3),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.raw],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
auto: tuya.enum(3),
}),
],
[40, "child_lock", tuya.valueConverter.lockUnlock],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_mul9abs3"]),
model: "AE-669K",
vendor: "ACMELEC",
description: "Compatible with Mitsubishi Electric vrf system",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON/OFF"),
e
.climate()
.withSystemMode(["cool", "heat", "fan_only", "dry"], ea.STATE_SET)
.withSetpoint("current_heating_setpoint", 16, 32, 1, ea.STATE_SET)
.withFanMode(["low", "medium", "high", "auto"], ea.STATE_SET)
.withLocalTemperature(ea.STATE),
e.child_lock(),
],
meta: {
tuyaDatapoints: [
[1, "state", tuya.valueConverter.onOff],
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
cool: tuya.enum(0),
heat: tuya.enum(1),
fan_only: tuya.enum(2),
dry: tuya.enum(3),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.raw],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
auto: tuya.enum(3),
}),
],
[40, "child_lock", tuya.valueConverter.lockUnlock],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_a14rjslz"]),
model: "ATMS10013Z3",
vendor: "Ourtop",
description: "Zigbee 3 Phase Meter",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
whiteLabel: [{ vendor: "Ourtop", model: "ATMS100133Z" }],
exposes: [
e.energy(),
tuya.exposes.voltageWithPhase("a"),
tuya.exposes.voltageWithPhase("b"),
tuya.exposes.voltageWithPhase("c"),
tuya.exposes.powerWithPhase("a"),
tuya.exposes.powerWithPhase("b"),
tuya.exposes.powerWithPhase("c"),
tuya.exposes.currentWithPhase("a"),
tuya.exposes.currentWithPhase("b"),
tuya.exposes.currentWithPhase("c"),
e.produced_energy(),
e.numeric("total_energy", ea.STATE).withUnit("kWh").withDescription("Total consumed and produced energy"),
e.power(),
e.power_reactive(),
e.power_factor().withUnit("%"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100], // "Forward Active Energy", 7685 -> 76.85kW
[6, null, tuya.valueConverter.phaseVariant2WithPhase("a")], // "Phase A", CJMAAEMAAAI=
[7, null, tuya.valueConverter.phaseVariant2WithPhase("b")], // "Phase B"
[8, null, tuya.valueConverter.phaseVariant2WithPhase("c")], // "Phase C"
[23, "produced_energy", tuya.valueConverter.divideBy100], // "Reverse Energy", 0 W*h -> 0.0 kW*h
[24, "total_energy", tuya.valueConverter.divideBy100], // total energy produced + consumed , 7692 W*h -> 76.92kW*h
[29, "power", tuya.valueConverter.power], // "Total Active Power", 1740 W
[30, "power_reactive", tuya.valueConverter.power], // "Total Reactive Power", 985 Var
[50, "power_factor", tuya.valueConverter.raw], // "Overall Power Factor" 88 -> 88 %
],
},
},
{
zigbeeModel: ["TS0901"],
model: "TS0901",
vendor: "Tuya",
description: "Battery powered light",
extend: [m.battery(), m.light()],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_atdqo4nj"]),
model: "ZG-WK-DA-Wh-Zigbee",
vendor: "Tuya",
description: "Wall thermostat with humidity sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.humidity(),
e.child_lock(),
//e.temperature_sensor_select(['internal', 'external', 'both']),
e
.climate()
.withSystemMode(["off", "heat"], ea.STATE_SET)
.withPreset(["manual", "auto"])
.withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
.withRunningState(["idle", "heat"], ea.STATE)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
],
meta: {
tuyaDatapoints: [
[1, "system_mode", tuya.valueConverterBasic.lookup({ heat: true, off: false })],
[2, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[3, "local_temperature", tuya.valueConverter.divideBy10],
[4, "preset", tuya.valueConverterBasic.lookup({ manual: 0, auto: 1 })],
[9, "child_lock", tuya.valueConverter.lockUnlock],
//[11, 'unknown', null],
[19, "local_temperature_calibration", tuya.valueConverterBasic.divideBy(1)],
[102, "running_state", tuya.valueConverterBasic.lookup({ heat: 0, idle: 1 })],
],
},
},
{
fingerprint: tuya.fingerprint("TS0003", ["_TZ3000_g9chy2ib"]),
model: "TS0003_3_gang_switch",
vendor: "Tuya",
description: "3 gang switch with backlight",
extend: [
tuya.modernExtend.tuyaOnOff({
powerOnBehavior2: true,
backlightModeOffOn: true,
onOffCountdown: true,
endpoints: ["l1", "l2", "l3"],
}),
],
fromZigbee: [],
toZigbee: [],
endpoint: (device) => ({ l1: 1, l2: 2, l3: 3 }),
meta: {
multiEndpoint: true,
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_ezqbvrqz", "_TZ3002_ymv5vytn"]),
model: "TS0726_2_gang_scene_switch",
vendor: "Tuya",
description: "2 gang switch with scene and backlight",
fromZigbee: [fz.ignore_basic_report, fzLocal.TS0726_action],
exposes: [e.action(["scene_1", "scene_2"])],
extend: [
tuya.modernExtend.tuyaOnOff({
switchMode: true,
powerOnBehavior2: true,
backlightModeOffOn: true,
indicatorModeNoneRelayPos: true,
onOffCountdown: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => ({ l1: 1, l2: 2 }),
meta: {
multiEndpoint: true,
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_noru9tix", "_TZ3002_rbnycsav"]),
model: "TS0726_3_gang_scene_switch",
vendor: "Tuya",
description: "3 gang switch with scene and backlight",
fromZigbee: [fz.ignore_basic_report, fzLocal.TS0726_action],
exposes: [e.action(["scene_1", "scene_2", "scene_3"])],
extend: [
tuya.modernExtend.tuyaOnOff({
switchMode: true,
powerOnBehavior2: true,
backlightModeOffOn: true,
indicatorModeNoneRelayPos: true,
onOffCountdown: true,
endpoints: ["l1", "l2", "l3"],
}),
],
endpoint: (device) => ({ l1: 1, l2: 2, l3: 3 }),
meta: {
multiEndpoint: true,
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_rsylfthg"]),
model: "TS0726_4_gang_scene_switch",
vendor: "Tuya",
description: "4 gang switch with scene and backlight",
fromZigbee: [fz.ignore_basic_report, fzLocal.TS0726_action],
exposes: [e.action(["scene_1", "scene_2", "scene_3", "scene_4"])],
extend: [
tuya.modernExtend.tuyaOnOff({
switchMode: true,
powerOnBehavior2: true,
backlightModeOffOn: true,
indicatorModeNoneRelayPos: true,
onOffCountdown: true,
endpoints: ["l1", "l2", "l3", "l4"],
}),
],
endpoint: (device) => ({ l1: 1, l2: 2, l3: 3, l4: 4 }),
meta: {
multiEndpoint: true,
},
configure: async (device, coordinatorEndpoint) => {
await tuya.configureMagicPacket(device, coordinatorEndpoint);
for (const ep of [1, 2, 3, 4]) {
await reporting.bind(device.getEndpoint(ep), coordinatorEndpoint, ["genOnOff"]);
}
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_oc7xqqbs"]),
model: "HY-SZLUMPIR",
vendor: "Homcloud",
description: "PIR sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEvent(),
configure: tuya.configureMagicPacket,
exposes: [e.occupancy(), e.illuminance(), e.battery()],
meta: {
tuyaDatapoints: [
[1, "occupancy", tuya.valueConverter.trueFalse0],
[4, "battery", tuya.valueConverter.raw],
[101, "illuminance", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_1drr8tab"]),
model: "XZ-AKT101",
vendor: "Tuya",
description: "Intelligent air conditioning wall switch",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
ota: true,
exposes: [
e.binary("air_switch", ea.STATE_SET, true, false),
e.child_lock(),
e
.climate()
.withLocalTemperature(ea.STATE)
.withSetpoint("current_heating_setpoint", 20, 30, 0.5, ea.STATE_SET)
.withSystemMode(["cool", "heat", "fan_only"], ea.STATE_SET, "Only for Homeassistant")
.withFanMode(["low", "medium", "high", "auto"]),
e
.numeric("boost_time", ea.STATE_SET)
.withUnit("H")
.withDescription("Boost running time. Minimum 0 - maximum 24 hours")
.withValueMin(0)
.withValueMax(24)
.withValueStep(0.5)
.withCategory("config"),
],
meta: {
tuyaDatapoints: [
[1, "air_switch", tuya.valueConverter.raw],
[
2,
"system_mode",
tuya.valueConverterBasic.lookup({
heat: tuya.enum(1),
cool: tuya.enum(0),
fan_only: tuya.enum(2),
}),
],
[
28,
"fan_mode",
tuya.valueConverterBasic.lookup({
low: tuya.enum(0),
medium: tuya.enum(1),
high: tuya.enum(2),
auto: tuya.enum(3),
}),
],
[16, "current_heating_setpoint", tuya.valueConverter.divideBy10],
[24, "local_temperature", tuya.valueConverter.divideBy10],
[40, "child_lock", tuya.valueConverter.lockUnlock],
[101, "boost_time", tuya.valueConverter.divideBy10],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_jcwbwckh"]),
model: "ZBN-JT-63",
vendor: "Tuya",
description: "Din rail switch with power monitoring",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
tuya.exposes.switch(),
e.numeric("power", ea.STATE).withDescription("power").withUnit("W").withDescription("Instantaneous measured power"),
e.numeric("current", ea.STATE).withDescription("current").withUnit("A").withDescription("Instantaneous measured electrical current"),
e.numeric("voltage", ea.STATE).withDescription("voltage").withUnit("V").withDescription("Measured electrical potential value"),
e.numeric("energy", ea.STATE).withDescription("energy").withUnit("kWh").withDescription("Consumed energy"),
e.enum("power_outage_memory", ea.STATE_SET, ["on", "off", "restore"]).withDescription("Recover state after power outage"),
e
.enum("fault", ea.STATE, [
"clear",
"short_circuit_alarm",
"surge_alarm",
"overload_alarm",
"leakagecurr_alarm",
"temp_dif_fault",
"fire_alarm",
"high_power_alarm",
"self_test_alarm",
"ov_cr",
"unbalance_alarm",
"ov_vol",
"undervoltage_alarm",
"miss_phase_alarm",
"outage_alarm",
"magnetism_alarm",
"credit_alarm",
"no_balance_alarm",
])
.withDescription("Fault status of the device (clear = nothing)"),
e.text("meter_id", ea.STATE).withDescription("Meter ID (ID of device)"),
],
meta: {
tuyaDatapoints: [
[1, "energy", tuya.valueConverter.divideBy100],
[3, null, null],
[4, null, null],
[6, null, tuya.valueConverter.phaseVariant3],
[
10,
"fault",
tuya.valueConverterBasic.lookup({
clear: 0,
ov_cr: 1,
unbalance_alarm: 2,
ov_vol: 4,
undervoltage_alarm: 8,
miss_phase_alarm: 16,
outage_alarm: 32,
magnetism_alarm: 64,
terminal_alarm: 128,
cover_alarm: 256,
credit_alarm: 512,
no_balance_alarm: 1024,
battery_alarm: 2048,
meter_hardware_alarm: 4096,
}),
],
[16, "state", tuya.valueConverter.onOff],
[
18,
"meter_id",
{
from: (v) => {
if (typeof v === "object") {
const buf = Buffer.from([v[0], v[1], v[2], v[3]]);
return buf.readUInt32BE();
}
return v;
},
},
],
[
23,
"power_outage_memory",
tuya.valueConverterBasic.lookup({
on: 0,
off: 1,
restore: 2,
}),
],
],
},
},
{
zigbeeModel: ["5rta89nj"],
fingerprint: [{ modelID: "TS0601", manufacturerName: "_TZ3210_emqmwtym" }],
model: "EPJ-ZB",
vendor: "Nova Digital",
description: "Smart sliding window pusher",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.cover_position(),
e.binary("charge_state", ea.STATE, "true", "false"),
e.enum("manual_mode", ea.STATE_SET, ["Enable", "Disable"]),
e.enum("fault", ea.STATE, ["Normal", "None", "Fault"]).withDescription("Motor Fault"),
e.numeric("countdown", ea.STATE_SET).withValueMin(10).withValueMax(90).withUnit("s").withDescription("Motor timeout"),
e.enum("motor_direction", ea.STATE_SET, ["Left Side", "Right Side"]).withDescription("Pusher install side"),
e.enum("mode", ea.STATE_SET, ["Enable", "Disable"]).withDescription("Slow stop mode"),
e.enum("fixed_window_sash", ea.STATE_SET, ["Up", "Down"]).withDescription("Button position"),
e.enum("window_detection", ea.STATE, ["Opened", "Closed", "Pending"]).withDescription("Window detection status"),
],
meta: {
tuyaSendCommand: "sendData",
tuyaDatapoints: [
[4, "battery", tuya.valueConverter.raw],
[102, "state", tuya.valueConverterBasic.lookup({ OPEN: 0, CLOSE: 1, STOP: 2 })],
[104, "position", tuya.valueConverter.coverPosition],
[105, "charge_state", tuya.valueConverter.trueFalse1],
[106, "manual_mode", tuya.valueConverterBasic.lookup({ Enable: 0, Disable: 1 })],
[107, "fault", tuya.valueConverterBasic.lookup({ Normal: 0, None: 1, Fault: 2 })],
[108, "countdown", tuya.valueConverter.raw],
[109, "motor_direction", tuya.valueConverterBasic.lookup({ "Left Side": 1, "Right Side": 0 })],
[110, "mode", tuya.valueConverterBasic.lookup({ Enable: 1, Disable: 0 })],
[112, "fixed_window_sash", tuya.valueConverterBasic.lookup({ Up: 1, Down: 0 })],
[114, "window_detection", tuya.valueConverterBasic.lookup({ Opened: 0, Closed: 1, Pending: 2 })],
],
},
},
{
zigbeeModel: ["ZG-102ZM"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wzk0x7fq"]),
model: "ZG-102ZM",
vendor: "HOBEIAN",
description: "Vibration sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.vibration(),
e.contact(),
e.battery(),
e
.numeric("sensitivity", ea.STATE_SET)
.withValueMin(1)
.withValueMax(50)
.withValueStep(1)
.withUnit("x")
.withDescription("The larger the value, the more sensitive it is (refresh and update only while active)"),
],
meta: {
tuyaDatapoints: [
[1, "vibration", tuya.valueConverter.trueFalse1],
[101, "contact", tuya.valueConverter.inverse],
[4, "battery", tuya.valueConverter.raw],
[6, "sensitivity", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-204ZV"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_uli8wasj", "_TZE200_grgol3xp", "_TZE200_rhgsbacq", "_TZE200_y8jijhba"]),
model: "ZG-204ZV",
vendor: "HOBEIAN",
description: "Millimeter wave motion detection",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.presence(),
e.illuminance(),
e.temperature(),
e.humidity(),
tuya.exposes.temperatureUnit(),
tuya.exposes.temperatureCalibration(),
tuya.exposes.humidityCalibration(),
e.battery(),
e
.numeric("fading_time", ea.STATE_SET)
.withValueMin(0)
.withValueMax(28800)
.withValueStep(1)
.withUnit("s")
.withDescription("Motion keep time"),
e.binary("indicator", ea.STATE_SET, "ON", "OFF").withDescription("LED indicator mode"),
e
.numeric("illuminance_interval", ea.STATE_SET)
.withValueMin(1)
.withValueMax(720)
.withValueStep(1)
.withUnit("minutes")
.withDescription("Light sensing sampling(refresh and update only while active)"),
e
.numeric("motion_detection_sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(19)
.withValueStep(1)
.withUnit("x")
.withDescription("The larger the value, the more sensitive it is (refresh and update only while active)"),
],
meta: {
tuyaDatapoints: [
[1, "presence", tuya.valueConverter.trueFalse1],
[106, "illuminance", tuya.valueConverter.raw],
[102, "fading_time", tuya.valueConverter.raw],
[2, "motion_detection_sensitivity", tuya.valueConverter.raw],
[108, "indicator", tuya.valueConverter.onOff],
[110, "battery", tuya.valueConverter.raw],
[111, "temperature", tuya.valueConverter.divideBy10],
[101, "humidity", tuya.valueConverter.raw],
[109, "temperature_unit", tuya.valueConverter.temperatureUnit],
[105, "temperature_calibration", tuya.valueConverter.divideBy10],
[104, "humidity_calibration", tuya.valueConverter.raw],
[107, "illuminance_interval", tuya.valueConverter.raw],
],
},
},
{
zigbeeModel: ["ZG-223Z"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_jsaqgakf"]),
model: "ZG-223Z",
vendor: "HOBEIAN",
description: "Rainwater detection sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.enum("rainwater", ea.STATE, ["none", "raining"]).withDescription("Sensor rainwater status"),
e.illuminance().withUnit("x"),
e
.numeric("sensitivity", ea.STATE_SET)
.withValueMin(0)
.withValueMax(9)
.withValueStep(1)
.withUnit("x")
.withDescription("The larger the value, the more sensitive it is (refresh and update only while active)"),
e
.numeric("illuminance_sampling", ea.STATE_SET)
.withValueMin(1)
.withValueMax(480)
.withValueStep(1)
.withUnit("minutes")
.withDescription("Brightness acquisition interval (refresh and update only while active)"),
e.battery(),
],
meta: {
tuyaDatapoints: [
[
1,
"rainwater",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
raining: tuya.enum(1),
}),
],
[102, "illuminance", tuya.valueConverter.raw],
[104, "battery", tuya.valueConverter.raw],
[2, "sensitivity", tuya.valueConverter.raw],
[101, "illuminance_sampling", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE204_no6qtgtl"]),
model: "RD24G01",
vendor: "Tuya",
description: "24GHz human presence sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
exposes: [
exposes
.enum("presence_state", exposes.access.STATE, ["none", "motion", "stationary"])
.withDescription("Presence state: none, motion, or stationary"),
exposes.numeric("target_distance_closest", exposes.access.STATE).withUnit("m").withDescription("Closest target distance"),
exposes
.numeric("near_detection", exposes.access.STATE_SET)
.withUnit("m")
.withDescription("Minimum detection range")
.withValueMin(0.1)
.withValueMax(6),
exposes
.numeric("far_detection", exposes.access.STATE_SET)
.withUnit("m")
.withDescription("Maximum detection range")
.withValueMin(0.1)
.withValueMax(6),
exposes
.numeric("static_sensitivity", exposes.access.STATE_SET)
.withDescription("Static presence sensitivity")
.withValueMin(0)
.withValueMax(10),
exposes.numeric("motion_sensitivity", exposes.access.STATE_SET).withDescription("Motion sensitivity").withValueMin(0).withValueMax(10),
],
meta: {
tuyaDatapoints: [
[
1,
"presence_state",
tuya.valueConverterBasic.lookup({
none: 0,
motion: 1,
stationary: 2,
}),
],
[3, "near_detection", tuya.valueConverter.divideBy100],
[4, "far_detection", tuya.valueConverter.divideBy100],
[9, "target_distance_closest", tuya.valueConverter.divideBy100],
[101, "static_sensitivity", tuya.valueConverter.raw],
[102, "motion_sensitivity", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_gubdgai2", "_TZE200_vdiuwbkq"]),
model: "M515EGBZTN",
vendor: "Quoya",
description: "Zigbee roller blind",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetTime,
configure: tuya.configureMagicPacket,
options: [exposes.options.invert_cover()],
exposes: [
e.cover_position().setAccess("position", ea.STATE_SET),
e.enum("motor_direction", ea.STATE_SET, ["forward", "back"]).withDescription("Motor direction"),
e.enum("border", ea.STATE_SET, ["up", "down", "up_delete", "down_delete", "remove_top_bottom"]).withDescription("Limit setting"),
],
meta: {
tuyaDatapoints: [
[
1,
"state",
tuya.valueConverterBasic.lookup({
OPEN: tuya.enum(0),
STOP: tuya.enum(1),
CLOSE: tuya.enum(2),
}),
],
[2, "position", tuya.valueConverter.coverPositionInverted],
[
5,
"motor_direction",
tuya.valueConverterBasic.lookup({
forward: tuya.enum(0),
back: tuya.enum(1),
}),
],
[
16,
"border",
tuya.valueConverterBasic.lookup({
up: tuya.enum(0),
down: tuya.enum(1),
up_delete: tuya.enum(2),
down_delete: tuya.enum(3),
remove_top_bottom: tuya.enum(4),
}),
],
],
},
},
{
zigbeeModel: ["ZG-303Z"],
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_npj9bug3"]),
model: "CS-201Z",
vendor: "COOLO",
description: "Soil moisture sensor",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.enum("water_warning", ea.STATE, ["none", "alarm"]).withDescription("Water shortage warning"),
e.temperature(),
e.humidity(),
e.soil_moisture(),
tuya.exposes.temperatureUnit(),
tuya.exposes.temperatureCalibration(),
tuya.exposes.humidityCalibration(),
tuya.exposes.soilCalibration(),
tuya.exposes.temperatureSampling(),
tuya.exposes.soilSampling(),
tuya.exposes.soilWarning(),
e.battery(),
],
meta: {
tuyaDatapoints: [
[
106,
"water_warning",
tuya.valueConverterBasic.lookup({
none: tuya.enum(0),
alarm: tuya.enum(1),
}),
],
[5, "temperature", tuya.valueConverter.divideBy10],
[109, "humidity", tuya.valueConverter.raw],
[3, "soil_moisture", tuya.valueConverter.raw],
[15, "battery", tuya.valueConverter.raw],
[9, "temperature_unit", tuya.valueConverter.temperatureUnit],
[104, "temperature_calibration", tuya.valueConverter.divideBy10],
[105, "humidity_calibration", tuya.valueConverter.raw],
[102, "soil_calibration", tuya.valueConverter.raw],
[111, "temperature_sampling", tuya.valueConverter.raw],
[112, "soil_sampling", tuya.valueConverter.raw],
[110, "soil_warning", tuya.valueConverter.raw],
],
},
},
{
fingerprint: tuya.fingerprint("TS0001", ["_TZE21C_dohbhb5k"]),
model: "TYONOFFTS",
vendor: "Scimagic",
description: "Smart switch with temperature sensor",
extend: [
tuya.modernExtend.tuyaMagicPacket(),
tuya.modernExtend.dpOnOff({
dp: 0x02,
}),
tuya.modernExtend.dpTemperature({ dp: 0x1b }),
tuya.modernExtend.dpNumeric({
dp: 0x1e,
name: "temperature_calibration",
type: tuya.dataTypes.number,
valueMin: -10,
valueMax: 10,
valueStep: 0.5,
unit: "°C",
scale: 2,
description: "Temperature calibration",
}),
tuya.modernExtend.dpNumeric({
dp: 0x1d,
name: "temperature_range",
type: tuya.dataTypes.number,
valueMin: 1,
valueMax: 10,
valueStep: 0.1,
unit: "°C",
scale: 10,
description: "Keep the temperature in a range",
}),
tuya.modernExtend.dpBinary({
name: "auto_work",
dp: 0x09,
type: tuya.dataTypes.bool,
valueOn: ["ON", true],
valueOff: ["OFF", false],
description: "Auto work mode",
}),
tuya.modernExtend.dpNumeric({
dp: 0x16,
name: "temperature_target",
type: tuya.dataTypes.number,
valueMin: -100,
valueMax: 100,
valueStep: 0.5,
unit: "°C",
scale: 10,
description: "Temperature target",
}),
tuya.modernExtend.dpEnumLookup({
dp: 0x08,
name: "mode",
type: tuya.dataTypes.enum,
lookup: { Heating: 0, Cooling: 2 },
description: "Work mode",
}),
tuya.modernExtend.dpBinary({
name: "delay",
dp: 0x38,
type: tuya.dataTypes.bool,
valueOn: ["ON", 1],
valueOff: ["OFF", 0],
description: "Switch delay time mode",
}),
tuya.modernExtend.dpNumeric({
dp: 0x37,
name: "delay_time",
type: tuya.dataTypes.number,
valueMin: 0,
valueMax: 10,
valueStep: 1,
unit: "minute",
scale: 1,
description: "Switch delay time",
}),
],
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_5ys44kzo"]),
model: "TYSCENECUBE",
vendor: "iHseno",
description: "Scene cube",
extend: [
tuya.modernExtend.tuyaMagicPacket(),
...convLocal.sceneCubeAction(),
tuya.modernExtend.dpBattery({
dp: 0x0a,
}),
],
},
{
fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_rul9yxcc"]),
model: "SM-PW801EZ",
vendor: "Coswall",
description: "2 gang switch with USB",
ota: true,
extend: [
tuya.modernExtend.tuyaOnOff({
childLock: true,
endpoints: ["l1", "l2"],
}),
],
endpoint: (device) => {
return { l1: 1, l2: 2 };
},
meta: {
multiEndpoint: true,
multiEndpointSkip: ["power_on_behavior"],
},
configure: tuya.configureMagicPacket,
},
{
fingerprint: tuya.fingerprint("TS0601", ["_TZE284_tgeqdjgk"]),
model: "TS0601_knob_dimmer_switch",
vendor: "Tuya",
description: "Dimmer knob with two lights",
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
exposes: [
e.switch().withEndpoint("l1"),
e.switch().withEndpoint("l2"),
e.light_brightness_colortemp([154, 370]),
e.enum("adjustment_mode", ea.STATE_SET, ["brightness", "color_temp"]).withDescription("Adjustment mode"),
],
meta: {
tuyaDatapoints: [
[102, "state", tuya.valueConverter.onOff],
[103, "brightness", tuya.valueConverter.raw],
[105, "adjustment_mode", tuya.valueConverterBasic.lookup({ brightness: tuya.enum(0), color_temp: tuya.enum(1) })],
[107, "color_temp", tuya.valueConverterBasic.scale(154, 370, 0, 1000)],
[121, "state_l1", tuya.valueConverter.onOff],
[122, "state_l2", tuya.valueConverter.onOff],
],
},
configure: tuya.configureMagicPacket,
endpoint: (device) => ({ default: 1 }),
},
];
//# sourceMappingURL=tuya.js.map