-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TS0601 from _TZE200_i48qyn9s #5860
Comments
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
up |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
up :-) |
What device is this? Can you please link it? Interesting because it reports battery state in %. |
Heizkörper-Thermostat ESSENTIALS, Zigbee https://amzn.eu/d/bfTXGAiAm 20.08.2023 um 04:07 schrieb Florian Asche ***@***.***>:
What device is this? Can you please link it? Interesting because it reports battery state in %.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***>
|
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
Please help me :-) |
working converter can be found here |
Thank you very much! - Now I can set the temperature again, but the schedules are not yet displayed again. The following info is shown to me (I hope it helps): MQTT publish: topic 'zigbee2mqtt/Regina Fenster rechts', payload '{"away_data":{"away_hours":0,"day":1,"hour":0,"minute":0,"month":1,"temperature":"17.0","year":2019},"away_mode":"OFF","battery":"74.8","battery_low":false,"child_lock":"UNLOCKED","comfort_temp_preset":"21.0","current_heating_setpoint":"21.5","eco_temp_preset":"17.0","linkquality":40,"local_temperature":"19.8","local_temperature_calibration":"0.0","manual_heating_setpoint":"21.5","open_window":"OFF","preset":"manual","schedule":"NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0 NaN:NaN/0","schedule_heating_setpoint_override":"17.0","system_mode":"heat","weekly-schedule":{"fri":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"mon":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"sat":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"sun":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"thu":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"tue":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}],"wed":[{"hour":6,"minute":0,"temperature":17},{"hour":9,"minute":0,"temperature":21},{"hour":17,"minute":0,"temperature":17},{"hour":23,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":24,"minute":0,"temperature":17},{"hour":24,"minute":0,"temperature":21},{"hour":null,"minute":null,"temperature":17}]}}' |
Poste mal deinen Code von oben in einem Markdown code block, so dass man den auch kopieren und adaptieren kann. so wie er aktuell gepostet ist, kann ich ihn nicht kopieren und "ausführen". |
das würde ich sehr gerne tun, wenn ich wüsste was du meinst - sorry |
nur noch einmal zum Verständnis, ich gehe in HA über die Z2MQTT-Oberfläche auf den Punkt "Logs", wähle filter dann nach dem Gerät und kopiere die Info mit den von dir gezeigten Klammern ein? |
Nein, ich hätte gerne deinen Code oben, aus deinem erste Post, deinen "alten" converter der nicht mehr funktionierte. die Logs aus HA helfen hier nicht, da wir uns hier im Z2M befinden, hier muss das gemacht werden. HA erkennt das dann automatisch. |
Aah, vielen Dank - das habe ich jetzt verstanden - was soll ich sagen, blond und Frau ;-) Dann sollte es dieser hier sein.. |
Mit dem was du angehängt hast, hätten die Scheduler auch vorher nicht angezeigt werden können. Sei es aber drum, ich programmier das gerade eh alles um (ich hatte gehofft das in deinem converter mehr drin steht), da dieses Thermostat liefert zu 95% die gleichen Datapoints wie das von Lidl |
Ich möchte sagen, dass es angezeigt wurde - möchte jetzt aber nicht drauf wetten.. By the way: es sieht auch haargenau aus wie das vom Lidl, habe diese bereits im Einsatz und dachte es wären die gleichen - leider nur optisch aber nicht von der Software. Vielen Dank für deine Mühen!! |
Sind fast identisch, es weichen nur 2 Datenpunkte ab. |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
Entschuldigung, ich habe gerade erst gesehen das du noch einmal geschrieben hattest.. |
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 30 days |
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 30 days |
Please add the radiator valve TS0601 from _TZE200_i48qyn9s
this external converter worked, more or less, until the last update of zigbee2mqtt
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const e = exposes.presets;
const ea = exposes.access;
const tuya = require("zigbee-herdsman-converters/lib/tuya");
const tuyaLocal = {
dataPoints: {
sh4Mode: 2,
sh4HeatingSetpoint: 16,
sh4LocalTemp: 24,
sh4ChildLock: 30,
sh4Battery: 34,
sh4FaultCode: 45,
sh4ComfortTemp: 101,
sh4EcoTemp: 102,
sh4VacationPeriod: 103,
sh4TempCalibration: 104,
sh4ScheduleTempOverride: 105,
sh4RapidHeating: 106,
sh4WindowStatus: 107,
sh4Hibernate: 108,
sh4ScheduleMon: 109,
sh4ScheduleTue: 110,
sh4ScheduleWed: 111,
sh4ScheduleThu: 112,
sh4ScheduleFri: 113,
sh4ScheduleSat: 114,
sh4ScheduleSun: 115,
sh4OpenWindowTemp: 116,
sh4OpenWindowTime: 117,
sh4RapidHeatCntdownTimer: 118,
sh4TempControl: 119,
sh4RequestUpdate: 120,
},
};
const fzLocal = {
sh4_thermostat: {
cluster: 'manuSpecificTuya',
type: ['commandDataResponse', 'commandDataReport'],
convert: (model, msg, publish, options, meta) => {
//const dp = msg.data.dp;
//const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
const dpValue = tuya.firstDpValue(msg, meta, 'sh4_thermostat');
const dp = dpValue.dp;
const value = tuya.getDataValue(dpValue);
function weeklySchedule(day, value) {
// byte 0 - Day of Week (0
7 = Mon ~ Sun) <- redundant?59 = 0.5// byte 1 - 1st period Temperature (1
29.5°C (0.5 step))96 = 0:15 ~ 24:00 (15 min increment, i.e. 2 = 0:30, 3 = 0:45, ...))// byte 2 - 1st period end time (1
// byte 3 - 2nd period Temperature
// byte 4 - 2nd period end time
// ...
// byte 16 - 8th period end time
// byte 17 - 9th period Temperature
const weekDays=['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
// we get supplied in value only a weekday schedule, so we must add it to
// the weekly schedule from meta.state, if it exists
const weeklySchedule= meta.state.hasOwnProperty('weekly_schedule') ? meta.state.weekly_schedule : {};
meta.logger.info(JSON.stringify({'received day': day, 'received values': value}));
let daySchedule = []; // result array
for (let i=1; i<18 && value[i]; ++i) {
const aTemp=value[i];
++i;
const time=value[i];
daySchedule=[...daySchedule, {
temperature: Math.floor(aTemp/2),
hour: Math.floor(time/4),
minute: time % 4 *15,
}];
}
meta.logger.info(JSON.stringify({'returned weekly schedule: ': daySchedule}));
return {'weekly-schedule': {...weeklySchedule, [weekDays[day]]: daySchedule}};
}
switch (dp) {
case tuyaLocal.dataPoints.sh4Mode: // 2
// 0-Schedule; 1-Manual; 2-Away
if (value == 0) {
return {
system_mode: 'auto',
away_mode: 'OFF',
current_heating_setpoint: meta.state.schedule_heating_setpoint_override
};
} else if (value == 1) {
return {
system_mode: 'heat',
away_mode: 'OFF',
current_heating_setpoint: meta.state.manual_heating_setpoint
};
} else if (value == 2) {
return {
system_mode: 'off',
away_mode: 'ON',
current_heating_setpoint: -1 // need implement read away_preset_temperature
};
};
break;
case tuyaLocal.dataPoints.sh4HeatingSetpoint: // 16
// 0 - Valve full OFF, 60 - Valve full ON : only in "manual" mode
return {
manual_heating_setpoint: (value / 2).toFixed(1),
current_heating_setpoint: (value / 2).toFixed(1)
};
case tuyaLocal.dataPoints.sh4LocalTemp: // 24
return {local_temperature: (value / 10).toFixed(1)};
case tuyaLocal.dataPoints.sh4ChildLock: // 30
return {child_lock: value ? 'LOCKED' : 'UNLOCKED'};
case tuyaLocal.dataPoints.sh4Battery: // 34
return {
battery: value > 130 ? 100 : value < 70 ? 0 : ((value - 70)*1.7).toFixed(1),
battery_low: value < 90,
};
case tuyaLocal.dataPoints.sh4FaultCode: // 45
break;
case tuyaLocal.dataPoints.sh4ComfortTemp: // 101
return {comfort_temp_preset: (value / 2).toFixed(1)};
case tuyaLocal.dataPoints.sh4EcoTemp: // 102
return {eco_temp_preset: (value / 2).toFixed(1)};
case tuyaLocal.dataPoints.sh4VacationPeriod: // 103
return {
away_data: {
year: value[0]+2000,
month: value[1],
day: value[2],
hour: value[3],
minute: value[4],
temperature: (value[5] /2).toFixed(1),
away_hours: value[6]<< 8 | value[7],
},
};
// byte 0 - Start Year (0x00 = 2000)
// byte 1 - Start Month
// byte 2 - Start Day
// byte 3 - Start Hour
// byte 4 - Start Minute
// byte 5 - Temperature (1
59 = 0.529.5°C (0.5 step))// byte 6-7 - Duration in Hours (0~2400 (100 days))
case tuyaLocal.dataPoints.sh4TempCalibration: // 104
return {local_temperature_calibration: value > 55 ?
((value - 0x100000000)/10).toFixed(1): (value/ 10).toFixed(1)};
case tuyaLocal.dataPoints.sh4ScheduleTempOverride: // 105
if (meta.state.system_mode == 'auto') {
return {
schedule_heating_setpoint_override: (value / 2).toFixed(1),
current_heating_setpoint: (value / 2).toFixed(1)
}
} else {
return {schedule_heating_setpoint_override: (value / 2).toFixed(1)}
}
case tuyaLocal.dataPoints.sh4RapidHeating: // 106
break;
case tuyaLocal.dataPoints.sh4WindowStatus: // 107
break;
case tuyaLocal.dataPoints.sh4Hibernate: // 108
break;
case tuyaLocal.dataPoints.sh4ScheduleMon: // 109
return weeklySchedule(0, value);
case tuyaLocal.dataPoints.sh4ScheduleTue: // 110
return weeklySchedule(1, value);
case tuyaLocal.dataPoints.sh4ScheduleWed: // 111
return weeklySchedule(2, value);
case tuyaLocal.dataPoints.sh4ScheduleThu: // 112
return weeklySchedule(3, value);
case tuyaLocal.dataPoints.sh4ScheduleFri: // 113
return weeklySchedule(4, value);
case tuyaLocal.dataPoints.sh4ScheduleSat: // 114
return weeklySchedule(5, value);
case tuyaLocal.dataPoints.sh4ScheduleSun: // 115
return weeklySchedule(6, value);
case tuyaLocal.dataPoints.sh4OpenWindowTemp: // 116
break;
case tuyaLocal.dataPoints.sh4OpenWindowTime: // 117
break;
case tuyaLocal.dataPoints.sh4RapidHeatCntdownTimer: // 118
break;
case tuyaLocal.dataPoints.sh4TempControl: // 119
break;
case tuyaLocal.dataPoints.sh4RequestUpdate: // 120
break;
default:
meta.logger.warn(
zigbee-herdsman-converters:sh4Thermostat: NOT RECOGNIZED DP #${ dp} with data ${JSON.stringify(msg.data)}
);}
},
},
};
const tzLocal = {
sh4_thermostat_current_heating_setpoint: {
key: ['current_heating_setpoint'],
convertSet: async (entity, key, value, meta) => {
const temp = Math.round(value * 2);
if (meta.state.system_mode == 'heat') {
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4HeatingSetpoint, temp);
} else if (meta.state.system_mode == 'auto') {
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4ScheduleTempOverride, temp);
}
},
convertGet: async (entity, key, value, meta) => {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4RequestUpdate, 0);
},
},
sh4_thermostat_comfort_temp_preset: {
key: ['comfort_temp_preset'],
convertSet: async (entity, key, value, meta) => {
const temp = Math.round(value * 2);
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4ComfortTemp, temp);
},
},
sh4_thermostat_eco_temp_preset: {
key: ['eco_temp_preset'],
convertSet: async (entity, key, value, meta) => {
const temp = Math.round(value * 2);
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4EcoTemp, temp);
},
},
sh4_thermostat_schedule_override_setpoint: {
key: ['schedule_override_setpoint'],
convertSet: async (entity, key, value, meta) => {
const temp = Math.round(value * 2);
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4ScheduleTempOverride, temp);
},
},
sh4_thermostat_get_data: {
key: ['local_temperature'],
convertGet: async (entity, key, value, meta) => {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4RequestUpdate, 0);
},
},
sh4_thermostat_mode: {
key: ['system_mode'],
convertSet: async (entity, key, value, meta) => {
if ( value == 'auto' ) {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4Mode, 0);
} else if ( value == 'heat' ) {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4Mode, 1);
} else if ( value == 'off') {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4Mode, 2);
//await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4HeatingSetpoint, 0);
}
},
convertGet: async (entity, key, value, meta) => {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4RequestUpdate, 0);
},
},
sh4_thermostat_away: {
key: ['away_mode', 'away_data'],
convertSet: async (entity, key, value, meta) => {
if (key==='away_mode') {
if ( value == 'ON' ) {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4Mode, 2);
} else {
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.sh4Mode, 0);
}
} else if (key==='away_data') {
const output= new Buffer(8);
// byte 0 - Start Year (0x00 = 2000)
// byte 1 - Start Month
// byte 2 - Start Day
// byte 3 - Start Hour
// byte 4 - Start Minute
// byte 5 - Temperature (1
59 = 0.529.5°C (0.5 step))// byte 6-7 - Duration in Hours (0
2400 (100 days))7 = Mon ~ Sun) <- redundant?output[0]=value.year > 2000 ? value.year-2000 : value.year; // year
output[1]=value.month; // month
output[2]=value.day; // day
output[3]=value.hour; // hour
output[4]=value.minute; // min
output[5]=Math.round(value.temperature * 2);
output[7]=value.away_hours & 0xFF;
output[6]=value.away_hours >> 8;
meta.logger.info(JSON.stringify({'send to tuya': output, 'value was': value, 'key was': key}));
await tuya.sendDataPointRaw(entity, tuyaLocal.dataPoints.sh4VacationPeriod, output);
}
},
},
sh4_thermostat_schedule: {
key: ['weekly_schedule'],
convertSet: async (entity, key, value, meta) => {
const weekDays=['mon' , 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
// byte 0 - Day of Week (0
// byte 1 - 1st period Temperature (1
59 = 0.529.5°C (0.5 step))// byte 2 - 1st period end time (1~96 = 0:15 ~ 24:00 (15 min increment, i.e. 2 = 0:30, 3 = 0:45, ...))
// byte 3 - 2nd period Temperature
// byte 4 - 2nd period end time
// ...
// byte 16 - 8th period end time
// byte 17 - 9th period Temperature
// we overwirte only the received days. The other ones keep stored on the device
const keys = Object.keys(value);
for (const dayName of keys) { // for loop in order to delete the empty day schedules
const output= new Buffer(17); // empty output byte buffer
const dayNo=weekDays.indexOf(dayName);
output[0]=dayNo+1;
const schedule=value[dayName];
schedule.forEach((el, Index) => {
if (Index <=8) {
output[1+2Index]=Math.round(el.temperature2);
output[2+2Index]=el.hour4+Math.floor((el.minute/15));
} else {
meta.logger.warn('more than 8 schedule points supplied for week-day '+dayName +
' additional schedule points will be ignored');
}
});
await tuya.sendDataPointRaw(entity, tuyaLocal.dataPoints.sh4ScheduleMon+dayNo, output);
await new Promise((r) => setTimeout(r, 2000));
// wait 2 seconds between schedule sends in order not to overload the device
}
},
},
sh4_thermostat_child_lock: {
key: ['child_lock'],
convertSet: async (entity, key, value, meta) => {
await tuya.sendDataPointBool(entity, tuyaLocal.dataPoints.sh4ChildLock,
['LOCKED', 'ON', 'LOCK'].includes(value.toUpperCase()));
},
},
sh4_thermostat_calibration: {
key: ['local_temperature_calibration'],
convertSet: async (entity, key, value, meta) => {
if (value > 0) value = value10;
if (value < 0) value = value10 + 0x100000000;
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.sh4TempCalibration, value);
},
},
};
const device = {
fingerprint: [
{
modelID: 'TS0601',
manufacturerName: '_TZE200_i48qyn9s'
},
],
model: 'SH4 Zigbee eTRV',
vendor: 'Tuya',
description: 'Zigbee Radiator Thermostat',
fromZigbee: [
fz.ignore_basic_report,
fzLocal.sh4_thermostat,
],
toZigbee: [
tzLocal.sh4_thermostat_current_heating_setpoint,
tzLocal.sh4_thermostat_comfort_temp_preset,
tzLocal.sh4_thermostat_eco_temp_preset,
tzLocal.sh4_thermostat_away,
tzLocal.sh4_thermostat_mode,
tzLocal.sh4_thermostat_child_lock,
tzLocal.sh4_thermostat_calibration,
tzLocal.sh4_thermostat_schedule_override_setpoint,
tzLocal.sh4_thermostat_schedule,
tzLocal.sh4_thermostat_get_data,
tz.tuya_data_point_test,
],
onEvent: tuya.onEventSetLocalTime,
exposes: [
e.battery(), e.battery_low(), e.child_lock(),
exposes.climate().withSetpoint('current_heating_setpoint', 0.5, 29.5, 0.5)
.withLocalTemperature()
.withSystemMode(['auto','heat','off'])
],
};
module.exports = device;
Thanks in advance
The text was updated successfully, but these errors were encountered: