Replies: 7 comments 6 replies
-
This would be amazing if it could be disabled! 😁 |
Beta Was this translation helpful? Give feedback.
-
|
yes child lock and led status are available on the Tretakt socket |
Beta Was this translation helpful? Give feedback.
-
|
I will dive a bit into this. Not sure how far I will be able to help |
Beta Was this translation helpful? Give feedback.
-
|
So, my definition works correctly on the TRETAKT. By the end of the week, I will have the opportunity to get an INSPELNING plug to test it as well. I would then be able, in a few days, to merge this work to Z2M... |
Beta Was this translation helpful? Give feedback.
-
|
For those interested to try, below are two definitions for the Tretakt and the Inspelning plug with the extra features supported. I still need to find a way to add those according to the firmware build. When this will be sorted, I would be able to submit a PR. TRETAKT: import {Zcl} from "zigbee-herdsman";
import * as m from "zigbee-herdsman-converters/lib/modernExtend";
import {addCustomClusterManuSpecificIkeaUnknown} from "zigbee-herdsman-converters/lib/ikea";
import {access, presets} from "zigbee-herdsman-converters/lib/exposes";
import {assertString} from "zigbee-herdsman-converters/lib/utils";
export const manufacturerOptions = {manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN};
export function ikeaSmartPlug() {
const exposes = [
presets.binary("child_lock", access.ALL, "LOCK", "UNLOCK").withDescription("Controls physical input on the device").withCategory("config"),
presets.binary("led_enable", access.ALL, "TRUE", "FALSE").withDescription("Controls the LED").withCategory("config"),
];
const fromZigbee = [
{
cluster: "manuSpecificIkeaSmartPlug",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const state = {};
if (msg.data.childLock !== undefined) {
state.child_lock = msg.data.childLock === 0 ? "UNLOCK" : "LOCK";
}
if (msg.data.ledEnable !== undefined) {
state.led_enable = msg.data.ledEnable === 1 ? "TRUE" : "FALSE";
}
return state;
},
},
];
const toZigbee = [
{
key: ["child_lock"],
convertSet: async (entity, key, value, meta) => {
assertString(value);
await entity.write(
"manuSpecificIkeaSmartPlug",
{childLock: value.toLowerCase() === "unlock" ? 0 : 1},
manufacturerOptions,
);
return {state: {child_lock: value.toLowerCase() === "lock" ? "LOCK" : "UNLOCK"}};
},
convertGet: async (entity, key, meta) => {
await entity.read("manuSpecificIkeaSmartPlug", ["childLock"]);
},
},
{
key: ["led_enable"],
convertSet: async (entity, key, value, meta) => {
assertString(value);
await entity.write(
"manuSpecificIkeaSmartPlug",
{ledEnable: value.toLowerCase() === "false" ? 0 : 1},
manufacturerOptions,
);
return {state: {led_enable: value.toLowerCase() === "false" ? "FALSE" : "TRUE"}};
},
convertGet: async (entity, key, meta) => {
await entity.read("manuSpecificIkeaSmartPlug", ["ledEnable"]);
},
},
];
const configure = [
async (device, coordinatorEndpoint, definition) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("manuSpecificIkeaSmartPlug", [
"childLock",
"ledEnable",
]);
},
];
return {exposes, fromZigbee, toZigbee, configure, isModernExtend: true};
}
export function addCustomClusterManuSpecificIkeaSmartPlug() {
return m.deviceAddCustomCluster("manuSpecificIkeaSmartPlug", {
ID: 0xfc85,
manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN,
attributes: {
childLock: {ID: 0x0000, type: Zcl.DataType.BOOLEAN},
ledEnable: {ID: 0x0001, type: Zcl.DataType.BOOLEAN},
},
commands: {},
commandsResponse: {},
});
}
export default {
zigbeeModel: ["TRETAKT Smart plug"],
model: "E22x4",
vendor: "IKEA",
description: "TRETAKT smart plug",
whiteLabel: [
{model: "E2204", vendor: "IKEA", description: "TRETAKT smart plug (EU)"},
{model: "E2214", vendor: "IKEA", description: "TRETAKT smart plug (CH)"},
],
extend: [
addCustomClusterManuSpecificIkeaSmartPlug(),
addCustomClusterManuSpecificIkeaUnknown(),
m.onOff(),
ikeaSmartPlug(),
m.identify(),
],
ota: true,
};INSPELNING import {Zcl} from "zigbee-herdsman";
import * as m from "zigbee-herdsman-converters/lib/modernExtend";
import {addCustomClusterManuSpecificIkeaUnknown} from "zigbee-herdsman-converters/lib/ikea";
import {access, presets} from "zigbee-herdsman-converters/lib/exposes";
import {assertString} from "zigbee-herdsman-converters/lib/utils";
import {repInterval} from "zigbee-herdsman-converters/lib/constants";
export const manufacturerOptions = {manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN};
export function ikeaSmartPlug() {
const exposes = [
presets.binary("child_lock", access.ALL, "LOCK", "UNLOCK").withDescription("Controls physical input on the device").withCategory("config"),
presets.binary("led_enable", access.ALL, "TRUE", "FALSE").withDescription("Controls the LED").withCategory("config"),
];
const fromZigbee = [
{
cluster: "manuSpecificIkeaSmartPlug",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const state = {};
if (msg.data.childLock !== undefined) {
state.child_lock = msg.data.childLock === 0 ? "UNLOCK" : "LOCK";
}
if (msg.data.ledEnable !== undefined) {
state.led_enable = msg.data.ledEnable === 1 ? "TRUE" : "FALSE";
}
return state;
},
},
];
const toZigbee = [
{
key: ["child_lock"],
convertSet: async (entity, key, value, meta) => {
assertString(value);
await entity.write(
"manuSpecificIkeaSmartPlug",
{childLock: value.toLowerCase() === "unlock" ? 0 : 1},
manufacturerOptions,
);
return {state: {child_lock: value.toLowerCase() === "lock" ? "LOCK" : "UNLOCK"}};
},
convertGet: async (entity, key, meta) => {
await entity.read("manuSpecificIkeaSmartPlug", ["childLock"]);
},
},
{
key: ["led_enable"],
convertSet: async (entity, key, value, meta) => {
assertString(value);
await entity.write(
"manuSpecificIkeaSmartPlug",
{ledEnable: value.toLowerCase() === "false" ? 0 : 1},
manufacturerOptions,
);
return {state: {led_enable: value.toLowerCase() === "false" ? "FALSE" : "TRUE"}};
},
convertGet: async (entity, key, meta) => {
await entity.read("manuSpecificIkeaSmartPlug", ["ledEnable"]);
},
},
];
const configure = [
async (device, coordinatorEndpoint, definition) => {
const endpoint = device.getEndpoint(1);
await endpoint.read("manuSpecificIkeaSmartPlug", [
"childLock",
"ledEnable",
]);
},
];
return {exposes, fromZigbee, toZigbee, configure, isModernExtend: true};
}
export function addCustomClusterManuSpecificIkeaSmartPlug() {
return m.deviceAddCustomCluster("manuSpecificIkeaSmartPlug", {
ID: 0xfc85,
manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN,
attributes: {
childLock: {ID: 0x0000, type: Zcl.DataType.BOOLEAN},
ledEnable: {ID: 0x0001, type: Zcl.DataType.BOOLEAN},
},
commands: {},
commandsResponse: {},
});
}
export default {
zigbeeModel: ["INSPELNING Smart plug"],
model: "E2206",
vendor: "IKEA",
description: "INSPELNING smart plug",
whiteLabel: [
{model: "E2220", vendor: "IKEA", description: "INSPELNING smart plug (US)"},
{model: "E2224", vendor: "IKEA", description: "INSPELNING smart plug (CH)"},
],
extend: [
addCustomClusterManuSpecificIkeaSmartPlug(),
addCustomClusterManuSpecificIkeaUnknown(),
m.onOff(),
ikeaSmartPlug(),
m.identify(),
m.electricityMeter(),
],
ota: true,
configure: async (device) => {
const endpoint = device.getEndpoint(1);
// Enable reporting of powerDivisor, needs to change dynamically with the amount of power
// For details, see: https://github.com/Koenkk/zigbee2mqtt/issues/23961#issuecomment-2366733453
await endpoint.configureReporting("haElectricalMeasurement", [
{attribute: "acPowerDivisor", minimumReportInterval: 10, maximumReportInterval: repInterval.MAX, reportableChange: 1},
]);
},
};@Koenkk, I am really sorry to ping you directly. Would you have any idea how I could implement an |
Beta Was this translation helpful? Give feedback.
-
|
I continued to look in the different converters, Finally, this is the cleanest way I found to have those functions added. It passes all the tests in a ZHC codespace. So both the javascrip and typscript codes seem good to me. import {Zcl} from "zigbee-herdsman";
import {gte as semverGte, valid as semverValid} from "semver";
import {access, binary} from "zigbee-herdsman-converters/lib/exposes";
import * as m from "zigbee-herdsman-converters/lib/modernExtend";
import {addCustomClusterManuSpecificIkeaUnknown} from "zigbee-herdsman-converters/lib/ikea";
import {isDummyDevice} from "zigbee-herdsman-converters/lib/utils";
export const manufacturerOptions = {manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN};
function addCustomClusterManuSpecificIkeaSmartPlug() {
return m.deviceAddCustomCluster("manuSpecificIkeaSmartPlug", {
ID: 0xfc85,
manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN,
attributes: {
childLock: {ID: 0x0000, type: Zcl.DataType.BOOLEAN},
ledEnable: {ID: 0x0001, type: Zcl.DataType.BOOLEAN},
},
commands: {},
commandsResponse: {},
});
}
const ikeaModernExtend = {
smartPlugChildLock: (args) => {
const resultName = "child_lock";
const resultDescription = "Enables/disables physical input on the device.";
const result = m.binary({
name: resultName,
cluster: "manuSpecificIkeaSmartPlug",
attribute: {ID: 0x0000, type: Zcl.DataType.BOOLEAN},
entityCategory: "config",
valueOff: ["UNLOCK", 0x00],
valueOn: ["LOCK", 0x01],
description: resultDescription,
zigbeeCommandOptions: {manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN},
});
result.exposes = [
(device, options) => {
if (
!isDummyDevice(device) &&
device.softwareBuildID &&
semverValid(device.softwareBuildID) &&
semverGte(device.softwareBuildID, "2.4.25")
) {
return [binary(resultName, access.ALL, "LOCK", "UNLOCK").withDescription(resultDescription).withCategory("config")];
}
return [];
},
];
return result;
},
smartPlugLedEnable: (args) => {
const resultName = "led_enable";
const resultDescription = "Enables/disables the led on the device.";
const result = m.binary({
name: resultName,
cluster: "manuSpecificIkeaSmartPlug",
attribute: {ID: 0x0001, type: Zcl.DataType.BOOLEAN},
entityCategory: "config",
valueOff: ["FALSE", 0x00],
valueOn: ["TRUE", 0x01],
description: resultDescription,
zigbeeCommandOptions: {manufacturerCode: Zcl.ManufacturerCode.IKEA_OF_SWEDEN},
});
result.exposes = [
(device, options) => {
if (
!isDummyDevice(device) &&
device.softwareBuildID &&
semverValid(device.softwareBuildID) &&
semverGte(device.softwareBuildID, "2.4.25")
) {
return [binary(resultName, access.ALL, "TRUE", "FALSE").withDescription(resultDescription).withCategory("config")];
}
return [];
},
];
return result;
},
};
export default {
zigbeeModel: ["TRETAKT Smart plug"],
model: "E22x4",
vendor: "IKEA",
description: "TRETAKT smart plug",
whiteLabel: [
{model: "E2204", vendor: "IKEA", description: "TRETAKT smart plug (EU)"},
{model: "E2214", vendor: "IKEA", description: "TRETAKT smart plug (CH)"},
],
extend: [
addCustomClusterManuSpecificIkeaSmartPlug(),
addCustomClusterManuSpecificIkeaUnknown(),
m.onOff(),
ikeaModernExtend.smartPlugChildLock(),
ikeaModernExtend.smartPlugLedEnable(),
m.identify(),
],
ota: true,
}; |
Beta Was this translation helpful? Give feedback.
-
|
PR on its way.... Let's hope I have done it correctly. |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
Hey there - I'm currently writing a ZHA quirk for this - Just wanted to let you people know that my Inspelning plugs on firmware 2.4.45 have a Child Lock and Disabling of Status LEDs feature. I'm expecting it to work the same way on Tretakt plugs, but I don't own one to test it out.
Cluster:
0xFC85, manufacturer-specific, one needs to send the manufacturer ID (4476in my case, I'm assuming this is constant).Attributes :
0x0000: Boolean, Enable Child Lock, default False (0) (disables hardware button when on)0x0001: Boolean, Enable Status LED, default True (1)cc @oneseventhree who asked in #23961 about the LED feature: I have successfully been able to deactivate the status LED on my Inspelning. Personally I don't know how to add this functionality to z2m, I hope other people here can help :)
Beta Was this translation helpful? Give feedback.
All reactions