zigbee2mqtt
zigbee2mqtt copied to clipboard
[New device support]: Thermostatic radiator valve _TZE200_p3dbf6qs
Link
https://aliexpress.ru/item/1005005770731714.html
Database entry
{"id":5,"type":"EndDevice","ieeeAddr":"0xa4c138e49df54f23","nwkAddr":59756,"manufId":4417,"manufName":"_TZE200_p3dbf6qs","powerSource":"Battery","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[4,5,61184,0],"outClusterList":[25,10],"clusters":{},"binds":[{"cluster":0,"type":"endpoint","deviceIeeeAddress":"0xe0798dfffecfba41","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":67,"stackVersion":0,"hwVersion":1,"dateCode":"","interviewCompleted":true,"meta":{"configured":821693351},"lastSeen":1697819079943,"defaultSendRequestWhen":"immediate"}
Comments
Hello, There is a thermostatic valve, presumably me167. I saw it on Github, they seemed to talk about its support. In fact, when connecting, z2m writes that the device is not supported. Then I installed an external converter from the author @twhittock twhittock - https://github.com/twhittock/avatto_me167. The thermostat has been identified, even the photo is correct. However, none of the functions are active. The Z2M does not see the temperature from the sensor. I also found the code for _TZE200_p3dbf6qs on Github, tried to replace βdataPoints: {β, in this case z2m does not start. Tnx!
External converter
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: {
me167Mode: 2,
me167HeatingSetpoint: 4,
me167LocalTemp: 5,
me167ChildLock: 7,
me167Heating: 3,
me167Schedule1: 28,
me167Schedule2: 29,
me167Schedule3: 30,
me167Schedule4: 31,
me167Schedule5: 32,
me167Schedule6: 33,
me167Schedule7: 34,
me167ErrorCode: 35,
me167FrostGuard: 36,
me167AntiScaling: 39,
me167TempCalibration: 47,
},
};
const fzLocal = {
me167_thermostat: {
cluster: 'manuSpecificTuya',
type: ['commandDataResponse', 'commandDataReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
function weeklySchedule(day, value) {
// byte 0 - Day of Week (0~7 = Wed ~ Tue) ???
// byte 1 - hour ???
// byte 2 - minute ???
// byte 3 - Temp (temp = value )
// byte 4 - Temperature (temp = value / 10)
const weekDays=[ 'wed', 'thu', 'fri', 'sat', 'sun','mon', 'tue'];
// 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<16 && value[i]; ++i) {
const aHour=value[i];
++i;
const aMinute=value[i];
++i;
const aTemp2=value[i];
++i;
const aTemp=value[i];
daySchedule=[...daySchedule, {
temperature: Math.floor((aTemp+aTemp2*256)/10),
hour: aHour,
minute: aMinute,
}];
}
meta.logger.info(JSON.stringify({'returned weekly schedule: ': daySchedule}));
return {'weekly-schedule': {...weeklySchedule, [weekDays[day]]: daySchedule}};
}
for (const dpValue of msg.data.dpValues) {
const value = tuya.getDataValue(dpValue);
switch (dpValue.dp) {
case tuyaLocal.dataPoints.me167ChildLock:
result.child_lock = value ? 'LOCK' : 'UNLOCK';
break;
case tuyaLocal.dataPoints.me167HeatingSetpoint:
result.current_heating_setpoint = value/10;
break;
case tuyaLocal.dataPoints.me167LocalTemp:
result.local_temperature = value/10;
break;
case tuyaLocal.dataPoints.me167Heating:
switch(value) {
case 0:
result.running_state = "heat"; // valve open
break;
case 1:
result.running_state = "idle"; // valve closed
break;
default:
meta.logger.warn('zigbee-herdsman-converters:me167_thermostat: ' +
`Running state ${value} is not recognized.`);
break;
}
break;
case tuyaLocal.dataPoints.me167Mode:
switch (value) {
case 0: // auto
result.system_mode = 'auto';
break;
case 1: // manu
result.system_mode = 'heat';
break;
case 2: // off
result.system_mode = 'off';
break;
default:
meta.logger.warn('zigbee-herdsman-converters:me167_thermostat: ' +
`Mode ${value} is not recognized.`);
break;
}
break;
case tuyaLocal.dataPoints.me167Schedule1:
weeklySchedule(0,value);
break;
case tuyaLocal.dataPoints.me167Schedule2:
weeklySchedule(1,value);
break;
case tuyaLocal.dataPoints.me167Schedule3:
weeklySchedule(2,value);
break;
case tuyaLocal.dataPoints.me167Schedule4:
weeklySchedule(3,value);
break;
case tuyaLocal.dataPoints.me167Schedule5:
weeklySchedule(4,value);
break;
case tuyaLocal.dataPoints.me167Schedule6:
weeklySchedule(5,value);
break;
case tuyaLocal.dataPoints.me167Schedule7:
weeklySchedule(6,value);
break;
case tuyaLocal.dataPoints.me167TempCalibration:
if (value >= 4294967295 ){
result.local_temperature_calibration = (value-4294967295)-1 // negative values
}else{
result.local_temperature_calibration = value
}
break;
case tuyaLocal.dataPoints.me167ErrorCode:
switch (value) {
case 0: // OK
result.battery_low = false;
meta.logger.info(`zigbee-herdsman-converters:me167_thermostat: BattOK - Error Code: ` +
`${JSON.stringify(dpValue)}`);
break;
case 1: // Empty Battery
result.battery_low = true;
meta.logger.info(`zigbee-herdsman-converters:me167_thermostat: BattEmtpy - Error Code: ` +
`${JSON.stringify(dpValue)}`);
break;
default:
meta.logger.warn(`zigbee-herdsman-converters:me167_thermostat: Error Code not recognized: ` +
`${JSON.stringify(dpValue)}`);
break;
}
break;
case tuyaLocal.dataPoints.me167FrostGuard:
result.frost_guard = value ? 'ON' : 'OFF';
break;
case tuyaLocal.dataPoints.me167AntiScaling:
result.anti_scaling = value ? 'ON' : 'OFF';
break;
default:
meta.logger.warn(`zigbee-herdsman-converters:me167_thermostat: NOT RECOGNIZED ` +
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
}
}
return result;
},
},
};
const tzLocal = {
me167_thermostat_current_heating_setpoint: {
key: ['current_heating_setpoint'],
convertSet: async (entity, key, value, meta) => {
const temp = Math.round(value * 10);
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.me167HeatingSetpoint, temp);
},
},
me167_thermostat_system_mode: {
key: ['system_mode'],
convertSet: async (entity, key, value, meta) => {
switch (value) {
case 'off':
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.me167Mode, 2 /* off */);
break;
case 'heat':
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.me167Mode, 1 /* manual */);
break;
case 'auto':
await tuya.sendDataPointEnum(entity, tuyaLocal.dataPoints.me167Mode, 0 /* auto */);
break;
}
},
},
me167_thermostat_child_lock: {
key: ['child_lock'],
convertSet: async (entity, key, value, meta) => {
await tuya.sendDataPointBool(entity, tuyaLocal.dataPoints.me167ChildLock, value === 'LOCK');
},
},
me167_thermostat_schedule: {
key: ['weekly_schedule'],
convertSet: async (entity, key, value, meta) => {
const weekDays=['wed', 'thu', 'fri', 'sat', 'sun', 'mon' , 'tue'];
// 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= []; // empty output byte buffer
const dayNo=weekDays.indexOf(dayName);
output[0]=dayNo+1;
const schedule=value[dayName];
schedule.forEach((el, Index) => {
if (Index <4) {
output[1+4*Index]=el.hour;
output[2+4*Index]=el.minute;
output[3+4*Index]=Math.floor((el.temperature*10)/256);
output[4+4*Index]=(el.temperature*10)%256;
} else {
meta.logger.warn('more than 4 schedule points supplied for week-day '+dayName +
' additional schedule points will be ignored');
}
});
meta.logger.info(`zigbee-herdsman-converters:me167_thermostat: Writing Schedule to ` +
`DP #${tuyaLocal.dataPoints.me167Schedule1+dayNo} with data ${JSON.stringify(output)}`);
await tuya.sendDataPointRaw(entity, tuyaLocal.dataPoints.me167Schedule1+dayNo, output);
await new Promise((r) => setTimeout(r, 2000));
// wait 2 seconds between schedule sends in order not to overload the device
}
},
},
me167_thermostat_calibration: {
key: ['local_temperature_calibration'],
convertSet: async (entity, key, value, meta) => {
if (value >= 0) value = value;
if (value < 0) value = value+4294967295+1;
await tuya.sendDataPointValue(entity, tuyaLocal.dataPoints.me167TempCalibration, value);
},
},
me167_thermostat_anti_scaling: {
key: ['anti_scaling'],
convertSet: async (entity, key, value, meta) => {
await tuya.sendDataPointBool(entity, tuyaLocal.dataPoints.me167AntiScaling, value === 'ON');
},
},
me167_thermostat_frost_guard: {
key: ['frost_guard'],
convertSet: async (entity, key, value, meta) => {
await tuya.sendDataPointBool(entity, tuyaLocal.dataPoints.me167FrostGuard, value === 'ON');
},
},
};
const definition = {
// Since a lot of Tuya devices use the same modelID, but use different data points
// it's usually necessary to provide a fingerprint instead of a zigbeeModel
fingerprint: [
{
// The model ID from: Device with modelID 'TS0601' is not supported
// You may need to add \u0000 at the end of the name in some cases
modelID: 'TS0601',
// The manufacturer name from: Device with modelID 'TS0601' is not supported.
manufacturerName: '_TZE200_p3dbf6qs'
},
],
model: 'ME167',
vendor: 'Avatto',
description: 'Thermostatic radiator valve',
fromZigbee: [
fz.ignore_basic_report, // Add this if you are getting no converter for 'genBasic'
//fz.tuya_data_point_dump, // This is a debug converter, it will be described in the next part
fzLocal.me167_thermostat,
],
toZigbee: [
//tz.tuya_data_point_test, // Another debug converter
tzLocal.me167_thermostat_child_lock,
tzLocal.me167_thermostat_current_heating_setpoint,
tzLocal.me167_thermostat_system_mode,
tzLocal.me167_thermostat_schedule,
tzLocal.me167_thermostat_calibration,
tzLocal.me167_thermostat_anti_scaling,
tzLocal.me167_thermostat_frost_guard,
],
onEvent: tuya.onEventSetTime, // Add this if you are getting no converter for 'commandMcuSyncTime'
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
},
exposes: [
e.child_lock(),
exposes.switch().withState('anti_scaling', true).withDescription('Anti Scaling feature is ON or OFF'),
exposes.switch().withState('frost_guard', true).withDescription('Frost Protection feature is ON or OFF'),
exposes.climate().withSetpoint('current_heating_setpoint', 5, 35, 1)
.withLocalTemperature()
.withSystemMode(['auto','heat','off'])
.withRunningState(['idle', 'heat'], ea.STATE)
.withLocalTemperatureCalibration(-10, 10, 1, ea.STATE_SET)
],
};
module.exports = definition;
Supported color modes
No response
Color temperature range
No response
I'm using: ME167 (AVATTO) modelID: TS0601, manufacturerName:_TZE200_6rdj8dzm ME168 (AVATTO) modelID: TS0601, manufacturerName:_TZE200_p3dbf6qs. Both are supported. Using "system mode" auto on ME168 causes strange values of "Current heating setpoint"
Π― ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ: ME167 (AVATTO) ID ΠΌΠΎΠ΄Π΅Π»ΠΈ: TS0601, ΠΈΠΌΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Ρ: _TZE200_6rdj8dzm ME168 (AVATTO) ID ΠΌΠΎΠ΄Π΅Π»ΠΈ: TS0601, ΠΈΠΌΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Ρ: _TZE200_p3dbf6qs. ΠΠ±Π° ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡΡΡ. ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ Β«ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΠ³ΠΎ ΡΠ΅ΠΆΠΈΠΌΠ°Β» Π½Π° ME168 ΠΏΡΠΈΠ²ΠΎΠ΄ΠΈΡ ΠΊ ΡΡΡΠ°Π½Π½ΡΠΌ Π·Π½Π°ΡΠ΅Π½ΠΈΡΠΌ Β«Π’Π΅ΠΊΡΡΠ΅ΠΉ ΡΡΡΠ°Π²ΠΊΠΈ Π½Π°Π³ΡΠ΅Π²Π°Β».
I wonder why it doesn't work for me then? The z2m versions are all the latest. Now I installed version 1.32.2-1 zigbee2mqtt. As you can see, it doesnβt work either out of the box or with the converter. Do you have any external converter for this trv?
I don't use an external converter. You might get the converter of ME167 manufacturerName:_TZE200_6rdj8dzm, change manufacturerName to _TZE200_p3dbf6qs and try this as external converter.
I also have the same model. I wanted to connect it to HomeAssistant via zigbee2MQTT. It got identified nicely but on HA with MQTT Integration all I see are the useless entities but the important climate once are all missing ( also checked for hidden entries)
zigbemqtt
homeassistant
ZZigbee2MQTT -> eclipse-misquitto -> HA (all docker) Zigbee2MQTT version [1.33.1] commit: [7e63039] Coordinator type EZSP v8 Coordinator revision 6.10.3.0 build 297 Coordinator IEEE Address 0xe0798dfffe9f25a6 Frontend version 0.6.136
anyway to fix what or check why the most important informations are not on HA?
TY
I just saw that error in HA: 2023-10-28 19:14:44.536 ERROR (MainThread) [homeassistant.util.logging] Exception in async_discover when dispatching 'mqtt_discovery_new_climate_mqtt': ({'action_template': "{% set values = {None:None,'idle':'off','heat':'heating','cool':'cooling','fan_only':'fan'} %}{{ values[value_json.running_state] }}", 'action_topic': 'zigbee2mqtt/TRV03', 'availability': [{'topic': 'zigbee2mqtt/bridge/state', 'value_template': '{{ value_json.state }}'}, {'topic': 'zigbee2mqtt/TRV03/availability', 'value_template': '{{ value_json.state }}'}], 'availability_mode': 'all', 'current_temperature_template': '{{ value_json.local_temperature }}', 'current_temperature_topic': 'zigbee2mqtt/TRV03', 'device': {'identifiers': ['zigbee2mqtt_0xa4c138853938d9cf'], 'manufacturer': 'AVATTO', 'model': 'Thermostatic radiator valve (ME168)', 'name': 'TRV03'}, 'json_attributes_topic': 'zigbee2mqtt/TRV03', 'max_temp': '35', 'min_temp': '5', 'mode_command_topic': 'zigbee2mqtt/TRV03/set/system_mode', 'mode_state_template': '{{ value_json.system_mode }}', 'mode_state_topic': 'zigbee2mqtt/TRV03', 'modes': ['auto', 'heat', 'off'], 'name': None, 'object_id': 'trv03', 'origin': {'name': 'Zigbee2MQTT', 'sw': '1.33.1', 'url': 'https://www.zigbee2mqtt.io'}, 'temp_step': 1, 'temperature_command_topic': 'zigbee2mqtt/TRV03/set/current_heating_setpoint', 'temperature_state_template': '{{ value_json.current_heating_setpoint }}', 'temperature_state_topic': 'zigbee2mqtt/TRV03', 'temperature_unit': 'C', 'unique_id': '0xa4c138853938d9cf_climate_zigbee2mqtt', 'platform': 'mqtt'},)
voluptuous.error.MultipleInvalid: string value is None for dictionary value @ data['name']
I'm using: ME167 (AVATTO) modelID: TS0601, manufacturerName:_TZE200_6rdj8dzm ME168 (AVATTO) modelID: TS0601, manufacturerName:_TZE200_p3dbf6qs. Both are supported. Using "system mode" auto on ME168 causes strange values of "Current heating setpoint"
I am facing the same issue. Setpoint ist sporadically set to 25Β°C. Any hint?
I updated to latest Version 2023.10 of HA and now the values are all there so climate seems to be rather new stuff
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