Skip to content

Instantly share code, notes, and snippets.

@ShadowBelmolve
Created August 13, 2025 02:45
Show Gist options
  • Select an option

  • Save ShadowBelmolve/8eac1e793c33985ade1cec7e44051115 to your computer and use it in GitHub Desktop.

Select an option

Save ShadowBelmolve/8eac1e793c33985ade1cec7e44051115 to your computer and use it in GitHub Desktop.
Modified version of Z2M TS001F for use with Girier and Zbeacon versions
import * as tuya from 'zigbee-herdsman-converters/lib/tuya';
import * as fz from 'zigbee-herdsman-converters/converters/fromZigbee';
import * as reporting from 'zigbee-herdsman-converters/lib/reporting';
import * as utils from 'zigbee-herdsman-converters/lib/utils';
import * as globalStore from 'zigbee-herdsman-converters/lib/store';
const fzLocal = {
TS011F_electrical_measurement: {
...fz.electrical_measurement,
convert: (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;
},
}
}
export default {
// 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("BSEED", "FK86ZEUSK1W", "Wall-mounted electrical socket", ["_TZ3000_4ux0ondb"]),
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"]),
tuya.whitelabel("Nous", "A7Z", "Smart ZigBee Socket", ["_TZ3210_rwmitwj4"]),
tuya.whitelabel("Zbeacon", "TS011F_plug_1", "Smart plug (with power monitoring)", ["Zbeacon"]),
],
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", "_TZ3000_ww6drja5", "Zbeacon"].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();
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment