[RELEASE] Tuya Wall Mount Thermostat (Water/Electric Floor Heating) Zigbee driver

Great! You can follow the steps for creating a 'developer' account on the Tuya cloud here :

Hopefully these are still valid (Tuya changes the IOT site quite frequently..)

Then, follow the instructions here :

1 Like

Done

Data Points Avatto TRV07
{
   "1":"Mode",
   "2":"Target temperature",
   "3":"Current temperature",
   "6":"Working status",
   "7":"Window status",
   "8":"Open window",
   "12":"Child lock",
   "13":"Battery",
   "14":"Fault alarm",
   "15":"Min. limit temperature",
   "16":"Max. limit temperature",
   "17":"Heating schedule",
   "18":"Week program Tuesday",
   "19":"Week program Wednesday",
   "20":"Week program Thursday",
   "21":"Week program Friday",
   "22":"Week program Saturday",
   "23":"Week program Sunday",
   "101":"Room sensor calibration",
   "108":"Valve",
   "109":"机型",
   "110":"Motor thrust",
   "111":"Display brightness",
   "112":"Software version",
   "113":"Screen orientation",
   "114":"System mode",
   "115":"Switch deviation (energy-saving mode only)",
   "116":"电机数据"
}
1 Like

You are really quick! :+1:

Can you copy also the Standard Instructon and Status sets - there we will find the scaling and max/min values...

1 Like

Sure thing:

Standard Instruction Set
mode	Enum	
{
  "range": [
    "auto",
    "manual",
    "off"
  ]
}
temp_set	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
window_check	Boolean	
"{true,false}"
child_lock	Boolean	
"{true,false}"
lower_temp	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 150,
  "scale": 1,
  "step": 10
}
upper_temp	Integer	
{
  "unit": "℃",
  "min": 200,
  "max": 350,
  "scale": 1,
  "step": 10
}
Standard Status Set
mode	Enum	
{
  "range": [
    "auto",
    "manual",
    "off"
  ]
}
temp_set	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
temp_current	Integer	
{
  "unit": "℃",
  "min": -100,
  "max": 500,
  "scale": 1,
  "step": 5
}
work_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_check	Boolean	
"{true,false}"
child_lock	Boolean	
"{true,false}"
battery_percentage	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 1
}
lower_temp	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 150,
  "scale": 1,
  "step": 10
}
upper_temp	Integer	
{
  "unit": "℃",
  "min": 200,
  "max": 350,
  "scale": 1,
  "step": 10
}

LE: I read this at the top of the page: The standard instruction set lets you control devices from different manufacturers with a single set of instructions. However, to achieve standardization, mapping relationships shall be manually created, and Tuya cannot guarantee that all hardware products support this function. You can view the standard adaptation of this product in [ Product Details] and change to the DP instruction mode as needed to get all the original instructions of devices.

So I went to the Product Details page and found this:

Table of instructions:

I switched it to DP, and found a lot more:

Extended Standard Instruction Set
Code	Type	Values
mode	Enum	
{
  "range": [
    "auto",
    "manual",
    "off",
    "on"
  ]
}
temp_set	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
temp_current	Integer	
{
  "unit": "℃",
  "min": -100,
  "max": 500,
  "scale": 1,
  "step": 5
}
work_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_check	Boolean	
"{true,false}"
child_lock	Boolean	
"{true,false}"
battery_percentage	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 1
}
fault	Bitmap	
{
  "label": [
    "fault_sensor",
    "fault_motor",
    "fault_low_batt",
    "fault_ug_low_batt"
  ],
  "maxlen": 4
}
lower_temp	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 150,
  "scale": 1,
  "step": 10
}
upper_temp	Integer	
{
  "unit": "℃",
  "min": 200,
  "max": 350,
  "scale": 1,
  "step": 10
}
week_program_13_1	Raw	
{}
week_program_13_2	Raw	
{}
week_program_13_3	Raw	
{}
week_program_13_4	Raw	
{}
week_program_13_5	Raw	
{}
week_program_13_6	Raw	
{}
week_program_13_7	Raw	
{}
temp_correction	Integer	
{
  "unit": "℃",
  "min": -100,
  "max": 100,
  "scale": 1,
  "step": 1
}
valve_open_degree	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 1000,
  "scale": 1,
  "step": 10
}
motor_thrust	Enum	
{
  "range": [
    "strong",
    "middle",
    "weak"
  ]
}
brightness	Enum	
{
  "range": [
    "high",
    "mid",
    "low"
  ]
}
screen_orientation	Enum	
{
  "range": [
    "up",
    "right",
    "down",
    "left"
  ]
}
system_mode	Enum	
{
  "range": [
    "comfort_mode",
    "Eco_mode"
  ]
}
switch_wrap	Integer	
{
  "unit": "℃",
  "min": 5,
  "max": 50,
  "scale": 1,
  "step": 1
}
Extended Standard Status Set
Code	Type	Values
mode	Enum	
{
  "range": [
    "auto",
    "manual",
    "off",
    "on"
  ]
}
temp_set	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
temp_current	Integer	
{
  "unit": "℃",
  "min": -100,
  "max": 500,
  "scale": 1,
  "step": 5
}
work_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_state	Enum	
{
  "range": [
    "closed",
    "opened"
  ]
}
window_check	Boolean	
"{true,false}"
child_lock	Boolean	
"{true,false}"
battery_percentage	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 1
}
fault	Bitmap	
{
  "label": [
    "fault_sensor",
    "fault_motor",
    "fault_low_batt",
    "fault_ug_low_batt"
  ],
  "maxlen": 4
}
lower_temp	Integer	
{
  "unit": "℃",
  "min": 50,
  "max": 150,
  "scale": 1,
  "step": 10
}
upper_temp	Integer	
{
  "unit": "℃",
  "min": 200,
  "max": 350,
  "scale": 1,
  "step": 10
}
week_program_13_1	Raw	
{}
week_program_13_2	Raw	
{}
week_program_13_3	Raw	
{}
week_program_13_4	Raw	
{}
week_program_13_5	Raw	
{}
week_program_13_6	Raw	
{}
week_program_13_7	Raw	
{}
temp_correction	Integer	
{
  "unit": "℃",
  "min": -100,
  "max": 100,
  "scale": 1,
  "step": 1
}
valve_open_degree	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 1000,
  "scale": 1,
  "step": 10
}
mfg_model	String	
{
  "maxlen": 255
}
motor_thrust	Enum	
{
  "range": [
    "strong",
    "middle",
    "weak"
  ]
}
brightness	Enum	
{
  "range": [
    "high",
    "mid",
    "low"
  ]
}
soft_version	Integer	
{
  "unit": "",
  "min": 0,
  "max": 65536,
  "scale": 0,
  "step": 1
}
screen_orientation	Enum	
{
  "range": [
    "up",
    "right",
    "down",
    "left"
  ]
}
system_mode	Enum	
{
  "range": [
    "comfort_mode",
    "Eco_mode"
  ]
}
switch_wrap	Integer	
{
  "unit": "℃",
  "min": 5,
  "max": 50,
  "scale": 1,
  "step": 1
}
motor_data	String	
{
  "maxlen": 255
}

The mfg_model is zt3l_60x

1 Like

Like I said, I've been testing some ZigBee TRVs, and I currently have a couple of others that work with the ZigBee - Tuya TRV driver, but only partially. One shows battery at 116% for example. I returned one that set the setPoint on a wrong scale (1/10 what I was setting). Going through this with you, I can see that these issues can be easy to fix if we have the right information.

As such, I've decided to hook them up to the gateway and gather their info from the Tuya IoT platform as well. Not sure if you want to make this driver the TRV heaven for Hubitat, but it may help other developers or other people get their devices working correctly, if they happen to have these:

res_3416860bb4d859c445e7abd54ab14187

#1 Mentor TRV TSW003 - I ordered from here
I noticed it moves the valve in 25% intervals, and I've seen weird periods of very frequent temperature updates varying by 0.5 degrees, sending a lot of events to the hub, like 40-50 in half an hour. It also has a very cheap plastic feel.
Looks like a Romanian firm branding Chinese products and selling them.

I guess some are better documented than others inside Tuya?

Pairing Info
Device pairing info
Manufacturer:	_TZE200_2dpplnsn
Endpoint 01 application:	53
Endpoint 01 endpointId:	01
Endpoint 01 idAsInt:	1
Endpoint 01 inClusters:	0000,0004,0005,EF00
Endpoint 01 initialized:	true
Endpoint 01 manufacturer:	_TZE200_2dpplnsn
Endpoint 01 model:	TS0601
Endpoint 01 outClusters:	0019,000A
Endpoint 01 profileId:	0104
Endpoint 01 stage:	4
Data Points
{
   "1":"Power",
   "2":"Setpoint",
   "3":"Current Temp",
   "4":"Mode",
   "7":"Child Lock",
   "13":"Fault",
   "14":"Status",
   "16":"Week Program",
   "101":"编程数据(周一)",
   "102":"编程数据(周二)",
   "103":"编程数据(周三)",
   "104":"编程数据(周四)",
   "105":"编程数据(周五)",
   "106":"编程数据(周六)",
   "107":"编程数据(周日)"
}
Standard Instruction Set
Code	Type	Values
switch	Boolean	
"{true,false}"
temp_set	Integer	
{
  "unit": "°C",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
mode	Enum	
{
  "range": [
    "Manual",
    "Eco",
    "Auto"
  ]
}
child_lock	Boolean	
"{true,false}"
week_program	Raw	
{}
prog_data_1	Raw	
{}
prog_data_2	Raw	
{}
prog_data_3	Raw	
{}
prog_data_4	Raw	
{}
prog_data_5	Raw	
{}
prog_data_6	Raw	
{}
prog_data_7	Raw	
{}
Standard Status Set
Code	Type	Values
switch	Boolean	
"{true,false}"
temp_set	Integer	
{
  "unit": "°C",
  "min": 50,
  "max": 350,
  "scale": 1,
  "step": 5
}
temp_current	Integer	
{
  "unit": "°C",
  "min": 0,
  "max": 500,
  "scale": 1,
  "step": 5
}
mode	Enum	
{
  "range": [
    "Manual",
    "Eco",
    "Auto"
  ]
}
child_lock	Boolean	
"{true,false}"
fault	Bitmap	
{
  "label": [
    "high_protect",
    "low_protect",
    "int_sensor",
    "ext_sensor",
    "battary_low",
    "device_offline"
  ],
  "maxlen": 6
}
work_state	Enum	
{
  "range": [
    "no_heating",
    "heating",
    "window_opened"
  ]
}
week_program	Raw	
{}
prog_data_1	Raw	
{}
prog_data_2	Raw	
{}
prog_data_3	Raw	
{}
prog_data_4	Raw	
{}
prog_data_5	Raw	
{}
prog_data_6	Raw	
{}
prog_data_7	Raw	
{}
Internal menu - help with ranges
Turn off, presss and hold M and arrow up for 3 seconds until 01 in shown on screen. Press M to go to next menu item. Use arrows to adjust.
01 Temp calibration: -8C to +8C default 0C
02 Set Point Max: 5C to 35C default 35C
03 Set Point Min: 5C to 35C default 5C
05 Frost Protection temp: 5 to 15 default: 5
10 Display 0: Room temp 1: Set temp default: 0
12 Open Window detect function: 0: disable 1: enable default: 0
13 OWD Detect time: 0 to 30 min default 15 min
14 OWD Drop temp select (within detect time) 2C, 3C, 4C degrees default: 2C
15 OWD Delay time select (return to previously working state) 10 to 60 min default 30 min
17 Factory reset: 0: No 1 Yes (and press On/Off for 5 sec, wait for restart)
18 Software version
19 Software version
31 Battery voltage: Unit 10mv
32 PID P-band select: 2 to 10C default: 7C
33 PID I-time select: 30 to 90 min default: 30 min

I will be returning this product. I wouldn't handle this with top priority. The other two are more interesting.

PS: Temp now works on the Avatto TRV07 on dev branch.

1 Like

res_d426f99832158760bc96617be0123bca

#2 Immax Neo Lite TRV 07732L - I ordered from here. Their website. Manual. Valve control types.
I've noticed the valve moves in 25% increments. It reports temperature every 15 minutes, and when the temperature changes. You can manually adjust the temperature by turning the part near the top of the device, you can feel it spinning the wheel on the inside.
This looks like a Czech company branding. I've also bought some contact sensors from them I am pleased with.

Pairing Info
Device pairing info
Manufacturer:	_TZE200_rufdtfyv
Endpoint 01 application:	55
Endpoint 01 endpointId:	01
Endpoint 01 idAsInt:	1
Endpoint 01 inClusters:	0000,0004,0005,EF00
Endpoint 01 initialized:	true
Endpoint 01 manufacturer:	_TZE200_rufdtfyv
Endpoint 01 model:	TS0601
Endpoint 01 outClusters:	0019,000A
Endpoint 01 profileId:	0104
Endpoint 01 stage:	4
Data Points
{
   "2":"Set temperature",
   "3":"Current temperature",
   "4":"Mode",
   "7":"Key Lock",
   "13":"Fault alarm",
   "44":"Temp Calibration",
   "102":"SetTemp.Min",
   "103":"SetTemp.Max",
   "104":"Window Parameter",
   "105":"Boost Time(S)",
   "106":"Valve Setting",
   "107":"ComfortTemp Set",
   "108":"EcoTemp Set",
   "109":"Valve Status",
   "110":"Battery Status",
   "111":"AutoMode Type",
   "112":"Workday Set",
   "113":"Restday Set",
   "114":"Holiday  Temperature",
   "115":"Window Status",
   "116":"KeyLock",
   "117":"Holiday Days",
   "118":"Valve openning"
}
Standard Instruction Set
Code	Type	Values
temp_set	Integer	
{
  "unit": "°C",
  "min": 10,
  "max": 700,
  "scale": 1,
  "step": 5
}
mode	Enum	
{
  "range": [
    "holiday",
    "auto",
    "manual",
    "comfort",
    "eco",
    "BOOST",
    "temp_auto",
    "Valve"
  ]
}
child_lock	Boolean	
"{true,false}"
roomtemp_calibrat	Integer	
{
  "unit": "℃",
  "min": -90,
  "max": 90,
  "scale": 1,
  "step": 10
}
lowtemp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 15,
  "scale": 0,
  "step": 1
}
hightemp	Integer	
{
  "unit": "℃",
  "min": 16,
  "max": 70,
  "scale": 0,
  "step": 1
}
wind	Raw	
{}
boost	Integer	
{
  "unit": "",
  "min": 100,
  "max": 900,
  "scale": 0,
  "step": 100
}
valve_set	Enum	
{
  "range": [
    "normal",
    "ForceOpen",
    "ForceClose"
  ]
}
comfort_temp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
eco_temp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
week_state	Enum	
{
  "range": [
    "0",
    "1",
    "2"
  ]
}
Prog_Workday	Raw	
{}
Prog_Restday	Raw	
{}
Temp_holiday	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
Auto_Lock	Boolean	
"{true,false}"
Days_Holiday	Integer	
{
  "unit": "天",
  "min": 1,
  "max": 30,
  "scale": 0,
  "step": 1
}
valve_openning	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 10
}
Standard Status Set
Code	Type	Values
temp_set	Integer	
{
  "unit": "°C",
  "min": 10,
  "max": 700,
  "scale": 1,
  "step": 5
}
temp_current	Integer	
{
  "unit": "°C",
  "min": 0,
  "max": 700,
  "scale": 1,
  "step": 5
}
mode	Enum	
{
  "range": [
    "holiday",
    "auto",
    "manual",
    "comfort",
    "eco",
    "BOOST",
    "temp_auto",
    "Valve"
  ]
}
child_lock	Boolean	
"{true,false}"
fault	Bitmap	
{
  "label": [
    "1",
    "2",
    "3",
    "4",
    "5"
  ],
  "maxlen": 5
}
roomtemp_calibrat	Integer	
{
  "unit": "℃",
  "min": -90,
  "max": 90,
  "scale": 1,
  "step": 10
}
lowtemp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 15,
  "scale": 0,
  "step": 1
}
hightemp	Integer	
{
  "unit": "℃",
  "min": 16,
  "max": 70,
  "scale": 0,
  "step": 1
}
wind	Raw	
{}
boost	Integer	
{
  "unit": "",
  "min": 100,
  "max": 900,
  "scale": 0,
  "step": 100
}
valve_set	Enum	
{
  "range": [
    "normal",
    "ForceOpen",
    "ForceClose"
  ]
}
comfort_temp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
eco_temp	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
valve	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 1
}
power_state	Boolean	
"{true,false}"
week_state	Enum	
{
  "range": [
    "0",
    "1",
    "2"
  ]
}
Prog_Workday	Raw	
{}
Prog_Restday	Raw	
{}
Temp_holiday	Integer	
{
  "unit": "℃",
  "min": 1,
  "max": 70,
  "scale": 0,
  "step": 1
}
windows_state	Boolean	
"{true,false}"
Auto_Lock	Boolean	
"{true,false}"
Days_Holiday	Integer	
{
  "unit": "天",
  "min": 1,
  "max": 30,
  "scale": 0,
  "step": 1
}
valve_openning	Integer	
{
  "unit": "%",
  "min": 0,
  "max": 100,
  "scale": 0,
  "step": 10
}

From my understanding of these values, this seems like a highly controllable TRV.

1 Like

Thanks for all the info, Vlad! Let's first try to make the TRV07 working with this driver, then I will see which way to go for adding more models.

Can you try again the new update, timeStamp "2023/11/16 7:41 АM". The change is that the heatingSetpoint is sent multiplied by 10 now.

When you change the heating setpoint manually from the TRV knob, is it reflected correctly in the current states?

I can confirm the new development branch is working for the thermostatSetPoint. Manually adjusting the TRV from the knob is reflected correctly in Hubitat. It works in 0.5 degree steps now, which is great.

Thanks!

Logs
dev:2592023-11-16 08:53:42.859infoDressing TRV heatingSetpoint is: 22.5°C
dev:2592023-11-16 08:53:42.845debugDressing TRV dp_id=2 dp=2 fncmd=225
dev:2592023-11-16 08:53:40.688infoDressing TRV heatingSetpoint is: 22.0°C
dev:2592023-11-16 08:53:40.681debugDressing TRV dp_id=2 dp=2 fncmd=220
dev:2592023-11-16 08:53:37.649infoDressing TRV heatingSetpoint is: 20.0°C
dev:2592023-11-16 08:53:37.643debugDressing TRV dp_id=2 dp=2 fncmd=200
dev:2592023-11-16 08:53:35.364infoDressing TRV heatingSetpoint is: 21.5°C
dev:2592023-11-16 08:53:35.358debugDressing TRV dp_id=2 dp=2 fncmd=215
dev:2592023-11-16 08:52:06.246infoDressing TRV TRV07 Valve (108) is: 530
dev:2592023-11-16 08:52:06.240debugDressing TRV dp_id=2 dp=108 fncmd=530
dev:2592023-11-16 08:52:06.062infoDressing TRV TRV07 Working status dp=6 fncmd=1
dev:2592023-11-16 08:52:06.056debugDressing TRV dp_id=4 dp=6 fncmd=1
dev:2592023-11-16 08:52:03.083infoDressing TRV heatingSetpoint is: 22.0°C
dev:2592023-11-16 08:52:03.055debugDressing TRV dp_id=2 dp=2 fncmd=220
dev:2592023-11-16 08:52:00.202debugDressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]
dev:2592023-11-16 08:51:59.771debugDressing TRV sendZigbeeCommands(cmd=[he cmd 0x0BCD 0x01 0xEF00 0x00 {000302020004000000DC} {}, delay 200])
dev:2592023-11-16 08:51:59.762debugDressing TRV sendTuyaCommand = [he cmd 0x0BCD 0x01 0xEF00 0x00 {000302020004000000DC} {}, delay 200]
dev:2592023-11-16 08:51:59.695debugDressing TRV changing setpoint to 220.0
dev:2592023-11-16 08:51:59.689debugDressing TRV sendTuyaHeatingSetpoint(22.0)
dev:2592023-11-16 08:51:59.681debug0.5 C correction of the heating setpoint22 for BEOK
dev:2592023-11-16 08:51:59.675debugDressing TRV setHeatingSetpoint temperature = 22 as int = 22 (previousSetpointt = 20.5)
dev:2592023-11-16 08:51:31.894infoDressing TRV heatingSetpoint is: 20.5°C
dev:2592023-11-16 08:51:31.864debugDressing TRV dp_id=2 dp=2 fncmd=205
dev:2592023-11-16 08:51:29.000debugDressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]
dev:2592023-11-16 08:51:28.281debugDressing TRV sendZigbeeCommands(cmd=[he cmd 0x0BCD 0x01 0xEF00 0x00 {000202020004000000CD} {}, delay 200])
dev:2592023-11-16 08:51:28.270debugDressing TRV sendTuyaCommand = [he cmd 0x0BCD 0x01 0xEF00 0x00 {000202020004000000CD} {}, delay 200]
dev:2592023-11-16 08:51:28.218debugDressing TRV changing setpoint to 205.0
dev:2592023-11-16 08:51:28.207debugDressing TRV sendTuyaHeatingSetpoint(20.5)
dev:2592023-11-16 08:51:28.198debug0.5 C correction of the heating setpoint20.5 for BEOK
dev:2592023-11-16 08:51:28.193debugDressing TRV setHeatingSetpoint temperature = 20.5 as int = 20 (previousSetpointt = 20.0)
dev:2592023-11-16 08:50:43.209infoDressing TRV temperature is: 20.7°C
dev:2592023-11-16 08:50:43.197debugDressing TRV processTuyaTemperatureReport descMap?.size() = 10 dp_id=2 dp=3 :
dev:2592023-11-16 08:50:43.169debugDressing TRV processing command dp=3 fncmd=207 (lastThermostatMode=heat)
dev:2592023-11-16 08:50:43.156debugDressing TRV dp_id=2 dp=3 fncmd=207
dev:2592023-11-16 08:50:42.986infoDressing TRV heatingSetpoint is: 20.0°C
dev:2592023-11-16 08:50:42.980debugDressing TRV dp_id=2 dp=2 fncmd=200
dev:2592023-11-16 08:50:40.113debugDressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]
dev:2592023-11-16 08:50:39.328debugDressing TRV sendZigbeeCommands(cmd=[he cmd 0x0BCD 0x01 0xEF00 0x00 {000102020004000000C8} {}, delay 200])
dev:2592023-11-16 08:50:39.322debugDressing TRV sendTuyaCommand = [he cmd 0x0BCD 0x01 0xEF00 0x00 {000102020004000000C8} {}, delay 200]
dev:2592023-11-16 08:50:39.243debugDressing TRV changing setpoint to 200.0
dev:2592023-11-16 08:50:39.229debugDressing TRV sendTuyaHeatingSetpoint(20.0)
dev:2592023-11-16 08:50:39.216debug0.5 C correction of the heating setpoint20 for BEOK
dev:2592023-11-16 08:50:39.211debugDressing TRV setHeatingSetpoint temperature = 20 as int = 20 (previousSetpointt = 15.0)
dev:2592023-11-16 08:50:20.643infoDressing TRV Round-trip time is 409 (ms)
dev:2592023-11-16 08:50:20.627debugDressing TRV Tuya check-in message (attribute 0001 reported: 48)
dev:2592023-11-16 08:50:20.589infoDressing TRV InitializeVars()... fullInit = false
dev:2592023-11-16 08:50:20.577debugDressing TRV updating the settings from the current driver version 1.3.2 2023/11/15 12:33 PM to the new version 1.3.2 2023/11/16 7:41 АM
1 Like

Are you planning to test also the Immax Neo Lite TRV 07732L ?

This driver can probably handle one more different TRV manufacturer, after that it will become time to retire it and add the same models into a new, refactored driver code.

I am indeed testing the Immax. At the moment I am trying to decide between the Immax and the Avatto TR07. I am looking at behavior over a couple of weeks, and, to be honest, at the feature set that may be available in the future in the drivers, and how complete the functionality in the driver may be.

I will return the Mentor ones. I have also ordered an Avatto TR06 to test, and have something similar to the Immax on the way. It will be a process to decide. I also have a Tuya Hub on the way, as I will be returning the one that came with the Mentor.

I haven't done much coding in the past 5 years, but I have been looking at the codebase a little bit, even got the thermostatOperatingState working on my branch. I agree with you that in order to support more TRVs, there needs to be refactoring.

I even have an idea of setting up like a database of Data points, Instruction and Status Sets and using that in the code as an abstraction layer for all the functions, so no more hard-coding the scales, for example. It should also be possible to only display the available options on the page, and other things that pertain to usability. For sure, it would mean a lot of work. My understanding of how Tuya, ZigBee, Hubitat, groovy works is rudimentary, so my contributions may be limited, but I am surely happy to chime in.

Example of data structure; would need a way to standardize all the functions, and just add the data for each new mode in a separate file (if that is supported in groovy, I have some JS background)
const data = {
    "dataPoints": {
        "1":"Mode",
        "2":"Target temperature", // done
        "3":"Current temperature",// done
        "6":"Working status", // done
        "7":"Window status",
        "8":"Open window",
        "12":"Child lock",
        "13":"Battery", //done
        "14":"Fault alarm",
        "15":"Min. limit temperature",
        "16":"Max. limit temperature",
        "17":"Heating schedule",
        "18":"Week program Tuesday",
        "19":"Week program Wednesday",
        "20":"Week program Thursday",
        "21":"Week program Friday",
        "22":"Week program Saturday",
        "23":"Week program Sunday",
        "101":"Room sensor calibration",
        "108":"Valve",
        "109":"Model", // original 机型
        "110":"Motor thrust",
        "111":"Display brightness",
        "112":"Software version",
        "113":"Screen orientation",
        "114":"System mode",
        "115":"Switch deviation (energy-saving mode only)",
        "116":"Motor data" // original 电机数据
     },
     "statusSet": {
        "mode": {
            "type": "enum",
            "range": [
              "auto",
              "manual",
              "off",
              "on"
            ]
          },
        "temp_set": {
            "type": "integer",
            "unit": "℃",
            "min": 50,
            "max": 350,
            "scale": 1,
            "step": 5
        },
        "temp_current": {
            "type": "integer",
            "unit": "℃",
            "min": -100,
            "max": 500,
            "scale": 1,
            "step": 5
        },
        "work_state": {
            "type": "enum",
            "range": [
                "closed",
                "opened"
                ]
        },
        "window_state": {
            "type": "enum",
            "range": [
                "closed",
                "opened"
                ]
        },
        "window_check": {
            "type": "boolean"
        },
        "child_lock": {
            "type": "boolean"
        },
        "battery_percentage": {
            "type": "integer",
            "unit": "%",
            "min": 0,
            "max": 100,
            "scale": 0,
            "step": 1
        },
        "fault": {
            "type": "bitmap",
            "label": [
                "fault_sensor",
                "fault_motor",
                "fault_low_batt",
                "fault_ug_low_batt"
            ],
            "maxlen": 4
        },
        "lower_temp": {
            "type": "integer",
            "unit": "℃",
            "min": 50,
            "max": 150,
            "scale": 1,
            "step": 10
        },
        "upper_temp": {
            "type": "integer",
            "unit": "℃",
            "min": 200,
            "max": 350,
            "scale": 1,
            "step": 10
        },
        "week_program_13_1": {
            "type": "raw"
        },
        "week_program_13_2": {
            "type": "raw"
        },
        "week_program_13_3": {
            "type": "raw"
        },
        "week_program_13_4": {
            "type": "raw"
        },
        "week_program_13_5": {
            "type": "raw"
        },
        "week_program_13_6": {
            "type": "raw"
        },
        "week_program_13_7": {
            "type": "raw"
        },
        "temp_correction": {
            "type": "integer",
            "unit": "℃",
            "min": -100,
            "max": 100,
            "scale": 1,
            "step": 1
        },
        "valve_open_degree": {
            "type": "integer",
            "unit": "%",
            "min": 0,
            "max": 1000,
            "scale": 1,
            "step": 10
        },
        "mfg_model": {
            "type": "string",
            "maxlen": 255
        },
        "motor_thrust": {
            "type": "enum",
            "range": [
                "strong",
                "middle",
                "weak"
            ]
        },
        "brightness": {
            "type": "enum",
            "range": [
                "high",
                "mid",
                "low"
            ]
        },
        "soft_version": {
            "type": "integer",
            "unit": "",
            "min": 0,
            "max": 65536,
            "scale": 0,
            "step": 1
        },
        "screen_orientation": {
            "type": "enum",
            "range": [
                "up",
                "right",
                "down",
                "left"
            ]
        },
        "system_mode": {
            "type": "enum",
            "range": [
                "comfort_mode",
                "Eco_mode"
            ]
        },
        "switch_wrap": {
            "type": "integer",
            "unit": "℃",
            "min": 5,
            "max": 50,
            "scale": 1,
            "step": 1
        },
        "motor_data": {
            "type": "string",
            "maxlen": 255
        }
    },
    "instructionSet": {
        "mode": {
            "type": "enum",
            "range": [
                "auto",
                "manual",
                "off",
                "on"
              ]
          },
        "temp_set": {
            "type": "integer",
            "unit": "℃",
            "min": 50,
            "max": 350,
            "scale": 1,
            "step": 5
        },
        "temp_current": {
            "type": "integer",
            "unit": "℃",
            "min": -100,
            "max": 500,
            "scale": 1,
            "step": 5
        },
        "work_state": {
            "type": "enum",
            "range": [
                "closed",
                "opened"
              ]
        },
        "window_state": {
            "type": "enum",
            "range": [
                "closed",
                "opened"
                ]
        },
        "window_check": {
            "type": "boolean"
        },
        "child_lock": {
            "type": "boolean"
        },
        "battery_percentage": {
            "type": "integer",
            "unit": "%",
            "min": 0,
            "max": 100,
            "scale": 0,
            "step": 1
        },
        "fault": {
            "type": "bitmap",
            "label": [
                "fault_sensor",
                "fault_motor",
                "fault_low_batt",
                "fault_ug_low_batt"
            ],
            "maxlen": 4
        },
        "lower_temp": {
            "type": "integer",
            "unit": "℃",
            "min": 50,
            "max": 150,
            "scale": 1,
            "step": 10
        },
        "upper_temp": {
            "type": "integer",
            "unit": "℃",
            "min": 200,
            "max": 350,
            "scale": 1,
            "step": 10
        },
        "week_program_13_1": {
            "type": "raw"
        },
        "week_program_13_2": {
            "type": "raw"
        },
        "week_program_13_3": {
            "type": "raw"
        },
        "week_program_13_4": {
            "type": "raw"
        },
        "week_program_13_5": {
            "type": "raw"
        },
        "week_program_13_6": {
            "type": "raw"
        },
        "week_program_13_7": {
            "type": "raw"
        },
        "temp_correction": {
            "type": "integer",
            "unit": "℃",
            "min": -100,
            "max": 100,
            "scale": 1,
            "step": 1
        },
        "valve_open_degree": {
            "type": "integer",
            "unit": "%",
            "min": 0,
            "max": 1000,
            "scale": 1,
            "step": 10
        },
        "motor_thrust": {
            "type": "enum",
            "range": [
                "strong",
                "middle",
                "weak"
              ]
        },
        "brightness": {
            "type": "enum",
            "range": [
                "high",
                "mid",
                "low"
              ]
        },
        "screen_orientation": {
            "type": "enum",
            "range": [
                "up",
                "right",
                "down",
                "left"
              ]
        },
        "system_mode": {
            "type": "enum",
            "range": [
                "comfort_mode",
                "Eco_mode"
              ]
        },
        "switch_wrap": {
            "type": "integer",
            "unit": "℃",
            "min": 5,
            "max": 50,
            "scale": 1,
            "step": 1
        }
    }
}
1 Like

You can see an example of a similar data structure definition (I called it 'Device Profile' ) in the Tuya Multi Sensor 4 In 1 driver.

1 Like

That is what I was thinking about, you're way ahead of me :slight_smile: I imagine that if it works for the sensors, it can work for TRVs. A master driver for TRVs would be amazing for those trying to use them with Hubitat.

I ordered several models and returned several models because functionality just wasn't there, and this can be avoided. I am a new user, but why this isn't already available standard in Hubitat is beyond me given the number of Tuya devices on the market.

later edit: I really only found your driver because it got automatically selected for the Avatto, I thought it was for wall thermostats, not TRVs.

OK, let's proceed this way - I can add the the Immax Neo Lite TRV 07732L to this driver (hopefully tonight) and you can continue with the testing and fixes (like the `thermostatOperatingState fix that you already did). Then, I can merge your changes and fixes into the published driver.

I will continue the work on the new driver that uses 'Device Profiles' for the different TRVs models / manufacturers. It will work also with non-Tuya TRVs like Aqara E1 thermostat and Soniff TRVZB.

For our reference - this is a collection of ZHA 'quirks' that can be used for adding more than 70 (seventy)! different TRVs based on Tuya platform :

(your 2 TRVs are new models and not there yet!)

Tuya devices are not officially supported in most of the commercial home automation platform that I know ( SmartThings, Homey, Hubitat...), as most of them are non-standard and require reverse engineering. In all the mentioned platforms above the Tuya Zigbee devices are supported by community drivers/aps.

I don't promote it, because it is a hell to support all the different Tuya manufactures TRVS... : (

1 Like

I am new, but my feeling is that what the Tuya hub is doing the first time it pairs a device is get the instruction sets and everything from the Tuya servers, and then operate the devices locally. What we need, in reality, is a driver for Tuya itself. Or am I completely wrong?

Looks like HA is way ahead on this front.

Sounds like a great plan. 70 TRV would be amazing to have in Hubitat!
I will do some work today, but I am travelling the next few days, so I expect to do more next week.

1 Like

Thank you for the PR in GitHub, Vlad!

I have also merged my additions from yesterday (added Immax Neo Lite TRV 07732L TS0601 _TZE200_rufdtfyv as HY367) into version 1.3.4.

I have started working on the new driver that will use the Device Profile data structures, the plans for the first version is to support only Moes BRT-100, Aqara E1 Thermostat, and Sonoff TRVZB. Once I have these working, should be much easier to add the rest of the models supported in this driver and new ones.

Please keep with the PR! :+1:

2 Likes

This is how my Thermostats Dashboard looks like at the moment :

1 Like

With what app did you do this?

@kkossev I wonder, does this driver not become "big" & difficult to maintain when supporting all those devices?

I started using the inbuilt webCoRe graphs ... It is the former HubiGraph app now in webCore.

I am not planing to add more devices into this driver, as it become really difficult to maintain.
A new driver is on the way ...

1 Like

OK, is there a topic where I can follow the progress?