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

I have the Hubitat C-8 and a Sonoff USB on a Raspberry Pi with zigbee2mqtt running that I thought would be linked to the same network so I could monitor messages, but it ended up being a separate.

What do you need me to do? Get one?

Neither Sonoff, nor Zigbee2MQTT supports this TRV yet. If you have a Tuya GW, then on iot.tuya.com all the 'data points' and their meaning will be visible and the implementation in HE will be much easier.

Let's make some more trues in the next 1-2 days and we can decide then.

1 Like

Wild guess: the heatingSetpoint is multiplied by 2 when sent to the TRV (because it can be set in 0.5 deg. increments) and is divided by 10 when received .. : )

TimeStamp : 2023/11/14 11:20 PM

We are making progress, as the setPoint was actually set this time, but no matter what I set it to, 20 or 40, it gets set to 5 in the TRV.

The temperature on the other hand has started showing decimals now!
Battery remains at 0.

Current States
Current States
battery : 0
childLock : off
coolingSetpoint : 30.0
healthStatus : online
heatingSetpoint : 5.0
rtt : 0
supportedThermostatFanModes : ["auto","circulate","on"]
supportedThermostatModes : ["off","heat","auto"]
temperature : 20.8
thermostatFanMode : auto
thermostatMode : heat
thermostatOperatingState : idle
thermostatSetpoint : 5.0
State Variables
State Variables
packetID : 2
deviceProfile : TRV07
lastTx : {"isModeSetReq":true,"isSetBrightnessReq":false,"isSetPointReq":true,"mode":"heat","setBrightness":-1,"setBrightnessRetries":0,"setModeRetries":0,"setPoint":40.0,"setPointRetries":0}
lastThermostatMode : heat
lastRx : {"dp":2,"fncmd":50,"setBrightness":-1,"setPoint":5.0}
lastThermostatOperatingState : idle
stats : {"dupeCtr":21,"rxCtr":110,"txCtr":65,"txFailCtr":0}
driverVersion : 1.3.2 2023/11/14 11:20 PM
heatingSetPointRetry : 0
notPresentCounter : 0```
Logs
[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:03.362[info](http://hubitat.local/logs#)Dressing TRV heatingSetpoint is: 5.0°C

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:03.349[debug](http://hubitat.local/logs#)Dressing TRV dp_id=2 **dp=2** fncmd=50

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:03.314[debug](http://hubitat.local/logs#)Dressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.558[debug](http://hubitat.local/logs#)Dressing TRV sendZigbeeCommands(cmd=[he cmd 0x8059 0x01 0xEF00 0x00 {00020202000400000050} {}, delay 200])

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.545[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaCommand = [he cmd 0x8059 0x01 0xEF00 0x00 {00020202000400000050} {}, delay 200]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.484[debug](http://hubitat.local/logs#)Dressing TRV changing setpoint to 80.0

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.472[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaHeatingSetpoint(40.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.444[debug](http://hubitat.local/logs#)0.5 C correction of the heating setpoint40 for BEOK

[dev:255](http://hubitat.local/logs#)2023-11-15 09:03:02.433[debug](http://hubitat.local/logs#)Dressing TRV setHeatingSetpoint temperature = 40 as int = 40 (previousSetpointt = 5.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:55.675[info](http://hubitat.local/logs#)Dressing TRV heatingSetpoint is: 5.0°C

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:55.659[debug](http://hubitat.local/logs#)Dressing TRV dp_id=2 **dp=2** fncmd=50

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:55.595[debug](http://hubitat.local/logs#)Dressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.742[debug](http://hubitat.local/logs#)Dressing TRV sendZigbeeCommands(cmd=[he cmd 0x8059 0x01 0xEF00 0x00 {0001020200040000003C} {}, delay 200])

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.736[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaCommand = [he cmd 0x8059 0x01 0xEF00 0x00 {0001020200040000003C} {}, delay 200]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.685[debug](http://hubitat.local/logs#)Dressing TRV changing setpoint to 60.0

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.676[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaHeatingSetpoint(30.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.671[debug](http://hubitat.local/logs#)0.5 C correction of the heating setpoint30 for BEOK

[dev:255](http://hubitat.local/logs#)2023-11-15 09:02:54.664[debug](http://hubitat.local/logs#)Dressing TRV setHeatingSetpoint temperature = 30 as int = 30 (previousSetpointt = 5.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:29.620[info](http://hubitat.local/logs#)Dressing TRV heatingSetpoint is: 5.0°C

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:29.610[debug](http://hubitat.local/logs#)Dressing TRV dp_id=2 **dp=2** fncmd=50

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:29.531[debug](http://hubitat.local/logs#)Dressing TRV device has received Tuya cluster ZCL command 0x00 response 0x00 data = [00, 00]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:29.512[info](http://hubitat.local/logs#)Dressing TRV InitializeVars()... fullInit = false

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:29.506[debug](http://hubitat.local/logs#)Dressing TRV updating the settings from the current driver version 1.3.2 2023/11/14 9:33 PM to the new version 1.3.2 2023/11/14 11:20 PM

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.750[debug](http://hubitat.local/logs#)Dressing TRV sendZigbeeCommands(cmd=[he cmd 0x8059 0x01 0xEF00 0x00 {0010020200040000002E} {}, delay 200])

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.743[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaCommand = [he cmd 0x8059 0x01 0xEF00 0x00 {0010020200040000002E} {}, delay 200]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.650[debug](http://hubitat.local/logs#)Dressing TRV changing setpoint to 46.0

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.640[debug](http://hubitat.local/logs#)Dressing TRV sendTuyaHeatingSetpoint(23.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.626[debug](http://hubitat.local/logs#)0.5 C correction of the heating setpoint23 for BEOK

[dev:255](http://hubitat.local/logs#)2023-11-15 09:01:28.619[debug](http://hubitat.local/logs#)Dressing TRV setHeatingSetpoint temperature = 23 as int = 23 (previousSetpointt = 24.0)

[dev:255](http://hubitat.local/logs#)2023-11-15 09:00:22.144[debug](http://hubitat.local/logs#)Dressing TRV device has received Tuya cluster ZCL command 0x24 response 0x00 data = [24, 00]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:00:22.001[debug](http://hubitat.local/logs#)Dressing TRV sending time data : [he cmd 0x8059 0x01 0xEF00 0x24 {000865546C85655488A5}, delay 2000]

[dev:255](http://hubitat.local/logs#)2023-11-15 09:00:21.994[debug](http://hubitat.local/logs#)Dressing TRV timezone offset of current location is 7200000 (2 hours), current hour is 9 h

[dev:255](http://hubitat.local/logs#)2023-11-15 09:00:21.984[debug](http://hubitat.local/logs#)Dressing TRV time synchronization request from device, descMap = [raw:catchall: 0104 EF00 01 01 0040 00 8059 01 00 0000 24 01 C400, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:8059, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:24, direction:01, data:[C4, 00]]
1 Like

Good news! I just realized one of the TRV sets I am testing comes with a little round ZigBee Tuya gateway. I've successfully linked the gateway to the Tuya Smart app, and factory reset the TRV and connected it to the gateway.

Do you have a guide on how I can get you the information you need?

1 Like

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