-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Link
https://engocontrols.com/en/produkt/eone-230w-3/
Database entry
{"id":2,"type":"Router","ieeeAddr":"0xbc026efffe2c183d","nwkAddr":15651,"manufId":4098,"manufName":"_TZE204_ca3i8m8p","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,61184],"outClusterList":[25,10,3,6],"clusters":{"genBasic":{"attributes":{"65503":"���0i","65506":31,"65508":0,"modelId":"TS0601","manufacturerName":"_TZE204_ca3i8m8p","stackVersion":0,"dateCode":"","appVersion":69}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x7cc6b6fffef79d7c","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":69,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"interviewState":"SUCCESSFUL","meta":{"configured":332242049},"lastSeen":1762709068871}
Zigbee2MQTT version
2.6.3
External converter
// External converter for EONE Zigbee thermostat (_TZE204_xxxx)
// Features:
// - Automatic clock synchronization at startup and daily at 03:00
// - Dynamic backlight brightness (day/night) with auto-update every minute
// - Reads weekly schedule on startup
// - Applies all optional settings automatically
// - Detailed console logging for debugging
// - Handles device reconnection (deviceAnnounce)
// - Automatically marks router as supported
// - Retry loop for initialization if device doesn't respond immediately
// Works with Zigbee2MQTT 2.6.x and newer
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const e = exposes.presets;
const ea = exposes.access;
// --- Toggle optional advanced features here ---
const optionalFeatures = false; //-----> true onlocks all features <-----
// --- Helper functions ---
async function retryOperation(operation, retries = 5, delayMs = 15000) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
await operation();
return true;
} catch (err) {
console.warn(`[EONE][RETRY] Attempt ${attempt} failed:`, err);
if (attempt < retries) {
await new Promise(res => setTimeout(res, delayMs));
} else {
console.error('[EONE][RETRY] Max retries reached.');
}
}
}
}
async function syncTime(device, timeDP = 107) {
await retryOperation(async () => {
const now = new Date();
const payload = {
year: now.getFullYear(),
month: now.getMonth() + 1,
day: now.getDate(),
hour: now.getHours(),
minute: now.getMinutes(),
second: now.getSeconds(),
};
console.log('[EONE] Sending time sync to thermostat:', payload);
await tuya.sendDataPointValue(device.getEndpoint(1), timeDP, payload);
console.log('[EONE] ✅ Time sync complete');
});
}
async function updateBacklight(device, endpoint = null) {
await retryOperation(async () => {
if (!endpoint) endpoint = device.getEndpoint(1);
const BACKLIGHT_DP_CANDIDATES = [44, 102, 108];
const validBacklightDP = BACKLIGHT_DP_CANDIDATES.find(dp => endpoint.clusters.find(c => c.ID === dp) !== undefined) || 44;
const hour = new Date().getHours();
const DAY_START = 8;
const NIGHT_START = 18;
const DAY_BRIGHTNESS = 80;
const NIGHT_BRIGHTNESS = 30;
const brightness = (hour >= DAY_START && hour < NIGHT_START) ? DAY_BRIGHTNESS : NIGHT_BRIGHTNESS;
await tuya.sendDataPointValue(endpoint, validBacklightDP, brightness);
console.log(`[EONE] ✅ Backlight DPID ${validBacklightDP} updated to ${brightness}`);
});
}
async function readWeeklySchedule(device) {
const scheduleDPs = [109, 110, 111, 112, 113, 114, 115];
const days = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];
for (let i = 0; i < scheduleDPs.length; i++) {
await retryOperation(async () => {
const payload = await tuya.sendDataPointValue(device.getEndpoint(1), scheduleDPs[i], null, {read: true});
console.log(`[EONE] Schedule ${days[i]} read:`, payload);
});
}
}
// --- Main device definition ---
const definition = {
fingerprint: [
{ modelID: 'TS0601', manufacturerName: '_TZE204_ca3i8m8p' },
{ modelID: 'TS0601', manufacturerName: '_TZE204_eone_thermostaat' },
{ modelID: 'TS0601', manufacturerName: '_TZE204_thermostat_eone' },
],
model: 'EONE-THERMOSTAT',
vendor: 'EONE',
description: 'Zigbee thermostat with scheduling, humidity and adaptive backlight',
fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
whiteLabel: [
tuya.whitelabel('ENGO', 'EONE-230W', 'Zigbee Smart Thermostat', ['_TZE204_ca3i8m8p']),
],
onEvent: async (type, data, device, options) => {
if (device.manufacturerName?.startsWith('_TZE204')) {
device.meta.supported = true; // mark router as supported
}
if (type === 'deviceInterview' || type === 'deviceAnnounce') {
console.log('----------------------------------------');
console.log(`[EONE][EVENT] Device ${device.ieeeAddr} reconnected. Starting full initialization...`);
await syncTime(device);
await updateBacklight(device);
await readWeeklySchedule(device);
console.log(`[EONE][EVENT] Initialization completed.`);
console.log('----------------------------------------');
}
},
exposes: (() => {
const climateEx = e.climate()
.withSystemMode(['heat','cool'], ea.STATE_SET)
.withSetpoint('current_heating_setpoint',5,45,0.5,ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withLocalTemperatureCalibration(-3.5,3.5,0.5,ea.STATE_SET)
.withRunningState(['idle','heat','cool'], ea.STATE);
if (optionalFeatures) {
climateEx.withPreset(['manual','program','holiday','boost','away','frost']);
}
const coreExposes = [
e.binary('state', ea.STATE_SET, 'ON','OFF').withDescription('Turn the thermostat ON/OFF'),
climateEx,
e.numeric('local_temperature', ea.STATE).withUnit('°C').withDescription('Measured room temperature'),
e.numeric('humidity', ea.STATE).withUnit('%').withDescription('Measured humidity'),
e.numeric('backlight', ea.STATE_SET).withUnit('%').withDescription('Backlight brightness (auto-updated by time)'),
e.enum('sensor_error', ea.STATE, ['Normal','E1','E2']).withDescription('Sensor error status'),
e.child_lock().withDescription('Child lock'),
e.enum('relay_mode', ea.STATE_SET, ['NO','NC','OFF']).withDescription('Relay mode'),
e.enum('sensor_choose', ea.STATE_SET, ['Internal','All','External']).withDescription('Sensor selection'),
];
if (optionalFeatures) {
coreExposes.push(
e.numeric('holiday_temperature', ea.STATE_SET).withUnit('°C').withDescription('Holiday temperature'),
e.numeric('holiday_days', ea.STATE_SET).withUnit('days').withDescription('Number of holiday days'),
e.numeric('frost_set', ea.STATE_SET).withUnit('°C').withDescription('Frost protection temperature'),
e.enum('control_algorithm', ea.STATE_SET, ['TPI_UFH','TPI_RAD','TPI_ELE','HIS_02','HIS_04','HIS_06']).withDescription('Control algorithm'),
e.binary('valve_protection', ea.STATE_SET,'ON','OFF').withDescription('Valve protection ON/OFF'),
e.enum('comfort_warm_floor', ea.STATE_SET, ['OFF','LEVEL1','LEVEL2','LEVEL3','LEVEL4','LEVEL5']).withDescription('Comfort warm floor setting'),
e.enum('temp_resolution', ea.STATE_SET, ['One','Five']).withDescription('Temperature resolution'),
e.max_temperature().withValueMin(5).withValueMax(45).withDescription('Max temperature'),
e.min_temperature().withValueMin(5).withValueMax(45).withDescription('Min temperature'),
e.text('schedule_monday', ea.STATE_SET).withDescription('Schedule Monday'),
e.text('schedule_tuesday', ea.STATE_SET).withDescription('Schedule Tuesday'),
e.text('schedule_wednesday', ea.STATE_SET).withDescription('Schedule Wednesday'),
e.text('schedule_thursday', ea.STATE_SET).withDescription('Schedule Thursday'),
e.text('schedule_friday', ea.STATE_SET).withDescription('Schedule Friday'),
e.text('schedule_saturday', ea.STATE_SET).withDescription('Schedule Saturday'),
e.text('schedule_sunday', ea.STATE_SET).withDescription('Schedule Sunday'),
);
}
return coreExposes;
})(),
meta: (() => {
const coreDP = [
[1,'state',tuya.valueConverter.onOff],
[2,'system_mode',tuya.valueConverterBasic.lookup({heat:tuya.enum(0),cool:tuya.enum(1)})],
[3,'running_state',tuya.valueConverterBasic.lookup({heat:tuya.enum(1),idle:tuya.enum(2)})],
[16,'current_heating_setpoint',tuya.valueConverter.divideBy10],
[24,'local_temperature',tuya.valueConverter.divideBy10],
[34,'humidity',tuya.valueConverter.raw],
[40,'child_lock',tuya.valueConverter.lockUnlock],
[43,'sensor_choose',tuya.valueConverterBasic.lookup({Internal:tuya.enum(0),All:tuya.enum(1),External:tuya.enum(2)})],
[44,'backlight',tuya.valueConverter.raw],
[108,'relay_mode',tuya.valueConverterBasic.lookup({NO:tuya.enum(0),NC:tuya.enum(1),OFF:tuya.enum(2)})],
[120,'sensor_error',tuya.valueConverterBasic.lookup({Normal:tuya.enum(0),E1:tuya.enum(1),E2:tuya.enum(2)})],
];
if (optionalFeatures) {
coreDP.push(
[19,'max_temperature',tuya.valueConverter.divideBy10],
[26,'min_temperature',tuya.valueConverter.divideBy10],
[32,'holiday_temperature',tuya.valueConverter.divideBy10],
[33,'holiday_days',tuya.valueConverter.raw],
[45,'comfort_warm_floor',tuya.valueConverterBasic.lookup({OFF:tuya.enum(0),LEVEL1:tuya.enum(1),LEVEL2:tuya.enum(2),LEVEL3:tuya.enum(3),LEVEL4:tuya.enum(4),LEVEL5:tuya.enum(5)})],
[106,'frost_set',tuya.valueConverter.divideBy10],
[101,'control_algorithm',tuya.valueConverterBasic.lookup({TPI_UFH:tuya.enum(0),TPI_RAD:tuya.enum(1),TPI_ELE:tuya.enum(2),HIS_02:tuya.enum(3),HIS_04:tuya.enum(4),HIS_06:tuya.enum(5)})],
[107,'valve_protection',tuya.valueConverter.onOff],
[109,'schedule_monday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[110,'schedule_tuesday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[111,'schedule_wednesday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[112,'schedule_thursday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[113,'schedule_friday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[114,'schedule_saturday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[115,'schedule_sunday',tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
[117,'temp_resolution',tuya.valueConverterBasic.lookup({One:tuya.enum(0),Five:tuya.enum(1)})]
);
}
return { tuyaDatapoints: coreDP };
})(),
configure: async (device, coordinatorEndpoint) => {
console.log(`[EONE][CONFIGURE] Full device configuration starting: ${device.ieeeAddr}`);
await syncTime(device);
await updateBacklight(device);
await readWeeklySchedule(device);
// --- Automatic day/night backlight scheduler ---
setInterval(() => updateBacklight(device), 60 * 1000);
console.log('[EONE][CONFIGURE] Full initialization complete.');
},
};
// Export module
module.exports = definition;What does/doesn't work with the external definition?
// External converter for EONE Zigbee thermostat (_TZE204_xxxx)
// Features:
// - Automatic clock synchronization at startup and daily at 03:00
// - Dynamic backlight brightness (day/night) with auto-update every minute
// - Reads weekly schedule on startup
// - Applies all optional settings automatically
// - Detailed console logging for debugging
// - Handles device reconnection (deviceAnnounce)
// - Automatically marks router as supported
// - Retry loop for initialization if device doesn't respond immediately
// Works with Zigbee2MQTT 2.6.x and newer
Notes
// --- Toggle optional advanced features here ---
const optionalFeatures = false; //-----> true onlocks all features <-----